Skip to content

Commit bd30901

Browse files
committed
do the precompile the easy way
1 parent d664121 commit bd30901

3 files changed

Lines changed: 88 additions & 29 deletions

File tree

Cargo.lock

Lines changed: 8 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ev-precompiles/src/mint.rs

Lines changed: 80 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ use alloy::{sol, sol_types::SolInterface};
44
use alloy_evm::{
55
precompiles::{Precompile, PrecompileInput},
66
revm::precompile::{PrecompileError, PrecompileId, PrecompileResult},
7+
EvmInternals, EvmInternalsError,
78
};
8-
use alloy_primitives::{address, Address, Bytes};
9+
use alloy_primitives::{address, Address, Bytes, U256};
910
use revm::precompile::PrecompileOutput;
1011
use std::sync::OnceLock;
1112

@@ -20,9 +21,9 @@ pub const MINT_PRECOMPILE_ADDR: Address = address!("0x00000000000000000000000000
2021

2122
/// A custom precompile that mints the native token
2223
#[derive(Clone, Debug, Default)]
23-
pub struct MintPrecompile{
24+
pub struct MintPrecompile {
2425
admin: Address,
25-
};
26+
}
2627

2728
impl MintPrecompile {
2829
// Use a lazily-initialized static for the ID since `custom` is not const.
@@ -31,17 +32,67 @@ impl MintPrecompile {
3132
ID.get_or_init(|| PrecompileId::custom("native_mint"))
3233
}
3334

34-
pub fn new(admin:Address ) -> Self {
35-
Self {
36-
admin,
37-
}
35+
pub fn new(admin: Address) -> Self {
36+
Self { admin }
3837
}
3938

40-
41-
4239
fn is_authorized(&self, caller: Address) -> bool {
4340
caller == self.admin
4441
}
42+
43+
fn map_internals_error(err: EvmInternalsError) -> PrecompileError {
44+
PrecompileError::Other(err.to_string())
45+
}
46+
47+
fn ensure_account_created(
48+
internals: &mut EvmInternals<'_>,
49+
addr: Address,
50+
) -> Result<(), PrecompileError> {
51+
let mut account = internals
52+
.load_account(addr)
53+
.map_err(Self::map_internals_error)?;
54+
55+
if account.is_loaded_as_not_existing() {
56+
account.mark_created();
57+
internals.touch_account(addr);
58+
}
59+
60+
Ok(())
61+
}
62+
63+
fn add_balance(
64+
internals: &mut EvmInternals<'_>,
65+
addr: Address,
66+
amount: U256,
67+
) -> Result<(), PrecompileError> {
68+
let mut account = internals
69+
.load_account(addr)
70+
.map_err(Self::map_internals_error)?;
71+
let new_balance = account
72+
.info
73+
.balance
74+
.checked_add(amount)
75+
.ok_or_else(|| PrecompileError::Other("balance overflow".to_string()))?;
76+
account.info.set_balance(new_balance);
77+
Ok(())
78+
}
79+
80+
fn sub_balance(
81+
internals: &mut EvmInternals<'_>,
82+
addr: Address,
83+
amount: U256,
84+
) -> Result<(), PrecompileError> {
85+
let mut account = internals
86+
.load_account(addr)
87+
.map_err(Self::map_internals_error)?;
88+
let new_balance = account
89+
.info
90+
.balance
91+
.checked_sub(amount)
92+
.ok_or_else(|| PrecompileError::Other("insufficient balance".to_string()))?;
93+
account.info.set_balance(new_balance);
94+
Ok(())
95+
}
4596
}
4697

4798
impl Precompile for MintPrecompile {
@@ -50,30 +101,44 @@ impl Precompile for MintPrecompile {
50101
}
51102

52103
/// Execute the precompile with the given input data, gas limit, and caller address.
53-
fn call(&self, input: PrecompileInput<'_>) -> PrecompileResult {
104+
fn call(&self, mut input: PrecompileInput<'_>) -> PrecompileResult {
54105
let caller: Address = input.caller;
55106

56107
// Enforce access control.
57108
if !self.is_authorized(caller) {
58109
return Err(PrecompileError::Other("unauthorized caller".to_string()));
59110
}
111+
let gas_limit = input.gas;
112+
60113
// 1) Decode by ABI — this inspects the 4-byte selector and picks the right variant.
61114
let decoded = match INativeToken::INativeTokenCalls::abi_decode(input.data) {
62115
Ok(v) => v,
63116
Err(e) => return Err(PrecompileError::Other(e.to_string())),
64117
};
65118

119+
let internals = input.internals_mut();
120+
66121
// 2) Dispatch to the right handler.
67122
match decoded {
68123
INativeToken::INativeTokenCalls::mint(call) => {
69-
// call.to, call.amount
70-
// ... do state changes / balances / checks ...
124+
let to = call.to;
125+
let amount = call.amount;
126+
127+
internals.touch_account(to);
128+
Self::ensure_account_created(internals, to)?;
129+
Self::add_balance(internals, to, amount)?;
71130

72-
Ok(PrecompileOutput::new(input.gas, Bytes::new()))
131+
Ok(PrecompileOutput::new(gas_limit, Bytes::new()))
73132
}
74133
INativeToken::INativeTokenCalls::burn(call) => {
75-
// call.from, call.amount
76-
Ok(PrecompileOutput::new(input.gas, Bytes::new()))
134+
let from = call.from;
135+
let amount = call.amount;
136+
137+
internals.touch_account(from);
138+
Self::ensure_account_created(internals, from)?;
139+
Self::sub_balance(internals, from, amount)?;
140+
141+
Ok(PrecompileOutput::new(gas_limit, Bytes::new()))
77142
}
78143
}
79144
}

crates/node/src/payload_service.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ use reth_ethereum::{
2020
use reth_payload_builder::{EthBuiltPayload, PayloadBuilderError};
2121
use reth_provider::HeaderProvider;
2222
use reth_revm::cached::CachedReads;
23-
use serde::{Deserialize, Serialize};
24-
use std::sync::Arc;
2523
use tokio::runtime::Handle;
2624
use tracing::info;
2725

0 commit comments

Comments
 (0)