Swapping - Fixed Input

If you want to run this example, be sure that you have followed the steps here to configure your Wallet Client.

SwapExactTokensForTokens - Provide a fixed number of tokens you want to swap and receive the number of tokens that would result from that swap. You’ll still get a quote before executing the swap to ensure you agree with the variable output amount.

Calculate the exact input (amountIn)

For the fixed-input flow we pick how much AUSD we’re willing to spend and convert that to raw units with the token’s decimals. We’ll be using the getTokenDecimal function to do this. It’s also important to remember our swapPath example showing that AUSD is token1 in the pair.

1 const { decimalsToken0, decimalsToken1 } = await getTokenDecimals(
2 client,
3 testnetPair,
4 );
5 // We define the exact amount of tokens that we would like to provide (in token1 Units)
6 const amountIn = 1000n * 10n ** BigInt(decimalsToken1);
7 console.log("Desired amount In ", amountIn);
1Desired amountIn (raw AUSD): 1000000000n
Why?

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

Now that we’ve defined the amountIn, we can get a quote from the pair to know how much CTK (token0) you’ll get. Furthermore we’ll actually use the swapPath defined here to execute this function.

1/**
2 * Quote how much token0 is output for a fixed token1 input
3 * Returns `[amountIn, amountOutMin]`
4 */
5async function getQuoteForAmountOut(
6 pair: `0x${string}`,
7 amountIn: bigint,
8 swapPath: `0x${string}`[],
9) {
10 return await client.readContract({
11 address: pair,
12 abi: stableSwapAbi,
13 functionName: "getAmountsOut",
14 args: [amountIn, swapPath],
15 });
16}
1const [, amountOutMin] = await getQuoteForAmountOut(
2 TESTNET_PAIR_AUSD_CTK,
3 amountIn,
4 swapPath,
5);
6console.log("Quoted amountOutMin (raw CTK):", amountOutMin);
1Quoted amountOutMin (raw CTK): 999800000000000000000n

Interpretation:

  • 1000 AUSD will return 999.8 CTK at the current price (fee included).

    You’ll pass this value as a floor; if the final output is lower the swap reverts with InsufficientOutputAmount error message.

Approve the allowance

AgoraStableSwapPair cannot pull AUSD from your wallet unless the ERC-20 allowance is set. This means we need to grant the pair permission to spend up to amountIn AUSD, and—as a best-practice—simulate the transaction before broadcasting it:

1/*
2 * Give `pair` permission to spend `amount` of `tokenToApprove`.
3 * Returns the transaction hash of the on-chain approval.
4 */
5async function approveAllowance(
6 tokenToApprove: `0x${string}`,
7 pair: `0x${string}`,
8 amount: bigint,
9) {
10 // 1) Dry-run to catch reverts & obtain gas estimate
11 const { request } = await client.simulateContract({
12 address: tokenToApprove,
13 abi: ausdImplementationAbi, // standard ERC-20 ABI
14 functionName: "approve",
15 args: [pair, amount],
16 });
17
18 // 2) Send the real transaction
19 return await client.writeContract(request);
20}
1 // Step 4. ─ approve AUSD allowance
2 console.log(`Approving pair to spend ${amountIn} units of AUSD...`);
3 const approveAllowanceTxHash = await approveAllowance(
4 swapPath[0],
5 TESTNET_PAIR_AUSD_CTK,
6 amountIn,
7 );
8 console.log("Approve transaction hash:", approveAllowanceTxHash);
1Approving pair to spend 1000000000 units of AUSD..
2Approve transaction hash: 0x360753e44c0be192cf633a9888c5cb31dc0a599c49197d7e969150d2f8f9824f

Swapping tokens

With allowance set, we trigger the atomic swap. The swap call will use swapExactTokensForTokens, and it will take the following args:

ArgMeaning
amountInAmount to be debited from your wallet (1 000 AUSD raw)
amountOutMinMinimum CTK you’ll accept (999.8 CTK raw)
swapPathAddresses of the tokens to swap: [0xa90...22dC,0x7BE...cd9D] (AUSD/CTK on Sepolia)
callerAddressWallet that will receive the CTK
deadlineTime allowance before the transaction reverts (+5 min in this example)
1// Step 5. Execute the swap.
2// Set a deadline for the swap (e.g. current time + 300 seconds)
3const deadline = BigInt(Math.floor(Date.now() / 1000) + 300);
4
5console.log("Executing swapExactTokensForTokens...");
6const { request: swapRequest } = await client.simulateContract({
7 address: TESTNET_PAIR_AUSD_CTK,
8 abi: stableSwapAbi,
9 functionName: "swapExactTokensForTokens",
10 args: [amountIn, amountOutMin, swapPath, callerAddress, BigInt(deadline)],
11});
12const swapRequestTxHash = await client.writeContract(swapRequest);
13console.log("Swap transaction hash:", swapRequestTxHash);
1Executing swapExactTokensForTokens...
2Swap transaction hash: 0x5693db026af155e5ce9a6678d2e0aa27ba62a0b15e91979b6bcd1c3731f7151c

If you want, you can choose to open the Sepolia Explorer and wait for it to process. No matter what, if the transaction is successfully executed, we can expect to have 999.8 token0(CTK) in the destination wallet’s balance.

For the full example, please refer to our examples repository