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