use alloc::vec::Vec;
use alloy_primitives::{Address, B256, U256};
use stylus_core::Host;
use crate::call::CachePolicy;
#[allow(unused_imports)]
#[cfg(feature = "reentrant")]
use crate::storage::StorageCache;
#[derive(Clone, Default)]
#[must_use]
pub struct RawDeploy {
salt: Option<B256>,
#[allow(unused)]
cache_policy: CachePolicy,
}
impl RawDeploy {
pub fn new() -> Self {
Default::default()
}
pub fn salt(mut self, salt: B256) -> Self {
self.salt = Some(salt);
self
}
pub fn salt_option(mut self, salt: Option<B256>) -> Self {
self.salt = salt;
self
}
#[cfg(feature = "reentrant")]
pub fn flush_storage_cache(mut self) -> Self {
self.cache_policy = self.cache_policy.max(CachePolicy::Flush);
self
}
#[cfg(feature = "reentrant")]
pub fn clear_storage_cache(mut self) -> Self {
self.cache_policy = CachePolicy::Clear;
self
}
pub unsafe fn deploy(
self,
host: &impl Host,
code: &[u8],
endowment: U256,
) -> Result<Address, Vec<u8>> {
#[cfg(feature = "reentrant")]
match self.cache_policy {
CachePolicy::Clear => host.flush_cache(true),
CachePolicy::Flush => host.flush_cache(false),
CachePolicy::DoNothing => {}
}
let mut contract = Address::default();
let mut revert_data_len: usize = 0;
let endowment: B256 = endowment.into();
if let Some(salt) = self.salt {
host.create2(
code.as_ptr(),
code.len(),
endowment.as_ptr(),
salt.as_ptr(),
contract.as_mut_ptr(),
&mut revert_data_len as *mut _,
);
} else {
host.create1(
code.as_ptr(),
code.len(),
endowment.as_ptr(),
contract.as_mut_ptr(),
&mut revert_data_len as *mut _,
);
}
if contract.is_zero() {
return Err(host.read_return_data(0, None));
}
Ok(contract)
}
}
#[cfg(test)]
mod test {
use alloy_primitives::{Address, U256};
use stylus_test::TestVM;
use super::*;
#[test]
fn test_deploy() {
let vm = TestVM::new();
let code = vec![0x60, 0x80, 0x60, 0x40];
let salt = B256::with_last_byte(1);
let deployed_address = Address::from([2u8; 20]);
vm.mock_deploy(code.clone(), Some(salt), Ok(deployed_address));
let deployer = RawDeploy::new().salt(salt);
let result = unsafe { deployer.deploy(&vm, &code, U256::ZERO).unwrap() };
assert_eq!(result, deployed_address);
}
}