Skip to content

Commit

Permalink
feat: Add paymaster parameters to broadcasting flow (#596)
Browse files Browse the repository at this point in the history
* Return actual gas used from zkvm transactions

* Remove debug print

* add paymaster to broadcasting

* Clippy improvement and add fork to cargo deny

* Update gas_params function to take into account paymaster, improve testing

* explicit check of paymaster

* extract variable is_paymaster_used

* Update crates/zksync/core/src/vm/runner.rs

Co-authored-by: Nisheeth Barthwal <nbaztec@gmail.com>

* change variable name

---------

Co-authored-by: elfedy <federico@moonsonglabs.com>
Co-authored-by: Nisheeth Barthwal <nbaztec@gmail.com>
  • Loading branch information
3 people authored Oct 4, 2024
1 parent cc27c50 commit dbb13e7
Show file tree
Hide file tree
Showing 12 changed files with 89 additions and 32 deletions.
14 changes: 8 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ alloy-trie = "0.4.1"

## zksync
era_test_node = { git="https://github.com/matter-labs/era-test-node.git" , rev = "2041018903aa7e00e74c450f8c0baf799c056d86" }
zksync-web3-rs = {git = "https://github.com/lambdaclass/zksync-web3-rs.git", rev = "2da644f5b8fc48a129e80fe0653e5334701c059b"}
zksync-web3-rs = {git = "https://github.com/jrigada/zksync-web3-rs.git", rev = "bc3e6d3e75b7ff3747ff2dccefa9fb74d770931b"}
zksync_basic_types = { git = "https://github.com/matter-labs/zksync-era.git", rev = "0d51cd6f3e65eef1bda981fe96f3026d8e12156d" }
zksync_types = { git = "https://github.com/matter-labs/zksync-era.git", rev = "0d51cd6f3e65eef1bda981fe96f3026d8e12156d" }
zksync_state = { git = "https://github.com/matter-labs/zksync-era.git", rev = "0d51cd6f3e65eef1bda981fe96f3026d8e12156d" }
Expand Down
1 change: 1 addition & 0 deletions crates/cheatcodes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ foundry-evm-core.workspace = true
foundry-wallets.workspace = true
foundry-zksync-core.workspace = true
foundry-zksync-compiler.workspace = true
zksync-web3-rs.workspace = true

zksync_types.workspace = true

Expand Down
32 changes: 27 additions & 5 deletions crates/cheatcodes/src/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use foundry_evm_core::{
};
use foundry_zksync_compiler::{DualCompiledContract, DualCompiledContracts};
use foundry_zksync_core::{
convert::{ConvertH160, ConvertH256, ConvertRU256, ConvertU256},
convert::{ConvertAddress, ConvertH160, ConvertH256, ConvertRU256, ConvertU256},
get_account_code_key, get_balance_key, get_nonce_key, Call, ZkPaymasterData,
ZkTransactionMetadata, DEFAULT_CREATE2_DEPLOYER_ZKSYNC,
};
Expand Down Expand Up @@ -69,6 +69,7 @@ use zksync_types::{
H256, KNOWN_CODES_STORAGE_ADDRESS, L2_BASE_TOKEN_ADDRESS, NONCE_HOLDER_ADDRESS,
SYSTEM_CONTEXT_ADDRESS,
};
use zksync_web3_rs::eip712::PaymasterParams;

mod utils;

Expand Down Expand Up @@ -842,6 +843,11 @@ impl Cheatcodes {
None
};
let rpc = ecx_inner.db.active_fork_url();
let paymaster_params =
self.paymaster_params.clone().map(|paymaster_data| PaymasterParams {
paymaster: paymaster_data.address.to_h160(),
paymaster_input: paymaster_data.input.to_vec(),
});
if let Some(factory_deps) = zk_tx {
let mut batched =
foundry_zksync_core::vm::batch_factory_dependencies(factory_deps);
Expand All @@ -859,7 +865,10 @@ impl Cheatcodes {
nonce: Some(nonce),
..Default::default()
},
zk_tx: Some(ZkTransactionMetadata { factory_deps }),
zk_tx: Some(ZkTransactionMetadata {
factory_deps,
paymaster_data: paymaster_params.clone(),
}),
});

//update nonce for each tx
Expand All @@ -881,7 +890,9 @@ impl Cheatcodes {
},
..Default::default()
},
zk_tx: zk_tx.map(ZkTransactionMetadata::new),
zk_tx: zk_tx.map(|factory_deps| {
ZkTransactionMetadata::new(factory_deps, paymaster_params)
}),
});

