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