Skip to content

Putting it together

Run the full flow in one binary: faucet -> deposit -> wait -> spend.

use alloy_primitives::U256;
use alloy_provider::ProviderBuilder;
use alloy_provider::network::{EthereumWallet, TxSigner};
use alloy_signer_local::LocalSigner;
use std::str::FromStr;
use std::time::{Duration, UNIX_EPOCH};
use tides_core_types::TidesChainId;
use trident_sdk::{EvmToEvmSpendRequest, TridentClient, envs};
#[tokio::main]
async fn main() {
// ---- START EXAMPLE CONFIG ----
// `chain_name` is used to find correct deployment, can use `TidesChainId` otherwise
// You can choose any of supported networks, see `TridentClient::get_deployments` for available deployments.
// `TEST_TOKEN` is an example token deployment on each chain for testing purposes.
// let src_chain_name = "base-sepolia";
// let src_rpc = "https://base-sepolia-public.nodies.app";
// let src_token = envs::testnet::sepolia_base::TEST_TOKEN;
let src_chain_name = "arc-testnet";
let src_rpc = "https://rpc.testnet.arc.network";
let src_token = envs::testnet::arc_testnet::TEST_TOKEN;
// let dst_chain_name = "base-sepolia";
// let dst_rpc = "https://base-sepolia-public.nodies.app";
let dst_chain_name = "ethereum-sepolia";
let dst_rpc = "https://ethereum-sepolia-rpc.publicnode.com";
// Hex encoded private key to sign transaction both on source and destination chains
let private_key = "0xYOUR_TEST_PRIVATE_KEY";
// Choose the amount.
let amount = U256::from(10u64).pow(U256::from(18u64));
// ---- END EXAMPLE CONFIG ----
// Build a signer from your private key.
let signer = LocalSigner::from_str(private_key).expect("valid private key");
// Connect to Trident testnet attester & resolve deployments.
let mut client = TridentClient::connect_testnet()
.await
.expect("attester connect");
let src_dep = client
.get_deployment_by_name(src_chain_name)
.unwrap_or_else(|| panic!("deployment '{}' not found", src_chain_name))
.clone();
let dst_dep = client
.get_deployment_by_name(dst_chain_name)
.unwrap_or_else(|| panic!("deployment '{}' not found", dst_chain_name))
.clone();
let source_chain_id = src_dep.chain_id as TidesChainId;
let destination_chain_id = dst_dep.chain_id as TidesChainId;
// Providers bound to the signer (for tx submission on each chain).
let src_provider = ProviderBuilder::new()
.wallet(EthereumWallet::from(signer.clone()))
.connect_http(src_rpc.parse().expect("src rpc"));
let dst_provider = ProviderBuilder::new()
.wallet(EthereumWallet::from(signer.clone()))
.connect_http(dst_rpc.parse().expect("dst rpc"));
println!("1) Requesting some money from faucet...");
let recipient = TxSigner::address(&signer);
let _faucet_receipt = client
.evm_faucet(&src_provider, src_token, recipient, amount)
.await
.expect("faucet mint on source");
let source_balance_before = client
.evm_balance(source_chain_id, recipient, src_token)
.await
.expect("balances");
println!("2) Depositing token amount to Trident vault...");
// Use ERC-20 approve
let deposit_result = client
.evm_deposit_with_approval(&src_provider, source_chain_id, src_token, amount)
.await
.expect("deposit with approval");
println!(
"Deposited balance on {} at block {:?}",
src_dep.chain_name, deposit_result.deposit_tx_receipt.block_number
);
// Or use ERC-7597 permit
// let _deposit_result = client
// .evm_sign_and_deposit_with_permit(&src_provider, &signer, source_chain_id, src_token, amount, U256::MAX)
// .await
// .expect("evm_sign_and_deposit_with_permit");
// 3) Wait for finalization on source chain by checking available balance via the attester
// Block finalization time is different on every chain so delay may vary.
loop {
let source_balance_after = client
.evm_balance(source_chain_id, recipient, src_token)
.await
.expect("balances");
println!(
"[{}] Available amount on source chain: {}",
std::time::SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis(),
source_balance_after,
);
if source_balance_after > source_balance_before {
println!("3) Deposit has been finalized");
break;
}
println!("Deposit hasn't arrived yet, wait 10 seconds");
tokio::time::sleep(Duration::from_secs(10)).await;
}
// 4) Craft and spend (Base Sepolia -> Ethereum Sepolia)
let req = EvmToEvmSpendRequest::new(
&signer,
source_chain_id,
src_token,
amount, // spend 1 token cross-chain
&dst_provider,
destination_chain_id,
recipient,
);
println!("4) Submitting EvmToEvmSpendRequest...");
let _spend_resp = client.evm_to_evm_spend(req).await.expect("spend src->dst");
println!(
"Submitted spend from {} to {} for 1 token",
src_chain_name, dst_chain_name
);
}
let src_chain_name = "arc-testnet";
let src_rpc = "https://rpc.testnet.arc.network";
let src_token = envs::testnet::arc_testnet::TEST_TOKEN;
let dst_chain_name = "ethereum-sepolia";
let dst_rpc = "https://ethereum-sepolia-rpc.publicnode.com";
let private_key = "0xYOUR_TEST_PRIVATE_KEY";
let amount = U256::from(10u64).pow(U256::from(18u64));