input.log_debug(self, &input.scheme().unwrap_or(CreateScheme::Create));
Expand Down Expand Up @@ -1428,11 +1439,22 @@ impl Cheatcodes {
ecx_inner.journaled_state.state().get_mut(&broadcast.new_origin).unwrap();

let zk_tx = if self.use_zk_vm {
let paymaster_params =
self.paymaster_params.clone().map(|paymaster_data| PaymasterParams {
paymaster: paymaster_data.address.to_h160(),
paymaster_input: paymaster_data.input.to_vec(),
});
// We shouldn't need factory_deps for CALLs
if call.target_address == DEFAULT_CREATE2_DEPLOYER_ZKSYNC {
Some(ZkTransactionMetadata { factory_deps: factory_deps.clone() })
Some(ZkTransactionMetadata {
factory_deps: factory_deps.clone(),
paymaster_data: paymaster_params,
})
} else {
Some(ZkTransactionMetadata { factory_deps: Default::default() })
Some(ZkTransactionMetadata {
factory_deps: Default::default(),
paymaster_data: paymaster_params,
})
}
} else {
None
Expand Down
12 changes: 9 additions & 3 deletions crates/forge/tests/fixtures/zk/Paymaster.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ contract TestPaymasterFlow is Test {
bob = makeAddr("Bob");
do_stuff = new DoStuff();
paymaster = new MyPaymaster();

// A small amount is needed for initial tx processing
vm.deal(alice, 1 ether);
vm.deal(address(paymaster), 10 ether);

// Encode paymaster input
Expand All @@ -29,6 +26,7 @@ contract TestPaymasterFlow is Test {
function testCallWithPaymaster() public {
vm.deal(address(do_stuff), 1 ether);
require(address(do_stuff).balance == 1 ether, "Balance is not 1 ether");
require(address(alice).balance == 0, "Balance is not 0 ether");

uint256 alice_balance = address(alice).balance;
(bool success,) = address(vm).call(
Expand Down Expand Up @@ -71,6 +69,14 @@ contract TestPaymasterFlow is Test {
require(address(alice).balance == alice_balance, "Balance is not the same");
require(address(paymaster).balance < paymaster_balance, "Paymaster balance is not less");
}

function testFailTransactionFailsWhenNotUsingPaymaster() public {
vm.deal(address(do_stuff), 1 ether);
require(address(alice).balance == 0, "Balance is not 0 ether");
vm.prank(alice, alice);

do_stuff.do_stuff(bob);
}
}

contract DoStuff {
Expand Down
6 changes: 5 additions & 1 deletion crates/script/src/broadcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ async fn convert_to_zksync(
tx: WithOtherFields<TransactionRequest>,
zk: &ZkTransaction,
) -> Result<(Eip712TransactionRequest, Eip712Transaction)> {
let custom_data = Eip712Meta::new().factory_deps(zk.factory_deps.clone());
let mut custom_data = Eip712Meta::new().factory_deps(zk.factory_deps.clone());

if let Some(paymaster_params) = &zk.paymaster_data {
custom_data = custom_data.paymaster_params(paymaster_params.clone());
}

let gas_price = match tx.gas_price() {
Some(price) => price,
Expand Down
11 changes: 8 additions & 3 deletions crates/script/src/simulate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,10 @@ impl PreSimulationState {
&self.execution_artifacts.decoder,
created_contracts,
is_fixed_gas_limit,
zk.map(|zk_tx| ZkTransaction { factory_deps: zk_tx.factory_deps }),
zk.map(|zk_tx| ZkTransaction {
factory_deps: zk_tx.factory_deps,
paymaster_data: zk_tx.paymaster_data,
}),
)?;

eyre::Ok((Some(tx), result.traces))
Expand Down Expand Up @@ -228,8 +231,10 @@ impl PreSimulationState {
.into_iter()
.map(|btx| {
let mut tx = TransactionWithMetadata::from_tx_request(btx.transaction);
tx.zk =
btx.zk_tx.map(|metadata| ZkTransaction { factory_deps: metadata.factory_deps });
tx.zk = btx.zk_tx.map(|metadata| ZkTransaction {
factory_deps: metadata.factory_deps,
paymaster_data: metadata.paymaster_data,
});
tx.rpc = btx.rpc.expect("missing broadcastable tx rpc url");
tx
})
Expand Down
2 changes: 2 additions & 0 deletions crates/script/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use itertools::Itertools;
use revm_inspectors::tracing::types::CallKind;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use zksync_web3_rs::eip712::PaymasterParams;

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
Expand All @@ -24,6 +25,7 @@ pub struct AdditionalContract {
#[serde(rename_all = "camelCase")]
pub struct ZkTransaction {
pub factory_deps: Vec<Vec<u8>>,
pub paymaster_data: Option<PaymasterParams>,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
Expand Down
8 changes: 5 additions & 3 deletions crates/zksync/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub use zksync_types::{
};
pub use zksync_utils::bytecode::hash_bytecode;
use zksync_web3_rs::{
eip712::{Eip712Meta, Eip712Transaction, Eip712TransactionRequest},
eip712::{Eip712Meta, Eip712Transaction, Eip712TransactionRequest, PaymasterParams},
zks_provider::types::Fee,
zks_utils::EIP712_TX_TYPE,
};
Expand Down Expand Up @@ -88,12 +88,14 @@ pub struct ZkPaymasterData {
pub struct ZkTransactionMetadata {
/// Factory Deps for ZK transactions.
pub factory_deps: Vec<Vec<u8>>,
/// Paymaster data for ZK transactions.
pub paymaster_data: Option<PaymasterParams>,
}

impl ZkTransactionMetadata {
/// Create a new [`ZkTransactionMetadata`] with the given factory deps
pub fn new(factory_deps: Vec<Vec<u8>>) -> Self {
Self { factory_deps }
pub fn new(factory_deps: Vec<Vec<u8>>, paymaster_data: Option<PaymasterParams>) -> Self {
Self { factory_deps, paymaster_data }
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/zksync/core/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ pub fn fix_l2_gas_limit(
value: U256,
balance: U256,
) -> U256 {
let gas_limit = if gas_price.is_zero() {
let gas_limit = if gas_price.is_zero() || balance <= value {
proposed_gas_limit
} else {
let max_gas_limit = balance.saturating_sub(value).div_mod(gas_price).0;
Expand Down
30 changes: 21 additions & 9 deletions crates/zksync/core/src/vm/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ where
TransactTo::Create => (CONTRACT_DEPLOYER_ADDRESS, true),
};

let (gas_limit, max_fee_per_gas) = gas_params(&mut ecx, caller);
let (gas_limit, max_fee_per_gas) = gas_params(&mut ecx, caller, &PaymasterParams::default());
debug!(?gas_limit, ?max_fee_per_gas, "tx gas parameters");
let tx = L2Tx::new(
transact_to,
Expand Down Expand Up @@ -134,9 +134,6 @@ where
let calldata = encode_create_params(&call.scheme, contract.zk_bytecode_hash, constructor_input);
let nonce = ZKVMData::new(ecx).get_tx_nonce(caller);

let (gas_limit, max_fee_per_gas) = gas_params(ecx, caller);
info!(?gas_limit, ?max_fee_per_gas, "tx gas parameters");

let paymaster_params = if let Some(paymaster_data) = &ccx.paymaster_data {
PaymasterParams {
paymaster: paymaster_data.address.to_h160(),
Expand All @@ -146,6 +143,9 @@ where
PaymasterParams::default()
};

let (gas_limit, max_fee_per_gas) = gas_params(ecx, caller, &paymaster_params);
info!(?gas_limit, ?max_fee_per_gas, "tx gas parameters");

let tx = L2Tx::new(
CONTRACT_DEPLOYER_ADDRESS,
calldata,
Expand Down Expand Up @@ -193,9 +193,6 @@ where
let caller = ecx.env.tx.caller;
let nonce: zksync_types::Nonce = ZKVMData::new(ecx).get_tx_nonce(caller);

let (gas_limit, max_fee_per_gas) = gas_params(ecx, caller);
info!(?gas_limit, ?max_fee_per_gas, "tx gas parameters");

let paymaster_params = if let Some(paymaster_data) = &ccx.paymaster_data {
PaymasterParams {
paymaster: paymaster_data.address.to_h160(),
Expand All @@ -205,6 +202,9 @@ where
PaymasterParams::default()
};

let (gas_limit, max_fee_per_gas) = gas_params(ecx, caller, &paymaster_params);
info!(?gas_limit, ?max_fee_per_gas, "tx gas parameters");

let tx = L2Tx::new(
call.bytecode_address.to_h160(),
call.input.to_vec(),
Expand Down Expand Up @@ -248,7 +248,11 @@ where
}

/// Assign gas parameters that satisfy zkSync's fee model.
fn gas_params<DB>(ecx: &mut EvmContext<DB>, caller: Address) -> (U256, U256)
fn gas_params<DB>(
ecx: &mut EvmContext<DB>,
caller: Address,
paymaster_params: &PaymasterParams,
) -> (U256, U256)
where
DB: Database,
<DB as Database>::Error: Debug,
Expand All @@ -259,7 +263,15 @@ where
error!("balance is 0 for {caller:?}, transaction will fail");
}
let max_fee_per_gas = fix_l2_gas_price(ecx.env.tx.gas_price.to_u256());
let gas_limit = fix_l2_gas_limit(ecx.env.tx.gas_limit.into(), max_fee_per_gas, value, balance);

let use_paymaster = !paymaster_params.paymaster.is_zero();

// We check if the paymaster is set, if it is not set, we use the proposed gas limit
let gas_limit = if use_paymaster {
ecx.env.tx.gas_limit.into()
} else {
fix_l2_gas_limit(ecx.env.tx.gas_limit.into(), max_fee_per_gas, value, balance)
};

(gas_limit, max_fee_per_gas)
}
Expand Down
1 change: 1 addition & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ allow-git = [
"https://github.com/Moonsong-Labs/foundry-zksync-fork-db",
"https://github.com/Moonsong-Labs/block-explorers",
"https://github.com/RustCrypto/hashes",
"https://github.com/jrigada/zksync-web3-rs.git",
]

[sources.allow-org]
Expand Down

0 comments on commit dbb13e7

Please sign in to comment.