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;
10
11pub use bobcat_maths::U;
12
13pub type Address = [u8; 20];
14
15#[cfg(target_arch = "wasm32")]
16mod impls {
17 #[link(wasm_import_module = "vm_hooks")]
18 unsafe extern "C" {
19 pub(crate) fn create1(
20 code: *const u8,
21 code_len: usize,
22 endowment: *const u8,
23 contract: *mut u8,
24 revert_data_len: *mut usize,
25 );
26
27 pub(crate) fn create2(
28 code: *const u8,
29 code_len: usize,
30 endowment: *const u8,
31 salt: *const u8,
32 contract: *mut u8,
33 revert_data_len: *mut usize,
34 );
35
36 pub(crate) fn read_return_data(dest: *mut u8, offset: usize, size: usize) -> usize;
37 }
38}
39
40#[cfg(not(target_arch = "wasm32"))]
41mod impls {
42 pub(crate) unsafe fn create1(
45 _code: *const u8,
46 _code_len: usize,
47 _endowment: *const u8,
48 _contract: *mut u8,
49 _revert_data_len: *mut usize,
50 ) {
51 }
52
53 pub(crate) unsafe fn create2(
54 _code: *const u8,
55 _code_len: usize,
56 _endowment: *const u8,
57 _salt: *const u8,
58 _contract: *mut u8,
59 _revert_data_len: *mut usize,
60 ) {
61 }
62
63 pub(crate) unsafe fn read_return_data(_dest: *mut u8, _offset: usize, _size: usize) -> usize {
64 0
65 }
66}
67
68fn create1_partial(code: &[u8], endowment: U) -> (Address, usize) {
69 let mut addr = [0u8; 20];
70 let mut revert_len = 0;
71 unsafe {
72 impls::create1(
73 code.as_ptr(),
74 code.len(),
75 endowment.as_ptr(),
76 addr.as_mut_ptr(),
77 &mut revert_len as *mut usize,
78 )
79 }
80 (addr, revert_len)
81}
82
83pub fn create1_slice<const REVERT_CAP: usize>(
84 code: &[u8],
85 endowment: U,
86) -> (Address, [u8; REVERT_CAP], usize) {
87 let (addr, i) = create1_partial(code, endowment);
88 let mut b = [0u8; REVERT_CAP];
89 let mut l = 0;
90 if addr != [0u8; 20] {
91 assert!(REVERT_CAP >= i, "create1 not enough space");
92 l = unsafe { impls::read_return_data(b.as_mut_ptr(), 0, i) };
93 }
94 (addr, b, l)
95}
96
97pub fn create1_slice_res<const REVERT_CAP: usize>(
98 code: &[u8],
99 endowment: U,
100) -> Result<Address, ([u8; REVERT_CAP], usize)> {
101 let (addr, b, l) = create1_slice(code, endowment);
102 if addr != [0u8; 20] {
103 Ok(addr)
104 } else {
105 Err((b, l))
106 }
107}
108
109#[cfg(feature = "alloc")]
110pub fn create1_vec(code: &[u8], endowment: U) -> Result<Address, Vec<u8>> {
111 let (addr, i) = create1_partial(code, endowment);
112 if addr != [0u8; 20] {
113 Ok(addr)
114 } else {
115 let mut b = Vec::with_capacity(i);
116 let l = unsafe { impls::read_return_data(b.as_mut_ptr(), 0, i) };
117 unsafe { b.set_len(l) }
118 Err(b)
119 }
120}
121
122fn create2_partial(code: &[u8], endowment: U, salt: U) -> Result<Address, usize> {
123 let mut addr = [0u8; 20];
124 let mut revert_len = 0;
125 unsafe {
126 impls::create2(
127 code.as_ptr(),
128 code.len(),
129 endowment.as_ptr(),
130 salt.as_ptr(),
131 addr.as_mut_ptr(),
132 &mut revert_len as *mut usize,
133 )
134 }
135 if addr == [0u8; 20] {
136 Err(revert_len)
137 } else {
138 Ok(addr)
139 }
140}
141
142pub fn create2_slice<const REVERT_CAP: usize>(
143 code: &[u8],
144 endowment: U,
145 salt: U,
146) -> Result<Address, ([u8; REVERT_CAP], usize)> {
147 create2_partial(code, endowment, salt).map_err(|i| {
148 let mut b = [0u8; REVERT_CAP];
149 assert!(REVERT_CAP >= i, "create2 not enough space");
150 let l = unsafe { impls::read_return_data(b.as_mut_ptr(), 0, i) };
151 (b, l)
152 })
153}
154
155#[cfg(feature = "alloc")]
156pub fn create2_vec(code: &[u8], endowment: U, salt: U) -> Result<Address, Vec<u8>> {
157 create2_partial(code, endowment, salt).map_err(|i| {
158 let mut b = Vec::with_capacity(i);
159 let l = unsafe { impls::read_return_data(b.as_mut_ptr(), 0, i) };
160 unsafe {
161 b.set_len(l);
162 }
163 b
164 })
165}
166
167pub fn create2_slice_salt_keccak256<const REVERT_CAP: usize>(
168 code: &[u8],
169 endowment: U,
170 salt: &[u8],
171) -> Result<Address, ([u8; REVERT_CAP], usize)> {
172 create2_slice::<REVERT_CAP>(code, endowment, const_keccak256(salt))
173}
174
175#[cfg(feature = "alloc")]
176pub fn create2_vec_salt_keccak256(
177 code: &[u8],
178 endowment: U,
179 salt: &[u8],
180) -> Result<Address, Vec<u8>> {
181 create2_vec(code, endowment, const_keccak256(salt))
182}