AVAX Examples
Copy-paste integration snippets for real AVAX ERC-4337 flows.
Example 1 — Backend submit (minimal)
Server-side flow with
sk_nogas_*.backend-minimal.ts
TypeScript
1import { createSmoothSendAvaxClient } from '@smoothsend/sdk/avax';2 3const avax = createSmoothSendAvaxClient({4 apiKey: process.env.SMOOTHSEND_API_KEY!, // sk_nogas_*5 network: 'testnet',6});7 8const result = await avax.submitCall({9 to: '0x0000000000000000000000000000000000000001',10 data: '0x',11 value: 0n,12 mode: 'developer-sponsored',13 smartAccountAddress: '0xYourSmartAccount',14 waitForReceipt: false,15});16 17console.log('userOpHash:', result.userOpHash);Example 2 — React sponsored call (wagmi)
Frontend wallet flow with
pk_nogas_*.SponsoredTransferButton.tsx
TypeScript (React)
1import { SmoothSendAvaxProvider, useSmoothSendAvax } from '@smoothsend/sdk/avax';2import { usePublicClient, useWalletClient } from 'wagmi';3 4function SponsoredTransferButton(props: { to: `0x${string}`; data: `0x${string}` }) {5 const publicClient = usePublicClient();6 const { data: walletClient } = useWalletClient();7 const { submitCall } = useSmoothSendAvax({8 publicClient,9 walletClient: walletClient ?? undefined,10 });11 12 return (13 <button14 onClick={() =>15 submitCall({16 to: props.to,17 data: props.data,18 mode: 'developer-sponsored',19 })20 }21 >22 Submit sponsored call23 </button>24 );25}26 27export function Root({ children }: { children: React.ReactNode }) {28 return (29 <SmoothSendAvaxProvider30 apiKey={process.env.NEXT_PUBLIC_SMOOTHSEND_API_KEY!}31 network="testnet"32 smartAccountAddress={'0xYourSmartAccount' as `0x${string}`}33 >34 {children}35 </SmoothSendAvaxProvider>36 );37}Example 3 — Atomic approve + transfer (user pays in USDC)
The user pays gas in USDC. An ERC20 approval and the actual transfer are bundled into a single UserOperation — one signature, zero AVAX required. This is the recommended pattern for the
user-pays-erc20 mode.AtomicUSDCTransfer.tsx
TypeScript (React)
1import { useSmoothSendAvax, fetchAvaxAaPublicDefaults } from '@smoothsend/sdk/avax';2import { encodeFunctionData, parseUnits } from 'viem';3import { usePublicClient, useWalletClient } from 'wagmi';4 5const ERC20_ABI = [6 {7 name: 'approve', type: 'function', stateMutability: 'nonpayable',8 inputs: [{ name: 'spender', type: 'address' }, { name: 'amount', type: 'uint256' }],9 outputs: [{ type: 'bool' }],10 },11 {12 name: 'transfer', type: 'function', stateMutability: 'nonpayable',13 inputs: [{ name: 'to', type: 'address' }, { name: 'amount', type: 'uint256' }],14 outputs: [{ type: 'bool' }],15 },16] as const;17 18// Fuji testnet address for USDC — swap for mainnet when ready19const USDC = '0x5425890298aed601595a70AB815c96711a31Bc65';20 21export function AtomicUSDCTransfer({ recipient }: { recipient: `0x${string}` }) {22 const publicClient = usePublicClient();23 const { data: walletClient } = useWalletClient();24 const { submitSponsoredUserOp } = useSmoothSendAvax({25 publicClient,26 walletClient: walletClient ?? undefined,27 });28 29 const handleSend = async () => {30 // 1. Fetch the correct paymaster address from SmoothSend dynamically31 const { paymasterFuji } = await fetchAvaxAaPublicDefaults();32 if (!paymasterFuji) throw new Error('Paymaster not found');33 34 const amount = parseUnits('1', 6); // 1 USDC35 36 // Step 1 in batch: approve the paymaster to collect USDC for gas37 const approveData = encodeFunctionData({38 abi: ERC20_ABI,39 functionName: 'approve',40 args: [paymasterFuji, parseUnits('1000', 6)],41 });42 43 // Step 2 in batch: transfer USDC to the recipient44 const transferData = encodeFunctionData({45 abi: ERC20_ABI,46 functionName: 'transfer',47 args: [recipient, amount],48 });49 50 // Both calls go in one UserOperation — executeBatch(dest[], value[], func[])51 const result = await submitSponsoredUserOp({52 calls: [53 { to: USDC, data: approveData, value: 0n },54 { to: USDC, data: transferData, value: 0n },55 ],56 sponsorshipMode: 'user-pays-erc20',57 paymaster: { token: USDC },58 });59 60 console.log('UserOp hash:', result.userOpHash);61 };62 63 return <button onClick={handleSend}>Send 1 USDC (gasless)</button>;64}The SDK calls encodeAvaxExecuteBatchCalldata internally, producing a single executeBatch calldata. By using fetchAvaxAaPublicDefaults(), you ensure the correct Paymaster address is always used for the approval step.
Use the new getSmartAccountAddress helper (or the smartAccountAddress returned by useSmoothSendAvax) to easily display the user’s gasless SCW address for funding.