example_contract_deployment/
main.rs

1//! Example that deploys a contract by forging and executing a contract creation transaction.
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(
56        TxEnv::builder()
57            .kind(TxKind::Create)
58            .data(bytecode.clone())
59            .build()
60            .unwrap(),
61    )?;
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    let output = evm.transact(
72        TxEnv::builder()
73            .kind(TxKind::Call(address))
74            .data(Default::default())
75            .nonce(1)
76            .build()
77            .unwrap(),
78    )?;
79    let Some(storage0) = output
80        .state
81        .get(&address)
82        .ok_or_else(|| anyhow!("Contract not found"))?
83        .storage
84        .get::<StorageValue>(&Default::default())
85    else {
86        bail!(
87            "Failed to write storage in the init code: {:#?}",
88            output.result
89        );
90    };
91
92    println!("storage U256(0) at {address}:  {storage0:#?}");
93    assert_eq!(
94        storage0.present_value(),
95        param.try_into()?,
96        "{:#?}",
97        output.result
98    );
99    Ok(())
100}