Approval Mechanics
Overview
The Naos Trade API automatically manages token approvals for EVM chains, ensuring seamless trading without manual approval steps. This document explains how approval transactions work for both BUY and SELL operations.
Key Concepts
What is Token Approval?
On EVM chains, before a smart contract (like the NAOS router) can spend your ERC20 tokens, you must first approve it. The API automatically:
Detects when approvals are needed
Generates approval transactions
Executes them in the correct order
Infinite Approval
The API uses infinite approval (type(uint256).max) to minimize gas costs. Once a token is approved, you never need to approve it again for future trades.
BUY Transaction Flow
When buying tokens with native currency (ETH, BNB, etc.):
1. Quote Generation
GET /api/v1/quote?side=BUY&...Response includes:
serializedTx: The buy transaction (unsigned)serializedApproveTx: Post-buy approval transaction (unsigned, if needed)quoteId: Unique identifier
Nonce Assignment:
Buy transaction: nonce
nApproval transaction: nonce
n+1
2. Sign Both Transactions
// Sign buy transaction
const buyTx = ethers.Transaction.from(quote.transaction.serializedTx)
const signedBuyTx = await wallet.signTransaction(buyTx)
// Sign approval transaction (if provided)
if (quote.transaction.serializedApproveTx) {
const approveTx = ethers.Transaction.from(quote.transaction.serializedApproveTx)
const signedApproveTx = await wallet.signTransaction(approveTx)
}3. Execute
POST /api/v1/execute
{
"txData": "0x...", // Signed buy transaction
"approveTxData": "0x...", // Signed approval transaction
"network": "BASE",
"quoteId": "...",
"mev": false,
"skipSimulation": false
}Execution Order:
✅ Buy transaction is broadcast and confirmed
📤 API returns success response to you
✅ Approval transaction is broadcast and confirmed (background)
🎉 Token is now approved for future sells
Why This Order?
You get your tokens immediately
Approval happens in the background
You can start planning your sell strategy while approval confirms
If approval fails, it's logged but doesn't affect your buy
SELL Transaction Flow
When selling tokens for native currency:
1. Quote Generation
GET /api/v1/quote?side=SELL&...Response includes:
serializedApproveTx: Pre-sell approval transaction (unsigned, if needed)serializedTx: The sell transaction (unsigned)quoteId: Unique identifier
Nonce Assignment:
Approval transaction: nonce
nSell transaction: nonce
n+1
2. Sign Both Transactions
// Sign approval transaction first (if provided)
if (quote.transaction.serializedApproveTx) {
const approveTx = ethers.Transaction.from(quote.transaction.serializedApproveTx)
const signedApproveTx = await wallet.signTransaction(approveTx)
}
// Sign sell transaction
const sellTx = ethers.Transaction.from(quote.transaction.serializedTx)
const signedSellTx = await wallet.signTransaction(sellTx)3. Execute
POST /api/v1/execute
{
"approveTxData": "0x...", // Signed approval transaction (if needed)
"txData": "0x...", // Signed sell transaction
"network": "BASE",
"quoteId": "...",
"mev": false,
"skipSimulation": false
}Execution Order:
✅ Approval transaction is broadcast and confirmed (if provided)
❌ If approval fails, entire request fails
✅ Sell transaction is broadcast and confirmed
📤 API returns success response
🎉 You have your native currency
Why This Order?
Approval must happen before the sell
If approval fails, you don't waste gas on a failing sell
Both transactions must succeed for success response
Nonce Management Summary
BUY
Trade (buy tokens)
Approval (approve token)
SELL
Approval (approve token)
Trade (sell tokens)
Critical: The nonces in the quote response are pre-calculated. You must:
Sign transactions with the provided nonces
Send them in the correct order to the execute endpoint
Not modify or reorder the nonces
When Are Approvals Needed?
Approvals ARE Generated For:
✅ First time buying a token (post-buy approval)
✅ First time selling a token (pre-sell approval)
✅ If approval was revoked manually
✅ If current allowance <
type(uint256).max
Approvals Are NOT Generated For:
❌ Token already has infinite approval
❌ Solana transactions (no approvals needed on Solana)
❌ Buying with native currency (no approval needed for ETH/BNB/etc.)
Best Practices
1. Always Check for Approval Transactions
const quote = await getQuote(params)
if (quote.transaction.serializedApproveTx) {
console.log('⚠️ Approval transaction required')
// Sign and include in execute request
}2. Don't Skip Approvals
Both transactions are signed client-side and must be included in the execute request:
await executeTransaction({
txData: signedTradeTx,
approveTxData: signedApproveTx, // Don't forget this!
// ...
})3. Monitor Approval Status
For BUY transactions, the approval happens after you receive the success response:
// You get success for the buy
const buyResult = await execute(...)
console.log('Buy complete:', buyResult.txRes.txHash)
// Approval is happening in the background
// Check blockchain explorer for approval TX
// It will use nonce n+14. Handle Errors Appropriately
try {
const result = await execute({...})
if (result.success) {
console.log('Trade executed:', result.txRes.txHash)
} else {
console.error('Trade failed:', result.error)
// For SELL: Could be approval failure
// For BUY: Could be trade failure (approval not attempted)
}
} catch (error) {
console.error('Request failed:', error)
}Solana Differences
Solana works differently and doesn't require approvals:
✅ No approval transactions ever generated
✅
serializedApproveTxis alwaysundefined✅ Single transaction for both BUY and SELL
✅ Simpler flow, fewer steps
Example: Complete BUY Flow
// 1. Get quote
const quote = await fetch('https://api.naos.trade/api/v1/quote?' + new URLSearchParams({
tokenAddress: '0xToken...',
amount: '0.1',
side: 'BUY',
slippageBps: '500',
trader: wallet.address,
chain: 'BASE'
}))
const quoteData = await quote.json()
// 2. Sign trade transaction
const buyTx = ethers.Transaction.from(quoteData.transaction.serializedTx)
const signedBuyTx = await wallet.signTransaction(buyTx)
// 3. Sign approval transaction if present
let signedApproveTx
if (quoteData.transaction.serializedApproveTx) {
const approveTx = ethers.Transaction.from(quoteData.transaction.serializedApproveTx)
signedApproveTx = await wallet.signTransaction(approveTx)
}
// 4. Execute
const result = await fetch('https://api.naos.trade/api/v1/execute', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
txData: signedBuyTx,
approveTxData: signedApproveTx,
network: 'BASE',
mev: false,
skipSimulation: false,
quoteId: quoteData.transaction.quoteId
})
})
const executeData = await result.json()
if (executeData.success) {
console.log('✅ Buy successful!')
console.log('TX:', executeData.txRes.txHash)
console.log('Tokens received:', executeData.txRes.received)
console.log('(Approval transaction broadcasting in background)')
}Troubleshooting
"Transaction simulation failed"
Usually means approval is needed but not provided
Check if
serializedApproveTxwas in the quote responseEnsure you signed and included the approval transaction
"Nonce too low" or "Nonce already used"
Don't modify the nonces from the quote response
Don't reuse signed transactions
Get a fresh quote if you need to retry
"Quote not found - invalid requestId"
Quote may have expired (get a new one)
Ensure you're using the correct
quoteId
Approval transaction not found on explorer
For BUY: Check transactions with nonce n+1 from your address
It may take a few seconds to appear
Check API logs for approval execution status
Summary
✨ The API handles all complexity:
Detects when approvals are needed
Generates correctly ordered transactions
Manages nonces automatically
Executes in the optimal order
🎯 You just need to:
Sign all provided transactions
Send them to the execute endpoint
Handle the response
🚀 Benefits:
Seamless trading experience
Optimized gas usage
No manual approval steps
Works across all supported chains
Last updated

