diff --git a/core/lib/test_contracts/contracts/transfer/ERC20.sol b/core/lib/test_contracts/contracts/transfer/ERC20.sol new file mode 100644 index 000000000000..aad741e66a56 --- /dev/null +++ b/core/lib/test_contracts/contracts/transfer/ERC20.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract TestERC20 is ERC20("Test", "TEST") { + constructor(uint256 _toMint) { + _mint(msg.sender, _toMint); + } +} diff --git a/core/lib/test_contracts/src/contracts.rs b/core/lib/test_contracts/src/contracts.rs index 09a0535824df..36d758c46de2 100644 --- a/core/lib/test_contracts/src/contracts.rs +++ b/core/lib/test_contracts/src/contracts.rs @@ -171,6 +171,13 @@ impl TestContract { &CONTRACT } + /// Returns a test ERC20 token implementation. + pub fn test_erc20() -> &'static Self { + static CONTRACT: Lazy = + Lazy::new(|| TestContract::new(raw::transfer::TestERC20)); + &CONTRACT + } + /// Returns a mock version of `ContractDeployer`. pub fn mock_deployer() -> &'static Self { static CONTRACT: Lazy = diff --git a/core/tests/vm-benchmark/benches/batch.rs b/core/tests/vm-benchmark/benches/batch.rs index 608f6be6d089..f4151c39a6f8 100644 --- a/core/tests/vm-benchmark/benches/batch.rs +++ b/core/tests/vm-benchmark/benches/batch.rs @@ -18,9 +18,9 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughpu use rand::{rngs::StdRng, Rng, SeedableRng}; use vm_benchmark::{ criterion::{is_test_mode, BenchmarkGroup, BenchmarkId, CriterionExt, MeteredTime}, - get_deploy_tx_with_gas_limit, get_heavy_load_test_tx, get_load_test_deploy_tx, - get_load_test_tx, get_realistic_load_test_tx, get_transfer_tx, BenchmarkingVm, - BenchmarkingVmFactory, Bytecode, Fast, Legacy, LoadTestParams, + get_deploy_tx_with_gas_limit, get_erc20_deploy_tx, get_erc20_transfer_tx, + get_heavy_load_test_tx, get_load_test_deploy_tx, get_load_test_tx, get_realistic_load_test_tx, + get_transfer_tx, BenchmarkingVm, BenchmarkingVmFactory, Bytecode, Fast, Legacy, LoadTestParams, }; use zksync_types::Transaction; @@ -146,6 +146,12 @@ fn bench_fill_bootloader( run_vm::(&mut group, "load_test_heavy", &txs); drop(txs); + // ERC-20 token transfers + let txs = (1..=max_txs).map(get_erc20_transfer_tx); + let txs: Vec<_> = iter::once(get_erc20_deploy_tx()).chain(txs).collect(); + run_vm::(&mut group, "erc20_transfer", &txs); + drop(txs); + // Base token transfers let txs: Vec<_> = (0..max_txs).map(get_transfer_tx).collect(); run_vm::(&mut group, "transfer", &txs); diff --git a/core/tests/vm-benchmark/src/lib.rs b/core/tests/vm-benchmark/src/lib.rs index dbe2fdb808db..8f43f61b28b6 100644 --- a/core/tests/vm-benchmark/src/lib.rs +++ b/core/tests/vm-benchmark/src/lib.rs @@ -2,9 +2,9 @@ use zksync_types::Transaction; pub use crate::{ transaction::{ - get_deploy_tx, get_deploy_tx_with_gas_limit, get_heavy_load_test_tx, - get_load_test_deploy_tx, get_load_test_tx, get_realistic_load_test_tx, get_transfer_tx, - LoadTestParams, + get_deploy_tx, get_deploy_tx_with_gas_limit, get_erc20_deploy_tx, get_erc20_transfer_tx, + get_heavy_load_test_tx, get_load_test_deploy_tx, get_load_test_tx, + get_realistic_load_test_tx, get_transfer_tx, LoadTestParams, }, vm::{BenchmarkingVm, BenchmarkingVmFactory, CountInstructions, Fast, Legacy, VmLabel}, }; diff --git a/core/tests/vm-benchmark/src/transaction.rs b/core/tests/vm-benchmark/src/transaction.rs index 5c1824e6ffa2..e50f40a06ef1 100644 --- a/core/tests/vm-benchmark/src/transaction.rs +++ b/core/tests/vm-benchmark/src/transaction.rs @@ -56,6 +56,38 @@ pub fn get_transfer_tx(nonce: u32) -> Transaction { signed.into() } +pub fn get_erc20_transfer_tx(nonce: u32) -> Transaction { + let transfer_fn = TestContract::test_erc20().function("transfer"); + let calldata = transfer_fn + .encode_input(&[ + Token::Address(Address::from_low_u64_be(nonce.into())), // send tokens to unique addresses + Token::Uint(1.into()), + ]) + .unwrap(); + + let mut signed = L2Tx::new_signed( + Some(*LOAD_TEST_CONTRACT_ADDRESS), + calldata, + Nonce(nonce), + tx_fee(1_000_000), + 0.into(), // value + L2ChainId::from(270), + &PRIVATE_KEY, + vec![], // factory deps + Default::default(), // paymaster params + ) + .expect("should create a signed execute transaction"); + + signed.set_input(H256::random().as_bytes().to_vec(), H256::random()); + signed.into() +} + +pub fn get_erc20_deploy_tx() -> Transaction { + let calldata = [Token::Uint(U256::one() << 128)]; // initial token amount minted to the deployer + let execute = TestContract::test_erc20().deploy_payload(&calldata); + Account::new(PRIVATE_KEY.clone()).get_l2_tx_for_execute(execute, Some(tx_fee(500_000_000))) +} + pub fn get_load_test_deploy_tx() -> Transaction { let calldata = [Token::Uint(LOAD_TEST_MAX_READS.into())]; let execute = TestContract::load_test().deploy_payload(&calldata); diff --git a/core/tests/vm-benchmark/src/vm.rs b/core/tests/vm-benchmark/src/vm.rs index 4bd7d7eb1aa6..e69e7ca1e909 100644 --- a/core/tests/vm-benchmark/src/vm.rs +++ b/core/tests/vm-benchmark/src/vm.rs @@ -240,7 +240,9 @@ mod tests { use super::*; use crate::{ get_deploy_tx, get_heavy_load_test_tx, get_load_test_deploy_tx, get_load_test_tx, - get_realistic_load_test_tx, get_transfer_tx, LoadTestParams, BYTECODES, + get_realistic_load_test_tx, get_transfer_tx, + transaction::{get_erc20_deploy_tx, get_erc20_transfer_tx}, + LoadTestParams, BYTECODES, }; #[test] @@ -259,6 +261,18 @@ mod tests { assert_matches!(res.result, ExecutionResult::Success { .. }); } + #[test] + fn can_erc20_transfer() { + let mut vm = BenchmarkingVm::new(); + let res = vm.run_transaction(&get_erc20_deploy_tx()); + assert_matches!(res.result, ExecutionResult::Success { .. }); + + for nonce in 1..=5 { + let res = vm.run_transaction(&get_erc20_transfer_tx(nonce)); + assert_matches!(res.result, ExecutionResult::Success { .. }); + } + } + #[test] fn can_load_test() { let mut vm = BenchmarkingVm::new();