example_contract_deployment/
main.rs

1//! Optimism-specific constants, types, and helpers.
2#![cfg_attr(not(test), warn(unused_crate_dependencies))]
3
4use anyhow::{anyhow, bail};
5use database::CacheDB;
6use revm::{
7    bytecode::opcode,
8    context::Context,
9    context_interface::result::{ExecutionResult, Output},
10    database_interface::EmptyDB,
11    handler::handler::EvmTr,
12    primitives::{hex, Bytes, TxKind, U256},
13    ExecuteCommitEvm, ExecuteEvm, MainBuilder, MainContext,
14};
15
16/// Load number parameter and set to storage with slot 0
17const INIT_CODE: &[u8] = &[
18    opcode::PUSH1,
19    0x01,
20    opcode::PUSH1,
21    0x17,
22    opcode::PUSH1,
23    0x1f,
24    opcode::CODECOPY,
25    opcode::PUSH0,
26    opcode::MLOAD,
27    opcode::PUSH0,
28    opcode::SSTORE,
29];
30
31/// Copy runtime bytecode to memory and return
32const RET: &[u8] = &[
33    opcode::PUSH1,
34    0x02,
35    opcode::PUSH1,
36    0x15,
37    opcode::PUSH0,
38    opcode::CODECOPY,
39    opcode::PUSH1,
40    0x02,
41    opcode::PUSH0,
42    opcode::RETURN,
43];
44
45/// Load storage from slot zero to memory
46const RUNTIME_BYTECODE: &[u8] = &[opcode::PUSH0, opcode::SLOAD];
47
48fn main() -> anyhow::Result<()> {
49    let param = 0x42;
50    let bytecode: Bytes = [INIT_CODE, RET, RUNTIME_BYTECODE, &[param]].concat().into();
51    let ctx = Context::mainnet()
52        .modify_tx_chained(|tx| {
53            tx.kind = TxKind::Create;
54            tx.data = bytecode.clone();
55        })
56        .with_db(CacheDB::<EmptyDB>::default());
57
58    let mut evm = ctx.build_mainnet();
59
60    println!("bytecode: {}", hex::encode(bytecode));
61    let ref_tx = evm.transact_commit_previous()?;
62    let ExecutionResult::Success {
63        output: Output::Create(_, Some(address)),
64        ..
65    } = ref_tx
66    else {
67        bail!("Failed to create contract: {ref_tx:#?}");
68    };
69
70    println!("Created contract at {address}");
71    evm.ctx().modify_tx(|tx| {
72        tx.kind = TxKind::Call(address);
73        tx.data = Default::default();
74        tx.nonce += 1;
75    });
76
77    let result = evm.transact_previous()?;
78    let Some(storage0) = result
79        .state
80        .get(&address)
81        .ok_or_else(|| anyhow!("Contract not found"))?
82        .storage
83        .get::<U256>(&Default::default())
84    else {
85        bail!("Failed to write storage in the init code: {result:#?}");
86    };
87
88    println!("storage U256(0) at {address}:  {storage0:#?}");
89    assert_eq!(storage0.present_value(), param.try_into()?, "{result:#?}");
90    Ok(())
91}