SwapExactTokensForTokens
SwapExactTokensForTokens - Useful when the user wants a fixed input amount and a variable output amount. You'll get a quote before executing the swap to ensure you agree with the variable output amount.
Decide the exact input amountIn
For the fixed-input flow we pick how much AUSD (token0) we're willing to spend and convert that to raw units with the token's decimals.
const { decimalsToken0, decimalsToken1 } = await getTokenDecimals(
client,
testnetPair,
);
// We define the exact amount of tokens that we would like to provide (in token0 Units)
const amountIn = 1000n * 10n ** BigInt(decimalsToken0);
console.log("Desired amount In ", amountIn);
Desired amountIn (raw AUSD): 1000000000n
swapExactTokensForTokens will debit precisely this amount of AUSD; the CTK you receive can only go up from the quote you accept next.
Getting the quote for AmountOutMin
With amountIn fixed, get a quote from the pair to know how much CTK (token 1) you'll get.
/**
* Quote how much token1 is outputed for a fixed token0 input
* Returns `[amountIn, amountOutMin]`
*/
async function getQuoteForAmountOut(
pair: `0x${string}`,
amountIn: bigint,
swapPath: `0x${string}`[],
) {
return await client.readContract({
address: pair,
abi: stableSwapAbi,
functionName: "getAmountsOut",
args: [amountIn, swapPath],
});
}
const [, amountOutMin] = await getQuoteForAmountOut(
TESTNET_PAIR_AUSD_CTK,
amountIn,
swapPath,
);
console.log("Quoted amountOutMin (raw CTK):", amountOutMin);
Quoted amountOutMin (raw CTK): 999800000000000000000n
Interpretation:
-
1000 AUSDwill return →999.8 CTKat the current price (fee included).You'll pass this value as a floor; if the final output is lower the swap reverts with
InsufficientOutputAmount.
Approve the allowance
AgoraStableSwapPair cannot pull AUSD from your wallet unless the ERC-20 allowance is set first. We grant the pair permission to spend up to amountIn AUSD, and—as a best-practice—simulate the transaction before broadcasting it
/*
* Give `pair` permission to spend `amount` of `tokenToApprove`.
* Returns the transaction hash of the on-chain approval.
*/
async function approveAllowance(
tokenToApprove: `0x${string}`,
pair: `0x${string}`,
amount: bigint,
) {
// 1) Dry-run to catch reverts & obtain gas estimate
const { request } = await client.simulateContract({
address: tokenToApprove,
abi: ausdImplementationAbi, // standard ERC-20 ABI
functionName: "approve",
args: [pair, amount],
});
// 2) Send the real transaction
return await client.writeContract(request);
}
// Step 4. ─ approve AUSD allowance
console.log(`Approving pair to spend ${amountIn} units of AUSD...`);
const approveAlowanceTxHash = await approveAllowance(
swapPath[0],
TESTNET_PAIR_AUSD_CTK,
amountIn,
);
console.log("Approve transaction hash:", approveAlowanceTxHash);
Approving pair to spend 1000000000 units of AUSD..
Approve transaction hash: 0x360753e44c0be192cf633a9888c5cb31dc0a599c49197d7e969150d2f8f9824f
Swapping tokens
With allowance set, we trigger the atomic swap. The swap call will be swapExactTokensForTokens, and it will take the following args:
| Arg | Meaning |
|---|---|
amountIn | 1 000 AUSD (raw) – debited from your wallet |
amountOutMin | minimum CTK you'll accept (999.8 CTK raw) |
swapPath | [AUSD, CTK] |
callerAddress | receives the CTK |
deadline | reverts if mined after now + 5 min |
// Step 5. Execute the swap.
// Set a deadline for the swap (e.g. current time + 300 seconds)
const deadline = BigInt(Math.floor(Date.now() / 1000) + 300);
console.log("Executing swapExactTokensForTokens...");
const { request: swapRequest } = await client.simulateContract({
address: TESTNET_PAIR_AUSD_CTK,
abi: stableSwapAbi,
functionName: "swapExactTokensForTokens",
args: [amountIn, amountOutMin, swapPath, callerAddress, BigInt(deadline)],
});
const swapRequestTxHash = await client.writeContract(swapRequest);
console.log("Swap transaction hash:", swapRequestTxHash);
Executing swapExactTokensForTokens...
Swap transaction hash: 0x5693db026af155e5ce9a6678d2e0aa27ba62a0b15e91979b6bcd1c3731f7151c
Checking the explorer allows us to see that the transaction was executed correctly and now we can expect to have 999.8 token1(CTK) in our wallet balance.

For the full example, please refer to our examples repository