Skip to content

Commit

Permalink
Merge pull request #970 from dfinity/tl/eth_get_balance
Browse files Browse the repository at this point in the history
Add get_balance endpoint to the basic_ethereum example
  • Loading branch information
THLO authored Sep 9, 2024
2 parents 17d70cb + 148ba4e commit 24aca5b
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 3 deletions.
36 changes: 36 additions & 0 deletions rust/basic_ethereum/Cargo.lock

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

4 changes: 3 additions & 1 deletion rust/basic_ethereum/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@ ic-crypto-extended-bip32 = { git = "https://github.com/dfinity/ic", tag = "relea
ic-crypto-sha3 = { git = "https://github.com/dfinity/ic", tag = "release-2024-06-26_23-01-base", package = "ic-crypto-sha3" }
ic-ethereum-types = { git = "https://github.com/dfinity/ic", tag = "release-2024-06-26_23-01-base", package = "ic-ethereum-types" }
serde = "1.0"
serde_json = "1.0"
serde_bytes = "0.11.15"
num-traits = "0.2.19"
num-traits = "0.2.19"
num = "0.4.3"
3 changes: 3 additions & 0 deletions rust/basic_ethereum/basic_ethereum.did
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ service : (opt InitArg) -> {
// If the owner is not set, it defaults to the caller's principal.
ethereum_address : (owner: opt principal) -> (text);

// Returns the balance of the given Ethereum address.
get_balance : (address: text) -> (Wei);

// Returns the transaction count for the Ethereum address derived for the given principal.
//
// If the owner is not set, it defaults to the caller's principal.
Expand Down
46 changes: 44 additions & 2 deletions rust/basic_ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ use alloy_consensus::{SignableTransaction, TxEip1559, TxEnvelope};
use alloy_primitives::{hex, Signature, TxKind, U256};
use candid::{CandidType, Deserialize, Nat, Principal};
use evm_rpc_canister_types::{
BlockTag, EvmRpcCanister, GetTransactionCountArgs, GetTransactionCountResult,
MultiGetTransactionCountResult,
BlockTag, EthMainnetService, EthSepoliaService, EvmRpcCanister, GetTransactionCountArgs,
GetTransactionCountResult, MultiGetTransactionCountResult, RequestResult, RpcService,
};
use ic_cdk::api::management_canister::ecdsa::{EcdsaCurve, EcdsaKeyId};
use ic_cdk::{init, update};
use ic_ethereum_types::Address;
use num::{BigUint, Num};
use std::str::FromStr;

pub const EVM_RPC_CANISTER_ID: Principal =
Expand All @@ -35,6 +36,47 @@ pub async fn ethereum_address(owner: Option<Principal>) -> String {
wallet.ethereum_address().to_string()
}

#[update]
pub async fn get_balance(address: String) -> Nat {
let _caller = validate_caller_not_anonymous();
let json = format!(
r#"{{ "jsonrpc": "2.0", "method": "eth_getBalance", "params": ["{}", "latest"], "id": 1 }}"#,
address
);

let max_response_size_bytes = 500_u64;
let num_cycles = 1_000_000_000u128;

let ethereum_network = read_state(|s| s.ethereum_network());

let rpc_service = match ethereum_network {
EthereumNetwork::Mainnet => RpcService::EthMainnet(EthMainnetService::PublicNode),
EthereumNetwork::Sepolia => RpcService::EthSepolia(EthSepoliaService::PublicNode),
};

let (response,) = EVM_RPC
.request(rpc_service, json, max_response_size_bytes, num_cycles)
.await
.expect("RPC call failed");

let hex_balance = match response {
RequestResult::Ok(balance_result) => {
// The response to a successful `eth_getBalance` call has the following format:
// { "id": "[ID]", "jsonrpc": "2.0", "result": "[BALANCE IN HEX]" }
let response: serde_json::Value = serde_json::from_str(&balance_result).unwrap();
response
.get("result")
.and_then(|v| v.as_str())
.unwrap()
.to_string()
}
RequestResult::Err(e) => panic!("Received an error response: {:?}", e),
};

// Remove the "0x" prefix before converting to a decimal number.
Nat(BigUint::from_str_radix(&hex_balance[2..], 16).unwrap())
}

#[update]
pub async fn transaction_count(owner: Option<Principal>, block: Option<BlockTag>) -> Nat {
let caller = validate_caller_not_anonymous();
Expand Down

0 comments on commit 24aca5b

Please sign in to comment.