Skip to Content
ExamplesMulti-Token Agent

Multi-Token Agent

An agent that handles payments in multiple tokens — ETH, WVRN, and USDC — with proper approval management.

Full Code

import { ethers } from 'ethers' import { WeavrnClient } from '@weavrn/sdk' const PRIVATE_KEY = process.env.PRIVATE_KEY! // Token addresses on Base Sepolia const TOKENS = { WVRN: '0x1c17b46bd9b37024e86EA5fe05e1dE835aE1Ce0E', USDC: '0x...', // your USDC address } async function main() { const provider = new ethers.JsonRpcProvider('https://sepolia.base.org') const signer = new ethers.Wallet(PRIVATE_KEY, provider) const client = new WeavrnClient({ signer, chainId: 84532 }) if (!(await client.isRegistered())) { await client.register('MultiTokenAgent', 'https://example.com/agent.json') } // Approve all tokens upfront with large allowances await approveTokens(client) // Now pay in any token const recipient = '0xRecipient...' // ETH — no approval needed await client.pay(recipient, ethers.parseEther('0.001'), { memo: 'eth payment', }) // WVRN (18 decimals) await client.payERC20(recipient, TOKENS.WVRN, ethers.parseEther('100'), { memo: 'wvrn payment', decimals: 18, }) // USDC (6 decimals) await client.payERC20(recipient, TOKENS.USDC, ethers.parseUnits('25', 6), { memo: 'usdc payment', decimals: 6, }) } async function approveTokens(client: WeavrnClient) { const MAX_ALLOWANCE = ethers.MaxUint256 // Approve router for payments for (const [name, address] of Object.entries(TOKENS)) { console.log(`Approving ${name} for PaymentRouter...`) await client.approveRouter(address, MAX_ALLOWANCE) } // Approve escrow for escrow-based payments for (const [name, address] of Object.entries(TOKENS)) { console.log(`Approving ${name} for EscrowRouter...`) await client.approveEscrow(address, MAX_ALLOWANCE) } // Wait for approvals to propagate await new Promise(r => setTimeout(r, 3000)) } main().catch(console.error)

Token Decimals

Different tokens use different decimal places. Always match the decimals parameter to the token:

TokenDecimals1 unit in smallest unit
ETH18ethers.parseEther('1')
WVRN18ethers.parseEther('1')
USDC6ethers.parseUnits('1', 6)

The decimals option in payERC20 only affects how the returned amount and fee strings are formatted — the on-chain transfer uses the raw bigint amount you provide.

Approval Strategy

Two approaches:

Max Approval (Simpler)

Approve ethers.MaxUint256 once per token per contract. Fewer transactions, but grants unlimited spending.

await client.approveRouter(token, ethers.MaxUint256)

Exact Approval (Safer)

Approve the exact amount needed before each transaction. More gas, but limits exposure.

await client.approveRouter(token, ethers.parseEther('100')) await client.payERC20(recipient, token, ethers.parseEther('100'))

Important

  • approveRouter and approveEscrow are separate approvals to different contracts
  • If you use both payment and escrow features with the same token, approve both
  • Wait 2-3 seconds after approval before the next transaction
Last updated on