Pick source/destination chains, RPCs, token, private key, and the amount to move end-to-end (defaults use Arc -> Ethereum Sepolia).

Connect to Trident and resolve deployments

Section titled “Connect to Trident and resolve deployments”
let signer = LocalSigner::from_str(private_key).expect("valid private key");
let mut client = TridentClient::connect_testnet()
.await
.expect("attester connect");
let src_dep = client
.get_deployment_by_name(src_chain_name)
.unwrap_or_else(|| panic!("deployment '{}' not found", src_chain_name))
.clone();
let dst_dep = client
.get_deployment_by_name(dst_chain_name)
.unwrap_or_else(|| panic!("deployment '{}' not found", dst_chain_name))
.clone();
let source_chain_id = src_dep.chain_id as TidesChainId;
let destination_chain_id = dst_dep.chain_id as TidesChainId;

Create the signer, connect to the attester, and fetch deployment metadata (including chain_ids) for both chains.

let src_provider = ProviderBuilder::new()
.wallet(EthereumWallet::from(signer.clone()))
.connect_http(src_rpc.parse().expect("src rpc"));
let dst_provider = ProviderBuilder::new()
.wallet(EthereumWallet::from(signer.clone()))
.connect_http(dst_rpc.parse().expect("dst rpc"));

Attach the signer to RPC providers on both chains so faucet, deposit, and spend transactions use the same key.

let recipient = TxSigner::address(&signer);
let _faucet_receipt = client
.evm_faucet(&src_provider, src_token, recipient, amount)
.await
.expect("faucet mint on source");
let source_balance_before = client
.evm_balance(source_chain_id, recipient, src_token)
.await
.expect("balances");

Mint test tokens on the source chain and record the attester-reported balance before depositing.

let deposit_result = client
.evm_deposit_with_approval(&src_provider, source_chain_id, src_token, amount)
.await
.expect("deposit with approval");

Approve and deposit in one call; the receipt includes the block where the deposit landed.

loop {
let source_balance_after = client
.evm_balance(source_chain_id, recipient, src_token)
.await
.expect("balances");
if source_balance_after > source_balance_before {
println!("3) Deposit has been finalized");
break;
}
tokio::time::sleep(Duration::from_secs(10)).await;
}

Poll evm_balance until it increases, signaling the attester has finalized the deposit.

let req = EvmToEvmSpendRequest::new(
&signer,
source_chain_id,
src_token,
amount,
&dst_provider,
destination_chain_id,
recipient,
);
let _spend_resp = client.evm_to_evm_spend(req).await.expect("spend src->dst");

Build the spend request and submit it to deliver the funds from the source chain to the destination chain.