diff --git a/SUPPORTED_APIS.md b/SUPPORTED_APIS.md index 9283f0dc..c3bec4c3 100644 --- a/SUPPORTED_APIS.md +++ b/SUPPORTED_APIS.md @@ -95,7 +95,7 @@ The `status` options are: | `HARDHAT` | `hardhat_metadata` | `NOT IMPLEMENTED` | Returns the metadata of the current network | | `HARDHAT` | `hardhat_mine` | `NOT IMPLEMENTED`
[GitHub Issue #75](https://github.com/matter-labs/era-test-node/issues/75) | Mine any number of blocks at once, in constant time | | `HARDHAT` | `hardhat_reset` | `NOT IMPLEMENTED` | Resets the state of the network | -| `HARDHAT` | `hardhat_setBalance` | `NOT IMPLEMENTED`
[GitHub Issue #76](https://github.com/matter-labs/era-test-node/issues/76) | Modifies the balance of an account | +| [`HARDHAT`](#hardhat-namespace) | [`hardhat_setBalance`](#hardhat_setbalance) | `SUPPORTED` | Modifies the balance of an account | | `HARDHAT` | `hardhat_setCode` | `NOT IMPLEMENTED` | Sets the bytecode of a given account | | `HARDHAT` | `hardhat_setCoinbase` | `NOT IMPLEMENTED` | Sets the coinbase address | | `HARDHAT` | `hardhat_setLoggingEnabled` | `NOT IMPLEMENTED` | Enables or disables logging in Hardhat Network | @@ -683,6 +683,40 @@ curl --request POST \ }' ``` +## `HARDHAT NAMESPACE` + +### `hardhat_setBalance` + +[source](src/hardhat.rs) + +Sets the balance of the given address to the given balance. + +#### Arguments + ++ `address: Address` - The `Address` whose balance will be edited ++ `balance: U256` - The balance to set for the given address, in wei + +#### Status + +`SUPPORTED` + +#### Example + +```bash +curl --request POST \ + --url http://localhost:8011/ \ + --header 'content-type: application/json' \ + --data '{ + "jsonrpc": "2.0", + "id": "1", + "method": "hardhat_setBalance", + "params": [ + "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049", + "0x1337" + ] + }' +``` + ## `ZKS NAMESPACE` ### `zks_estimateFee` diff --git a/src/hardhat.rs b/src/hardhat.rs new file mode 100644 index 00000000..0cb206f9 --- /dev/null +++ b/src/hardhat.rs @@ -0,0 +1,97 @@ +use std::sync::{Arc, RwLock}; + +use crate::{fork::ForkSource, node::InMemoryNodeInner}; +use jsonrpc_core::{BoxFuture, Result}; +use jsonrpc_derive::rpc; +use zksync_basic_types::{Address, U256}; +use zksync_core::api_server::web3::backend_jsonrpc::error::into_jsrpc_error; +use zksync_types::utils::storage_key_for_eth_balance; +use zksync_utils::u256_to_h256; +use zksync_web3_decl::error::Web3Error; + +/// Implementation of HardhatNamespaceImpl +pub struct HardhatNamespaceImpl { + node: Arc>>, +} + +impl HardhatNamespaceImpl { + /// Creates a new `Hardhat` instance with the given `node`. + pub fn new(node: Arc>>) -> Self { + Self { node } + } +} + +#[rpc] +pub trait HardhatNamespaceT { + /// 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 = "hardhat_setBalance")] + fn set_balance(&self, address: Address, balance: U256) -> BoxFuture>; +} + +impl HardhatNamespaceT + for HardhatNamespaceImpl +{ + fn set_balance( + &self, + address: Address, + balance: U256, + ) -> jsonrpc_core::BoxFuture> { + let inner = Arc::clone(&self.node); + + Box::pin(async move { + match inner.write() { + Ok(mut inner_guard) => { + let balance_key = storage_key_for_eth_balance(&address); + inner_guard + .fork_storage + .set_value(balance_key, u256_to_h256(balance)); + println!( + "👷 Balance for address {:?} has been manually set to {} Wei", + address, balance + ); + Ok(true) + } + Err(_) => { + let web3_error = Web3Error::InternalError; + Err(into_jsrpc_error(web3_error)) + } + } + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{http_fork_source::HttpForkSource, node::InMemoryNode}; + use std::str::FromStr; + use zksync_core::api_server::web3::backend_jsonrpc::namespaces::eth::EthNamespaceT; + + #[tokio::test] + async fn test_set_balance() { + let address = Address::from_str("0x36615Cf349d7F6344891B1e7CA7C72883F5dc049").unwrap(); + let node = InMemoryNode::::default(); + let hardhat = HardhatNamespaceImpl::new(node.get_inner()); + + let balance_before = node.get_balance(address, None).await.unwrap(); + + let result = hardhat + .set_balance(address, U256::from(1337)) + .await + .unwrap(); + assert!(result); + + let balance_after = node.get_balance(address, None).await.unwrap(); + assert_eq!(balance_after, U256::from(1337)); + assert_ne!(balance_before, balance_after); + } +} diff --git a/src/main.rs b/src/main.rs index 719784ac..47636b11 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,7 +41,7 @@ //! ## Contributions //! //! Contributions to improve `era-test-node` are welcome. Please refer to the contribution guidelines for more details. - +use crate::hardhat::{HardhatNamespaceImpl, HardhatNamespaceT}; use crate::node::{ShowGasDetails, ShowStorageLogs, ShowVMDetails}; use clap::{Parser, Subcommand}; use configuration_api::ConfigurationApiNamespaceT; @@ -55,6 +55,7 @@ mod console_log; mod deps; mod fork; mod formatter; +mod hardhat; mod http_fork_source; mod node; mod resolver; @@ -139,6 +140,7 @@ async fn build_json_http< net: NetNamespace, config_api: ConfigurationApiNamespace, zks: ZkMockNamespaceImpl, + hardhat: HardhatNamespaceImpl, ) -> tokio::task::JoinHandle<()> { let (sender, recv) = oneshot::channel::<()>(); @@ -148,7 +150,7 @@ async fn build_json_http< io.extend_with(net.to_delegate()); io.extend_with(config_api.to_delegate()); io.extend_with(zks.to_delegate()); - + io.extend_with(hardhat.to_delegate()); io }; @@ -315,6 +317,7 @@ async fn main() -> anyhow::Result<()> { let net = NetNamespace::new(L2ChainId(TEST_NODE_NETWORK_ID)); let config_api = ConfigurationApiNamespace::new(node.get_inner()); let zks = ZkMockNamespaceImpl::new(node.get_inner()); + let hardhat = HardhatNamespaceImpl::new(node.get_inner()); let threads = build_json_http( SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), opt.port), @@ -322,6 +325,7 @@ async fn main() -> anyhow::Result<()> { net, config_api, zks, + hardhat, ) .await; diff --git a/test_endpoints.http b/test_endpoints.http index 0e72fa95..2d2572dc 100644 --- a/test_endpoints.http +++ b/test_endpoints.http @@ -265,6 +265,20 @@ content-type: application/json POST http://localhost:8011 content-type: application/json +{ + "jsonrpc": "2.0", + "id": "2", + "method": "hardhat_setBalance", + "params": [ + "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049", + "0x1337" + ] +} + +### +POST http://localhost:8011 +content-type: application/json + { "jsonrpc": "2.0", "id": "1",