Skip to content

Spending: non-leverage mode

Spend finalized testnet deposits in one call.

use alloy_primitives::{Address, U256};
use alloy_provider::network::{EthereumWallet, TxSigner};
use alloy_provider::ProviderBuilder;
use alloy_signer_local::LocalSigner;
use std::str::FromStr;
use tides_core_types::TidesChainId;
use trident_sdk::{envs, EvmToEvmSpendRequest, TridentClient};
#[tokio::main]
async fn main() {
println!("==== Trident spend-only walkthrough (assumes funds already deposited) ====");
// Example config: adjust chain names, RPCs, token, and private key as needed.
let src_chain_name = "arc-testnet";
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 recipient = Address::from_str("0x0123456789abcdef0123456789abcdef01234567")
.expect("recipient address");
let amount = U256::from(1u64).pow(U256::from(18u64)); // 1 token
println!("1) Prepare signer and attester client");
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;
println!("2) Confirm available balance on source chain (attester view)");
let available_balance = client
.evm_balance(source_chain_id, recipient, src_token)
.await
.expect("attester balance lookup");
println!(
" - Available on {} for {}: {}",
src_dep.chain_name, recipient, available_balance
);
assert!(
available_balance >= amount,
"Insufficient balance for spend; deposit funds first"
);
println!("3) Bind destination provider (for claim submission)");
let dst_provider = ProviderBuilder::new()
.wallet(EthereumWallet::from(signer.clone()))
.connect_http(dst_rpc.parse().expect("dst rpc"));
println!("4) Craft spend request and submit cross-chain transfer");
let spend_req = EvmToEvmSpendRequest::new(
&signer,
source_chain_id,
src_token,
amount,
&dst_provider,
destination_chain_id,
recipient,
);
let _spend_resp = client
.evm_to_evm_spend(spend_req)
.await
.expect("spend src->dst");
println!(
"Submitted spend from {} to {} for {} token(s).",
src_dep.chain_name, dst_dep.chain_name, amount
);
}
let src_chain_name = "arc-testnet";
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 recipient = Address::from_str("0x0123456789abcdef0123456789abcdef01234567")
.expect("recipient address");
let amount = U256::from(1u64).pow(U256::from(18u64)); // 1 token

Choose source/destination chains, RPCs, token, signing key, recipient, and spend amount for the cross-chain transfer.

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;

Load the signer, connect to the attester, and pull deployment metadata for both chains (including their chain_ids).

let available_balance = client
.evm_balance(source_chain_id, recipient, src_token)
.await
.expect("attester balance lookup");
assert!(
available_balance >= amount,
"Insufficient balance for spend; deposit funds first"
);

Read the attester-reported balance on the source chain and ensure it covers the requested spend.

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

Attach the signer to the destination RPC so the spend claim is submitted with the same key.

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

Construct the EvmToEvmSpendRequest and submit it via evm_to_evm_spend to deliver the funds on the destination chain.