Skip to content

Commit 24aca5b

Browse files
authored
Merge pull request #970 from dfinity/tl/eth_get_balance
Add get_balance endpoint to the basic_ethereum example
2 parents 17d70cb + 148ba4e commit 24aca5b

File tree

4 files changed

+86
-3
lines changed

4 files changed

+86
-3
lines changed

rust/basic_ethereum/Cargo.lock

Lines changed: 36 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/basic_ethereum/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,7 @@ ic-crypto-extended-bip32 = { git = "https://github.com/dfinity/ic", tag = "relea
2121
ic-crypto-sha3 = { git = "https://github.com/dfinity/ic", tag = "release-2024-06-26_23-01-base", package = "ic-crypto-sha3" }
2222
ic-ethereum-types = { git = "https://github.com/dfinity/ic", tag = "release-2024-06-26_23-01-base", package = "ic-ethereum-types" }
2323
serde = "1.0"
24+
serde_json = "1.0"
2425
serde_bytes = "0.11.15"
25-
num-traits = "0.2.19"
26+
num-traits = "0.2.19"
27+
num = "0.4.3"

rust/basic_ethereum/basic_ethereum.did

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ service : (opt InitArg) -> {
4242
// If the owner is not set, it defaults to the caller's principal.
4343
ethereum_address : (owner: opt principal) -> (text);
4444

45+
// Returns the balance of the given Ethereum address.
46+
get_balance : (address: text) -> (Wei);
47+
4548
// Returns the transaction count for the Ethereum address derived for the given principal.
4649
//
4750
// If the owner is not set, it defaults to the caller's principal.

rust/basic_ethereum/src/lib.rs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ use alloy_consensus::{SignableTransaction, TxEip1559, TxEnvelope};
88
use alloy_primitives::{hex, Signature, TxKind, U256};
99
use candid::{CandidType, Deserialize, Nat, Principal};
1010
use evm_rpc_canister_types::{
11-
BlockTag, EvmRpcCanister, GetTransactionCountArgs, GetTransactionCountResult,
12-
MultiGetTransactionCountResult,
11+
BlockTag, EthMainnetService, EthSepoliaService, EvmRpcCanister, GetTransactionCountArgs,
12+
GetTransactionCountResult, MultiGetTransactionCountResult, RequestResult, RpcService,
1313
};
1414
use ic_cdk::api::management_canister::ecdsa::{EcdsaCurve, EcdsaKeyId};
1515
use ic_cdk::{init, update};
1616
use ic_ethereum_types::Address;
17+
use num::{BigUint, Num};
1718
use std::str::FromStr;
1819

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

39+
#[update]
40+
pub async fn get_balance(address: String) -> Nat {
41+
let _caller = validate_caller_not_anonymous();
42+
let json = format!(
43+
r#"{{ "jsonrpc": "2.0", "method": "eth_getBalance", "params": ["{}", "latest"], "id": 1 }}"#,
44+
address
45+
);
46+
47+
let max_response_size_bytes = 500_u64;
48+
let num_cycles = 1_000_000_000u128;
49+
50+
let ethereum_network = read_state(|s| s.ethereum_network());
51+
52+
let rpc_service = match ethereum_network {
53+
EthereumNetwork::Mainnet => RpcService::EthMainnet(EthMainnetService::PublicNode),
54+
EthereumNetwork::Sepolia => RpcService::EthSepolia(EthSepoliaService::PublicNode),
55+
};
56+
57+
let (response,) = EVM_RPC
58+
.request(rpc_service, json, max_response_size_bytes, num_cycles)
59+
.await
60+
.expect("RPC call failed");
61+
62+
let hex_balance = match response {
63+
RequestResult::Ok(balance_result) => {
64+
// The response to a successful `eth_getBalance` call has the following format:
65+
// { "id": "[ID]", "jsonrpc": "2.0", "result": "[BALANCE IN HEX]" }
66+
let response: serde_json::Value = serde_json::from_str(&balance_result).unwrap();
67+
response
68+
.get("result")
69+
.and_then(|v| v.as_str())
70+
.unwrap()
71+
.to_string()
72+
}
73+
RequestResult::Err(e) => panic!("Received an error response: {:?}", e),
74+
};
75+
76+
// Remove the "0x" prefix before converting to a decimal number.
77+
Nat(BigUint::from_str_radix(&hex_balance[2..], 16).unwrap())
78+
}
79+
3880
#[update]
3981
pub async fn transaction_count(owner: Option<Principal>, block: Option<BlockTag>) -> Nat {
4082
let caller = validate_caller_not_anonymous();

0 commit comments

Comments
 (0)