Documentation>AVAX Examples

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 <button
14 onClick={() =>
15 submitCall({
16 to: props.to,
17 data: props.data,
18 mode: 'developer-sponsored',
19 })
20 }
21 >
22 Submit sponsored call
23 </button>
24 );
25}
26 
27export function Root({ children }: { children: React.ReactNode }) {
28 return (
29 <SmoothSendAvaxProvider
30 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 ready
19const 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 dynamically
31 const { paymasterFuji } = await fetchAvaxAaPublicDefaults();
32 if (!paymasterFuji) throw new Error('Paymaster not found');
33 
34 const amount = parseUnits('1', 6); // 1 USDC
35 
36 // Step 1 in batch: approve the paymaster to collect USDC for gas
37 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 recipient
44 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.