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"))]
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(all(target_family = "wasm", target_os = "unknown")))]
43mod impls {
44 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
214pub 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
241pub fn estimate_addr_pre(factory: Address, initcode_pre: &[u8], salt_pre: &[u8]) -> Address {
243 estimate_addr(factory, keccak256(initcode_pre), keccak256(salt_pre))
244}