Skip to main content

bobcat_create/
lib.rs

1#![no_std]
2
3#[cfg(feature = "alloc")]
4extern crate alloc;
5
6#[cfg(feature = "alloc")]
7use alloc::vec::Vec;
8
9use bobcat_storage::{const_keccak256, keccak256};
10
11pub use bobcat_maths::U;
12
13type Address = [u8; 20];
14
15use bobcat_proxy::{make_minimal_proxy, make_beacon_proxy, make_beacon_sel_proxy_sel, make_upgradeable_beacon_proxy, make_multi3_proxy};
16
17use array_concat::concat_arrays;
18
19#[cfg(all(target_family = "wasm", target_os = "unknown"))]
20use bobcat_host as impls;
21
22#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
23mod impls {
24    // Sorry -- on the host, these don't do anything.
25
26    pub(crate) unsafe fn create1(
27        _code: *const u8,
28        _code_len: usize,
29        _endowment: *const u8,
30        _contract: *mut u8,
31        _revert_data_len: *mut usize,
32    ) {
33    }
34
35    pub(crate) unsafe fn create2(
36        _code: *const u8,
37        _code_len: usize,
38        _endowment: *const u8,
39        _salt: *const u8,
40        _contract: *mut u8,
41        _revert_data_len: *mut usize,
42    ) {
43    }
44
45    pub(crate) unsafe fn read_return_data(_dest: *mut u8, _offset: usize, _size: usize) -> usize {
46        0
47    }
48}
49
50pub fn create1_partial(code: &[u8], endowment: U) -> (Address, usize) {
51    let mut addr = [0u8; 20];
52    let mut revert_len = 0;
53    unsafe {
54        impls::create1(
55            code.as_ptr(),
56            code.len(),
57            endowment.as_ptr(),
58            addr.as_mut_ptr(),
59            &mut revert_len as *mut usize,
60        )
61    }
62    (addr, revert_len)
63}
64
65pub fn create1_unit(code: &[u8], endowment: U) -> Option<Address> {
66    let (addr, _) = create1_partial(code, endowment);
67    if addr == [0u8; 20] {
68        return None;
69    }
70    Some(addr)
71}
72
73pub fn create1_slice<const REVERT_CAP: usize>(
74    code: &[u8],
75    endowment: U,
76) -> (Address, [u8; REVERT_CAP], usize) {
77    let (addr, i) = create1_partial(code, endowment);
78    let mut b = [0u8; REVERT_CAP];
79    let mut l = 0;
80    if addr != [0u8; 20] {
81        assert!(REVERT_CAP >= i, "create1 not enough space");
82        l = unsafe { impls::read_return_data(b.as_mut_ptr(), 0, i) };
83    }
84    (addr, b, l)
85}
86
87pub fn create1_slice_res<const REVERT_CAP: usize>(
88    code: &[u8],
89    endowment: U,
90) -> Result<Address, ([u8; REVERT_CAP], usize)> {
91    let (addr, b, l) = create1_slice(code, endowment);
92    if addr != [0u8; 20] {
93        Ok(addr)
94    } else {
95        Err((b, l))
96    }
97}
98
99#[cfg(feature = "alloc")]
100pub fn create1_vec(code: &[u8], endowment: U) -> (Address, Option<Vec<u8>>) {
101    let (addr, rd) = create1_partial(code, endowment);
102    if addr != [0u8; 20] {
103        (addr, None)
104    } else {
105        let mut b = Vec::with_capacity(rd);
106        unsafe { impls::read_return_data(b.as_mut_ptr(), 0, rd) };
107        unsafe { b.set_len(rd) }
108        (addr, Some(b))
109    }
110}
111
112pub fn create2_partial(code: &[u8], endowment: U, salt: U) -> (Address, usize) {
113    let mut addr = [0u8; 20];
114    let mut revert_len = 0;
115    unsafe {
116        impls::create2(
117            code.as_ptr(),
118            code.len(),
119            endowment.as_ptr(),
120            salt.as_ptr(),
121            addr.as_mut_ptr(),
122            &mut revert_len as *mut usize,
123        )
124    }
125    (addr, revert_len)
126}
127
128pub fn create2_slice<const REVERT_CAP: usize>(
129    code: &[u8],
130    endowment: U,
131    salt: U,
132) -> (Address, [u8; REVERT_CAP], usize) {
133    let (addr, rd) = create2_partial(code, endowment, salt);
134    let mut b = [0u8; REVERT_CAP];
135    if addr == [0u8; 20] {
136        assert!(REVERT_CAP >= rd, "create2 not enough space");
137        unsafe { impls::read_return_data(b.as_mut_ptr(), 0, rd) };
138    }
139    (addr, b, rd)
140}
141
142pub fn create2_slice_res<const REVERT_CAP: usize>(
143    code: &[u8],
144    endowment: U,
145    salt: U,
146) -> Result<Address, ([u8; REVERT_CAP], usize)> {
147    let (addr, b, l) = create2_slice(code, endowment, salt);
148    if addr != [0u8; 20] {
149        Ok(addr)
150    } else {
151        Err((b, l))
152    }
153}
154
155pub fn create2_post_unit(code: &[u8], endowment: U, salt_digest: U) -> Option<Address> {
156    let (addr, _) = create2_partial(code, endowment, salt_digest);
157    if addr == [0u8; 20] {
158        return None;
159    }
160    Some(addr)
161}
162
163pub fn create2_pre_unit(code: &[u8], endowment: U, salt_pre: &[u8]) -> Option<Address> {
164    create2_post_unit(code, endowment, keccak256(salt_pre))
165}
166
167#[cfg(feature = "alloc")]
168pub fn create2_post_vec(code: &[u8], endowment: U, salt: U) -> (Address, Option<Vec<u8>>) {
169    let (addr, rd) = create2_partial(code, endowment, salt);
170    if addr == [0u8; 20] {
171        let mut b = Vec::with_capacity(rd);
172        unsafe { impls::read_return_data(b.as_mut_ptr(), 0, rd) };
173        unsafe {
174            b.set_len(rd);
175        }
176        return (addr, Some(b));
177    }
178    (addr, None)
179}
180
181#[cfg(feature = "alloc")]
182pub fn create2_pre_vec(code: &[u8], endowment: U, salt_pre: &[u8]) -> (Address, Option<Vec<u8>>) {
183    create2_post_vec(code, endowment, kecak256(salt_pre))
184}
185
186pub fn create2_slice_pre_keccak256<const REVERT_CAP: usize>(
187    code: &[u8],
188    endowment: U,
189    salt_pre: &[u8],
190) -> (Address, [u8; REVERT_CAP], usize) {
191    create2_slice::<REVERT_CAP>(code, endowment, const_keccak256(salt_pre))
192}
193
194#[cfg(feature = "alloc")]
195pub fn create2_vec_pre_keccak256(
196    code: &[u8],
197    endowment: U,
198    salt_pre: &[u8],
199) -> (Address, Option<Vec<u8>>) {
200    create2_post_vec(code, endowment, keccak256(salt_pre))
201}
202
203pub fn const_estimate_addr_pre(factory: Address, initcode_pre: &[u8], salt_pre: &[u8]) -> Address {
204    const_estimate_addr_post(
205        factory,
206        const_keccak256(initcode_pre),
207        const_keccak256(salt_pre),
208    )
209}
210
211/// Estimate the address of the create2 deployment.
212pub fn const_estimate_addr_post(factory: Address, initcode_digest: U, salt_digest: U) -> Address {
213    let b: [u8; 1 + 20 + 32 * 2] =
214        concat_arrays!([0xff], factory, salt_digest.0, initcode_digest.0);
215    const_keccak256(&b).into()
216}
217
218pub fn estimate_addr(factory: Address, initcode: U, salt: U) -> Address {
219    let b: [u8; 1 + 20 + 32 * 2] = concat_arrays!([0xff], factory, salt.0, initcode.0);
220    keccak256(&b).into()
221}
222
223/// Estimate the address of the create2 deployment.
224pub fn estimate_addr_pre(factory: Address, initcode_pre: &[u8], salt_pre: &[u8]) -> Address {
225    estimate_addr(factory, keccak256(initcode_pre), keccak256(salt_pre))
226}
227
228/// Deploy a bobcat-proxy minimal proxy for the implementation address provided.
229pub fn deploy_minimal_proxy_endowment(addr: Address, endowment: U) -> Address {
230    create1_unit(&make_minimal_proxy(addr), endowment).unwrap()
231}
232
233/// Deploy a bobcat-proxy beacon proxy for the beacon provided.
234pub fn deploy_beacon_proxy_endowment(beacon: Address, endowment: U) -> Address {
235    create1_unit(&make_beacon_proxy(beacon), endowment).unwrap()
236}
237
238/// Deploy an upgradeable beacon proxy for the beacon provided.
239pub fn deploy_upgradeable_beacon_proxy_endowment(beacon: Address, endowment: U) -> Address {
240    create1_unit(&make_upgradeable_beacon_proxy(beacon), endowment).unwrap()
241}
242
243/// Deploy a multi3 proxy for the implementations provided. Read
244/// bobcat-proxy for context. TLDR: we select a proxy based on the first
245/// byte in the selector.
246pub fn deploy_multi3_proxy_endowment(
247    one: Address,
248    two: Address,
249    three: Address,
250    all: Address,
251    endowment: U,
252) -> Address {
253    create1_unit(&make_multi3_proxy(one, two, three, all), endowment).unwrap()
254}
255
256/// Create a proxy that calls the selector on the beacon proxy to figure
257/// out how to delegate the calldata to.
258pub fn deploy_beacon_sel_proxy_sel_endowment(
259    sel: [u8; 4],
260    beacon: Address,
261    endowment: U,
262) -> Address {
263    create1_unit(&make_beacon_sel_proxy_sel(sel, beacon), endowment).unwrap()
264}
265
266/// Deploy a bobcat-proxy minimal proxy for the implementation address provided.
267pub fn deploy_minimal_proxy(addr: Address) -> Address {
268    deploy_minimal_proxy_endowment(addr, U::ZERO)
269}
270
271/// Deploy a bobcat-proxy beacon proxy for the beacon provided.
272pub fn deploy_beacon_proxy(beacon: Address) -> Address {
273    deploy_beacon_proxy_endowment(beacon, U::ZERO)
274}
275
276/// Deploy an upgradeable beacon proxy for the beacon provided.
277pub fn deploy_upgradeable_beacon_proxy(beacon: Address) -> Address {
278    deploy_upgradeable_beacon_proxy_endowment(beacon, U::ZERO)
279}
280
281/// Deploy a multi3 proxy for the implementations provided. Read
282/// bobcat-proxy for context. TLDR: we select a proxy based on the first
283/// byte in the selector.
284pub fn deploy_multi3_proxy(one: Address, two: Address, three: Address, all: Address) -> Address {
285    deploy_multi3_proxy_endowment(one, two, three, all, U::ZERO)
286}
287
288/// Create a proxy that calls the selector on the beacon proxy to figure
289/// out how to delegate the calldata to.
290pub fn deploy_beacon_sel_proxy_sel(sel: [u8; 4], beacon: Address) -> Address {
291    deploy_beacon_sel_proxy_sel_endowment(sel, beacon, U::ZERO)
292}
293
294/// Deploy a bobcat-proxy minimal proxy for the implementation address provided.
295pub fn deploy_minimal_proxy_create2_endowment(addr: Address, endowment: U, salt: U) -> Address {
296    create2_post_unit(&make_minimal_proxy(addr), endowment, salt).unwrap()
297}
298
299/// Deploy a bobcat-proxy beacon proxy for the beacon provided.
300pub fn deploy_beacon_proxy_create2_endowment(beacon: Address, endowment: U, salt: U) -> Address {
301    create2_post_unit(&make_beacon_proxy(beacon), endowment, salt).unwrap()
302}
303
304/// Deploy an upgradeable beacon proxy for the beacon provided.
305pub fn deploy_upgradeable_beacon_proxy_create2_endowment(
306    beacon: Address,
307    endowment: U,
308    salt: U,
309) -> Address {
310    create2_post_unit(&make_upgradeable_beacon_proxy(beacon), endowment, salt).unwrap()
311}
312
313/// Deploy a multi3 proxy for the implementations provided. Read
314/// bobcat-proxy for context. TLDR: we select a proxy based on the first
315/// byte in the selector.
316pub fn deploy_multi3_proxy_create2_endowment(
317    one: Address,
318    two: Address,
319    three: Address,
320    all: Address,
321    endowment: U,
322    salt: U,
323) -> Address {
324    create2_post_unit(&make_multi3_proxy(one, two, three, all), endowment, salt).unwrap()
325}
326
327/// Create a proxy that calls the selector on the beacon proxy to figure
328/// out how to delegate the calldata to.
329pub fn deploy_beacon_sel_proxy_sel_create2_endowment(
330    sel: [u8; 4],
331    beacon: Address,
332    endowment: U,
333    salt: U,
334) -> Address {
335    create2_post_unit(&make_beacon_sel_proxy_sel(sel, beacon), endowment, salt).unwrap()
336}
337
338/// Deploy a bobcat-proxy minimal proxy for the implementation address provided.
339pub fn deploy_minimal_proxy_create2(addr: Address, salt: U) -> Address {
340    deploy_minimal_proxy_create2_endowment(addr, U::ZERO, salt)
341}
342
343/// Deploy a bobcat-proxy beacon proxy for the beacon provided.
344pub fn deploy_beacon_proxy_create2(beacon: Address, salt: U) -> Address {
345    deploy_beacon_proxy_create2_endowment(beacon, U::ZERO, salt)
346}
347
348/// Deploy an upgradeable beacon proxy for the beacon provided.
349pub fn deploy_upgradeable_beacon_proxy_create2(beacon: Address, salt: U) -> Address {
350    deploy_upgradeable_beacon_proxy_create2_endowment(beacon, U::ZERO, salt)
351}
352
353/// Deploy a multi3 proxy for the implementations provided. Read
354/// bobcat-proxy for context. TLDR: we select a proxy based on the first
355/// byte in the selector.
356pub fn deploy_multi3_proxy_create2(
357    one: Address,
358    two: Address,
359    three: Address,
360    all: Address,
361    salt: U,
362) -> Address {
363    deploy_multi3_proxy_create2_endowment(one, two, three, all, U::ZERO, salt)
364}
365
366/// Create a proxy that calls the selector on the beacon proxy to figure
367/// out how to delegate the calldata to.
368pub fn deploy_beacon_sel_proxy_sel_create2(sel: [u8; 4], beacon: Address, salt: U) -> Address {
369    deploy_beacon_sel_proxy_sel_create2_endowment(sel, beacon, U::ZERO, salt)
370}
371/* --- create2 with a salt preimage --- */
372
373/// Deploy a bobcat-proxy minimal proxy for the implementation address provided.
374pub fn deploy_minimal_proxy_create2_pre_endowment(
375    addr: Address,
376    endowment: U,
377    salt_pre: &[u8],
378) -> Address {
379    deploy_minimal_proxy_create2_endowment(addr, endowment, keccak256(salt_pre))
380}
381
382/// Deploy a bobcat-proxy beacon proxy for the beacon provided.
383pub fn deploy_beacon_proxy_create2_pre_endowment(
384    beacon: Address,
385    endowment: U,
386    salt_pre: &[u8],
387) -> Address {
388    deploy_beacon_proxy_create2_endowment(beacon, endowment, keccak256(salt_pre))
389}
390
391/// Create a proxy that calls the selector on the beacon proxy to figure
392/// out how to delegate the calldata to.
393pub fn deploy_beacon_sel_proxy_sel_create2_pre_endowment(
394    sel: [u8; 4],
395    beacon: Address,
396    endowment: U,
397    salt_pre: &[u8],
398) -> Address {
399    deploy_beacon_sel_proxy_sel_create2_endowment(sel, beacon, endowment, keccak256(salt_pre))
400}
401
402/// Deploy an upgradeable beacon proxy for the beacon provided.
403pub fn deploy_upgradeable_beacon_proxy_create2_pre_endowment(
404    beacon: Address,
405    endowment: U,
406    salt_pre: &[u8],
407) -> Address {
408    deploy_upgradeable_beacon_proxy_create2_endowment(beacon, endowment, keccak256(salt_pre))
409}
410
411/// Deploy an upgradeable beacon proxy for the beacon provided.
412pub fn deploy_upgradeable_beacon_proxy_create2_pre(beacon: Address, salt_pre: &[u8]) -> Address {
413    deploy_upgradeable_beacon_proxy_create2_pre_endowment(beacon, U::ZERO, salt_pre)
414}
415
416/// Deploy a multi3 proxy for the implementations provided. Read
417/// bobcat-proxy for context. TLDR: we select a proxy based on the first
418/// byte in the selector.
419pub fn deploy_multi3_proxy_create2_pre_endowment(
420    one: Address,
421    two: Address,
422    three: Address,
423    all: Address,
424    endowment: U,
425    salt_pre: &[u8],
426) -> Address {
427    deploy_multi3_proxy_create2_endowment(one, two, three, all, endowment, keccak256(salt_pre))
428}
429
430
431/// Deploy a multi3 proxy for the implementations provided. Read
432/// bobcat-proxy for context. TLDR: we select a proxy based on the first
433/// byte in the selector.
434pub fn deploy_multi3_proxy_create2_pre(
435    one: Address,
436    two: Address,
437    three: Address,
438    all: Address,
439    salt_pre: &[u8],
440) -> Address {
441    deploy_multi3_proxy_create2_pre_endowment(one, two, three, all, U::ZERO, salt_pre)
442}
443
444/// Create a proxy that calls the selector on the beacon proxy to figure
445/// out how to delegate the calldata to.
446pub fn deploy_beacon_sel_proxy_sel_create2_pre(
447    sel: [u8; 4],
448    beacon: Address,
449    salt_pre: &[u8],
450) -> Address {
451    deploy_beacon_sel_proxy_sel_create2_pre_endowment(sel, beacon, U::ZERO, salt_pre)
452}