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