🌐Quick start
Let's go over an example of how to perform a token swap using the AKKA Swap API.
Before You Start
You must have a valid AKKA API Key. You can get one from the AKKA Telegram support account.
Your wallet must have:
USDC (or the token you're swapping)
Native tokens (such as ETH on Base) to pay gas fees
What the Program Does
Loads configuration variables (private key, wallet address, RPC URL, and Developer Portal API key) from the environment or a local
.env
fileConnects to the Base chain using viem
Uses the AKKA
/approve/allowance
endpoint to check if your wallet has granted the proper USDC allowance to the AKKA routerIf the allowance is insufficient, it uses the
/approve/transaction
endpoint to construct and send an approval transactionThen, it uses the
/swap
endpoint to construct the swap transactionIt signs and broadcasts the transaction using viem
Dependencies
npm install dotenv viem
Required Parameters
import dotenv from "dotenv";
import { createPublicClient, createWalletClient, Hex, http } from "viem";
import { base } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
dotenv.config();
const requiredEnvVars = ["WALLET_ADDRESS", "PRIVATE_KEY", "API_KEY", "RPC_URL"];
for (const key of requiredEnvVars) {
if (!process.env[key]) {
console.error(`Missing required environment variable: ${key}`);
process.exit(1);
}
}
const config = {
walletAddress: process.env.WALLET_ADDRESS!.toLowerCase(),
privateKey: process.env.PRIVATE_KEY! as Hex,
apiKey: process.env.API_KEY!,
rpcUrl: process.env.RPC_URL!,
tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
amountToSwap: 100_000, // 0.1 USDC
dstToken: "0x4200000000000000000000000000000000000006", // WETH on Base
slippage: 1,
};
type AllowanceResponse = { allowance: string };
type TransactionPayload = { to: Hex; data: Hex; value: bigint };
type TxResponse = { tx: TransactionPayload };
type ApproveTransactionResponse = {
to: Hex;
data: Hex;
value: bigint;
gasPrice: string;
};
const baseUrl = `https://api.akka.finance/swap/v1/${base.id}`;
const publicClient = createPublicClient({
chain: base,
transport: http(config.rpcUrl),
});
const account = privateKeyToAccount(config.privateKey);
const walletClient = createWalletClient({
account,
chain: base,
transport: http(config.rpcUrl),
});
function buildQueryURL(path: string, params: Record<string, string>): string {
const url = new URL(baseUrl + path);
url.search = new URLSearchParams(params).toString();
return url.toString();
}
async function callAKKAAPI<T>(
endpointPath: string,
queryParams: Record<string, string>,
): Promise<T> {
const url = buildQueryURL(endpointPath, queryParams);
const response = await fetch(url, {
method: "GET",
headers: {
Accept: "application/json",
Authorization: `Bearer ${config.apiKey}`,
},
});
if (!response.ok) {
const body = await response.text();
throw new Error(`AKKA API returned status ${response.status}: ${body}`);
}
return (await response.json()) as T;
}
async function signAndSendTransaction(tx: TransactionPayload): Promise<string> {
const nonce = await publicClient.getTransactionCount({
address: account.address,
blockTag: "pending",
});
console.log("Nonce:", nonce.toString());
try {
return await walletClient.sendTransaction({
account,
to: tx.to,
data: tx.data,
value: BigInt(tx.value),
chain: base,
nonce,
kzg: undefined,
});
} catch (err) {
console.error("Transaction signing or broadcasting failed");
console.error("Transaction data:", tx);
console.error("Nonce:", nonce.toString());
throw err;
}
}
async function checkAllowance(): Promise<bigint> {
console.log("Checking token allowance...");
const allowanceRes = await callAKKAAPI<AllowanceResponse>(
"/approve/allowance",
{
tokenAddress: config.tokenAddress,
walletAddress: config.walletAddress,
},
);
const allowance = BigInt(allowanceRes.allowance);
console.log("Allowance:", allowance.toString());
return allowance;
}
async function approveIfNeeded(requiredAmount: bigint): Promise<void> {
const allowance = await checkAllowance();
if (allowance >= requiredAmount) {
console.log("Allowance is sufficient for the swap.");
return;
}
console.log("Insufficient allowance. Creating approval transaction...");
const approveTx = await callAKKAAPI<ApproveTransactionResponse>(
"/approve/transaction",
{
tokenAddress: config.tokenAddress,
amount: requiredAmount.toString(),
},
);
console.log("Approval transaction details:", approveTx);
const txHash = await signAndSendTransaction({
to: approveTx.to,
data: approveTx.data,
value: approveTx.value,
});
console.log("Approval transaction sent. Hash:", txHash);
console.log("Waiting 10 seconds for confirmation...");
await new Promise((res) => setTimeout(res, 10000));
}
async function performSwap(): Promise<void> {
const swapParams = {
src: config.tokenAddress,
dst: config.dstToken,
amount: config.amountToSwap.toString(),
from: config.walletAddress,
slippage: config.slippage.toString(),
disableEstimate: "false",
allowPartialFill: "false",
};
console.log("Fetching swap transaction...");
const swapTx = await callAKKAAPI<TxResponse>("/swap", swapParams);
console.log("Swap transaction:", swapTx.tx);
const txHash = await signAndSendTransaction(swapTx.tx);
console.log("Swap transaction sent. Hash:", txHash);
}
async function main() {
try {
await approveIfNeeded(BigInt(config.amountToSwap));
await performSwap();
} catch (err) {
console.error("Error:", (err as Error).message);
}
}
main().catch((err) => {
console.error("Unhandled error in main:", err);
process.exit(1);
});
Last updated