Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion tools/anda_bnb/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ reqwest = { workspace = true }
thiserror = { workspace = true }
k256 = { workspace = true }
async-trait = { workspace = true }
alloy = { version = "1.0", features = [
structured-logger = { workspace = true }
alloy = { version = "1.0.25", features = [
"providers",
"network",
"sol-types",
Expand Down
122 changes: 122 additions & 0 deletions tools/anda_bnb/examples/balance_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/// Tests the balance retrieval functionality for BNB ledgers.
///
/// This async function demonstrates the process of:
/// - Loading cryptographic identity and secrets
/// - Initializing a Web3 client for BNB Chain
/// - Creating BNB ledgers and a balance query tool
/// - Deriving a user's EVM address
/// - Querying balances for different token symbols
///
/// # Examples
///
/// test_bnb_ledger_balance().await;
///
use std::sync::Arc;

use alloy::hex;
use anda_bnb::ledger::{BNBLedgers, BalanceOfArgs, BalanceOfTool, DRVT_PATH, bnb_rpc};
use anda_bnb::signer::derive_address_from_pubkey;
use anda_core::{KeysFeatures, Tool};
use anda_engine::{context::Web3SDK, engine::EngineBuilder, extension::extractor::Extractor};
use anda_web3_client::client::{Client as Web3Client, load_identity};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::collections::BTreeSet;
use structured_logger::Builder;

use crate::common::{CHAIN_ID, TOKEN_ADDR};
mod common;

pub async fn test_bnb_ledger_balance() {
Builder::with_level("debug").init();

// Read identity and root secret
let id_secret = dotenv::var("ID_SECRET").unwrap();
let root_secret_org = dotenv::var("ROOT_SECRET").unwrap();

// Parse and validate cryptographic secrets
let identity = load_identity(&id_secret).unwrap();
let root_secret = hex::decode(&root_secret_org).unwrap();
let root_secret: [u8; 48] = root_secret
.try_into()
.map_err(|_| format!("invalid root_secret: {:?}", &root_secret_org))
.unwrap();

// Initialize Web3 client for BNB Chain network interaction
let web3 = Web3Client::builder()
.with_identity(Arc::new(identity))
.with_root_secret(root_secret)
.build()
.await
.unwrap();

let mut token_addrs = BTreeSet::new();
token_addrs.insert(TOKEN_ADDR.to_string());
let drvt_path: Vec<Vec<u8>> = DRVT_PATH.iter().map(|&s| s.to_vec()).collect();
// Create ledgers instance
let ledgers = BNBLedgers::load(bnb_rpc(), CHAIN_ID, drvt_path.clone(), token_addrs)
.await
.unwrap();
let ledgers = Arc::new(ledgers);
let tool = BalanceOfTool::new(ledgers.clone());
let definition = tool.definition();
assert_eq!(definition.name, "bnb_ledger_balance_of");

// Create an agent for testing
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
struct TestStruct {
name: String,
age: Option<u8>,
}
let agent = Extractor::<TestStruct>::default();

// Create a context for testing
let engine_ctx = EngineBuilder::new()
// .with_name("BNB_TEST".to_string()).unwrap()
.with_web3_client(Arc::new(Web3SDK::from_web3(Arc::new(web3))))
.register_agent(agent)
.unwrap()
.mock_ctx();
let base_ctx = engine_ctx.base.clone();

// Derive EVM address from derivation path
let pubkey_bytes = base_ctx
.secp256k1_public_key(drvt_path)
.await
.map_err(|e| {
format!(
"Failed to get public key from derivation path: {:?}. Error: {:?}",
DRVT_PATH,
e.to_string()
)
})
.unwrap();
let user_address = derive_address_from_pubkey(&pubkey_bytes).unwrap();
log::debug!(
"User pubkey: {:?}, User EVM address: {:?}",
hex::encode(pubkey_bytes),
user_address
);

// Iterate through the ledgers and perform balance queries
for (symbol, _) in ledgers.ledgers.clone() {
// Create arguments for balance query
let args = BalanceOfArgs {
account: user_address.to_string(),
symbol: symbol,
};

// Call the tool to query balance
let res = tool.call(base_ctx.clone(), args, vec![]).await;
assert!(res.is_ok(), "Balance query failed: {:?}", res);
println!("Balance query result: {:#?}", res.unwrap());
}
}

// cargo run --example balance_test
// cargo run -p anda_bnb --example balance_test
#[tokio::main]
async fn main() {
println!("Anda BNB query test!");
test_bnb_ledger_balance().await;
}
5 changes: 5 additions & 0 deletions tools/anda_bnb/examples/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// public static url of BNB BEP20 contract address
pub static TOKEN_ADDR: &str = "0xDE3a190D9D26A8271Ae9C27573c03094A8A2c449"; // BNB testnet

// public static chain id of BNB
pub static CHAIN_ID: u64 = 97; // BNB testnet
112 changes: 112 additions & 0 deletions tools/anda_bnb/examples/transfer_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/// Tests the BNB ledger transfer functionality by performing token transfers across different ledgers.
///
/// This test function demonstrates the process of:
/// - Loading cryptographic identity and secrets
/// - Creating a BNB ledger instance
/// - Initializing a Web3 client
/// - Creating an engine context
/// - Iterating through ledgers and performing token transfers
///
/// # Panics
/// Panics if identity loading, ledger loading, or token transfers fail
///
/// # Environment Variables
/// - `ID_SECRET`: Cryptographic identity secret
/// - `ROOT_SECRET`: Root secret for Web3 client
///
use std::{collections::BTreeSet, sync::Arc};

use alloy::hex;
use alloy::primitives::address;
use anda_bnb::ledger::{BNBLedgers, DRVT_PATH, TransferToArgs, TransferTool, bnb_rpc};
use anda_core::Tool;
use anda_engine::{context::Web3SDK, engine::EngineBuilder, extension::extractor::Extractor};
use anda_web3_client::client::{Client as Web3Client, load_identity};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use structured_logger::Builder;

use crate::common::{CHAIN_ID, TOKEN_ADDR};
mod common;

pub async fn test_bnb_ledger_transfer() {
Builder::with_level("debug").init();

// Generate random bytes for identity and root secret
let id_secret = dotenv::var("ID_SECRET").unwrap();
let root_secret_org = dotenv::var("ROOT_SECRET").unwrap();

// Parse cryptographic secrets
let identity = load_identity(&id_secret).unwrap();
let root_secret = hex::decode(&root_secret_org).unwrap();
let root_secret: [u8; 48] = root_secret
.try_into()
.map_err(|_| format!("invalid root_secret: {:?}", &root_secret_org))
.unwrap();

let mut token_addrs = BTreeSet::new();
token_addrs.insert(TOKEN_ADDR.to_string());
let drvt_path: Vec<Vec<u8>> = DRVT_PATH.iter().map(|&s| s.to_vec()).collect();

// Create a BNB ledger instance
let ledgers = BNBLedgers::load(bnb_rpc(), CHAIN_ID, drvt_path.clone(), token_addrs)
.await
.unwrap();
let ledgers = Arc::new(ledgers);
let tool = TransferTool::new(ledgers.clone());
let definition = tool.definition();
assert_eq!(definition.name, "bnb_ledger_transfer");
assert!(
tool.description()
.contains(ledgers.ledgers.clone().first_key_value().unwrap().0)
);

// Create an agent for testing
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
struct TestStruct {
name: String,
age: Option<u8>,
}
let agent = Extractor::<TestStruct>::default();

// Initialize Web3 client for BNB network
let web3 = Web3Client::builder()
.with_identity(Arc::new(identity))
.with_root_secret(root_secret)
.build()
.await
.unwrap();

// Create a context for testing
let engine_ctx = EngineBuilder::new()
.with_web3_client(Arc::new(Web3SDK::from_web3(Arc::new(web3))))
.register_agent(agent)
.unwrap()
.mock_ctx();
let base_ctx = engine_ctx.base;

// Iterate through the ledgers and perform transfers
for (symbol, _) in ledgers.ledgers.clone() {
// Init transfer arguments
let to_addr = address!("0xA8c4AAE4ce759072D933bD4a51172257622eF128"); // Receiver addr
let transfer_amount = 0.00012;
let transfer_to_args = TransferToArgs {
account: to_addr.to_string(),
symbol: symbol.clone(),
amount: transfer_amount,
};

// Call tool to transfer tokens
let res = tool.call(base_ctx.clone(), transfer_to_args, vec![]).await;
assert!(res.is_ok(), "Transfer failed: {:?}", res);
println!("Transfer result: {:#?}", res.unwrap());
}
}

// cargo run --example transfer_test
// cargo run -p anda_bnb --example transfer_test
#[tokio::main]
async fn main() {
println!("Anda BNB transfer test!");
test_bnb_ledger_transfer().await;
}
10 changes: 2 additions & 8 deletions tools/anda_bnb/src/ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,6 @@ pub fn bnb_rpc() -> String {
dotenv::var("BNB_RPC").unwrap_or_else(|_| "https://bsc-testnet.bnbchain.org".to_string())
}

// public static url of BNB BEP20 contract address
pub static TOKEN_ADDR: &str = "0xDE3a190D9D26A8271Ae9C27573c03094A8A2c449"; // BNB testnet

// public static chain id of BNB
pub static CHAIN_ID: u64 = 97; // BNB testnet

// public static derivation path
pub static DRVT_PATH: &[&[u8]] = &[b"44'", b"60'", b"10'", b"20", b"30"];

Expand All @@ -68,7 +62,7 @@ pub struct BNBLedgers {
chain_id: u64,
derivation_path: Vec<Vec<u8>>,
/// Map of token symbols to their corresponding canister ID and decimals places
ledgers: BTreeMap<String, (Address, u8)>,
pub ledgers: BTreeMap<String, (Address, u8)>,
}

impl BNBLedgers {
Expand Down Expand Up @@ -136,7 +130,7 @@ impl BNBLedgers {
// Get sender EVM address
let sender_address = NetworkWallet::<AnyNetwork>::default_signer_address(&wallet);
log::debug!("Sender EVM address: {:?}", sender_address);

// Create a provider with the wallet.
let provider = ProviderBuilder::new()
.with_simple_nonce_management()
Expand Down
5 changes: 4 additions & 1 deletion tools/anda_bnb/src/signer/anda_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ mod tests {
sync::Arc,
};

use crate::ledger::{CHAIN_ID, DRVT_PATH};
use crate::ledger::DRVT_PATH;
use anda_engine::{
context::Web3SDK,
engine::{AgentInfo, EngineBuilder},
Expand All @@ -226,6 +226,9 @@ mod tests {

use super::*;

// public static chain id of BNB
pub static CHAIN_ID: u64 = 97; // BNB testnet

#[tokio::test]
async fn test_sign_message() {
// Create an agent for testing
Expand Down