From 052530b761d8fb7d9a3f84d46b06127244bf98b4 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 10 Jul 2024 12:35:53 +0200 Subject: [PATCH 01/32] added evm_setAccountNonce alias --- SUPPORTED_APIS.md | 2 +- e2e-tests/test/evm-apis.test.ts | 15 +++++++++++++++ src/namespaces/evm.rs | 15 ++++++++++++++- src/node/evm.rs | 11 ++++++++++- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/SUPPORTED_APIS.md b/SUPPORTED_APIS.md index 221ff473..44f9e38a 100644 --- a/SUPPORTED_APIS.md +++ b/SUPPORTED_APIS.md @@ -85,7 +85,7 @@ The `status` options are: | [`EVM`](#evm-namespace) | [`evm_revert`](#evm_revert) | `SUPPORTED` | Revert the state of the blockchain to a previous snapshot | | `EVM` | `evm_setAccountBalance` | `NOT IMPLEMENTED` | Sets the given account's balance to the specified WEI value | | `EVM` | `evm_setAccountCode` | `NOT IMPLEMENTED` | Sets the given account's code to the specified data | -| `EVM` | `evm_setAccountNonce` | `NOT IMPLEMENTED` | Sets the given account's nonce to the specified value | +| [`EVM`](#evm-namespace) | [`evm_setAccountNonce`](#evm_setaccountnonce) | `SUPPORTED` | Sets the given account's nonce to the specified value | | `EVM` | `evm_setAccountStorageAt` | `NOT IMPLEMENTED` | Sets the given account's storage slot to the specified data | | `EVM` | `evm_setAutomine` | `NOT IMPLEMENTED` | Enables or disables the automatic mining of new blocks with each new transaction submitted to the network | | `EVM` | `evm_setBlockGasLimit` | `NOT IMPLEMENTED` | Sets the Block Gas Limit of the network | diff --git a/e2e-tests/test/evm-apis.test.ts b/e2e-tests/test/evm-apis.test.ts index 5bdd8d70..761530a8 100644 --- a/e2e-tests/test/evm-apis.test.ts +++ b/e2e-tests/test/evm-apis.test.ts @@ -8,6 +8,21 @@ import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; const provider = getTestProvider(); +describe("evm_setAccountNonce", function () { + it("Should update the nonce of an account", async function () { + // Arrange + const userWallet = Wallet.createRandom().connect(provider); + const newNonce = 42; + + // Act + await provider.send("evm_setAccountNonce", [userWallet.address, ethers.utils.hexlify(newNonce)]); + + // Assert + const nonce = await userWallet.getNonce(); + expect(nonce).to.equal(newNonce); + }); +}); + describe("evm_mine", function () { it("Should mine one block", async function () { // Arrange diff --git a/src/namespaces/evm.rs b/src/namespaces/evm.rs index 79b95341..a420b6d2 100644 --- a/src/namespaces/evm.rs +++ b/src/namespaces/evm.rs @@ -1,5 +1,5 @@ use jsonrpc_derive::rpc; -use zksync_basic_types::U64; +use zksync_basic_types::{Address, U256, U64}; use crate::namespaces::RpcResult; @@ -15,6 +15,19 @@ pub trait EvmNamespaceT { #[rpc(name = "evm_increaseTime")] fn increase_time(&self, time_delta_seconds: u64) -> RpcResult; + /// Modifies an account's nonce by overwriting it. + /// + /// # Arguments + /// + /// * `address` - The `Address` whose nonce is to be changed + /// * `nonce` - The new nonce + /// + /// # Returns + /// + /// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation. + #[rpc(name = "evm_setAccountNonce")] + fn set_nonce(&self, address: Address, balance: U256) -> RpcResult; + /// Force a single block to be mined. /// /// Will mine an empty block (containing zero transactions) diff --git a/src/node/evm.rs b/src/node/evm.rs index 29cad6ff..af19f301 100644 --- a/src/node/evm.rs +++ b/src/node/evm.rs @@ -1,4 +1,4 @@ -use zksync_basic_types::U64; +use zksync_basic_types::{Address, U256, U64}; use zksync_web3_decl::error::Web3Error; use crate::{ @@ -20,6 +20,15 @@ impl EvmNamespa .into_boxed_future() } + fn set_nonce(&self, address: Address, balance: U256) -> RpcResult { + self.set_nonce(address, balance) + .map_err(|err| { + tracing::error!("failed setting nonce: {:?}", err); + into_jsrpc_error(Web3Error::InternalError(err)) + }) + .into_boxed_future() + } + fn evm_mine(&self) -> RpcResult { self.mine_block() .map_err(|err| { From a2d1f0d8d262c3ff690a85242b4dc6686ad961f5 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 10 Jul 2024 13:51:18 +0200 Subject: [PATCH 02/32] added anvil_setNonce alias --- e2e-tests/test/anvil-apis.test.ts | 20 ++++++++++++++++++++ src/main.rs | 6 ++++-- src/namespaces/anvil.rs | 20 ++++++++++++++++++++ src/namespaces/mod.rs | 2 ++ src/node/anvil.rs | 22 ++++++++++++++++++++++ src/node/mod.rs | 1 + 6 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 e2e-tests/test/anvil-apis.test.ts create mode 100644 src/namespaces/anvil.rs create mode 100644 src/node/anvil.rs diff --git a/e2e-tests/test/anvil-apis.test.ts b/e2e-tests/test/anvil-apis.test.ts new file mode 100644 index 00000000..39a6f1a1 --- /dev/null +++ b/e2e-tests/test/anvil-apis.test.ts @@ -0,0 +1,20 @@ +import { expect } from "chai"; +import { Wallet } from "zksync-web3"; +import { getTestProvider } from "../helpers/utils"; + +const provider = getTestProvider(); + +describe("anvil_setNonce", function () { + it("Should update the nonce of an account", async function () { + // Arrange + const userWallet = Wallet.createRandom().connect(provider); + const newNonce = 42; + + // Act + await provider.send("anvil_setNonce", [userWallet.address, ethers.utils.hexlify(newNonce)]); + + // Assert + const nonce = await userWallet.getNonce(); + expect(nonce).to.equal(newNonce); + }); +}); diff --git a/src/main.rs b/src/main.rs index ac99215d..44b1160b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,8 +44,9 @@ use jsonrpc_core::MetaIoHandler; use zksync_basic_types::H160; use crate::namespaces::{ - ConfigurationApiNamespaceT, DebugNamespaceT, EthNamespaceT, EthTestNodeNamespaceT, - EvmNamespaceT, HardhatNamespaceT, NetNamespaceT, Web3NamespaceT, ZksNamespaceT, + AnvilNamespaceT, ConfigurationApiNamespaceT, DebugNamespaceT, EthNamespaceT, + EthTestNodeNamespaceT, EvmNamespaceT, HardhatNamespaceT, NetNamespaceT, Web3NamespaceT, + ZksNamespaceT, }; /// List of legacy wallets (address, private key) that we seed with tokens at start. @@ -165,6 +166,7 @@ async fn build_json_http< io.extend_with(DebugNamespaceT::to_delegate(node.clone())); io.extend_with(EthNamespaceT::to_delegate(node.clone())); io.extend_with(EthTestNodeNamespaceT::to_delegate(node.clone())); + io.extend_with(AnvilNamespaceT::to_delegate(node.clone())); io.extend_with(EvmNamespaceT::to_delegate(node.clone())); io.extend_with(HardhatNamespaceT::to_delegate(node.clone())); io.extend_with(ZksNamespaceT::to_delegate(node)); diff --git a/src/namespaces/anvil.rs b/src/namespaces/anvil.rs new file mode 100644 index 00000000..c41464fc --- /dev/null +++ b/src/namespaces/anvil.rs @@ -0,0 +1,20 @@ +use jsonrpc_derive::rpc; +use zksync_basic_types::{Address, U256}; + +use super::RpcResult; + +#[rpc] +pub trait AnvilNamespaceT { + /// Modifies an account's nonce by overwriting it. + /// + /// # Arguments + /// + /// * `address` - The `Address` whose nonce is to be changed + /// * `nonce` - The new nonce + /// + /// # Returns + /// + /// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation. + #[rpc(name = "anvil_setNonce")] + fn set_nonce(&self, address: Address, balance: U256) -> RpcResult; +} diff --git a/src/namespaces/mod.rs b/src/namespaces/mod.rs index 760140fe..f1102fb4 100644 --- a/src/namespaces/mod.rs +++ b/src/namespaces/mod.rs @@ -1,3 +1,4 @@ +mod anvil; mod config; mod debug; mod eth; @@ -8,6 +9,7 @@ mod net; mod web3; mod zks; +pub use anvil::AnvilNamespaceT; pub use config::ConfigurationApiNamespaceT; pub use debug::DebugNamespaceT; pub use eth::EthNamespaceT; diff --git a/src/node/anvil.rs b/src/node/anvil.rs new file mode 100644 index 00000000..e201fade --- /dev/null +++ b/src/node/anvil.rs @@ -0,0 +1,22 @@ +use zksync_basic_types::{Address, U256}; +use zksync_web3_decl::error::Web3Error; + +use crate::{ + fork::ForkSource, + namespaces::{AnvilNamespaceT, RpcResult}, + node::InMemoryNode, + utils::{into_jsrpc_error, IntoBoxedFuture}, +}; + +impl AnvilNamespaceT + for InMemoryNode +{ + fn set_nonce(&self, address: Address, balance: U256) -> RpcResult { + self.set_nonce(address, balance) + .map_err(|err| { + tracing::error!("failed setting nonce: {:?}", err); + into_jsrpc_error(Web3Error::InternalError(err)) + }) + .into_boxed_future() + } +} diff --git a/src/node/mod.rs b/src/node/mod.rs index c0e434f5..463bb87e 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -1,5 +1,6 @@ //! In-memory node, that supports forking other networks. +mod anvil; mod config_api; mod debug; mod eth; From 7ab50f072e4cd8608804455aea38b08167d32f53 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 10 Jul 2024 14:37:38 +0200 Subject: [PATCH 03/32] added anvil_impersonateAccount & anvil_stopImpersonatingAccount aliases --- src/namespaces/anvil.rs | 28 ++++++++++++++++++++++++++++ src/node/anvil.rs | 18 ++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/namespaces/anvil.rs b/src/namespaces/anvil.rs index c41464fc..aa3b8860 100644 --- a/src/namespaces/anvil.rs +++ b/src/namespaces/anvil.rs @@ -17,4 +17,32 @@ pub trait AnvilNamespaceT { /// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation. #[rpc(name = "anvil_setNonce")] fn set_nonce(&self, address: Address, balance: U256) -> RpcResult; + + /// Era Test Node allows transactions impersonating specific account and contract addresses. + /// To impersonate an account use this method, passing the address to impersonate as its parameter. + /// After calling this method, any transactions with this sender will be executed without verification. + /// Multiple addresses can be impersonated at once. + /// + /// # Arguments + /// + /// * `address` - The address to impersonate + /// + /// # Returns + /// + /// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation. + #[rpc(name = "anvil_impersonateAccount")] + fn impersonate_account(&self, address: Address) -> RpcResult; + + /// Use this method to stop impersonating an account after having previously used `anvil_impersonateAccount` + /// The method returns `true` if the account was being impersonated and `false` otherwise. + /// + /// # Arguments + /// + /// * `address` - The address to stop impersonating. + /// + /// # Returns + /// + /// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation. + #[rpc(name = "anvil_stopImpersonatingAccount")] + fn stop_impersonating_account(&self, address: Address) -> RpcResult; } diff --git a/src/node/anvil.rs b/src/node/anvil.rs index e201fade..c71434fd 100644 --- a/src/node/anvil.rs +++ b/src/node/anvil.rs @@ -19,4 +19,22 @@ impl AnvilNames }) .into_boxed_future() } + + fn impersonate_account(&self, address: Address) -> RpcResult { + self.impersonate_account(address) + .map_err(|err| { + tracing::error!("failed impersonating account: {:?}", err); + into_jsrpc_error(Web3Error::InternalError(err)) + }) + .into_boxed_future() + } + + fn stop_impersonating_account(&self, address: Address) -> RpcResult { + InMemoryNode::::stop_impersonating_account(self, address) + .map_err(|err| { + tracing::error!("failed stopping to impersonate account: {:?}", err); + into_jsrpc_error(Web3Error::InternalError(err)) + }) + .into_boxed_future() + } } From 37e6bf5ce92afffa2ba4c348cf2518ea6ff54d4e Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 10 Jul 2024 15:03:23 +0200 Subject: [PATCH 04/32] added anvil_mine alias --- src/namespaces/anvil.rs | 17 ++++++++++++++++- src/node/anvil.rs | 11 ++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/namespaces/anvil.rs b/src/namespaces/anvil.rs index aa3b8860..a4ec5c9b 100644 --- a/src/namespaces/anvil.rs +++ b/src/namespaces/anvil.rs @@ -1,5 +1,5 @@ use jsonrpc_derive::rpc; -use zksync_basic_types::{Address, U256}; +use zksync_basic_types::{Address, U256, U64}; use super::RpcResult; @@ -18,6 +18,21 @@ pub trait AnvilNamespaceT { #[rpc(name = "anvil_setNonce")] fn set_nonce(&self, address: Address, balance: U256) -> RpcResult; + /// Sometimes you may want to advance the latest block number of the network by a large number of blocks. + /// One way to do this would be to call the evm_mine RPC method multiple times, but this is too slow if you want to mine thousands of blocks. + /// The hardhat_mine method can mine any number of blocks at once, in constant time. (It exhibits the same performance no matter how many blocks are mined.) + /// + /// # Arguments + /// + /// * `num_blocks` - The number of blocks to mine, defaults to 1 + /// * `interval` - The interval between the timestamps of each block, in seconds, and it also defaults to 1 + /// + /// # Returns + /// + /// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation. + #[rpc(name = "anvil_mine")] + fn hardhat_mine(&self, num_blocks: Option, interval: Option) -> RpcResult; + /// Era Test Node allows transactions impersonating specific account and contract addresses. /// To impersonate an account use this method, passing the address to impersonate as its parameter. /// After calling this method, any transactions with this sender will be executed without verification. diff --git a/src/node/anvil.rs b/src/node/anvil.rs index c71434fd..f93d554f 100644 --- a/src/node/anvil.rs +++ b/src/node/anvil.rs @@ -1,4 +1,4 @@ -use zksync_basic_types::{Address, U256}; +use zksync_basic_types::{Address, U256, U64}; use zksync_web3_decl::error::Web3Error; use crate::{ @@ -20,6 +20,15 @@ impl AnvilNames .into_boxed_future() } + fn hardhat_mine(&self, num_blocks: Option, interval: Option) -> RpcResult { + self.mine_blocks(num_blocks, interval) + .map_err(|err| { + tracing::error!("failed mining blocks: {:?}", err); + into_jsrpc_error(Web3Error::InternalError(err)) + }) + .into_boxed_future() + } + fn impersonate_account(&self, address: Address) -> RpcResult { self.impersonate_account(address) .map_err(|err| { From f083ab28536a74ea2c2f7775e84f8c652c564a54 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 10 Jul 2024 15:35:16 +0200 Subject: [PATCH 05/32] added anvil_reset alias --- src/namespaces/anvil.rs | 14 +++++++++++++- src/node/anvil.rs | 11 ++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/namespaces/anvil.rs b/src/namespaces/anvil.rs index a4ec5c9b..fb4d7e8b 100644 --- a/src/namespaces/anvil.rs +++ b/src/namespaces/anvil.rs @@ -1,7 +1,7 @@ use jsonrpc_derive::rpc; use zksync_basic_types::{Address, U256, U64}; -use super::RpcResult; +use super::{ResetRequest, RpcResult}; #[rpc] pub trait AnvilNamespaceT { @@ -33,6 +33,18 @@ pub trait AnvilNamespaceT { #[rpc(name = "anvil_mine")] fn hardhat_mine(&self, num_blocks: Option, interval: Option) -> RpcResult; + /// Reset the state of the network back to a fresh forked state, or disable forking. + /// + /// # Arguments + /// + /// * `reset_spec` - The requested state, defaults to resetting the current network. + /// + /// # Returns + /// + /// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation. + #[rpc(name = "anvil_reset")] + fn reset_network(&self, reset_spec: Option) -> RpcResult; + /// Era Test Node allows transactions impersonating specific account and contract addresses. /// To impersonate an account use this method, passing the address to impersonate as its parameter. /// After calling this method, any transactions with this sender will be executed without verification. diff --git a/src/node/anvil.rs b/src/node/anvil.rs index f93d554f..6b0cfdc6 100644 --- a/src/node/anvil.rs +++ b/src/node/anvil.rs @@ -3,7 +3,7 @@ use zksync_web3_decl::error::Web3Error; use crate::{ fork::ForkSource, - namespaces::{AnvilNamespaceT, RpcResult}, + namespaces::{AnvilNamespaceT, ResetRequest, RpcResult}, node::InMemoryNode, utils::{into_jsrpc_error, IntoBoxedFuture}, }; @@ -29,6 +29,15 @@ impl AnvilNames .into_boxed_future() } + fn reset_network(&self, reset_spec: Option) -> RpcResult { + self.reset_network(reset_spec) + .map_err(|err| { + tracing::error!("failed reset: {:?}", err); + into_jsrpc_error(Web3Error::InternalError(err)) + }) + .into_boxed_future() + } + fn impersonate_account(&self, address: Address) -> RpcResult { self.impersonate_account(address) .map_err(|err| { From 08eaafa3d456bd1007d479831ba32fba8f016a5a Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 10 Jul 2024 15:52:56 +0200 Subject: [PATCH 06/32] added anvil_setBalance alias --- e2e-tests/test/anvil-apis.test.ts | 16 ++++++++++++++++ src/namespaces/anvil.rs | 13 +++++++++++++ src/node/anvil.rs | 9 +++++++++ 3 files changed, 38 insertions(+) diff --git a/e2e-tests/test/anvil-apis.test.ts b/e2e-tests/test/anvil-apis.test.ts index 39a6f1a1..80979ea9 100644 --- a/e2e-tests/test/anvil-apis.test.ts +++ b/e2e-tests/test/anvil-apis.test.ts @@ -1,9 +1,25 @@ import { expect } from "chai"; import { Wallet } from "zksync-web3"; import { getTestProvider } from "../helpers/utils"; +import { ethers } from "hardhat"; const provider = getTestProvider(); +describe("anvil_setBalance", function () { + it("Should update the balance of an account", async function () { + // Arrange + const userWallet = Wallet.createRandom().connect(provider); + const newBalance = ethers.utils.parseEther("42"); + + // Act + await provider.send("anvil_setBalance", [userWallet.address, newBalance._hex]); + + // Assert + const balance = await userWallet.getBalance(); + expect(balance.eq(newBalance)).to.true; + }); +}); + describe("anvil_setNonce", function () { it("Should update the nonce of an account", async function () { // Arrange diff --git a/src/namespaces/anvil.rs b/src/namespaces/anvil.rs index fb4d7e8b..86bdfebe 100644 --- a/src/namespaces/anvil.rs +++ b/src/namespaces/anvil.rs @@ -5,6 +5,19 @@ use super::{ResetRequest, RpcResult}; #[rpc] pub trait AnvilNamespaceT { + /// Sets the balance of the given address to the given balance. + /// + /// # Arguments + /// + /// * `address` - The `Address` whose balance will be edited + /// * `balance` - The new balance to set for the given address, in wei + /// + /// # Returns + /// + /// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation. + #[rpc(name = "anvil_setBalance")] + fn set_balance(&self, address: Address, balance: U256) -> RpcResult; + /// Modifies an account's nonce by overwriting it. /// /// # Arguments diff --git a/src/node/anvil.rs b/src/node/anvil.rs index 6b0cfdc6..eed43c03 100644 --- a/src/node/anvil.rs +++ b/src/node/anvil.rs @@ -11,6 +11,15 @@ use crate::{ impl AnvilNamespaceT for InMemoryNode { + fn set_balance(&self, address: Address, balance: U256) -> RpcResult { + self.set_balance(address, balance) + .map_err(|err| { + tracing::error!("failed setting balance : {:?}", err); + into_jsrpc_error(Web3Error::InternalError(err)) + }) + .into_boxed_future() + } + fn set_nonce(&self, address: Address, balance: U256) -> RpcResult { self.set_nonce(address, balance) .map_err(|err| { From f76d5e6c66f4bd7e35f959f13a046ddfa93cec95 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 10 Jul 2024 16:02:23 +0200 Subject: [PATCH 07/32] added anvil_setCode alias --- src/namespaces/anvil.rs | 13 +++++++++++++ src/node/anvil.rs | 11 ++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/namespaces/anvil.rs b/src/namespaces/anvil.rs index 86bdfebe..75a28567 100644 --- a/src/namespaces/anvil.rs +++ b/src/namespaces/anvil.rs @@ -85,4 +85,17 @@ pub trait AnvilNamespaceT { /// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation. #[rpc(name = "anvil_stopImpersonatingAccount")] fn stop_impersonating_account(&self, address: Address) -> RpcResult; + + /// Modifies the bytecode stored at an account's address. + /// + /// # Arguments + /// + /// * `address` - The address where the given code should be stored. + /// * `code` - The code to be stored. + /// + /// # Returns + /// + /// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation. + #[rpc(name = "anvil_setCode")] + fn set_code(&self, address: Address, code: Vec) -> RpcResult<()>; } diff --git a/src/node/anvil.rs b/src/node/anvil.rs index eed43c03..bd6f5266 100644 --- a/src/node/anvil.rs +++ b/src/node/anvil.rs @@ -5,7 +5,7 @@ use crate::{ fork::ForkSource, namespaces::{AnvilNamespaceT, ResetRequest, RpcResult}, node::InMemoryNode, - utils::{into_jsrpc_error, IntoBoxedFuture}, + utils::{into_jsrpc_error, into_jsrpc_error_message, IntoBoxedFuture}, }; impl AnvilNamespaceT @@ -64,4 +64,13 @@ impl AnvilNames }) .into_boxed_future() } + + fn set_code(&self, address: Address, code: Vec) -> RpcResult<()> { + self.set_code(address, code) + .map_err(|err| { + tracing::error!("failed setting code: {:?}", err); + into_jsrpc_error_message(err.to_string()) + }) + .into_boxed_future() + } } From 6f4c64d4b10a8e7be18dc63815f931e57c8d8a52 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 10 Jul 2024 16:27:54 +0200 Subject: [PATCH 08/32] added anvil_setStorageAt alias --- src/namespaces/anvil.rs | 14 ++++++++++++++ src/node/anvil.rs | 9 +++++++++ 2 files changed, 23 insertions(+) diff --git a/src/namespaces/anvil.rs b/src/namespaces/anvil.rs index 75a28567..fa2919e2 100644 --- a/src/namespaces/anvil.rs +++ b/src/namespaces/anvil.rs @@ -98,4 +98,18 @@ pub trait AnvilNamespaceT { /// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation. #[rpc(name = "anvil_setCode")] fn set_code(&self, address: Address, code: Vec) -> RpcResult<()>; + + /// Directly modifies the storage of a contract at a specified slot. + /// + /// # Arguments + /// + /// * `address` - The contract address whose storage is to be modified. + /// * `slot` - The storage slot to modify. + /// * `value` - The value to be set at the specified slot. + /// + /// # Returns + /// + /// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation. + #[rpc(name = "anvil_setStorageAt")] + fn set_storage_at(&self, address: Address, slot: U256, value: U256) -> RpcResult; } diff --git a/src/node/anvil.rs b/src/node/anvil.rs index bd6f5266..a0a23101 100644 --- a/src/node/anvil.rs +++ b/src/node/anvil.rs @@ -73,4 +73,13 @@ impl AnvilNames }) .into_boxed_future() } + + fn set_storage_at(&self, address: Address, slot: U256, value: U256) -> RpcResult { + self.set_storage_at(address, slot, value) + .map_err(|err| { + tracing::error!("failed setting storage: {:?}", err); + into_jsrpc_error(Web3Error::InternalError(err)) + }) + .into_boxed_future() + } } From b5dc622007505e0ef146b5ef1d519de28680914c Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 24 Jul 2024 09:10:38 +0200 Subject: [PATCH 09/32] added anvil_* aliases --- SUPPORTED_APIS.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/SUPPORTED_APIS.md b/SUPPORTED_APIS.md index 44f9e38a..2c96e674 100644 --- a/SUPPORTED_APIS.md +++ b/SUPPORTED_APIS.md @@ -14,6 +14,14 @@ The `status` options are: | Namespace | API |
Status
| Description | | --- | --- | --- | --- | +| [`ANVIL`](#anvil-namespace) | [`anvil_setNonce`](#anvil_setnonce) | `SUPPORTED` | Sets the nonce of a given account | +| [`ANVIL`](#anvil-namespace) | [`anvil_impersonateAccount`](#anvil_impersonateaccount) | `SUPPORTED` | Impersonate an account | +| [`ANVIL`](#anvil-namespace) | [`anvil_stopImpersonatingAccount`](#anvil_stopimpersonatingaccount) | `SUPPORTED` | Stop impersonating an account after having previously used `anvil_impersonateAccount` | +| [`ANVIL`](#anvil-namespace) | [`anvil_reset`](#anvil_reset) | `PARTIALLY` | Resets the state of the network; cannot revert to past block numbers, unless they're in a fork | +| [`ANVIL`](#anvil-namespace) | [`anvil_mine`](#anvil_mine) | `SUPPORTED` | Mine any number of blocks at once, in constant time | +| [`ANVIL`](#anvil-namespace) | [`anvil_setBalance`](#anvil_setbalance) | `SUPPORTED` | Modifies the balance of an account | +| [`ANVIL`](#anvil-namespace) | [`anvil_setCode`](#anvil_setcode) | `SUPPORTED` | Sets the bytecode of a given account | +| [`ANVIL`](#anvil-namespace) | [`anvil_setStorageAt`](#anvil_setstorageat) | `SUPPORTED` | Sets the storage value at a given key for a given account | | [`CONFIG`](#config-namespace) | [`config_getShowCalls`](#config_getshowcalls) | `SUPPORTED` | Gets the current value of `show_calls` that's originally set with `--show-calls` option | | [`CONFIG`](#config-namespace) | [`config_getShowOutputs`](#config_getshowoutputs) | `SUPPORTED` | Gets the current value of `show_outputs` that's originally set with `--show-outputs` option | | [`CONFIG`](#config-namespace) | [`config_getCurrentTimestamp`](#config_getcurrenttimestamp) | `SUPPORTED` | Gets the value of `current_timestamp` for the node | From 7b8392bb2384c8b9da5cf6679c3d03e8e2630a91 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 24 Jul 2024 09:21:02 +0200 Subject: [PATCH 10/32] added anvil_mine test --- e2e-tests/test/anvil-apis.test.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/e2e-tests/test/anvil-apis.test.ts b/e2e-tests/test/anvil-apis.test.ts index 80979ea9..61fc5556 100644 --- a/e2e-tests/test/anvil-apis.test.ts +++ b/e2e-tests/test/anvil-apis.test.ts @@ -34,3 +34,27 @@ describe("anvil_setNonce", function () { expect(nonce).to.equal(newNonce); }); }); + +describe("anvil_mine", function () { + it("Should mine multiple blocks with a given interval", async function () { + // Arrange + const numberOfBlocks = 100; + const intervalInSeconds = 60; + const startingBlock = await provider.getBlock("latest"); + const startingTimestamp: number = await provider.send("config_getCurrentTimestamp", []); + + // Act + await provider.send("anvil_mine", [ + ethers.utils.hexlify(numberOfBlocks), + ethers.utils.hexlify(intervalInSeconds), + ]); + + // Assert + const latestBlock = await provider.getBlock("latest"); + expect(latestBlock.number).to.equal(startingBlock.number + numberOfBlocks, "Block number mismatch"); + expect(latestBlock.timestamp).to.equal( + startingTimestamp + (numberOfBlocks - 1) * intervalInSeconds * 1000 + 1, + "Timestamp mismatch" + ); + }); +}); From 34c9dd0a2c00d3df2d048406bbbc252a2b81ae49 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 24 Jul 2024 12:49:15 +0200 Subject: [PATCH 11/32] modified hardhat_impersonateAccount & hardhat_stopImpersonatingAccount to actually call hardhat_stopImpersonatingAccount, interfere less with other tests --- e2e-tests/test/hardhat-apis.test.ts | 10 ++++++---- e2e-tests/test/main.test.ts | 20 +++++++++++++++++--- e2e-tests/test/zks-apis.test.ts | 7 ++++--- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/e2e-tests/test/hardhat-apis.test.ts b/e2e-tests/test/hardhat-apis.test.ts index b55b7a15..e17aa233 100644 --- a/e2e-tests/test/hardhat-apis.test.ts +++ b/e2e-tests/test/hardhat-apis.test.ts @@ -68,12 +68,12 @@ describe("hardhat_impersonateAccount & hardhat_stopImpersonatingAccount", functi it("Should allow transfers of funds without knowing the Private Key", async function () { // Arrange const userWallet = Wallet.createRandom().connect(provider); - const beforeBalance = await provider.getBalance(RichAccounts[0].Account); + const beforeBalance = await provider.getBalance(RichAccounts[5].Account); // Act - await provider.send("hardhat_impersonateAccount", [RichAccounts[0].Account]); + await provider.send("hardhat_impersonateAccount", [RichAccounts[5].Account]); - const signer = await ethers.getSigner(RichAccounts[0].Account); + const signer = await ethers.getSigner(RichAccounts[5].Account); const tx = { to: userWallet.address, value: ethers.utils.parseEther("0.42"), @@ -82,9 +82,11 @@ describe("hardhat_impersonateAccount & hardhat_stopImpersonatingAccount", functi const recieptTx = await signer.sendTransaction(tx); await recieptTx.wait(); + await provider.send("hardhat_stopImpersonatingAccount", [RichAccounts[5].Account]); + // Assert expect((await userWallet.getBalance()).eq(ethers.utils.parseEther("0.42"))).to.true; - expect((await provider.getBalance(RichAccounts[0].Account)).eq(beforeBalance.sub(ethers.utils.parseEther("0.42")))) + expect((await provider.getBalance(RichAccounts[5].Account)).eq(beforeBalance.sub(ethers.utils.parseEther("0.42")))) .to.true; }); }); diff --git a/e2e-tests/test/main.test.ts b/e2e-tests/test/main.test.ts index a5739dad..8a131abb 100644 --- a/e2e-tests/test/main.test.ts +++ b/e2e-tests/test/main.test.ts @@ -62,8 +62,13 @@ describe("Greeter Smart Contract", function () { // Validate log is created expect(receipt.logs.length).to.greaterThanOrEqual(1); - const setGreetingLog = receipt.logs[0]; - expect(setGreetingLog.address).to.equal(greeter.address); + var setGreetingLog = null; + for (var i = 0; (setGreetingLog == null) && (i < receipt.logs.length); ++i) { + if (receipt.logs[i].address == greeter.address) { + setGreetingLog = receipt.logs[i]; + } + } + expect(setGreetingLog).not.to.equal(null); const eventInterface = new ethers.utils.Interface(["event LogString(string value)"]); expect(eventInterface.parseLog(setGreetingLog).args[0]).to.equal("Greeting is being updated to Luke Skywalker"); @@ -78,8 +83,17 @@ describe("Greeter Smart Contract", function () { const setGreetingTx = await greeter.setGreeting("Luke Skywalker"); let receipt: TransactionReceipt = await setGreetingTx.wait(); + expect(receipt.logs.length).to.greaterThanOrEqual(1); + var setGreetingLog = null; + for (var i = 0; (setGreetingLog == null) && (i < receipt.logs.length); ++i) { + if (receipt.logs[i].address == greeter.address) { + setGreetingLog = receipt.logs[i]; + } + } + expect(setGreetingLog).not.to.equal(null); + // Create filter - const topic = receipt.logs[0].topics[0]; + const topic = setGreetingLog.topics[0]; const filterId = await provider.send("eth_newFilter", [ { fromBlock: "earliest", diff --git a/e2e-tests/test/zks-apis.test.ts b/e2e-tests/test/zks-apis.test.ts index 2966fe19..cf6b7a54 100644 --- a/e2e-tests/test/zks-apis.test.ts +++ b/e2e-tests/test/zks-apis.test.ts @@ -30,13 +30,14 @@ describe("zks_estimateFee", function () { // Act const response: Fee = await provider.send("zks_estimateFee", [transaction]); // Assert - expect(ethers.BigNumber.from(response.gas_limit)).to.eql(ethers.BigNumber.from("3606743"), "Unexpected gas_limit"); + expect(ethers.BigNumber.from(response.gas_limit).toNumber()).to.be.within(3606743, 5868728, "Unexpected gas_limit"); expect(ethers.BigNumber.from(response.gas_per_pubdata_limit)).to.eql( ethers.BigNumber.from("50000"), "Unexpected gas_per_pubdata_limit" ); - expect(ethers.BigNumber.from(response.max_fee_per_gas)).to.eql( - ethers.BigNumber.from("37500000"), + expect(ethers.BigNumber.from(response.max_fee_per_gas).toNumber()).to.be.within( + 25500297, + 37500000, "Unexpected max_fee_per_gas" ); expect(ethers.BigNumber.from(response.max_priority_fee_per_gas)).to.eql( From 037399381db666b5e28c4f2b46382b077a2045a3 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 24 Jul 2024 14:03:44 +0200 Subject: [PATCH 12/32] added anvil_impersonateAccount & anvil_stopImpersonatingAccount test --- e2e-tests/test/anvil-apis.test.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/e2e-tests/test/anvil-apis.test.ts b/e2e-tests/test/anvil-apis.test.ts index 61fc5556..a6aa1dda 100644 --- a/e2e-tests/test/anvil-apis.test.ts +++ b/e2e-tests/test/anvil-apis.test.ts @@ -1,5 +1,6 @@ import { expect } from "chai"; import { Wallet } from "zksync-web3"; +import { RichAccounts } from "../helpers/constants"; import { getTestProvider } from "../helpers/utils"; import { ethers } from "hardhat"; @@ -58,3 +59,30 @@ describe("anvil_mine", function () { ); }); }); + +describe("anvil_impersonateAccount & anvil_stopImpersonatingAccount", function () { + it("Should allow transfers of funds without knowing the Private Key", async function () { + // Arrange + const userWallet = Wallet.createRandom().connect(provider); + const beforeBalance = await provider.getBalance(RichAccounts[5].Account); + + // Act + await provider.send("anvil_impersonateAccount", [RichAccounts[5].Account]); + + const signer = await ethers.getSigner(RichAccounts[5].Account); + const tx = { + to: userWallet.address, + value: ethers.utils.parseEther("0.42"), + }; + + const recieptTx = await signer.sendTransaction(tx); + await recieptTx.wait(); + + await provider.send("anvil_stopImpersonatingAccount", [RichAccounts[5].Account]); + + // Assert + expect((await userWallet.getBalance()).eq(ethers.utils.parseEther("0.42"))).to.true; + expect((await provider.getBalance(RichAccounts[5].Account)).eq(beforeBalance.sub(ethers.utils.parseEther("0.42")))) + .to.true; + }); +}); From 97b943bd6f501f0269226d3e0edcf6bd9a1677bd Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 24 Jul 2024 14:11:47 +0200 Subject: [PATCH 13/32] added anvil_setCode test --- e2e-tests/test/anvil-apis.test.ts | 83 ++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/e2e-tests/test/anvil-apis.test.ts b/e2e-tests/test/anvil-apis.test.ts index a6aa1dda..81f97888 100644 --- a/e2e-tests/test/anvil-apis.test.ts +++ b/e2e-tests/test/anvil-apis.test.ts @@ -1,8 +1,12 @@ import { expect } from "chai"; import { Wallet } from "zksync-web3"; +import { deployContract, expectThrowsAsync, getTestProvider } from "../helpers/utils"; import { RichAccounts } from "../helpers/constants"; -import { getTestProvider } from "../helpers/utils"; import { ethers } from "hardhat"; +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import * as hre from "hardhat"; +import { keccak256 } from "ethers/lib/utils"; +import { BigNumber } from "ethers"; const provider = getTestProvider(); @@ -86,3 +90,80 @@ describe("anvil_impersonateAccount & anvil_stopImpersonatingAccount", function ( .to.true; }); }); + +describe("anvil_setCode", function () { + it("Should set code at an address", async function () { + // Arrange + const wallet = new Wallet(RichAccounts[0].PrivateKey); + const deployer = new Deployer(hre, wallet); + + const address = "0x1000000000000000000000000000000000001111"; + const artifact = await deployer.loadArtifact("Return5"); + const contractCode = [...ethers.utils.arrayify(artifact.deployedBytecode)]; + + // Act + await provider.send("anvil_setCode", [address, contractCode]); + + // Assert + const result = await provider.send("eth_call", [ + { + to: address, + data: keccak256(ethers.utils.toUtf8Bytes("value()")).substring(0, 10), + from: wallet.address, + gas: "0x1000", + gasPrice: "0x0ee6b280", + value: "0x0", + nonce: "0x1", + }, + "latest", + ]); + expect(BigNumber.from(result).toNumber()).to.eq(5); + }); + + it("Should reject invalid code", async function () { + const action = async () => { + // Arrange + const wallet = new Wallet(RichAccounts[0].PrivateKey); + const deployer = new Deployer(hre, wallet); + + const address = "0x1000000000000000000000000000000000001111"; + const artifact = await deployer.loadArtifact("Return5"); + const contractCode = [...ethers.utils.arrayify(artifact.deployedBytecode)]; + const shortCode = contractCode.slice(0, contractCode.length - 1); + + // Act + await provider.send("anvil_setCode", [address, shortCode]); + }; + + await expectThrowsAsync(action, "bytes must be divisible by 32"); + }); + + it("Should update code with a different smart contract", async function () { + // Arrange + const wallet = new Wallet(RichAccounts[0].PrivateKey); + const deployer = new Deployer(hre, wallet); + + const greeter = await deployContract(deployer, "Greeter", ["Hi"]); + expect(await greeter.greet()).to.eq("Hi"); + const artifact = await deployer.loadArtifact("Return5"); + const newContractCode = [...ethers.utils.arrayify(artifact.deployedBytecode)]; + + // Act + await provider.send("anvil_setCode", [greeter.address, newContractCode]); + + // Assert + const result = await provider.send("eth_call", [ + { + to: greeter.address, + data: keccak256(ethers.utils.toUtf8Bytes("value()")).substring(0, 10), + from: wallet.address, + gas: "0x1000", + gasPrice: "0x0ee6b280", + value: "0x0", + nonce: "0x1", + }, + "latest", + ]); + expect(BigNumber.from(result).toNumber()).to.eq(5); + }); +}); From ac62abf0bca3a1a9a826e418f4a9ad3bc3f18cce Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 24 Jul 2024 15:44:55 +0200 Subject: [PATCH 14/32] added hardhat_setStorageAt and anvil_setStorageAt tests --- e2e-tests/test/anvil-apis.test.ts | 24 ++++++++++++++++++++++++ e2e-tests/test/hardhat-apis.test.ts | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/e2e-tests/test/anvil-apis.test.ts b/e2e-tests/test/anvil-apis.test.ts index 81f97888..4e294e7d 100644 --- a/e2e-tests/test/anvil-apis.test.ts +++ b/e2e-tests/test/anvil-apis.test.ts @@ -167,3 +167,27 @@ describe("anvil_setCode", function () { expect(BigNumber.from(result).toNumber()).to.eq(5); }); }); + +describe("anvil_setStorageAt", function () { + it("Should set storage at an address", async function () { + const wallet = new Wallet(RichAccounts[0].PrivateKey, provider); + const userWallet = Wallet.createRandom().connect(provider); + await wallet.sendTransaction({ + to: userWallet.address, + value: ethers.utils.parseEther("3"), + }); + + const deployer = new Deployer(hre, userWallet); + const artifact = await deployer.loadArtifact("MyERC20"); + const token = await deployer.deploy(artifact, ["MyToken", "MyToken", 18]); + + const before = await provider.send("eth_getStorageAt", [token.address, "0x0", "latest"]); + expect(BigNumber.from(before).toNumber()).to.eq(0); + + const value = ethers.utils.hexlify(ethers.utils.zeroPad("0x10", 32)); + await provider.send("anvil_setStorageAt", [token.address, "0x0", value]); + + const after = await provider.send("eth_getStorageAt", [token.address, "0x0", "latest"]); + expect(BigNumber.from(after).toNumber()).to.eq(16); + }); +}); diff --git a/e2e-tests/test/hardhat-apis.test.ts b/e2e-tests/test/hardhat-apis.test.ts index e17aa233..f221f72d 100644 --- a/e2e-tests/test/hardhat-apis.test.ts +++ b/e2e-tests/test/hardhat-apis.test.ts @@ -167,3 +167,27 @@ describe("hardhat_setCode", function () { expect(BigNumber.from(result).toNumber()).to.eq(5); }); }); + +describe("hardhat_setStorageAt", function () { + it("Should set storage at an address", async function () { + const wallet = new Wallet(RichAccounts[0].PrivateKey, provider); + const userWallet = Wallet.createRandom().connect(provider); + await wallet.sendTransaction({ + to: userWallet.address, + value: ethers.utils.parseEther("3"), + }); + + const deployer = new Deployer(hre, userWallet); + const artifact = await deployer.loadArtifact("MyERC20"); + const token = await deployer.deploy(artifact, ["MyToken", "MyToken", 18]); + + const before = await provider.send("eth_getStorageAt", [token.address, "0x0", "latest"]); + expect(BigNumber.from(before).toNumber()).to.eq(0); + + const value = ethers.utils.hexlify(ethers.utils.zeroPad("0x10", 32)); + await provider.send("hardhat_setStorageAt", [token.address, "0x0", value]); + + const after = await provider.send("eth_getStorageAt", [token.address, "0x0", "latest"]); + expect(BigNumber.from(after).toNumber()).to.eq(16); + }); +}); From a14ca13afab88ade189065e8c34092f421dabc16 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 24 Jul 2024 15:51:02 +0200 Subject: [PATCH 15/32] formatted --- e2e-tests/test/anvil-apis.test.ts | 5 +---- e2e-tests/test/main.test.ts | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/e2e-tests/test/anvil-apis.test.ts b/e2e-tests/test/anvil-apis.test.ts index 4e294e7d..2d7c542c 100644 --- a/e2e-tests/test/anvil-apis.test.ts +++ b/e2e-tests/test/anvil-apis.test.ts @@ -49,10 +49,7 @@ describe("anvil_mine", function () { const startingTimestamp: number = await provider.send("config_getCurrentTimestamp", []); // Act - await provider.send("anvil_mine", [ - ethers.utils.hexlify(numberOfBlocks), - ethers.utils.hexlify(intervalInSeconds), - ]); + await provider.send("anvil_mine", [ethers.utils.hexlify(numberOfBlocks), ethers.utils.hexlify(intervalInSeconds)]); // Assert const latestBlock = await provider.getBlock("latest"); diff --git a/e2e-tests/test/main.test.ts b/e2e-tests/test/main.test.ts index 8a131abb..65df1b2b 100644 --- a/e2e-tests/test/main.test.ts +++ b/e2e-tests/test/main.test.ts @@ -63,7 +63,7 @@ describe("Greeter Smart Contract", function () { // Validate log is created expect(receipt.logs.length).to.greaterThanOrEqual(1); var setGreetingLog = null; - for (var i = 0; (setGreetingLog == null) && (i < receipt.logs.length); ++i) { + for (var i = 0; setGreetingLog == null && i < receipt.logs.length; ++i) { if (receipt.logs[i].address == greeter.address) { setGreetingLog = receipt.logs[i]; } @@ -85,7 +85,7 @@ describe("Greeter Smart Contract", function () { expect(receipt.logs.length).to.greaterThanOrEqual(1); var setGreetingLog = null; - for (var i = 0; (setGreetingLog == null) && (i < receipt.logs.length); ++i) { + for (var i = 0; setGreetingLog == null && i < receipt.logs.length; ++i) { if (receipt.logs[i].address == greeter.address) { setGreetingLog = receipt.logs[i]; } From d36852f40b076aed4f9fd17b0cf774ce16ec7184 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 31 Jul 2024 13:41:39 +0200 Subject: [PATCH 16/32] removed links to anvil namespace --- SUPPORTED_APIS.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/SUPPORTED_APIS.md b/SUPPORTED_APIS.md index 2c96e674..77b98396 100644 --- a/SUPPORTED_APIS.md +++ b/SUPPORTED_APIS.md @@ -14,14 +14,14 @@ The `status` options are: | Namespace | API |
Status
| Description | | --- | --- | --- | --- | -| [`ANVIL`](#anvil-namespace) | [`anvil_setNonce`](#anvil_setnonce) | `SUPPORTED` | Sets the nonce of a given account | -| [`ANVIL`](#anvil-namespace) | [`anvil_impersonateAccount`](#anvil_impersonateaccount) | `SUPPORTED` | Impersonate an account | -| [`ANVIL`](#anvil-namespace) | [`anvil_stopImpersonatingAccount`](#anvil_stopimpersonatingaccount) | `SUPPORTED` | Stop impersonating an account after having previously used `anvil_impersonateAccount` | -| [`ANVIL`](#anvil-namespace) | [`anvil_reset`](#anvil_reset) | `PARTIALLY` | Resets the state of the network; cannot revert to past block numbers, unless they're in a fork | -| [`ANVIL`](#anvil-namespace) | [`anvil_mine`](#anvil_mine) | `SUPPORTED` | Mine any number of blocks at once, in constant time | -| [`ANVIL`](#anvil-namespace) | [`anvil_setBalance`](#anvil_setbalance) | `SUPPORTED` | Modifies the balance of an account | -| [`ANVIL`](#anvil-namespace) | [`anvil_setCode`](#anvil_setcode) | `SUPPORTED` | Sets the bytecode of a given account | -| [`ANVIL`](#anvil-namespace) | [`anvil_setStorageAt`](#anvil_setstorageat) | `SUPPORTED` | Sets the storage value at a given key for a given account | +| `ANVIL` | `anvil_setNonce` | `SUPPORTED` | Sets the nonce of a given account | +| `ANVIL` | `anvil_impersonateAccount` | `SUPPORTED` | Impersonate an account | +| `ANVIL` | `anvil_stopImpersonatingAccount` | `SUPPORTED` | Stop impersonating an account after having previously used `anvil_impersonateAccount` | +| `ANVIL` | `anvil_reset` | `PARTIALLY` | Resets the state of the network; cannot revert to past block numbers, unless they're in a fork | +| `ANVIL` | `anvil_mine` | `SUPPORTED` | Mine any number of blocks at once, in constant time | +| `ANVIL` | `anvil_setBalance` | `SUPPORTED` | Modifies the balance of an account | +| `ANVIL` | `anvil_setCode` | `SUPPORTED` | Sets the bytecode of a given account | +| `ANVIL` | `anvil_setStorageAt` | `SUPPORTED` | Sets the storage value at a given key for a given account | | [`CONFIG`](#config-namespace) | [`config_getShowCalls`](#config_getshowcalls) | `SUPPORTED` | Gets the current value of `show_calls` that's originally set with `--show-calls` option | | [`CONFIG`](#config-namespace) | [`config_getShowOutputs`](#config_getshowoutputs) | `SUPPORTED` | Gets the current value of `show_outputs` that's originally set with `--show-outputs` option | | [`CONFIG`](#config-namespace) | [`config_getCurrentTimestamp`](#config_getcurrenttimestamp) | `SUPPORTED` | Gets the value of `current_timestamp` for the node | From 4a54fe8ff150c0604944e9461fe2cff539245613 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 31 Jul 2024 14:14:47 +0200 Subject: [PATCH 17/32] split tables --- SUPPORTED_APIS.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/SUPPORTED_APIS.md b/SUPPORTED_APIS.md index 77b98396..7c3e4dd0 100644 --- a/SUPPORTED_APIS.md +++ b/SUPPORTED_APIS.md @@ -22,6 +22,9 @@ The `status` options are: | `ANVIL` | `anvil_setBalance` | `SUPPORTED` | Modifies the balance of an account | | `ANVIL` | `anvil_setCode` | `SUPPORTED` | Sets the bytecode of a given account | | `ANVIL` | `anvil_setStorageAt` | `SUPPORTED` | Sets the storage value at a given key for a given account | + +| Namespace | API |
Status
| Description | +| --- | --- | --- | --- | | [`CONFIG`](#config-namespace) | [`config_getShowCalls`](#config_getshowcalls) | `SUPPORTED` | Gets the current value of `show_calls` that's originally set with `--show-calls` option | | [`CONFIG`](#config-namespace) | [`config_getShowOutputs`](#config_getshowoutputs) | `SUPPORTED` | Gets the current value of `show_outputs` that's originally set with `--show-outputs` option | | [`CONFIG`](#config-namespace) | [`config_getCurrentTimestamp`](#config_getcurrenttimestamp) | `SUPPORTED` | Gets the value of `current_timestamp` for the node | @@ -33,10 +36,16 @@ The `status` options are: | [`CONFIG`](#config-namespace) | [`config_setShowGasDetails`](#config_setshowgasdetails) | `SUPPORTED` | Updates `show_gas_details` to print more details about gas estimation and usage | | [`CONFIG`](#config-namespace) | [`config_setLogLevel`](#config_setloglevel) | `SUPPORTED` | Sets the logging level for the node and only displays the node logs. | | [`CONFIG`](#config-namespace) | [`config_setLogging`](#config_setlogging) | `SUPPORTED` | Sets the fine-tuned logging levels for the node and any of its dependencies | + +| Namespace | API |
Status
| Description | +| --- | --- | --- | --- | | [`DEBUG`](#debug-namespace) | [`debug_traceCall`](#debug_tracecall) | `SUPPORTED` | Performs a call and returns structured traces of the execution | | [`DEBUG`](#debug-namespace) | [`debug_traceBlockByHash`](#debug_traceblockbyhash) | `SUPPORTED` | Returns structured traces for operations within the block of the specified block hash | | [`DEBUG`](#debug-namespace) | [`debug_traceBlockByNumber`](#debug_traceblockbynumber) | `SUPPORTED` | Returns structured traces for operations within the block of the specified block number | | [`DEBUG`](#debug-namespace) | [`debug_traceTransaction`](#debug_tracetransaction) | `SUPPORTED` | Returns a structured trace of the execution of the specified transaction | + +| Namespace | API |
Status
| Description | +| --- | --- | --- | --- | | `ETH` | `eth_accounts` | `SUPPORTED` | Returns a list of addresses owned by client | | [`ETH`](#eth-namespace) | [`eth_chainId`](#eth_chainid) | `SUPPORTED` | Returns the currently configured chain id
_(default is `260`)_ | | `ETH` | `eth_coinbase` | `NOT IMPLEMENTED` | Returns the client coinbase address | @@ -86,6 +95,9 @@ The `status` options are: | [`ETH`](#eth-namespace) | [`eth_syncing`](#eth_syncing) | `SUPPORTED` | Returns an object containing data about the sync status or `false` when not syncing | | [`ETH`](#eth-namespace) | [`eth_uninstallFilter`](#`eth_uninstallfilter) | `SUPPORTED` | Uninstalls a filter with given id | | `ETH` | `eth_unsubscribe` | `NOT IMPLEMENTED` | Cancel a subscription to a particular event | + +| Namespace | API |
Status
| Description | +| --- | --- | --- | --- | | `EVM` | `evm_addAccount` | `NOT IMPLEMENTED` | Adds any arbitrary account | | [`EVM`](#evm-namespace) | [`evm_increaseTime`](#evm_increasetime) | `SUPPORTED` | Jump forward in time by the given amount of time, in seconds | | [`EVM`](#evm-namespace) | [`evm_mine`](#evm_mine) | `SUPPORTED` | Force a single block to be mined | @@ -101,6 +113,9 @@ The `status` options are: | [`EVM`](#evm-namespace) | [`evm_setNextBlockTimestamp`](#evm_setnextblocktimestamp) | `SUPPORTED` | Works like `evm_increaseTime`, but takes the exact timestamp that you want in the next block, and increases the time accordingly | | [`EVM`](#evm-namespace) | [`evm_setTime`](#evm_settime) | `SUPPORTED` | Sets the internal clock time to the given timestamp | | [`EVM`](#evm-namespace) | [`evm_snapshot`](#evm_snapshot) | `SUPPORTED` | Snapshot the state of the blockchain at the current block | + +| Namespace | API |
Status
| Description | +| --- | --- | --- | --- | | `HARDHAT` | `hardhat_addCompilationResult` | `NOT IMPLEMENTED` | Add information about compiled contracts | | `HARDHAT` | `hardhat_dropTransaction` | `NOT IMPLEMENTED` | Remove a transaction from the mempool | | [`HARDHAT`](#hardhat-namespace) | [`hardhat_impersonateAccount`](#hardhat_impersonateaccount) | `SUPPORTED` | Impersonate an account | @@ -118,10 +133,19 @@ The `status` options are: | [`HARDHAT`](#hardhat-namespace) | [`hardhat_setNonce`](#hardhat_setnonce) | `SUPPORTED` | Sets the nonce of a given account | | [`HARDHAT`](#hardhat-namespace) | [`hardhat_setStorageAt`](#hardhat_setstorageat) | `SUPPORTED` | Sets the storage value at a given key for a given account | | [`HARDHAT`](#hardhat-namespace) | [`hardhat_stopImpersonatingAccount`](#hardhat_stopimpersonatingaccount) | `SUPPORTED` | Stop impersonating an account after having previously used `hardhat_impersonateAccount` | + +| Namespace | API |
Status
| Description | +| --- | --- | --- | --- | | [`NETWORK`](#network-namespace) | [`net_version`](#net_version) | `SUPPORTED` | Returns the current network id
_(default is `260`)_ | | [`NETWORK`](#network-namespace) | [`net_peerCount`](#net_peercount) | `SUPPORTED` | Returns the number of peers currently connected to the client
_(hard-coded to `0`)_ | | [`NETWORK`](#network-namespace) | [`net_listening`](#net_listening) | `SUPPORTED` | Returns `true` if the client is actively listening for network connections
_(hard-coded to `false`)_ | + +| Namespace | API |
Status
| Description | +| --- | --- | --- | --- | | [`WEB3`](#web3-namespace) | [`web3_clientVersion`](#web3_clientversion) | `SUPPORTED` | Returns `zkSync/v2.0` | + +| Namespace | API |
Status
| Description | +| --- | --- | --- | --- | | [`ZKS`](#zks-namespace) | [`zks_estimateFee`](#zks_estimateFee) | `SUPPORTED` | Gets the Fee estimation data for a given Request | | `ZKS` | `zks_estimateGasL1ToL2` | `NOT IMPLEMENTED` | Estimate of the gas required for a L1 to L2 transaction | | [`ZKS`](#zks-namespace) | [`zks_getAllAccountBalances`](#zks_getallaccountbalances) | `SUPPORTED` | Returns all balances for confirmed tokens given by an account address | From bcb3397a56cf2279d80f99bee24eda4e106823ba Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 31 Jul 2024 14:16:31 +0200 Subject: [PATCH 18/32] Revert "split tables" This reverts commit 4a54fe8ff150c0604944e9461fe2cff539245613. --- SUPPORTED_APIS.md | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/SUPPORTED_APIS.md b/SUPPORTED_APIS.md index 7c3e4dd0..77b98396 100644 --- a/SUPPORTED_APIS.md +++ b/SUPPORTED_APIS.md @@ -22,9 +22,6 @@ The `status` options are: | `ANVIL` | `anvil_setBalance` | `SUPPORTED` | Modifies the balance of an account | | `ANVIL` | `anvil_setCode` | `SUPPORTED` | Sets the bytecode of a given account | | `ANVIL` | `anvil_setStorageAt` | `SUPPORTED` | Sets the storage value at a given key for a given account | - -| Namespace | API |
Status
| Description | -| --- | --- | --- | --- | | [`CONFIG`](#config-namespace) | [`config_getShowCalls`](#config_getshowcalls) | `SUPPORTED` | Gets the current value of `show_calls` that's originally set with `--show-calls` option | | [`CONFIG`](#config-namespace) | [`config_getShowOutputs`](#config_getshowoutputs) | `SUPPORTED` | Gets the current value of `show_outputs` that's originally set with `--show-outputs` option | | [`CONFIG`](#config-namespace) | [`config_getCurrentTimestamp`](#config_getcurrenttimestamp) | `SUPPORTED` | Gets the value of `current_timestamp` for the node | @@ -36,16 +33,10 @@ The `status` options are: | [`CONFIG`](#config-namespace) | [`config_setShowGasDetails`](#config_setshowgasdetails) | `SUPPORTED` | Updates `show_gas_details` to print more details about gas estimation and usage | | [`CONFIG`](#config-namespace) | [`config_setLogLevel`](#config_setloglevel) | `SUPPORTED` | Sets the logging level for the node and only displays the node logs. | | [`CONFIG`](#config-namespace) | [`config_setLogging`](#config_setlogging) | `SUPPORTED` | Sets the fine-tuned logging levels for the node and any of its dependencies | - -| Namespace | API |
Status
| Description | -| --- | --- | --- | --- | | [`DEBUG`](#debug-namespace) | [`debug_traceCall`](#debug_tracecall) | `SUPPORTED` | Performs a call and returns structured traces of the execution | | [`DEBUG`](#debug-namespace) | [`debug_traceBlockByHash`](#debug_traceblockbyhash) | `SUPPORTED` | Returns structured traces for operations within the block of the specified block hash | | [`DEBUG`](#debug-namespace) | [`debug_traceBlockByNumber`](#debug_traceblockbynumber) | `SUPPORTED` | Returns structured traces for operations within the block of the specified block number | | [`DEBUG`](#debug-namespace) | [`debug_traceTransaction`](#debug_tracetransaction) | `SUPPORTED` | Returns a structured trace of the execution of the specified transaction | - -| Namespace | API |
Status
| Description | -| --- | --- | --- | --- | | `ETH` | `eth_accounts` | `SUPPORTED` | Returns a list of addresses owned by client | | [`ETH`](#eth-namespace) | [`eth_chainId`](#eth_chainid) | `SUPPORTED` | Returns the currently configured chain id
_(default is `260`)_ | | `ETH` | `eth_coinbase` | `NOT IMPLEMENTED` | Returns the client coinbase address | @@ -95,9 +86,6 @@ The `status` options are: | [`ETH`](#eth-namespace) | [`eth_syncing`](#eth_syncing) | `SUPPORTED` | Returns an object containing data about the sync status or `false` when not syncing | | [`ETH`](#eth-namespace) | [`eth_uninstallFilter`](#`eth_uninstallfilter) | `SUPPORTED` | Uninstalls a filter with given id | | `ETH` | `eth_unsubscribe` | `NOT IMPLEMENTED` | Cancel a subscription to a particular event | - -| Namespace | API |
Status
| Description | -| --- | --- | --- | --- | | `EVM` | `evm_addAccount` | `NOT IMPLEMENTED` | Adds any arbitrary account | | [`EVM`](#evm-namespace) | [`evm_increaseTime`](#evm_increasetime) | `SUPPORTED` | Jump forward in time by the given amount of time, in seconds | | [`EVM`](#evm-namespace) | [`evm_mine`](#evm_mine) | `SUPPORTED` | Force a single block to be mined | @@ -113,9 +101,6 @@ The `status` options are: | [`EVM`](#evm-namespace) | [`evm_setNextBlockTimestamp`](#evm_setnextblocktimestamp) | `SUPPORTED` | Works like `evm_increaseTime`, but takes the exact timestamp that you want in the next block, and increases the time accordingly | | [`EVM`](#evm-namespace) | [`evm_setTime`](#evm_settime) | `SUPPORTED` | Sets the internal clock time to the given timestamp | | [`EVM`](#evm-namespace) | [`evm_snapshot`](#evm_snapshot) | `SUPPORTED` | Snapshot the state of the blockchain at the current block | - -| Namespace | API |
Status
| Description | -| --- | --- | --- | --- | | `HARDHAT` | `hardhat_addCompilationResult` | `NOT IMPLEMENTED` | Add information about compiled contracts | | `HARDHAT` | `hardhat_dropTransaction` | `NOT IMPLEMENTED` | Remove a transaction from the mempool | | [`HARDHAT`](#hardhat-namespace) | [`hardhat_impersonateAccount`](#hardhat_impersonateaccount) | `SUPPORTED` | Impersonate an account | @@ -133,19 +118,10 @@ The `status` options are: | [`HARDHAT`](#hardhat-namespace) | [`hardhat_setNonce`](#hardhat_setnonce) | `SUPPORTED` | Sets the nonce of a given account | | [`HARDHAT`](#hardhat-namespace) | [`hardhat_setStorageAt`](#hardhat_setstorageat) | `SUPPORTED` | Sets the storage value at a given key for a given account | | [`HARDHAT`](#hardhat-namespace) | [`hardhat_stopImpersonatingAccount`](#hardhat_stopimpersonatingaccount) | `SUPPORTED` | Stop impersonating an account after having previously used `hardhat_impersonateAccount` | - -| Namespace | API |
Status
| Description | -| --- | --- | --- | --- | | [`NETWORK`](#network-namespace) | [`net_version`](#net_version) | `SUPPORTED` | Returns the current network id
_(default is `260`)_ | | [`NETWORK`](#network-namespace) | [`net_peerCount`](#net_peercount) | `SUPPORTED` | Returns the number of peers currently connected to the client
_(hard-coded to `0`)_ | | [`NETWORK`](#network-namespace) | [`net_listening`](#net_listening) | `SUPPORTED` | Returns `true` if the client is actively listening for network connections
_(hard-coded to `false`)_ | - -| Namespace | API |
Status
| Description | -| --- | --- | --- | --- | | [`WEB3`](#web3-namespace) | [`web3_clientVersion`](#web3_clientversion) | `SUPPORTED` | Returns `zkSync/v2.0` | - -| Namespace | API |
Status
| Description | -| --- | --- | --- | --- | | [`ZKS`](#zks-namespace) | [`zks_estimateFee`](#zks_estimateFee) | `SUPPORTED` | Gets the Fee estimation data for a given Request | | `ZKS` | `zks_estimateGasL1ToL2` | `NOT IMPLEMENTED` | Estimate of the gas required for a L1 to L2 transaction | | [`ZKS`](#zks-namespace) | [`zks_getAllAccountBalances`](#zks_getallaccountbalances) | `SUPPORTED` | Returns all balances for confirmed tokens given by an account address | From db1269bd48df7981254dc2b84750be14a05ab792 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 14 Aug 2024 10:19:42 +0200 Subject: [PATCH 19/32] renamed AnvilNamespaceT::hardhat_mine to anvil_mine --- src/namespaces/anvil.rs | 2 +- src/node/anvil.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/namespaces/anvil.rs b/src/namespaces/anvil.rs index fa2919e2..b0140521 100644 --- a/src/namespaces/anvil.rs +++ b/src/namespaces/anvil.rs @@ -44,7 +44,7 @@ pub trait AnvilNamespaceT { /// /// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation. #[rpc(name = "anvil_mine")] - fn hardhat_mine(&self, num_blocks: Option, interval: Option) -> RpcResult; + fn anvil_mine(&self, num_blocks: Option, interval: Option) -> RpcResult; /// Reset the state of the network back to a fresh forked state, or disable forking. /// diff --git a/src/node/anvil.rs b/src/node/anvil.rs index a0a23101..b1a7abcf 100644 --- a/src/node/anvil.rs +++ b/src/node/anvil.rs @@ -29,7 +29,7 @@ impl AnvilNames .into_boxed_future() } - fn hardhat_mine(&self, num_blocks: Option, interval: Option) -> RpcResult { + fn anvil_mine(&self, num_blocks: Option, interval: Option) -> RpcResult { self.mine_blocks(num_blocks, interval) .map_err(|err| { tracing::error!("failed mining blocks: {:?}", err); From 781c5a036dac92fe0fe245fa05c51d7ab7250f2a Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 14 Aug 2024 10:27:29 +0200 Subject: [PATCH 20/32] Update SUPPORTED_APIS.md Co-authored-by: AnastasiiaVashchuk <72273339+AnastasiiaVashchuk@users.noreply.github.com> --- SUPPORTED_APIS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUPPORTED_APIS.md b/SUPPORTED_APIS.md index 77b98396..d5480dc9 100644 --- a/SUPPORTED_APIS.md +++ b/SUPPORTED_APIS.md @@ -14,7 +14,7 @@ The `status` options are: | Namespace | API |
Status
| Description | | --- | --- | --- | --- | -| `ANVIL` | `anvil_setNonce` | `SUPPORTED` | Sets the nonce of a given account | +| `ANVIL` | `anvil_setNonce` | `SUPPORTED` | Sets the nonce of an address.| | `ANVIL` | `anvil_impersonateAccount` | `SUPPORTED` | Impersonate an account | | `ANVIL` | `anvil_stopImpersonatingAccount` | `SUPPORTED` | Stop impersonating an account after having previously used `anvil_impersonateAccount` | | `ANVIL` | `anvil_reset` | `PARTIALLY` | Resets the state of the network; cannot revert to past block numbers, unless they're in a fork | From 0ed672c1d19200eb1d49861522478c0420fc2cf9 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 14 Aug 2024 11:01:48 +0200 Subject: [PATCH 21/32] added section for evm_setAccountNonce --- SUPPORTED_APIS.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/SUPPORTED_APIS.md b/SUPPORTED_APIS.md index d5480dc9..28ae9c0d 100644 --- a/SUPPORTED_APIS.md +++ b/SUPPORTED_APIS.md @@ -1677,6 +1677,35 @@ curl --request POST \ }' ``` +### `evm_setAccountNonce` + +[source](src/node/evm.rs) + +Modifies an account's nonce by overwriting it. +The new nonce must be greater than the existing nonce. + +#### Arguments + ++ `address: Address` - The `Address` whose nonce is to be changed ++ `nonce: U256` - The new nonce + +#### Example + +```bash +curl --request POST \ + --url http://localhost:8011/ \ + --header 'content-type: application/json' \ + --data '{ + "jsonrpc": "2.0", + "id": "1", + "method": "evm_setAccountNonce", + "params": [ + "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049", + "0x1337" + ] + }' +``` + ### `evm_increaseTime` [source](src/node/evm.rs) From 5857b4b94b7ea5c3a1d73dafabae24c535a674fa Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 14 Aug 2024 12:18:21 +0200 Subject: [PATCH 22/32] changed var to let to satisfy linter --- e2e-tests/test/main.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e-tests/test/main.test.ts b/e2e-tests/test/main.test.ts index 65df1b2b..d5719358 100644 --- a/e2e-tests/test/main.test.ts +++ b/e2e-tests/test/main.test.ts @@ -62,7 +62,7 @@ describe("Greeter Smart Contract", function () { // Validate log is created expect(receipt.logs.length).to.greaterThanOrEqual(1); - var setGreetingLog = null; + let setGreetingLog = null; for (var i = 0; setGreetingLog == null && i < receipt.logs.length; ++i) { if (receipt.logs[i].address == greeter.address) { setGreetingLog = receipt.logs[i]; @@ -84,7 +84,7 @@ describe("Greeter Smart Contract", function () { let receipt: TransactionReceipt = await setGreetingTx.wait(); expect(receipt.logs.length).to.greaterThanOrEqual(1); - var setGreetingLog = null; + let setGreetingLog = null; for (var i = 0; setGreetingLog == null && i < receipt.logs.length; ++i) { if (receipt.logs[i].address == greeter.address) { setGreetingLog = receipt.logs[i]; From 879ac9454f39795c3255f06627e7593ef5566c56 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 14 Aug 2024 12:22:25 +0200 Subject: [PATCH 23/32] using random address in anvil_setCode test --- e2e-tests/test/anvil-apis.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/e2e-tests/test/anvil-apis.test.ts b/e2e-tests/test/anvil-apis.test.ts index 2d7c542c..5e0b351a 100644 --- a/e2e-tests/test/anvil-apis.test.ts +++ b/e2e-tests/test/anvil-apis.test.ts @@ -94,7 +94,8 @@ describe("anvil_setCode", function () { const wallet = new Wallet(RichAccounts[0].PrivateKey); const deployer = new Deployer(hre, wallet); - const address = "0x1000000000000000000000000000000000001111"; + const randomWallet = Wallet.createRandom() + const address = randomWallet.address; const artifact = await deployer.loadArtifact("Return5"); const contractCode = [...ethers.utils.arrayify(artifact.deployedBytecode)]; From 6befae30cc2b7ce3685222f2d180f53c9c86ab64 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 14 Aug 2024 12:28:33 +0200 Subject: [PATCH 24/32] added semicolon --- e2e-tests/test/anvil-apis.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/test/anvil-apis.test.ts b/e2e-tests/test/anvil-apis.test.ts index 5e0b351a..76d5fb3e 100644 --- a/e2e-tests/test/anvil-apis.test.ts +++ b/e2e-tests/test/anvil-apis.test.ts @@ -94,7 +94,7 @@ describe("anvil_setCode", function () { const wallet = new Wallet(RichAccounts[0].PrivateKey); const deployer = new Deployer(hre, wallet); - const randomWallet = Wallet.createRandom() + const randomWallet = Wallet.createRandom(); const address = randomWallet.address; const artifact = await deployer.loadArtifact("Return5"); const contractCode = [...ethers.utils.arrayify(artifact.deployedBytecode)]; From 5ded038731bed4a2901ccac5b95884e5b953c914 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Wed, 14 Aug 2024 12:29:42 +0200 Subject: [PATCH 25/32] named test account address --- e2e-tests/test/anvil-apis.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/e2e-tests/test/anvil-apis.test.ts b/e2e-tests/test/anvil-apis.test.ts index 76d5fb3e..60d78969 100644 --- a/e2e-tests/test/anvil-apis.test.ts +++ b/e2e-tests/test/anvil-apis.test.ts @@ -65,12 +65,13 @@ describe("anvil_impersonateAccount & anvil_stopImpersonatingAccount", function ( it("Should allow transfers of funds without knowing the Private Key", async function () { // Arrange const userWallet = Wallet.createRandom().connect(provider); - const beforeBalance = await provider.getBalance(RichAccounts[5].Account); + const richAccount = RichAccounts[5].Account; + const beforeBalance = await provider.getBalance(richAccount); // Act - await provider.send("anvil_impersonateAccount", [RichAccounts[5].Account]); + await provider.send("anvil_impersonateAccount", [richAccount]); - const signer = await ethers.getSigner(RichAccounts[5].Account); + const signer = await ethers.getSigner(richAccount); const tx = { to: userWallet.address, value: ethers.utils.parseEther("0.42"), @@ -79,12 +80,11 @@ describe("anvil_impersonateAccount & anvil_stopImpersonatingAccount", function ( const recieptTx = await signer.sendTransaction(tx); await recieptTx.wait(); - await provider.send("anvil_stopImpersonatingAccount", [RichAccounts[5].Account]); + await provider.send("anvil_stopImpersonatingAccount", [richAccount]); // Assert expect((await userWallet.getBalance()).eq(ethers.utils.parseEther("0.42"))).to.true; - expect((await provider.getBalance(RichAccounts[5].Account)).eq(beforeBalance.sub(ethers.utils.parseEther("0.42")))) - .to.true; + expect((await provider.getBalance(richAccount)).eq(beforeBalance.sub(ethers.utils.parseEther("0.42")))).to.true; }); }); From ee3da1e98af88660bd13ffe920ab518b5f7afa0a Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Thu, 15 Aug 2024 08:26:42 +0200 Subject: [PATCH 26/32] changed var to let to satisfy linter --- e2e-tests/test/main.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e-tests/test/main.test.ts b/e2e-tests/test/main.test.ts index d5719358..d408f594 100644 --- a/e2e-tests/test/main.test.ts +++ b/e2e-tests/test/main.test.ts @@ -63,7 +63,7 @@ describe("Greeter Smart Contract", function () { // Validate log is created expect(receipt.logs.length).to.greaterThanOrEqual(1); let setGreetingLog = null; - for (var i = 0; setGreetingLog == null && i < receipt.logs.length; ++i) { + for (let i = 0; setGreetingLog == null && i < receipt.logs.length; ++i) { if (receipt.logs[i].address == greeter.address) { setGreetingLog = receipt.logs[i]; } @@ -85,7 +85,7 @@ describe("Greeter Smart Contract", function () { expect(receipt.logs.length).to.greaterThanOrEqual(1); let setGreetingLog = null; - for (var i = 0; setGreetingLog == null && i < receipt.logs.length; ++i) { + for (let i = 0; setGreetingLog == null && i < receipt.logs.length; ++i) { if (receipt.logs[i].address == greeter.address) { setGreetingLog = receipt.logs[i]; } From 2440f93ed787bc5e5732b7dbdddf322e5cff49ba Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Thu, 15 Aug 2024 09:41:00 +0200 Subject: [PATCH 27/32] Update src/namespaces/anvil.rs Co-authored-by: AnastasiiaVashchuk <72273339+AnastasiiaVashchuk@users.noreply.github.com> --- src/namespaces/anvil.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/namespaces/anvil.rs b/src/namespaces/anvil.rs index b0140521..3ce169bb 100644 --- a/src/namespaces/anvil.rs +++ b/src/namespaces/anvil.rs @@ -33,7 +33,7 @@ pub trait AnvilNamespaceT { /// Sometimes you may want to advance the latest block number of the network by a large number of blocks. /// One way to do this would be to call the evm_mine RPC method multiple times, but this is too slow if you want to mine thousands of blocks. - /// The hardhat_mine method can mine any number of blocks at once, in constant time. (It exhibits the same performance no matter how many blocks are mined.) + /// The `anvil_mine` method can mine any number of blocks at once, in constant time. (It exhibits the same performance no matter how many blocks are mined.) /// /// # Arguments /// From 5ff27011451e89af799b697b09dd844323164519 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Thu, 15 Aug 2024 10:10:25 +0200 Subject: [PATCH 28/32] removed to.be.within checks --- e2e-tests/test/zks-apis.test.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/e2e-tests/test/zks-apis.test.ts b/e2e-tests/test/zks-apis.test.ts index cf6b7a54..424e9ace 100644 --- a/e2e-tests/test/zks-apis.test.ts +++ b/e2e-tests/test/zks-apis.test.ts @@ -30,16 +30,12 @@ describe("zks_estimateFee", function () { // Act const response: Fee = await provider.send("zks_estimateFee", [transaction]); // Assert - expect(ethers.BigNumber.from(response.gas_limit).toNumber()).to.be.within(3606743, 5868728, "Unexpected gas_limit"); + expect(ethers.BigNumber.from(response.gas_limit).toNumber()).to.eql(4048728, "Unexpected gas_limit"); expect(ethers.BigNumber.from(response.gas_per_pubdata_limit)).to.eql( ethers.BigNumber.from("50000"), "Unexpected gas_per_pubdata_limit" ); - expect(ethers.BigNumber.from(response.max_fee_per_gas).toNumber()).to.be.within( - 25500297, - 37500000, - "Unexpected max_fee_per_gas" - ); + expect(ethers.BigNumber.from(response.max_fee_per_gas).toNumber()).to.eql(37500000, "Unexpected max_fee_per_gas"); expect(ethers.BigNumber.from(response.max_priority_fee_per_gas)).to.eql( ethers.BigNumber.from("0"), "Unexpected max_priority_fee_per_gas" From 1f8a1f4b98e9b2545e0bb1ed1d6660479aba6dc1 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Thu, 15 Aug 2024 10:27:07 +0200 Subject: [PATCH 29/32] supressing TypeScript errors --- e2e-tests/test/main.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/e2e-tests/test/main.test.ts b/e2e-tests/test/main.test.ts index d408f594..39dac548 100644 --- a/e2e-tests/test/main.test.ts +++ b/e2e-tests/test/main.test.ts @@ -71,7 +71,9 @@ describe("Greeter Smart Contract", function () { expect(setGreetingLog).not.to.equal(null); const eventInterface = new ethers.utils.Interface(["event LogString(string value)"]); - expect(eventInterface.parseLog(setGreetingLog).args[0]).to.equal("Greeting is being updated to Luke Skywalker"); + const parsedLog = eventInterface.parseLog(setGreetingLog); + const parsedLogArg = parsedLog.args[0].toString(); + expect(parsedLogArg).to.equal("Greeting is being updated to Luke Skywalker"); }); it("Should filter event logs", async function () { @@ -93,7 +95,7 @@ describe("Greeter Smart Contract", function () { expect(setGreetingLog).not.to.equal(null); // Create filter - const topic = setGreetingLog.topics[0]; + const topic = setGreetingLog!.topics[0]; const filterId = await provider.send("eth_newFilter", [ { fromBlock: "earliest", From 2fd9f3fdb683f76af810fabcc0cf031ec6ad5bbb Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Thu, 15 Aug 2024 11:08:14 +0200 Subject: [PATCH 30/32] supressing TypeScript errors --- e2e-tests/test/main.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/test/main.test.ts b/e2e-tests/test/main.test.ts index 39dac548..dce70215 100644 --- a/e2e-tests/test/main.test.ts +++ b/e2e-tests/test/main.test.ts @@ -71,7 +71,7 @@ describe("Greeter Smart Contract", function () { expect(setGreetingLog).not.to.equal(null); const eventInterface = new ethers.utils.Interface(["event LogString(string value)"]); - const parsedLog = eventInterface.parseLog(setGreetingLog); + const parsedLog = eventInterface.parseLog(setGreetingLog!); const parsedLogArg = parsedLog.args[0].toString(); expect(parsedLogArg).to.equal("Greeting is being updated to Luke Skywalker"); }); From 18fb13616c03bb7329f6a821ac468da8a5877386 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Tue, 20 Aug 2024 12:52:06 +0200 Subject: [PATCH 31/32] changed anvil_setCode code type --- e2e-tests/test/anvil-apis.test.ts | 8 ++++---- src/namespaces/anvil.rs | 2 +- src/node/anvil.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/e2e-tests/test/anvil-apis.test.ts b/e2e-tests/test/anvil-apis.test.ts index 60d78969..787b2fd6 100644 --- a/e2e-tests/test/anvil-apis.test.ts +++ b/e2e-tests/test/anvil-apis.test.ts @@ -97,7 +97,7 @@ describe("anvil_setCode", function () { const randomWallet = Wallet.createRandom(); const address = randomWallet.address; const artifact = await deployer.loadArtifact("Return5"); - const contractCode = [...ethers.utils.arrayify(artifact.deployedBytecode)]; + const contractCode = artifact.deployedBytecode; // Act await provider.send("anvil_setCode", [address, contractCode]); @@ -126,8 +126,8 @@ describe("anvil_setCode", function () { const address = "0x1000000000000000000000000000000000001111"; const artifact = await deployer.loadArtifact("Return5"); - const contractCode = [...ethers.utils.arrayify(artifact.deployedBytecode)]; - const shortCode = contractCode.slice(0, contractCode.length - 1); + const contractCode = artifact.deployedBytecode; + const shortCode = contractCode.slice(0, contractCode.length - 2); // Act await provider.send("anvil_setCode", [address, shortCode]); @@ -144,7 +144,7 @@ describe("anvil_setCode", function () { const greeter = await deployContract(deployer, "Greeter", ["Hi"]); expect(await greeter.greet()).to.eq("Hi"); const artifact = await deployer.loadArtifact("Return5"); - const newContractCode = [...ethers.utils.arrayify(artifact.deployedBytecode)]; + const newContractCode = artifact.deployedBytecode; // Act await provider.send("anvil_setCode", [greeter.address, newContractCode]); diff --git a/src/namespaces/anvil.rs b/src/namespaces/anvil.rs index 3ce169bb..4e332cfb 100644 --- a/src/namespaces/anvil.rs +++ b/src/namespaces/anvil.rs @@ -97,7 +97,7 @@ pub trait AnvilNamespaceT { /// /// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation. #[rpc(name = "anvil_setCode")] - fn set_code(&self, address: Address, code: Vec) -> RpcResult<()>; + fn set_code(&self, address: Address, code: String) -> RpcResult<()>; /// Directly modifies the storage of a contract at a specified slot. /// diff --git a/src/node/anvil.rs b/src/node/anvil.rs index b1a7abcf..bed94535 100644 --- a/src/node/anvil.rs +++ b/src/node/anvil.rs @@ -65,7 +65,7 @@ impl AnvilNames .into_boxed_future() } - fn set_code(&self, address: Address, code: Vec) -> RpcResult<()> { + fn set_code(&self, address: Address, code: String) -> RpcResult<()> { self.set_code(address, code) .map_err(|err| { tracing::error!("failed setting code: {:?}", err); From bb268134ac5842d2f3322f1c98e94f8d92c73689 Mon Sep 17 00:00:00 2001 From: Vaclav Barta Date: Tue, 27 Aug 2024 12:22:32 +0200 Subject: [PATCH 32/32] using find instead of an explicit loop --- e2e-tests/test/main.test.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/e2e-tests/test/main.test.ts b/e2e-tests/test/main.test.ts index dce70215..75d4a217 100644 --- a/e2e-tests/test/main.test.ts +++ b/e2e-tests/test/main.test.ts @@ -62,12 +62,7 @@ describe("Greeter Smart Contract", function () { // Validate log is created expect(receipt.logs.length).to.greaterThanOrEqual(1); - let setGreetingLog = null; - for (let i = 0; setGreetingLog == null && i < receipt.logs.length; ++i) { - if (receipt.logs[i].address == greeter.address) { - setGreetingLog = receipt.logs[i]; - } - } + const setGreetingLog = receipt.logs.find((log) => log.address === greeter.address); expect(setGreetingLog).not.to.equal(null); const eventInterface = new ethers.utils.Interface(["event LogString(string value)"]); @@ -86,12 +81,7 @@ describe("Greeter Smart Contract", function () { let receipt: TransactionReceipt = await setGreetingTx.wait(); expect(receipt.logs.length).to.greaterThanOrEqual(1); - let setGreetingLog = null; - for (let i = 0; setGreetingLog == null && i < receipt.logs.length; ++i) { - if (receipt.logs[i].address == greeter.address) { - setGreetingLog = receipt.logs[i]; - } - } + const setGreetingLog = receipt.logs.find((log) => log.address === greeter.address); expect(setGreetingLog).not.to.equal(null); // Create filter