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;
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    // Sorry -- on the host, these don't do anything.
43
44    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) -> Result<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    if addr == [0u8; 20] {
81        Err(revert_len)
82    } else {
83        Ok(addr)
84    }
85}
86
87pub fn create1_slice<const REVERT_CAP: usize>(
88    code: &[u8],
89    endowment: U,
90) -> Result<Address, ([u8; REVERT_CAP], usize)> {
91    create1_partial(code, endowment).map_err(|i| {
92        let mut b = [0u8; REVERT_CAP];
93        assert!(REVERT_CAP >= i, "create1 not enough space");
94        let l = unsafe { impls::read_return_data(b.as_mut_ptr(), 0, i) };
95        (b, l)
96    })
97}
98
99#[cfg(feature = "alloc")]
100pub fn create1_vec(code: &[u8], endowment: U) -> Result<Address, Vec<u8>> {
101    create1_partial(code, endowment).map_err(|i| {
102        let mut b = Vec::with_capacity(i);
103        let l = unsafe { impls::read_return_data(b.as_mut_ptr(), 0, i) };
104        unsafe { b.set_len(l) }
105        b
106    })
107}
108
109fn create2_partial(code: &[u8], endowment: U, salt: U) -> Result<Address, usize> {
110    let mut addr = [0u8; 20];
111    let mut revert_len = 0;
112    unsafe {
113        impls::create2(
114            code.as_ptr(),
115            code.len(),
116            endowment.as_ptr(),
117            salt.as_ptr(),
118            addr.as_mut_ptr(),
119            &mut revert_len as *mut usize,
120        )
121    }
122    if addr == [0u8; 20] {
123        Err(revert_len)
124    } else {
125        Ok(addr)
126    }
127}
128
129pub fn create2_slice<const REVERT_CAP: usize>(
130    code: &[u8],
131    endowment: U,
132    salt: U,
133) -> Result<Address, ([u8; REVERT_CAP], usize)> {
134    create2_partial(code, endowment, salt).map_err(|i| {
135        let mut b = [0u8; REVERT_CAP];
136        assert!(REVERT_CAP >= i, "create2 not enough space");
137        let l = unsafe { impls::read_return_data(b.as_mut_ptr(), 0, i) };
138        (b, l)
139    })
140}
141
142#[cfg(feature = "alloc")]
143pub fn create2_vec(code: &[u8], endowment: U, salt: U) -> Result<Address, Vec<u8>> {
144    create2_partial(code, endowment, salt).map_err(|i| {
145        let mut b = Vec::with_capacity(i);
146        let l = unsafe { impls::read_return_data(b.as_mut_ptr(), 0, i) };
147        unsafe {
148            b.set_len(l);
149        }
150        b
151    })
152}
153
154pub fn create2_slice_salt_keccak256<const REVERT_CAP: usize>(
155    code: &[u8],
156    endowment: U,
157    salt: &[u8],
158) -> Result<Address, ([u8; REVERT_CAP], usize)> {
159    create2_slice::<REVERT_CAP>(code, endowment, const_keccak256(salt))
160}
161
162#[cfg(feature = "alloc")]
163pub fn create2_vec_salt_keccak256(
164    code: &[u8],
165    endowment: U,
166    salt: &[u8],
167) -> Result<Address, Vec<u8>> {
168    create2_vec(code, endowment, const_keccak256(salt))
169}