Skip to content

Commit

Permalink
initial cofig
Browse files Browse the repository at this point in the history
  • Loading branch information
ManojJiSharma committed Oct 15, 2024
1 parent 12bc709 commit c613410
Show file tree
Hide file tree
Showing 6 changed files with 326 additions and 0 deletions.
23 changes: 23 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ members = [
"chains/binance",
"chains/avalanche",
"chains/rosetta-chain-testing",
"chains/base",
]
resolver = "2"

Expand Down
29 changes: 29 additions & 0 deletions chains/base/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "rosetta-testing-base"
version = "0.1.0"
edition = "2021"
license = "MIT"
repository = "https://github.com/analog-labs/chain-connectors"
description = "base rosetta test."


[dependencies]
alloy-sol-types = { version = "0.7" }
anyhow = "1.0"
ethers = { version = "2.0", default-features = true, features = ["abigen", "rustls", "ws"] }
ethers-solc = "2.0"
hex-literal = "0.4"
rand_core = { version = "0.6", features = ["getrandom"] }
rosetta-chain-testing = { path = "../rosetta-chain-testing" }
rosetta-client.workspace = true
rosetta-config-ethereum.workspace = true
rosetta-core.workspace = true
rosetta-docker = { workspace = true, features = ["tests"] }
rosetta-server-ethereum.workspace = true
sha3 = "0.10"
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
tracing = "0.1.40"
url = "2.4"

[dev-dependencies]
serial_test = "3.1.1"
255 changes: 255 additions & 0 deletions chains/base/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
#![allow(clippy::large_futures)]

