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 array_concat::concat_arrays;
16
17#[cfg(target_arch = "wasm32")]
18mod impls {
19    #[link(wasm_import_module = "vm_hooks")]
20    unsafe extern "C" {
21        pub(crate) fn create1(
22            code: *const u8,
23            code_len: usize,
24            endowment: *const u8,
25            contract: *mut u8,
26            revert_data_len: *mut usize,
27        );
28
29        pub(crate) fn create2(
30            code: *const u8,
31            code_len: usize,
32            endowment: *const u8,
33            salt: *const u8,
34            contract: *mut u8,
35            revert_data_len: *mut usize,
36        );
37
38        pub(crate) fn read_return_data(dest: *mut u8, offset: usize, size: usize) -> usize;
39    }
40}
41
42#[cfg(not(target_arch = "wasm32"))]
43mod impls {
44    // Sorry -- on the host, these don't do anything.
45
46    pub(crate) unsafe fn create1(
47        _code: *const u8,
48        _code_len: usize,
49        _endowment: *const u8,
50        _contract: *mut u8,
51        _revert_data_len: *mut usize,
52    ) {
53    }
54
55    pub(crate) unsafe fn create2(
56        _code: *const u8,
57        _code_len: usize,
58        _endowment: *const u8,
59        _salt: *const u8,
60        _contract: *mut u8,
61        _revert_data_len: *mut usize,
62    ) {
63    }
64
65    pub(crate) unsafe fn read_return_data(_dest: *mut u8, _offset: usize, _size: usize) -> usize {
66        0
67    }
68}
69
70fn create1_partial(code: &[u8], endowment: U) -> (Address, usize) {
71    let mut addr = [0u8; 20];
72    let mut revert_len = 0;
73    unsafe {
74        impls::create1(
75            code.as_ptr(),
76            code.len(),
77            endowment.as_ptr(),
78            addr.as_mut_ptr(),
79            &mut revert_len as *mut usize,
80        )
81    }
82    (addr, revert_len)
83}
84
85pub fn create1_unit(code: &[u8], endowment: U) -> Option<Address> {
86    let (addr, _) = create1_partial(code, endowment);
87    if addr == [0u8; 20] {
88        return None;
89    }
90    Some(addr)
91}
92
93pub fn create1_slice<const REVERT_CAP: usize>(
94    code: &[u8],
95    endowment: U,
96) -> (Address, [u8; REVERT_CAP], usize) {
97    let (addr, i) = create1_partial(code, endowment);
98    let mut b = [0u8; REVERT_CAP];
99    let mut l = 0;
100    if addr != [0u8; 20] {
101        assert!(REVERT_CAP >= i, "create1 not enough space");
102        l = unsafe { impls::read_return_data(b.as_mut_ptr(), 0, i) };
103    }
104    (addr, b, l)
105}
106
107pub fn create1_slice_res<const REVERT_CAP: usize>(
108    code: &[u8],
109    endowment: U,
110) -> Result<Address, ([u8; REVERT_CAP], usize)> {
111    let (addr, b, l) = create1_slice(code, endowment);
112    if addr != [0u8; 20] {
113        Ok(addr)
114    } else {
115        Err((b, l))
116    }
117}
118
119#[cfg(feature = "alloc")]
120pub fn create1_vec(code: &[u8], endowment: U) -> (Address, Option<Vec<u8>>) {
121    let (addr, rd) = create1_partial(code, endowment);
122    if addr != [0u8; 20] {
123        (addr, None)
124    } else {
125        let mut b = Vec::with_capacity(rd);
126        unsafe { impls::read_return_data(b.as_mut_ptr(), 0, rd) };
127        unsafe { b.set_len(rd) }
128        (addr, Some(b))
129    }
130}
131
132fn create2_partial(code: &[u8], endowment: U, salt: U) -> (Address, usize) {
133    let mut addr = [0u8; 20];
134    let mut revert_len = 0;
135    unsafe {
136        impls::create2(
137            code.as_ptr(),
138            code.len(),
139            endowment.as_ptr(),
140            salt.as_ptr(),
141            addr.as_mut_ptr(),
142            &mut revert_len as *mut usize,
143        )
144    }
145    (addr, revert_len)
146}
147
148pub fn create2_slice<const REVERT_CAP: usize>(
149    code: &[u8],
150    endowment: U,
151    salt: U,
152) -> (Address, [u8; REVERT_CAP], usize) {
153    let (addr, rd) = create2_partial(code, endowment, salt);
154    let mut b = [0u8; REVERT_CAP];
155    if addr == [0u8; 20] {
156        assert!(REVERT_CAP >= rd, "create2 not enough space");
157        unsafe { impls::read_return_data(b.as_mut_ptr(), 0, rd) };
158    }
159    (addr, b, rd)
160}
161
162pub fn create2_slice_res<const REVERT_CAP: usize>(
163    code: &[u8],
164    endowment: U,
165    salt: U,
166) -> Result<Address, ([u8; REVERT_CAP], usize)> {
167    let (addr, b, l) = create2_slice(code, endowment, salt);
168    if addr != [0u8; 20] {
169        Ok(addr)
170    } else {
171        Err((b, l))
172    }
173}
174
175pub fn create2_unit(code: &[u8], endowment: U, salt: U) -> Option<Address> {
176    let (addr, _) = create2_partial(code, endowment, salt);
177    if addr == [0u8; 20] {
178        return None;
179    }
180    Some(addr)
181}
182
183#[cfg(feature = "alloc")]
184pub fn create2_vec(code: &[u8], endowment: U, salt: U) -> (Address, Option<Vec<u8>>) {
185    let (addr, rd) = create2_partial(code, endowment, salt);
186    if addr == [0u8; 20] {
187        let mut b = Vec::with_capacity(rd);
188        unsafe { impls::read_return_data(b.as_mut_ptr(), 0, rd) };
189        unsafe {
190            b.set_len(rd);
191        }
192        return (addr, Some(b))
193    }
194    (addr, None)
195}
196
197pub fn create2_slice_salt_keccak256<const REVERT_CAP: usize>(
198    code: &[u8],
199    endowment: U,
200    salt_pre: &[u8],
201) -> (Address, [u8; REVERT_CAP], usize) {
202    create2_slice::<REVERT_CAP>(code, endowment, const_keccak256(salt_pre))
203}
204
205#[cfg(feature = "alloc")]
206pub fn create2_vec_salt_keccak256(
207    code: &[u8],
208    endowment: U,
209    salt_pre: &[u8],
210) -> (Address, Option<Vec<u8>>) {
211    create2_vec(code, endowment, keccak256(salt_pre))
212}
213
214/// Estimate the address of the create2 deployment.
215pub const fn const_estimate_addr_pre(
216    factory: Address,
217    initcode_pre: &[u8],
218    salt_pre: &[u8],
219) -> Address {
220    let b: [u8; 1 + 20 + 32 * 2] = concat_arrays!(
221        [0xff],
222        factory,
223        const_keccak256(salt_pre).0,
224        const_keccak256(initcode_pre).0
225    );
226    let x = const_keccak256(&b);
227    let mut b = [0u8; 20];
228    let mut i = 0;
229    while i < 20 {
230        b[i] = x.0[i + 20];
231        i += 1;
232    }
233    b
234}
235
236pub fn estimate_addr(factory: Address, initcode: U, salt: U) -> Address {
237    let b: [u8; 1 + 20 + 32 * 2] = concat_arrays!([0xff], factory, salt.0, initcode.0);
238    keccak256(&b).into()
239}
240
241/// Estimate the address of the create2 deployment.
242pub fn estimate_addr_pre(factory: Address, initcode_pre: &[u8], salt_pre: &[u8]) -> Address {
243    estimate_addr(factory, keccak256(initcode_pre), keccak256(salt_pre))
244}