use alloy_primitives::{address, Address, Bytes, TxKind, U256};
use alloy_sol_types::SolCall;
use mega_evm::{
constants,
revm::context::result::ExecutionResult,
sandbox::tests::{CREATE2_FACTORY_DEPLOYER, CREATE2_FACTORY_TX},
test_utils::MemoryDatabase,
EvmTxRuntimeLimits, IKeylessDeploy, MegaContext, MegaEvm, MegaHaltReason, MegaSpecId,
MegaTransaction, TestExternalEnvs, KEYLESS_DEPLOY_ADDRESS,
};
use revm::{context::TxEnv, handler::EvmTr, inspector::NoOpInspector};
const TEST_CALLER: Address = address!("0000000000000000000000000000000000100000");
const LARGE_GAS_LIMIT_OVERRIDE: u64 = 10_000_000_000;
fn execute_keyless_deploy(
spec: MegaSpecId,
db: &mut MemoryDatabase,
tx_bytes: Bytes,
gas_limit_override: u64,
) -> (ExecutionResult<MegaHaltReason>, u64) {
let call_data = IKeylessDeploy::keylessDeployCall {
keylessDeploymentTransaction: tx_bytes,
gasLimitOverride: U256::from(gas_limit_override),
}
.abi_encode();
let external_envs = TestExternalEnvs::<std::convert::Infallible>::new();
let mut context = MegaContext::new(db, spec).with_external_envs((&external_envs).into());
context.modify_chain(|chain| {
chain.operator_fee_scalar = Some(U256::from(0));
chain.operator_fee_constant = Some(U256::from(0));
});
let tx = TxEnv {
caller: TEST_CALLER,
kind: TxKind::Call(KEYLESS_DEPLOY_ADDRESS),
data: call_data.into(),
value: U256::ZERO,
gas_limit: 1_000_000_000_000,
gas_price: 0,
..Default::default()
};
let mut tx = MegaTransaction::new(tx);
tx.enveloped_tx = Some(Bytes::new());
let mut evm = MegaEvm::new(context).with_inspector(NoOpInspector);
let result_envelope = alloy_evm::Evm::transact_raw(&mut evm, tx).unwrap();
let result = result_envelope.result;
let compute_gas_used = evm.ctx_ref().additional_limit.borrow().get_usage().compute_gas;
(result, compute_gas_used)
}
#[test]
fn test_rex3_keyless_deploy_records_compute_gas() {
let mut db = MemoryDatabase::default();
db.set_account_balance(CREATE2_FACTORY_DEPLOYER, U256::from(1_000_000_000_000_000_000_000u128));
let (result, compute_gas_used) = execute_keyless_deploy(
MegaSpecId::REX3,
&mut db,
Bytes::from_static(CREATE2_FACTORY_TX),
LARGE_GAS_LIMIT_OVERRIDE,
);
assert!(result.is_success(), "Transaction should succeed, got: {:?}", result);
assert!(
compute_gas_used >= constants::rex2::KEYLESS_DEPLOY_OVERHEAD_GAS,
"Rex3 compute gas ({}) should include keyless deploy overhead ({})",
compute_gas_used,
constants::rex2::KEYLESS_DEPLOY_OVERHEAD_GAS,
);
}
#[test]
fn test_rex2_keyless_deploy_does_not_record_compute_gas() {
let mut db = MemoryDatabase::default();
db.set_account_balance(CREATE2_FACTORY_DEPLOYER, U256::from(1_000_000_000_000_000_000_000u128));
let (result, compute_gas_used) = execute_keyless_deploy(
MegaSpecId::REX2,
&mut db,
Bytes::from_static(CREATE2_FACTORY_TX),
LARGE_GAS_LIMIT_OVERRIDE,
);
assert!(result.is_success(), "Transaction should succeed, got: {:?}", result);
assert!(
compute_gas_used < constants::rex2::KEYLESS_DEPLOY_OVERHEAD_GAS,
"Rex2 compute gas ({}) should NOT include keyless deploy overhead ({})",
compute_gas_used,
constants::rex2::KEYLESS_DEPLOY_OVERHEAD_GAS,
);
}
#[test]
fn test_rex3_keyless_deploy_exceeds_compute_gas_limit() {
let mut db = MemoryDatabase::default();
db.set_account_balance(CREATE2_FACTORY_DEPLOYER, U256::from(1_000_000_000_000_000_000_000u128));
let call_data = IKeylessDeploy::keylessDeployCall {
keylessDeploymentTransaction: Bytes::from_static(CREATE2_FACTORY_TX),
gasLimitOverride: U256::from(LARGE_GAS_LIMIT_OVERRIDE),
}
.abi_encode();
let external_envs = TestExternalEnvs::<std::convert::Infallible>::new();
let mut context =
MegaContext::new(&mut db, MegaSpecId::REX3).with_external_envs((&external_envs).into());
context.modify_chain(|chain| {
chain.operator_fee_scalar = Some(U256::from(0));
chain.operator_fee_constant = Some(U256::from(0));
});
let tx = TxEnv {
caller: TEST_CALLER,
kind: TxKind::Call(KEYLESS_DEPLOY_ADDRESS),
data: call_data.into(),
value: U256::ZERO,
gas_limit: 1_000_000_000_000,
gas_price: 0,
..Default::default()
};
let mut tx = MegaTransaction::new(tx);
tx.enveloped_tx = Some(Bytes::new());
let runtime_limits =
EvmTxRuntimeLimits::from_spec(MegaSpecId::REX3).with_tx_compute_gas_limit(50_000);
let mut evm =
MegaEvm::new(context).with_tx_runtime_limits(runtime_limits).with_inspector(NoOpInspector);
let result_envelope = alloy_evm::Evm::transact_raw(&mut evm, tx).unwrap();
let result = result_envelope.result;
assert!(
!result.is_success(),
"Keyless deploy should fail when compute gas limit ({}) is below overhead ({})",
50_000,
constants::rex2::KEYLESS_DEPLOY_OVERHEAD_GAS,
);
}