//! # Base Testnet Rosetta Server
//!
//! This module contains the production test for an Base Rosetta server implementation
//! specifically designed for interacting with the Base Nitro Testnet. The code includes
//! tests for network status, account management, and smart contract interaction.
//!
//! ## Features
//!
//! - Network status tests to ensure proper connection and consistency with the Base Nitro
//! Testnet.
//! - Account tests, including faucet funding, balance retrieval, and error handling.
//! - Smart contract tests covering deployment, event emission, and view function calls.
//!
//! ## Dependencies
//!
//! - `anyhow`: For flexible error handling.
//! - `alloy_sol_types`: Custom types and macros for interacting with Solidity contracts.
//! - `ethers`: Ethereum library for interaction with Ethereum clients.
//! - `ethers_solc`: Integration for compiling Solidity code using the Solc compiler.
//! - `rosetta_client`: Client library for Rosetta API interactions.
//! - `rosetta_config_ethereum`: Configuration for Ethereum Rosetta server.
//! - `rosetta_server_base`: Custom client implementation for interacting with Base.
//! - `sha3`: SHA-3 (Keccak) implementation for hashing.
//! - `tokio`: Asynchronous runtime for running async functions.
//!
//! ## Usage
//!
//! To run the tests, execute the following command:
//!
//! ```sh
//! cargo test --package rosetta-testing-base --lib -- tests --nocapture
//! ```
//!
//! Note: The code assumes a local Base Nitro Testnet node running on `ws://127.0.0.1:8548` and
//! a local Ethereum node on `http://localhost:8545`. Ensure that these endpoints are configured correctly.
#[allow(clippy::ignored_unit_patterns, clippy::pub_underscore_fields)]
#[cfg(test)]
mod tests {
use alloy_sol_types::{sol, SolCall};
use anyhow::Result;
use ethers::types::H256;
use ethers_solc::{artifacts::Source, CompilerInput, EvmVersion, Solc};
use hex_literal::hex;
use rosetta_chain_testing::run_test;
use rosetta_client::Wallet;
use rosetta_config_ethereum::{AtBlock, CallResult};
use rosetta_core::BlockchainClient;
use rosetta_server_ethereum::MaybeWsEthereumClient;
use serial_test::serial;
use sha3::Digest;
use std::{collections::BTreeMap, path::Path};

/// Account used to fund other testing accounts.
const FUNDING_ACCOUNT_PRIVATE_KEY: [u8; 32] =
hex!("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d");

/// Base rpc url
const BASE_RPC_WS_URL: &str = "wss://base-sepolia-rpc.publicnode.com";

sol! {
interface TestContract {
event AnEvent();
function emitEvent() external;

function identity(bool a) external view returns (bool);
}
}

#[tokio::test]
#[serial]
async fn network_status() {
run_test(async move {
let client = MaybeWsEthereumClient::new("base", "dev", BASE_RPC_WS_URL, None)
.await
.expect("Error creating client");
// Check if the genesis is consistent
let genesis_block = client.genesis_block();
assert_eq!(genesis_block.index, 0);

// Check if the current block is consistent
let current_block = client.current_block().await.unwrap();
if current_block.index > 0 {
assert_ne!(current_block.hash, genesis_block.hash);
} else {
assert_eq!(current_block.hash, genesis_block.hash);
}

// Check if the finalized block is consistent
let finalized_block = client.finalized_block().await.unwrap();
assert!(finalized_block.index >= genesis_block.index);
})
.await;
}

#[tokio::test]
#[serial]
async fn test_account() {
run_test(async move {
let client = MaybeWsEthereumClient::new(
"base",
"dev",
BASE_RPC_WS_URL,
Some(FUNDING_ACCOUNT_PRIVATE_KEY),
)
.await
.expect("Error creating BaseClient");
let wallet = Wallet::from_config(
client.config().clone(),
BASE_RPC_WS_URL,
None,
Some(FUNDING_ACCOUNT_PRIVATE_KEY),
)
.await
.unwrap();
let value = 10 * u128::pow(10, client.config().currency_decimals);
let _ = wallet.faucet(value, Some(25_000_000_000)).await;
let amount = wallet.balance().await.unwrap();
assert_eq!(amount, value);
})
.await;
}

fn compile_snippet(source: &str) -> Result<Vec<u8>> {
let solc = Solc::default();
let source = format!("contract Contract {{ {source} }}");
let mut sources = BTreeMap::new();
sources.insert(Path::new("contract.sol").into(), Source::new(source));
let input = CompilerInput::with_sources(sources)[0]
.clone()
.evm_version(EvmVersion::Homestead);
let output = solc.compile_exact(&input)?;
let file = output.contracts.get("contract.sol").unwrap();
let contract = file.get("Contract").unwrap();
let bytecode = contract
.evm
.as_ref()
.unwrap()
.bytecode
.as_ref()
.unwrap()
.object
.as_bytes()
.unwrap()
.to_vec();
Ok(bytecode)
}

#[tokio::test]
#[serial]
async fn test_smart_contract() {
run_test(async move {
let client = MaybeWsEthereumClient::new(
"base",
"dev",
BASE_RPC_WS_URL,
Some(FUNDING_ACCOUNT_PRIVATE_KEY),
)
.await
.expect("Error creating BaseClient");
let faucet = 10 * u128::pow(10, client.config().currency_decimals);
let wallet = Wallet::from_config(
client.config().clone(),
BASE_RPC_WS_URL,
None,
Some(FUNDING_ACCOUNT_PRIVATE_KEY),
)
.await
.unwrap();
wallet.faucet(faucet, Some(50_000_000_000)).await.unwrap();

let bytes = compile_snippet(
r"
event AnEvent();
function emitEvent() public {
emit AnEvent();
}
",
)
.unwrap();
let tx_hash = wallet.eth_deploy_contract(bytes).await.unwrap().tx_hash().0;
let receipt = wallet.eth_transaction_receipt(tx_hash).await.unwrap().unwrap();
let contract_address = receipt.contract_address.unwrap();
let tx_hash = {
let call = TestContract::emitEventCall {};
wallet
.eth_send_call(contract_address.0, call.abi_encode(), 0, None, None)
.await
.unwrap()
.tx_hash()
.0
};
let receipt = wallet.eth_transaction_receipt(tx_hash).await.unwrap().unwrap();
assert_eq!(receipt.logs.len(), 1);
let topic = receipt.logs[0].topics[0];
let expected = H256(sha3::Keccak256::digest("AnEvent()").into());
assert_eq!(topic, expected);
})
.await;
}

#[tokio::test]
#[serial]
async fn test_smart_contract_view() {
run_test(async move {
let client = MaybeWsEthereumClient::new(
"base",
"dev",
BASE_RPC_WS_URL,
Some(FUNDING_ACCOUNT_PRIVATE_KEY),
)
.await
.expect("Error creating BaseClient");
let faucet = 10 * u128::pow(10, client.config().currency_decimals);
let wallet = Wallet::from_config(
client.config().clone(),
BASE_RPC_WS_URL,
None,
Some(FUNDING_ACCOUNT_PRIVATE_KEY),
)
.await
.unwrap();
wallet.faucet(faucet, Some(25_000_000_000)).await.unwrap();
let bytes = compile_snippet(
r"
function identity(bool a) public view returns (bool) {
return a;
}
",
)
.unwrap();
let tx_hash = wallet.eth_deploy_contract(bytes).await.unwrap().tx_hash().0;
let receipt = wallet.eth_transaction_receipt(tx_hash).await.unwrap().unwrap();
let contract_address = receipt.contract_address.unwrap();

let response = {
let call = TestContract::identityCall { a: true };
wallet
.eth_view_call(contract_address.0, call.abi_encode(), AtBlock::Latest)
.await
.unwrap()
};
assert_eq!(
response,
CallResult::Success(
hex!("0000000000000000000000000000000000000000000000000000000000000001")
.to_vec()
)
);
})
.await;
}
}
17 changes: 17 additions & 0 deletions chains/ethereum/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,23 @@ pub fn avalanche_config(network: &str) -> anyhow::Result<BlockchainConfig> {
Ok(evm_config("avalanche", network, "AVAX", bip44_id, is_dev))
}

/// Retrieve the [`BlockchainConfig`] from the provided base `network`
///
/// # Errors
/// Returns `Err` if the network is not supported
pub fn base_config(network: &str) -> anyhow::Result<BlockchainConfig> {
// All available networks are listed here:
let (network, bip44_id, is_dev) = match network {
"dev" => ("dev", 1, true),
"sepolia" => ("sepolia", 84532, true),
"mainnet" => ("mainnet", 8453, false),
_ => anyhow::bail!("unsupported network: {}", network),
};
Ok(evm_config("avalanche", network, "AVAX", bip44_id, is_dev))
}



/// Retrieve the [`BlockchainConfig`] from the provided ethereum `network`
///
/// # Errors
Expand Down
1 change: 1 addition & 0 deletions chains/ethereum/server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ impl MaybeWsEthereumClient {
"arbitrum" => rosetta_config_ethereum::arbitrum_config(network)?,
"binance" => rosetta_config_ethereum::binance_config(network)?,
"avalanche" => rosetta_config_ethereum::avalanche_config(network)?,
"base" => rosetta_config_ethereum::base_config(network)?,
blockchain => anyhow::bail!("unsupported blockchain: {blockchain}"),
};
Self::from_config(config, addr, private_key).await
Expand Down

0 comments on commit c613410

Please sign in to comment.