# Generate Approve Transaction Source: https://docs.akka.finance/api-reference/approve-transaction GET /swap/v1/{chainId}/approve/transaction Generate the transaction data needed to approve the AKKA Router to spend a token on your behalf. Returns encoded calldata that must be signed and submitted to the blockchain. If no amount is specified, unlimited approval is granted. ## Unlimited vs. specific approval * **Omit `amount`**: Grants unlimited approval. The AKKA Router can spend any amount of this token. Recommended for frequent swapping — you only need to approve once. * **Set `amount`**: Grants approval for exactly this many tokens (in wei). More secure, but requires a new approval transaction each time the allowance is consumed. ## Using the response Sign and submit the returned transaction object to the blockchain: ```javascript theme={null} const hash = await walletClient.sendTransaction({ to: approveTx.to, // Token contract address data: approveTx.data, // Encoded approve() calldata value: BigInt(approveTx.value), // Always "0" }); await publicClient.waitForTransactionReceipt({ hash }); ``` Wait for the approval transaction to be confirmed before calling the swap endpoint. # Check Allowance Source: https://docs.akka.finance/api-reference/check-allowance GET /swap/v1/{chainId}/approve/allowance Check how many tokens the AKKA Router is currently allowed to spend on behalf of a wallet address. Use this to determine if an approval transaction is needed before swapping. ## When to use Call this before swapping an ERC-20 token to check if the AKKA Router already has sufficient spending approval: ```javascript theme={null} const { allowance } = await response.json(); const swapAmount = BigInt('1000000000000000000'); if (BigInt(allowance) < swapAmount) { // Need to approve first — call /approve/transaction } else { // Allowance sufficient — proceed to /swap } ``` For native tokens (HYPE), allowance is always unlimited. You can skip the allowance check and go directly to the swap. # Compare DEX Quotes Source: https://docs.akka.finance/api-reference/dex-compare GET /swap/v1/{chainId}/dex-compare Find the top pools by reserve for a token pair, quote each one individually, and return results sorted by output amount descending. Also includes the AKKA aggregator's exact quote for comparison. Useful for demonstrating the value of aggregated routing vs. single-DEX swaps. This endpoint is useful for demonstrating the value of AKKA's aggregated routing compared to swapping through a single DEX pool. ## How it works 1. Finds the top pools by reserve for the given token pair 2. Quotes each pool individually 3. Returns results sorted by output amount (descending) 4. Includes the AKKA aggregator's exact quote (`akkaQuote`) for comparison The `akkaQuote` will typically be higher than any individual pool because AKKA splits the swap across multiple pools for better pricing. # Get Quote Source: https://docs.akka.finance/api-reference/get-quote GET /swap/v1/{chainId}/quote Find the best quote to exchange tokens via AKKA router. Returns expected output amount and optional token/protocol information. The Pathfinder algorithm splits transactions across multiple protocols and market depths to find the most efficient swap route. The quote endpoint returns the best available rate but does **not** generate transaction data. To execute the swap, use the [swap endpoint](/api-reference/get-swap). ## Optional response fields By default, the response only includes `dstAmount`. Use these flags to include additional data: | Flag | What it adds | | ------------------------ | ------------------------------------------------------------------------------ | | `includeTokensInfo=true` | `srcToken` and `dstToken` metadata (symbol, name, decimals, logo) | | `includeGas=true` | `gas` — estimated gas amount | | `includeRoutes=true` | `routes` — parallel path breakdown with pools and tokens | | `includeGraph=true` | `graph` — flat list of on-chain DAG hops (mirrors the actual router execution) | # Get Spender Address Source: https://docs.akka.finance/api-reference/get-spender GET /swap/v1/{chainId}/approve/spender Returns the AKKA router smart contract address that needs to be approved as a token spender before executing swaps. You must approve this address to spend your tokens before calling the swap endpoint. This returns the AKKA Router contract address. You must approve this address to spend your ERC-20 tokens before calling the [swap endpoint](/api-reference/get-swap). Native token swaps (e.g., HYPE on HyperEVM) do **not** require approval. # Generate Swap Transaction Source: https://docs.akka.finance/api-reference/get-swap GET /swap/v1/{chainId}/swap Generate complete transaction data for executing a token swap via the AKKA router. The endpoint performs a full exact quote (graph walk), validates the user's token balance and allowance, and returns a ready-to-sign transaction object. This endpoint always performs an **exact quote** (full graph walk) regardless of the chain's default quote policy. The returned `dstAmount` is the precise expected output. ## Using the response The response includes a `tx` object that is ready to sign and broadcast: ```javascript theme={null} const { tx } = swapResponse; const hash = await walletClient.sendTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value), gasPrice: BigInt(tx.gasPrice), gas: BigInt(tx.gas), }); ``` ## Slippage recommendations | Swap type | Recommended slippage | | -------------------- | -------------------- | | Stable-to-stable | 0.1 — 0.5% | | Major tokens | 0.5 — 1% | | Low-liquidity tokens | 1 — 5% | ## Balance and allowance validation When `from` is provided, the API validates: * **Balance**: The wallet has enough tokens to cover the swap amount * **Allowance**: The AKKA Router is approved to spend enough tokens If either check fails, the API returns a `400` error with a descriptive message. # Get Token by Address Source: https://docs.akka.finance/api-reference/get-token-by-address GET /{chainId}/tokens/{address} Retrieve detailed information about a specific token using its smart contract address. Use this endpoint to look up a specific token's metadata when you already have its contract address. Returns the same data as the token list endpoint, but for a single token. # Get Token List Source: https://docs.akka.finance/api-reference/get-tokens GET /{chainId}/tokens Retrieve a paginated list of tokens available for swapping on the specified chain. Returns token metadata including symbol, name, decimals, logo, verification status, and USD pricing. Token data is cached and refreshed periodically. Prices (`buyPriceUsd`, `sellPriceUsd`) are updated every few seconds. ## Filtering Use `verified=true` to return only tokens that have been verified by the AKKA team. This is recommended for user-facing token selectors to avoid showing low-quality or scam tokens. # Authentication Source: https://docs.akka.finance/authentication API keys, base URL, and rate limits ## Base URL All API requests are made to: ``` https://api.akka.finance ``` ## API Key Every request requires an API key passed in the `apikey` header. ```bash theme={null} curl -H "apikey: YOUR_API_KEY" \ "https://api.akka.finance/swap/v1/999/quote?src=0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee&dst=0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb&amount=1000000000000000000" ``` To get your API key, contact the AKKA team on [Telegram](https://t.me/akka_finance). ## Rate Limits | Limit | Value | | --------------- | ----------------- | | Requests per IP | 20 per 60 seconds | When you exceed the rate limit, the API returns HTTP `429 Too Many Requests`. Wait for the window to reset before retrying. ## Swagger / OpenAPI The interactive Swagger UI is publicly available at: ``` https://api.akka.finance/docs ``` Swagger does not require an API key. Use it to explore endpoints and test requests during development. # Error Handling Source: https://docs.akka.finance/error-handling Error response format, common error codes, and troubleshooting ## Error Response Format All errors return a consistent JSON structure: ```json theme={null} { "statusCode": 400, "message": "Not enough balance. Current balance: 500000000000000000", "error": "Bad Request", "timestamp": "2025-01-15T12:00:00.000Z", "path": "/swap/v1/999/swap" } ``` | Field | Type | Description | | ------------ | ------- | ------------------------------------ | | `statusCode` | integer | HTTP status code | | `message` | string | Human-readable error description | | `error` | string | Error category | | `timestamp` | string | ISO 8601 timestamp | | `path` | string | Request path that produced the error | ## Common Errors ### 400 Bad Request | Message | Cause | Fix | | ---------------------------------------------- | -------------------------------------------------- | --------------------------------------------------------- | | `src must be an Ethereum address` | Invalid source token address | Use a valid `0x`-prefixed 40-character hex address | | `dst must be an Ethereum address` | Invalid destination token address | Same as above | | `amount should be positive integer string` | Amount is missing, negative, or not a number | Pass a positive integer string in wei | | `No route found for the given token pair` | No liquidity path exists between the two tokens | Verify both tokens exist on the chain and have liquidity | | `Not enough balance. Current balance: ...` | Wallet balance is insufficient for the swap amount | Reduce the amount or fund the wallet | | `Not enough allowance. Current allowance: ...` | AKKA Router is not approved to spend enough tokens | Call `/approve/transaction` first and submit the approval | | `slippage must not be greater than 50` | Slippage exceeds the 50% maximum | Use a value between 0 and 50 | ### 404 Not Found | Message | Cause | Fix | | ------------------------- | ------------------------------------------- | --------------------------------------------- | | Chain not found | Unsupported chain ID | Use a [supported chain ID](/supported-chains) | | Token not found | Token does not exist on the specified chain | Verify the token address on a block explorer | | No spender contract found | No AKKA Router deployed on this chain | Use a chain with a deployed router | ### 429 Too Many Requests You exceeded the rate limit of 20 requests per 60 seconds. Wait for the rate limit window to reset. ### 500 Internal Server Error An unexpected error occurred. If this persists, contact support on [Telegram](https://t.me/akka_finance). ## Troubleshooting This usually means the price moved beyond your slippage tolerance between the quote and execution. Increase the `slippage` parameter (e.g., from 1 to 3) or execute the swap faster after getting the quote. The token may exist on-chain but have no liquidity in any DEX pool that AKKA indexes. Check that the token has active trading pairs on at least one supported DEX. Make sure the approval transaction was confirmed on-chain before checking the allowance. If you approved a specific amount and already swapped some tokens, the remaining allowance may be less than expected. The API adds a 20% safety buffer to gas estimates. The actual gas used will typically be lower. You can override the gas limit using the `gasLimit` parameter on the swap endpoint. # FAQ Source: https://docs.akka.finance/faq Frequently asked questions about integrating with the AKKA API The most common reasons: 1. **Slippage exceeded** — The price moved between quoting and execution. Increase your slippage tolerance or retry with a fresh swap call. 2. **Stale transaction** — Too much time passed between getting the swap data and broadcasting. Re-fetch from `/swap` and try again. 3. **Insufficient allowance** — The token wasn't approved, or the approval hasn't confirmed yet. Check with `/approve/allowance` before swapping. 4. **Insufficient balance** — The wallet doesn't have enough tokens to cover the swap amount plus gas. In all revert cases, **no tokens are lost** — you only pay the gas fee for the failed transaction. Use `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee` to represent the chain's native token (HYPE on HyperEVM). This is a convention shared across most DEX aggregators. Native tokens don't need approval — skip the allowance check when swapping from HYPE. Prices in the token endpoints (`buyPriceUsd`, `sellPriceUsd`) are refreshed every **\~5 seconds** from actual DEX pool reserves. For most use cases, polling every 15–30 seconds is sufficient. See the [Price API guide](/guides/price-api) for a polling pattern with local caching. No. The default approval sets an unlimited allowance for the AKKA Router contract. Once approved, you can swap that token as many times as you want without re-approving. Always call `/approve/allowance` first to check — if the allowance is already sufficient, skip the approval step. **20 requests per 60 seconds** per IP address. If you exceed this, the API returns HTTP 429. Tips to stay within limits: * Debounce user input (400ms+) before fetching quotes * Cache token lists — they don't change frequently * Use `GET /{chainId}/tokens` to fetch all tokens in one call instead of individual lookups Currently **HyperEVM (chain ID 999)** is the only supported chain. Ethereum, Arbitrum, and Base are coming soon. See [Supported Chains](/supported-chains) for details. * **`/quote`** returns the expected output amount and optional route/gas info. It's read-only — use it to display prices to the user. * **`/swap`** returns everything from `/quote` plus a ready-to-sign transaction object (`tx`). Use it when the user is ready to execute. Typical flow: show the user a quote as they type, then call `/swap` only when they click the swap button. The `from` parameter is the wallet address that will execute the transaction. It's optional — if omitted, the API builds the transaction without a `from` field, and your wallet/library will fill it in when signing. Providing `from` allows the API to do balance and allowance pre-checks and return more accurate gas estimates. Yes. The `/swap` endpoint accepts optional `gasPrice` and `gasLimit` parameters. If omitted, the API uses current network values. On HyperEVM, gas prices are low and stable — the API defaults are usually fine. Only override if you have a specific reason. `encodedTx` is the full transaction tuple (from, to, data, value, gasPrice, gas) ABI-encoded as a hex string. It allows frontends to decode and execute the swap without needing the router contract ABI. Most integrations use the `tx` object directly — `encodedTx` is an alternative for advanced use cases. Contact the AKKA team on [Telegram](https://t.me/akka_finance) to request an API key. The key is passed as an `apikey` header on every request. The API provides instant swap execution, not scheduled orders. However, you can build limit orders or DCA on top of the API: * **Limit orders**: Poll `/quote` at intervals and execute `/swap` when the rate hits your target. See the [Node.js guide](/guides/node-backend) for a price monitoring example. * **DCA (Dollar Cost Averaging)**: Run a cron job or interval that executes a fixed swap at regular intervals. AKKA indexes liquidity from 20+ DEX pool types on HyperEVM, including Uniswap V2/V3 forks, Algebra, Curve, Balancer, and more. The pathfinder algorithm evaluates all pools to find the optimal route — including splitting across multiple pools when that gives a better rate. Use `/dex-compare` to see how the aggregated rate compares to individual DEX pools. # Slippage & Best Practices Source: https://docs.akka.finance/guides/best-practices How to choose slippage, handle errors, and build reliable swap integrations ## Slippage Slippage is the maximum price difference you're willing to accept between the quoted rate and the executed rate. It protects against price movement during the time between quoting and on-chain execution. ### Choosing a slippage value | Slippage | When to use | | ------------ | ------------------------------------------------------------------ | | **0.1–0.5%** | Stablecoins or high-liquidity pairs (e.g., USDC → USDT) | | **0.5–1%** | Standard pairs with good liquidity (e.g., HYPE → USDC) | | **1–3%** | Lower-liquidity tokens or volatile markets | | **3–5%** | Very low liquidity or fast-moving prices | | **> 5%** | Generally not recommended — consider splitting into smaller trades | Pass slippage as a percentage (not a fraction) to the `/swap` endpoint: ```bash theme={null} # 1% slippage curl -H "apikey: YOUR_API_KEY" \ "https://api.akka.finance/swap/v1/999/swap?src=0x...&dst=0x...&amount=1000000000000000000&from=0x...&slippage=1" ``` The allowed range is `0` to `50`. Up to 4 decimal places are supported (e.g., `0.5`, `1.25`). ### What happens when slippage is exceeded The on-chain transaction **reverts**. You pay gas but no tokens are swapped and no tokens are lost. The user keeps their full balance. *** ## Quote-then-swap timing The quote endpoint returns an estimated output amount. The swap endpoint returns the transaction to execute. Between these two calls (and before the transaction confirms), pool prices can move. **Best practice:** Keep the gap between `/quote` and `/swap` as short as possible. In a frontend, fetch the swap data only when the user clicks "Swap" — don't pre-fetch it while they're still reviewing. ```typescript theme={null} // Good: quote for display, swap on click const quote = await getQuote(src, dst, amount); // show to user // ... user reviews and clicks "Swap" ... const swap = await getSwap(src, dst, amount, from, slippage); // fetch right before execution await sendTransaction(swap.tx); ``` *** ## Handling reverts If a swap transaction reverts on-chain, it's usually one of these: | Cause | Solution | | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | Price moved beyond slippage tolerance | Increase slippage or retry immediately with a fresh quote | | Stale quote (too much time between quote and execution) | Re-fetch the swap data and retry | | Insufficient gas | Let the API set gas automatically (don't override `gas` and `gasPrice` unless you have a reason) | | Insufficient balance | Check the user's balance before initiating the swap | | Insufficient allowance | The token wasn't approved, or the approval transaction hasn't confirmed yet | ### Retry pattern ```typescript theme={null} async function swapWithRetry( src: string, dst: string, amount: string, from: string, slippage: number, maxRetries = 2, ) { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { const { tx } = await getSwap(src, dst, amount, from, slippage); const hash = await sendTransaction(tx); return hash; } catch (err) { console.error(`Attempt ${attempt} failed:`, err); if (attempt === maxRetries) throw err; // Bump slippage slightly on retry slippage = Math.min(slippage * 1.5, 5); } } } ``` *** ## Gas on HyperEVM HyperEVM has low and stable gas prices. The API returns `gasPrice` and `gas` (limit) in the swap response — use them as-is unless you have a specific reason to override. ```typescript theme={null} const { tx } = await getSwap(src, dst, amount, from, slippage); // Use the gas values from the API directly await walletClient.sendTransaction({ to: tx.to as `0x${string}`, data: tx.data as `0x${string}`, value: BigInt(tx.value), gasPrice: BigInt(tx.gasPrice), gas: BigInt(tx.gas), }); ``` If you need to override gas, set a higher limit — never lower: ```typescript theme={null} const gasWithBuffer = BigInt(tx.gas) * 130n / 100n; // 30% buffer ``` *** ## Rate limiting The API allows **20 requests per 60 seconds** per IP. Tips to stay within limits: * **Cache quotes** — Don't re-fetch on every keystroke. Use debouncing (see [React Hooks guide](/guides/react-hooks)). * **Poll at reasonable intervals** — For price feeds, 15–30 seconds is sufficient. Prices refresh every \~5 seconds on the backend. * **Batch token lookups** — Use `GET /{chainId}/tokens` to fetch all tokens in one call instead of fetching individually. If you hit the rate limit, the API returns HTTP 429. Back off and retry: ```typescript theme={null} async function fetchWithBackoff(url: string, headers: Record): Promise { const res = await fetch(url, { headers }); if (res.status === 429) { await new Promise((r) => setTimeout(r, 5000)); // wait 5 seconds return fetchWithBackoff(url, headers); } if (!res.ok) throw new Error(`HTTP ${res.status}`); return res.json(); } ``` *** ## Approval best practices * **Approve once, swap many times** — The default approval sets an unlimited allowance. You only need to approve once per token. * **Check before approving** — Always call `/approve/allowance` first. Sending an unnecessary approval wastes gas. * **Wait for confirmation** — Don't call `/swap` until the approval transaction is confirmed on-chain. * **Native tokens skip approval** — HYPE (`0xeeee...eeee`) doesn't need approval. Skip the allowance check for native tokens. ```typescript theme={null} const NATIVE = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; if (src.toLowerCase() !== NATIVE) { const { allowance } = await checkAllowance(src, walletAddress); if (BigInt(allowance) < BigInt(amount)) { const approveTx = await getApproveTransaction(src); const hash = await sendTransaction(approveTx); await waitForReceipt(hash); // wait before swapping } } ``` *** ## Amounts and decimals All amounts in the API are in **wei** (the token's smallest unit). Each token has its own `decimals` value. | Token | Decimals | 1.0 in wei | | ----- | -------- | --------------------- | | HYPE | 18 | `1000000000000000000` | | USDC | 6 | `1000000` | | UBTC | 18 | `1000000000000000000` | Use viem's `parseUnits` and `formatUnits` to convert: ```typescript theme={null} import { parseUnits, formatUnits } from 'viem'; // Human → wei const amountWei = parseUnits('1.5', 18).toString(); // "1500000000000000000" // Wei → human const amountHuman = formatUnits(BigInt('1500000000000000000'), 18); // "1.5" ``` Always use the token's actual `decimals` value from the API — don't hardcode 18. Some tokens use 6, 8, or other values. # DEX Comparison Source: https://docs.akka.finance/guides/dex-compare Show users how much they save by routing through AKKA vs trading on a single DEX The `/dex-compare` endpoint returns the AKKA aggregated quote alongside the top individual DEX pool quotes for the same pair and amount. Use it to show users the price advantage of aggregation. ## How it works AKKA splits and routes trades across multiple pools to find the best rate. A single DEX can only use its own liquidity. The difference is your value proposition. ```bash theme={null} curl -H "apikey: YOUR_API_KEY" \ "https://api.akka.finance/swap/v1/999/dex-compare?src=0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee&dst=0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb&amount=1000000000000000000" ``` ```json Response theme={null} { "akkaQuote": "12723902882990271", "decimalsOut": 18, "pools": [ { "poolAddress": "0xabc...", "poolType": "uni_v3", "amountOut": "12650000000000000", "decimalsOut": 18 }, { "poolAddress": "0xdef...", "poolType": "slipstream", "amountOut": "12580000000000000", "decimalsOut": 18 }, { "poolAddress": "0x123...", "poolType": "algebra_v4", "amountOut": "12490000000000000", "decimalsOut": 18 } ] } ``` ## Calculating the savings ```typescript theme={null} import { formatUnits } from 'viem'; interface DexCompareResult { akkaQuote: string; decimalsOut: number; pools: { poolAddress: string; poolType: string; amountOut: string; decimalsOut: number }[]; } function calculateSavings(data: DexCompareResult) { const akka = Number(formatUnits(BigInt(data.akkaQuote), data.decimalsOut)); return data.pools.map((pool) => { const dex = Number(formatUnits(BigInt(pool.amountOut), pool.decimalsOut)); const savingsPercent = ((akka - dex) / dex) * 100; return { poolType: pool.poolType, dexOutput: dex, akkaOutput: akka, savingsPercent: savingsPercent.toFixed(2), }; }); } ``` Example output: | DEX | DEX Output | AKKA Output | Savings | | ----------- | ------------ | ------------ | ------- | | uni\_v3 | 0.01265 UBTC | 0.01272 UBTC | +0.58% | | slipstream | 0.01258 UBTC | 0.01272 UBTC | +1.13% | | algebra\_v4 | 0.01249 UBTC | 0.01272 UBTC | +1.87% | ## React component Display a comparison table in your swap UI: ```tsx DexComparison.tsx theme={null} import { useState, useEffect } from 'react'; import { formatUnits } from 'viem'; const API_BASE = 'https://api.akka.finance'; const API_KEY = process.env.NEXT_PUBLIC_AKKA_API_KEY!; interface Pool { poolType: string; amountOut: string; decimalsOut: number; } interface CompareData { akkaQuote: string; decimalsOut: number; pools: Pool[]; } export function DexComparison({ src, dst, amount, }: { src: string; dst: string; amount: string; }) { const [data, setData] = useState(null); useEffect(() => { if (!amount || amount === '0') return; const params = new URLSearchParams({ src, dst, amount }); fetch(`${API_BASE}/swap/v1/999/dex-compare?${params}`, { headers: { apikey: API_KEY }, }) .then((r) => r.json()) .then(setData) .catch(console.error); }, [src, dst, amount]); if (!data || data.pools.length === 0) return null; const akkaAmount = Number(formatUnits(BigInt(data.akkaQuote), data.decimalsOut)); return ( {data.pools.map((pool) => { const dexAmount = Number(formatUnits(BigInt(pool.amountOut), pool.decimalsOut)); const diff = ((akkaAmount - dexAmount) / dexAmount) * 100; return ( ); })}
Source Output vs AKKA
AKKA (aggregated) {akkaAmount.toFixed(8)}
{pool.poolType} {dexAmount.toFixed(8)} 0 ? 'green' : 'red' }}> {diff > 0 ? '+' : ''}{diff.toFixed(2)}%
); } ``` ## Backend usage For analytics dashboards or reports: ```typescript theme={null} const API_BASE = 'https://api.akka.finance'; const API_KEY = process.env.AKKA_API_KEY!; async function getAkkaSavings(src: string, dst: string, amount: string) { const params = new URLSearchParams({ src, dst, amount }); const res = await fetch(`${API_BASE}/swap/v1/999/dex-compare?${params}`, { headers: { apikey: API_KEY }, }); const data = await res.json(); if (!data.pools?.length) return null; const bestDex = data.pools[0]; // pools are sorted by amountOut descending const akka = BigInt(data.akkaQuote); const best = BigInt(bestDex.amountOut); const savingsBps = Number((akka - best) * 10000n / best); return { akkaOutput: data.akkaQuote, bestDexOutput: bestDex.amountOut, bestDexType: bestDex.poolType, savingsBps, savingsPercent: (savingsBps / 100).toFixed(2), }; } ``` The `pools` array is sorted by `amountOut` descending — the first entry is the best single-DEX quote. Compare it against `akkaQuote` to get the minimum savings percentage. # Complete Swap Example Source: https://docs.akka.finance/guides/first-swap A full working TypeScript example that checks allowance, approves, and executes a token swap This is a complete, copy-paste-ready TypeScript script that swaps tokens on HyperEVM using the AKKA API and [viem](https://viem.sh). ## Prerequisites ```bash theme={null} npm install viem dotenv ``` Create a `.env` file: ```bash theme={null} WALLET_ADDRESS=0xYourWalletAddress PRIVATE_KEY=0xYourPrivateKey RPC_URL=https://rpc.hyperliquid.xyz/evm API_KEY=your_akka_api_key ``` ## Full Script ```typescript swap.ts theme={null} import 'dotenv/config'; import { createPublicClient, createWalletClient, http, parseUnits, defineChain, } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; // ─── Configuration ────────────────────────────────────────── const API_BASE = 'https://api.akka.finance'; const CHAIN_ID = 999; const API_KEY = process.env.API_KEY!; const SRC_TOKEN = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; // HYPE (native) const DST_TOKEN = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'; // UBTC const AMOUNT = parseUnits('1', 18).toString(); // 1 HYPE const SLIPPAGE = 1; // 1% // ─── Chain Definition ─────────────────────────────────────── const hyperEVM = defineChain({ id: CHAIN_ID, name: 'HyperEVM', nativeCurrency: { name: 'HYPE', symbol: 'HYPE', decimals: 18 }, rpcUrls: { default: { http: [process.env.RPC_URL!] }, }, }); // ─── Clients ──────────────────────────────────────────────── const account = privateKeyToAccount(process.env.PRIVATE_KEY! as `0x${string}`); const publicClient = createPublicClient({ chain: hyperEVM, transport: http(), }); const walletClient = createWalletClient({ account, chain: hyperEVM, transport: http(), }); // ─── Helpers ──────────────────────────────────────────────── async function akkaFetch(path: string, params: Record) { const url = `${API_BASE}${path}?${new URLSearchParams(params)}`; const res = await fetch(url, { headers: { apikey: API_KEY } }); if (!res.ok) { const error = await res.json(); throw new Error(`AKKA API error: ${error.message}`); } return res.json(); } // ─── Step 1: Check Allowance ──────────────────────────────── async function checkAllowance(): Promise { // Native tokens don't need approval if (SRC_TOKEN.toLowerCase() === '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') { console.log('Native token — no approval needed'); return BigInt(2) ** BigInt(256) - BigInt(1); // max uint256 } const data = await akkaFetch(`/swap/v1/${CHAIN_ID}/approve/allowance`, { tokenAddress: SRC_TOKEN, walletAddress: process.env.WALLET_ADDRESS!, }); console.log('Current allowance:', data.allowance); return BigInt(data.allowance); } // ─── Step 2: Approve If Needed ────────────────────────────── async function approveIfNeeded(currentAllowance: bigint) { if (currentAllowance >= BigInt(AMOUNT)) { console.log('Allowance sufficient — skipping approval'); return; } console.log('Approving AKKA Router...'); const approveTx = await akkaFetch( `/swap/v1/${CHAIN_ID}/approve/transaction`, { tokenAddress: SRC_TOKEN }, ); const hash = await walletClient.sendTransaction({ to: approveTx.to as `0x${string}`, data: approveTx.data as `0x${string}`, value: BigInt(approveTx.value), }); console.log('Approval tx sent:', hash); const receipt = await publicClient.waitForTransactionReceipt({ hash }); console.log('Approval confirmed in block:', receipt.blockNumber); } // ─── Step 3: Execute Swap ─────────────────────────────────── async function executeSwap() { console.log('Getting swap transaction...'); const swap = await akkaFetch(`/swap/v1/${CHAIN_ID}/swap`, { src: SRC_TOKEN, dst: DST_TOKEN, amount: AMOUNT, from: process.env.WALLET_ADDRESS!, slippage: SLIPPAGE.toString(), }); console.log('Expected output:', swap.dstAmount); const { tx } = swap; const hash = await walletClient.sendTransaction({ to: tx.to as `0x${string}`, data: tx.data as `0x${string}`, value: BigInt(tx.value), gasPrice: BigInt(tx.gasPrice), gas: BigInt(tx.gas), }); console.log('Swap tx sent:', hash); const receipt = await publicClient.waitForTransactionReceipt({ hash }); console.log('Swap confirmed in block:', receipt.blockNumber); } // ─── Main ─────────────────────────────────────────────────── async function main() { try { const allowance = await checkAllowance(); await approveIfNeeded(allowance); await executeSwap(); console.log('Done!'); } catch (error) { console.error('Error:', error); process.exit(1); } } main(); ``` ## Running the script ```bash theme={null} npx tsx swap.ts ``` ## What this script does If the source token is native (HYPE), skips approval entirely. For ERC-20 tokens, checks if the AKKA Router already has sufficient spending approval. If allowance is insufficient, generates and submits an unlimited approval transaction, then waits for confirmation. Calls the swap endpoint with the desired parameters, then signs and broadcasts the returned transaction. Waits for on-chain confirmation. ## Adapting for ERC-20 to ERC-20 swaps To swap between two ERC-20 tokens (e.g., USDC to UBTC), change the `SRC_TOKEN`: ```typescript theme={null} const SRC_TOKEN = '0xYourERC20TokenAddress'; // e.g., USDC on HyperEVM const DST_TOKEN = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'; const AMOUNT = parseUnits('100', 6).toString(); // 100 USDC (6 decimals) ``` The script will automatically detect that the source is an ERC-20 token and handle the approval flow. # MCP Server (AI Agents) Source: https://docs.akka.finance/guides/mcp-server Connect AI agents like Claude, Cursor, and VS Code Copilot to AKKA's DEX aggregation via the Model Context Protocol AKKA provides an official [MCP server](https://github.com/Akka-Finance/akka-mcp-server) that lets AI agents get swap quotes, compare DEX prices, and build unsigned transactions — all through natural language. ## What is MCP? The [Model Context Protocol](https://modelcontextprotocol.io/) is an open standard that connects AI assistants to external tools. With AKKA's MCP server, an AI agent can: * Get the best swap quote across 25+ DEXes * Compare prices across individual liquidity pools * Build unsigned swap and approval transactions * Look up token details and supported chains The server is a thin client that calls the AKKA REST API. It does not hold private keys or execute transactions — it only returns unsigned transaction data. ## Prerequisites An AKKA API key is required. [Get your API key here](/authentication). ## Install Add to your `claude_desktop_config.json`: ```json theme={null} { "mcpServers": { "akka-dex": { "command": "npx", "args": ["-y", "@akka-finance/mcp-server"], "env": { "AKKA_API_KEY": "your-api-key" } } } } ``` ```bash theme={null} claude mcp add akka-dex -e AKKA_API_KEY=your-api-key -- npx -y @akka-finance/mcp-server ``` Add to `.cursor/mcp.json`: ```json theme={null} { "mcpServers": { "akka-dex": { "command": "npx", "args": ["-y", "@akka-finance/mcp-server"], "env": { "AKKA_API_KEY": "your-api-key" } } } } ``` Add to `.vscode/mcp.json`: ```json theme={null} { "servers": { "akka-dex": { "command": "npx", "args": ["-y", "@akka-finance/mcp-server"], "env": { "AKKA_API_KEY": "your-api-key" } } } } ``` ## Available tools Once connected, your AI agent has access to these tools: | Tool | Description | | ---------------------- | -------------------------------------------------- | | `akka_get_quote` | Get the best swap quote across all supported DEXes | | `akka_get_swap` | Build an unsigned swap transaction | | `akka_dex_compare` | Compare quotes across individual DEX pools | | `akka_get_spender` | Get the router contract address for token approval | | `akka_get_approve_tx` | Build an ERC-20 approve transaction | | `akka_check_allowance` | Check current token spending allowance | | `akka_list_tokens` | List tradeable tokens on a chain | | `akka_get_token` | Get token details by address | | `akka_list_chains` | List all supported chains | ## Example conversations Once the MCP server is connected, you can ask your AI agent things like: **You:** "What's the best rate for swapping 1 ETH to USDC on Arbitrum?" The agent calls `akka_get_quote` with the correct chain ID, token addresses, and amount in wei, then shows you the expected output. **You:** "Compare prices for 1000 USDC to WETH across all DEXes on Base" The agent calls `akka_dex_compare` and presents a table showing which DEX offers the best rate. **You:** "Build a swap transaction for 0.5 HYPE to USDC on HyperEVM for wallet 0xabc..." The agent calls `akka_get_quote` first, confirms the rate with you, then calls `akka_get_swap` to return the unsigned transaction data you can sign and broadcast. ## Configuration The MCP server can be configured via environment variables: | Variable | Default | Description | | -------------------- | -------------------------- | ---------------------------- | | `AKKA_API_BASE` | `https://api.akka.finance` | AKKA API base URL | | `AKKA_API_KEY` | **required** | API key for AKKA Finance API | | `AKKA_MCP_TRANSPORT` | `stdio` | Transport: `stdio` or `http` | | `AKKA_MCP_PORT` | `3100` | Port for HTTP transport | | `AKKA_TIMEOUT` | `15000` | Request timeout in ms | ### HTTP transport For remote or web-based agents, run the server with HTTP transport: ```bash theme={null} npx @akka-finance/mcp-server --transport=http --port=3100 ``` This exposes a Streamable HTTP endpoint at `http://localhost:3100/mcp`. ## Architecture ``` AI Agent (Claude, Cursor, VS Code, etc.) ↕ MCP Protocol (stdio or HTTP) AKKA MCP Server (@akka-finance/mcp-server) ↕ HTTP REST AKKA Finance API (api.akka.finance) ↕ On-chain 25+ DEXes across EVM chains ``` The MCP server translates natural language tool calls into AKKA API requests and formats the responses for the AI agent. All swap and approve tools return **unsigned transaction data** — signing and broadcasting is always the user's responsibility. ## Links * [npm package](https://www.npmjs.com/package/@akka-finance/mcp-server) * [GitHub repository](https://github.com/Akka-Finance/akka-mcp-server) * [MCP Registry](https://registry.modelcontextprotocol.io) * [Model Context Protocol](https://modelcontextprotocol.io/) # Node.js Backend Source: https://docs.akka.finance/guides/node-backend Execute swaps from a Node.js backend using viem — no React, no browser A complete server-side integration for bots, payment processors, or any backend service that needs to swap tokens programmatically. ## Prerequisites ```bash theme={null} npm install viem dotenv ``` Create a `.env` file: ```bash .env theme={null} AKKA_API_KEY=your_api_key PRIVATE_KEY=0xabc123... # your wallet private key ``` ## Full working script This script checks allowance, approves if needed, and executes a swap — all from the command line. ```typescript swap.ts theme={null} import 'dotenv/config'; import { createPublicClient, createWalletClient, http, parseUnits, formatUnits, defineChain, } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; // ── Config ────────────────────────────────────────────────────────── const API_BASE = 'https://api.akka.finance'; const API_KEY = process.env.AKKA_API_KEY!; const PRIVATE_KEY = process.env.PRIVATE_KEY! as `0x${string}`; const NATIVE = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; const CHAIN_ID = 999; const hyperEVM = defineChain({ id: CHAIN_ID, name: 'HyperEVM', nativeCurrency: { name: 'HYPE', symbol: 'HYPE', decimals: 18 }, rpcUrls: { default: { http: ['https://rpc.hyperliquid.xyz/evm'] } }, }); const account = privateKeyToAccount(PRIVATE_KEY); const publicClient = createPublicClient({ chain: hyperEVM, transport: http() }); const walletClient = createWalletClient({ chain: hyperEVM, transport: http(), account }); // ── API helpers ───────────────────────────────────────────────────── async function akkaGet(path: string, params: Record): Promise { const url = `${API_BASE}${path}?${new URLSearchParams(params)}`; const res = await fetch(url, { headers: { apikey: API_KEY } }); if (!res.ok) { const body = await res.json(); throw new Error(body.message || `HTTP ${res.status}`); } return res.json(); } // ── Swap flow ─────────────────────────────────────────────────────── async function swap( src: string, dst: string, amount: string, // in wei slippage: number, ) { const from = account.address; // 1. Check allowance (skip for native token) if (src.toLowerCase() !== NATIVE) { console.log('Checking allowance...'); const { allowance } = await akkaGet<{ allowance: string }>( `/swap/v1/${CHAIN_ID}/approve/allowance`, { tokenAddress: src, walletAddress: from }, ); if (BigInt(allowance) < BigInt(amount)) { console.log('Approving token spend...'); const approveTx = await akkaGet<{ to: string; data: string; value: string }>( `/swap/v1/${CHAIN_ID}/approve/transaction`, { tokenAddress: src }, ); const approveHash = await walletClient.sendTransaction({ to: approveTx.to as `0x${string}`, data: approveTx.data as `0x${string}`, value: BigInt(approveTx.value), }); await publicClient.waitForTransactionReceipt({ hash: approveHash }); console.log(`Approved: ${approveHash}`); } else { console.log('Allowance sufficient, skipping approval.'); } } // 2. Get swap transaction console.log('Fetching swap data...'); const swapData = await akkaGet<{ dstAmount: string; tx: { to: string; data: string; value: string; gasPrice: string; gas: string }; }>(`/swap/v1/${CHAIN_ID}/swap`, { src, dst, amount, from, slippage: slippage.toString(), }); // 3. Execute console.log('Sending swap transaction...'); const { tx } = swapData; const hash = await walletClient.sendTransaction({ to: tx.to as `0x${string}`, data: tx.data as `0x${string}`, value: BigInt(tx.value), gasPrice: BigInt(tx.gasPrice), gas: BigInt(tx.gas), }); const receipt = await publicClient.waitForTransactionReceipt({ hash }); console.log(`Swap confirmed in block ${receipt.blockNumber}`); console.log(`TX: https://hyperevmscan.io/tx/${hash}`); console.log(`Output: ${swapData.dstAmount} wei`); } // ── Run ───────────────────────────────────────────────────────────── const SRC = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; // HYPE const DST = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'; // UBTC const AMOUNT = parseUnits('1', 18).toString(); // 1 HYPE const SLIPPAGE = 1; // 1% swap(SRC, DST, AMOUNT, SLIPPAGE).catch(console.error); ``` Run it: ```bash theme={null} npx tsx swap.ts ``` ## Reusable client class For services that make multiple swaps, wrap the logic into a class: ```typescript akkaClient.ts theme={null} const API_BASE = 'https://api.akka.finance'; export class AkkaClient { constructor( private apiKey: string, private chainId: number = 999, ) {} private async get(path: string, params: Record = {}): Promise { const url = `${API_BASE}${path}?${new URLSearchParams(params)}`; const res = await fetch(url, { headers: { apikey: this.apiKey } }); if (!res.ok) { const body = await res.json(); throw new Error(body.message || `HTTP ${res.status}`); } return res.json(); } async quote(src: string, dst: string, amount: string) { return this.get<{ dstAmount: string; gas?: string }>( `/swap/v1/${this.chainId}/quote`, { src, dst, amount, includeGas: 'true' }, ); } async swap(src: string, dst: string, amount: string, from: string, slippage: number) { return this.get<{ dstAmount: string; tx: { to: string; data: string; value: string; gasPrice: string; gas: string }; }>(`/swap/v1/${this.chainId}/swap`, { src, dst, amount, from, slippage: slippage.toString(), }); } async allowance(tokenAddress: string, walletAddress: string) { return this.get<{ allowance: string }>( `/swap/v1/${this.chainId}/approve/allowance`, { tokenAddress, walletAddress }, ); } async approveTransaction(tokenAddress: string) { return this.get<{ to: string; data: string; value: string }>( `/swap/v1/${this.chainId}/approve/transaction`, { tokenAddress }, ); } async tokens(verified = true) { return this.get<{ tokens: Record }>( `/${this.chainId}/tokens`, { verified: String(verified) }, ); } } ``` Usage: ```typescript theme={null} const akka = new AkkaClient(process.env.AKKA_API_KEY!); const { dstAmount } = await akka.quote(SRC, DST, amount); console.log(`Expected output: ${dstAmount}`); ``` ## Polling for price changes Monitor a pair and swap when the rate is favorable: ```typescript priceMonitor.ts theme={null} import { AkkaClient } from './akkaClient'; import { parseUnits, formatUnits } from 'viem'; const akka = new AkkaClient(process.env.AKKA_API_KEY!); const SRC = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; const DST = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'; const AMOUNT = parseUnits('10', 18).toString(); // 10 HYPE const TARGET_RATE = 0.0005; // trigger when 10 HYPE buys >= 0.0005 UBTC async function monitor() { console.log('Monitoring price...'); setInterval(async () => { try { const { dstAmount } = await akka.quote(SRC, DST, AMOUNT); const output = Number(formatUnits(BigInt(dstAmount), 18)); console.log(`${new Date().toISOString()} — 10 HYPE → ${output.toFixed(8)} UBTC`); if (output >= TARGET_RATE) { console.log('Target rate reached!'); // Execute swap or send notification here } } catch (err) { console.error('Quote failed:', err); } }, 15_000); // every 15 seconds } monitor(); ``` All amounts are in **wei** (the smallest unit). Use `parseUnits` and `formatUnits` from viem to convert between human-readable amounts and wei. # Price API Source: https://docs.akka.finance/guides/price-api Use AKKA as a real-time token price feed on HyperEVM AKKA aggregates liquidity across every DEX on HyperEVM. As a side effect, the token endpoints provide real-time USD prices derived from actual pool reserves — not a single source, but a volume-weighted view across all indexed markets. ## Get all token prices in one call Fetch the full token list to get prices for every token on the chain: ```bash cURL theme={null} curl -H "apikey: YOUR_API_KEY" \ "https://api.akka.finance/999/tokens?verified=true" ``` ```javascript JavaScript theme={null} const res = await fetch( 'https://api.akka.finance/999/tokens?verified=true', { headers: { apikey: 'YOUR_API_KEY' } } ); const { tokens } = await res.json(); // tokens is a map: { [address]: { symbol, buyPriceUsd, sellPriceUsd, ... } } for (const [address, token] of Object.entries(tokens)) { console.log(`${token.symbol}: $${token.buyPriceUsd}`); } ``` ```python Python theme={null} import requests res = requests.get( "https://api.akka.finance/999/tokens", params={"verified": "true"}, headers={"apikey": "YOUR_API_KEY"}, ) tokens = res.json()["tokens"] for address, token in tokens.items(): print(f"{token['symbol']}: ${token['buyPriceUsd']}") ``` Each token includes two price fields: | Field | Description | | -------------- | ------------------------------------------------------ | | `buyPriceUsd` | Cost to buy 1 unit of this token (USD) | | `sellPriceUsd` | Value received when selling 1 unit of this token (USD) | The spread between `buyPriceUsd` and `sellPriceUsd` reflects real market liquidity — tighter spreads indicate deeper liquidity. ## Get a single token price If you only need the price for one token: ```bash theme={null} curl -H "apikey: YOUR_API_KEY" \ "https://api.akka.finance/999/tokens/0x5555555555555555555555555555555555555555" ``` ```json theme={null} { "symbol": "WHYPE", "name": "Wrapped HYPE", "decimals": 18, "address": "0x5555555555555555555555555555555555555555", "verified": true, "buyPriceUsd": 25.42, "sellPriceUsd": 25.38 } ``` ## Price polling pattern Prices are refreshed every \~5 seconds on the backend. For most use cases, polling every 15–30 seconds is sufficient and stays well within the rate limit. ```typescript priceService.ts theme={null} const API_BASE = 'https://api.akka.finance'; const API_KEY = process.env.AKKA_API_KEY!; const POLL_INTERVAL = 15_000; // 15 seconds interface TokenPrice { symbol: string; address: string; buyPriceUsd: number | null; sellPriceUsd: number | null; } let priceCache = new Map(); async function refreshPrices(): Promise { const res = await fetch( `${API_BASE}/999/tokens?verified=true`, { headers: { apikey: API_KEY } }, ); const { tokens } = await res.json(); const updated = new Map(); for (const [address, token] of Object.entries(tokens) as [string, any][]) { updated.set(address.toLowerCase(), { symbol: token.symbol, address: token.address, buyPriceUsd: token.buyPriceUsd, sellPriceUsd: token.sellPriceUsd, }); } priceCache = updated; } // Start polling refreshPrices(); setInterval(refreshPrices, POLL_INTERVAL); // Read from cache (instant, no API call) export function getPrice(tokenAddress: string): TokenPrice | undefined { return priceCache.get(tokenAddress.toLowerCase()); } export function getAllPrices(): Map { return priceCache; } ``` ## React hook for prices ```typescript hooks/useTokenPrice.ts theme={null} import { useState, useEffect } from 'react'; const API_BASE = 'https://api.akka.finance'; const API_KEY = process.env.NEXT_PUBLIC_AKKA_API_KEY!; interface TokenPrice { symbol: string; buyPriceUsd: number | null; sellPriceUsd: number | null; } export function useTokenPrice(chainId: number, tokenAddress: string) { const [price, setPrice] = useState(null); useEffect(() => { if (!tokenAddress) return; let cancelled = false; async function fetchPrice() { const res = await fetch( `${API_BASE}/${chainId}/tokens/${tokenAddress}`, { headers: { apikey: API_KEY } }, ); if (!res.ok || cancelled) return; const data = await res.json(); setPrice({ symbol: data.symbol, buyPriceUsd: data.buyPriceUsd, sellPriceUsd: data.sellPriceUsd, }); } fetchPrice(); const interval = setInterval(fetchPrice, 30_000); return () => { cancelled = true; clearInterval(interval); }; }, [chainId, tokenAddress]); return price; } ``` Usage: ```tsx theme={null} const whypePrice = useTokenPrice(999, '0x5555555555555555555555555555555555555555'); return WHYPE: ${whypePrice?.buyPriceUsd?.toFixed(2)}; ``` ## USD value helper Convert a token amount in wei to its USD value: ```typescript theme={null} import { formatUnits } from 'viem'; function toUsdValue(amountWei: string, decimals: number, priceUsd: number | null): string | null { if (!priceUsd) return null; const amount = Number(formatUnits(BigInt(amountWei), decimals)); return (amount * priceUsd).toFixed(2); } // Example: 1 WHYPE (18 decimals) at $25.42 toUsdValue('1000000000000000000', 18, 25.42); // → "25.42" ``` ## Use cases Show USD values next to token amounts so users know the dollar value of their swap. Display wallet holdings in USD by multiplying token balances by their current prices. Poll prices and trigger notifications when a token crosses a threshold. Track token price movements over time for dashboards and reporting. Prices are derived from real DEX pool reserves across all indexed markets on HyperEVM. They reflect actual on-chain liquidity, not centralized exchange prices. # React Hooks Source: https://docs.akka.finance/guides/react-hooks Drop-in React hooks for quoting and executing swaps with AKKA Two hooks that handle the entire swap lifecycle. Copy them into your project and you have a working swap UI. ## useAkkaQuote Fetches a quote from AKKA with automatic debouncing. Returns the expected output amount, token info, and loading/error states. ```typescript hooks/useAkkaQuote.ts theme={null} import { useState, useEffect, useRef } from 'react'; const API_BASE = 'https://api.akka.finance'; const API_KEY = process.env.NEXT_PUBLIC_AKKA_API_KEY!; const CHAIN_ID = 999; const DEBOUNCE_MS = 400; interface TokenInfo { address: string; symbol: string; name: string; decimals: number; logoUri: string | null; } interface QuoteResult { dstAmount: string; srcToken?: TokenInfo; dstToken?: TokenInfo; gas?: string; } interface UseAkkaQuoteReturn { quote: QuoteResult | null; loading: boolean; error: string | null; } export function useAkkaQuote( src: string, dst: string, amount: string, // in wei ): UseAkkaQuoteReturn { const [quote, setQuote] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const abortRef = useRef(); useEffect(() => { // Don't fetch for zero/empty amounts if (!src || !dst || !amount || amount === '0') { setQuote(null); setError(null); return; } const timer = setTimeout(async () => { // Cancel previous in-flight request abortRef.current?.abort(); const controller = new AbortController(); abortRef.current = controller; setLoading(true); setError(null); try { const params = new URLSearchParams({ src, dst, amount, includeTokensInfo: 'true', includeGas: 'true', }); const res = await fetch( `${API_BASE}/swap/v1/${CHAIN_ID}/quote?${params}`, { headers: { apikey: API_KEY }, signal: controller.signal, }, ); if (!res.ok) { const body = await res.json(); throw new Error(body.message || `HTTP ${res.status}`); } const data: QuoteResult = await res.json(); setQuote(data); } catch (err) { if (err instanceof DOMException && err.name === 'AbortError') return; setError(err instanceof Error ? err.message : 'Quote failed'); setQuote(null); } finally { setLoading(false); } }, DEBOUNCE_MS); return () => { clearTimeout(timer); abortRef.current?.abort(); }; }, [src, dst, amount]); return { quote, loading, error }; } ``` ### Usage ```tsx theme={null} import { parseUnits, formatUnits } from 'viem'; import { useAkkaQuote } from './hooks/useAkkaQuote'; const HYPE = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; const UBTC = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'; function QuoteDisplay() { const [input, setInput] = useState(''); const amountWei = input ? parseUnits(input, 18).toString() : '0'; const { quote, loading, error } = useAkkaQuote(HYPE, UBTC, amountWei); return (
setInput(e.target.value)} /> {loading && Fetching best rate...} {error && {error}} {quote && (

You'll receive: {formatUnits(BigInt(quote.dstAmount), quote.dstToken?.decimals ?? 18)} {quote.dstToken?.symbol}

{quote.gas &&

Estimated gas: {quote.gas}

}
)}
); } ``` The hook automatically: * **Debounces** — waits 400ms after the user stops typing before fetching * **Cancels stale requests** — if the user types again, the previous request is aborted * **Resets on zero input** — clears the quote when the input is empty *** ## useAkkaSwap Handles the full approve-and-swap flow. Pass in the swap parameters, get back an `execute` function and status. ```typescript hooks/useAkkaSwap.ts theme={null} import { useState, useCallback } from 'react'; import { useSendTransaction, useAccount, usePublicClient } from 'wagmi'; const API_BASE = 'https://api.akka.finance'; const API_KEY = process.env.NEXT_PUBLIC_AKKA_API_KEY!; const CHAIN_ID = 999; const NATIVE_TOKEN = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; type SwapStatus = 'idle' | 'checking' | 'approving' | 'waitingApproval' | 'swapping' | 'waitingSwap' | 'done' | 'error'; interface UseAkkaSwapReturn { execute: () => Promise; status: SwapStatus; txHash: string | null; error: string | null; reset: () => void; } export function useAkkaSwap( src: string, dst: string, amount: string, slippage: number = 1, ): UseAkkaSwapReturn { const { address } = useAccount(); const publicClient = usePublicClient(); const { sendTransactionAsync } = useSendTransaction(); const [status, setStatus] = useState('idle'); const [txHash, setTxHash] = useState(null); const [error, setError] = useState(null); const reset = useCallback(() => { setStatus('idle'); setTxHash(null); setError(null); }, []); const execute = useCallback(async () => { if (!address || !amount || amount === '0') return; setError(null); setTxHash(null); try { // Step 1: Check allowance (skip for native tokens) if (src.toLowerCase() !== NATIVE_TOKEN) { setStatus('checking'); const allowanceRes = await fetch( `${API_BASE}/swap/v1/${CHAIN_ID}/approve/allowance?` + new URLSearchParams({ tokenAddress: src, walletAddress: address }), { headers: { apikey: API_KEY } }, ); const { allowance } = await allowanceRes.json(); // Step 2: Approve if needed if (BigInt(allowance) < BigInt(amount)) { setStatus('approving'); const approveRes = await fetch( `${API_BASE}/swap/v1/${CHAIN_ID}/approve/transaction?` + new URLSearchParams({ tokenAddress: src }), { headers: { apikey: API_KEY } }, ); const approveTx = await approveRes.json(); const approveHash = await sendTransactionAsync({ to: approveTx.to as `0x${string}`, data: approveTx.data as `0x${string}`, value: BigInt(approveTx.value), }); setStatus('waitingApproval'); await publicClient!.waitForTransactionReceipt({ hash: approveHash }); } } // Step 3: Execute swap setStatus('swapping'); const swapRes = await fetch( `${API_BASE}/swap/v1/${CHAIN_ID}/swap?` + new URLSearchParams({ src, dst, amount, from: address, slippage: slippage.toString(), }), { headers: { apikey: API_KEY } }, ); if (!swapRes.ok) { const body = await swapRes.json(); throw new Error(body.message || 'Swap failed'); } const { tx } = await swapRes.json(); const hash = await sendTransactionAsync({ to: tx.to as `0x${string}`, data: tx.data as `0x${string}`, value: BigInt(tx.value), gasPrice: BigInt(tx.gasPrice), gas: BigInt(tx.gas), }); setStatus('waitingSwap'); await publicClient!.waitForTransactionReceipt({ hash }); setTxHash(hash); setStatus('done'); } catch (err) { setError(err instanceof Error ? err.message : 'Swap failed'); setStatus('error'); } }, [address, src, dst, amount, slippage, sendTransactionAsync, publicClient]); return { execute, status, txHash, error, reset }; } ``` ### Usage ```tsx theme={null} import { parseUnits } from 'viem'; import { useAkkaSwap } from './hooks/useAkkaSwap'; const HYPE = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; const UBTC = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'; function SwapForm() { const [input, setInput] = useState('1'); const amountWei = parseUnits(input || '0', 18).toString(); const { execute, status, txHash, error, reset } = useAkkaSwap( HYPE, UBTC, amountWei, 1, // 1% slippage ); const statusLabels: Record = { idle: 'Swap', checking: 'Checking allowance...', approving: 'Approve in wallet...', waitingApproval: 'Waiting for approval...', swapping: 'Confirm swap in wallet...', waitingSwap: 'Waiting for confirmation...', done: 'Swap complete!', error: 'Retry', }; const isWorking = ['checking', 'approving', 'waitingApproval', 'swapping', 'waitingSwap'].includes(status); return (
{ setInput(e.target.value); reset(); }} /> {error &&

{error}

} {txHash && ( View on explorer )}
); } ``` The hook provides **granular status tracking** so you can show the user exactly what's happening: | Status | Meaning | | ----------------- | -------------------------------------------------------- | | `idle` | Ready to swap | | `checking` | Checking current token allowance | | `approving` | Waiting for user to confirm approval in wallet | | `waitingApproval` | Approval tx submitted, waiting for on-chain confirmation | | `swapping` | Waiting for user to confirm swap in wallet | | `waitingSwap` | Swap tx submitted, waiting for on-chain confirmation | | `done` | Swap confirmed on-chain | | `error` | Something failed — check `error` for details | *** ## Combining Both Hooks For a complete swap UI, use `useAkkaQuote` for the live price preview and `useAkkaSwap` for execution: ```tsx theme={null} function CompleteSwapUI() { const [input, setInput] = useState(''); const amountWei = input ? parseUnits(input, 18).toString() : '0'; // Live quote as user types const { quote, loading: quoteLoading } = useAkkaQuote(HYPE, UBTC, amountWei); // Swap execution const { execute, status, txHash, error } = useAkkaSwap(HYPE, UBTC, amountWei, 1); return (
setInput(e.target.value)} /> {quoteLoading &&

Finding best rate...

} {quote &&

{formatUnits(BigInt(quote.dstAmount), 18)} UBTC

} {error &&

{error}

} {txHash && View tx}
); } ``` # Wagmi Integration Source: https://docs.akka.finance/guides/wagmi-integration Integrate AKKA swaps into a React app using wagmi and viem A complete guide to wiring AKKA's API into a [wagmi](https://wagmi.sh) + [viem](https://viem.sh) frontend. By the end, you'll have a working swap flow: connect wallet, check allowance, approve, and execute. ## Prerequisites ```bash theme={null} npm install wagmi viem @tanstack/react-query ``` ## 1. Chain Configuration Define HyperEVM as a custom chain for wagmi: ```typescript config.ts theme={null} import { defineChain } from 'viem'; import { createConfig, http } from 'wagmi'; export const hyperEVM = defineChain({ id: 999, name: 'HyperEVM', nativeCurrency: { name: 'HYPE', symbol: 'HYPE', decimals: 18 }, rpcUrls: { default: { http: ['https://rpc.hyperliquid.xyz/evm'] }, }, blockExplorers: { default: { name: 'HyperEVM Scan', url: 'https://hyperevmscan.io' }, }, }); export const config = createConfig({ chains: [hyperEVM], transports: { [hyperEVM.id]: http(), }, }); ``` ## 2. AKKA API Client A thin wrapper around the AKKA API: ```typescript akka.ts theme={null} const API_BASE = 'https://api.akka.finance'; const API_KEY = process.env.NEXT_PUBLIC_AKKA_API_KEY!; const NATIVE_TOKEN = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; const CHAIN_ID = 999; async function akkaFetch(path: string, params: Record): Promise { const url = `${API_BASE}${path}?${new URLSearchParams(params)}`; const res = await fetch(url, { headers: { apikey: API_KEY } }); if (!res.ok) { const error = await res.json(); throw new Error(error.message || 'AKKA API error'); } return res.json(); } export async function getQuote(src: string, dst: string, amount: string) { return akkaFetch<{ dstAmount: string; srcToken?: { symbol: string; decimals: number }; dstToken?: { symbol: string; decimals: number }; gas?: string; }>(`/swap/v1/${CHAIN_ID}/quote`, { src, dst, amount, includeTokensInfo: 'true', includeGas: 'true', }); } export async function getSwap( src: string, dst: string, amount: string, from: string, slippage: number, ) { return akkaFetch<{ dstAmount: string; tx: { to: string; data: string; value: string; gasPrice: string; gas: string }; }>(`/swap/v1/${CHAIN_ID}/swap`, { src, dst, amount, from, slippage: slippage.toString(), }); } export async function getAllowance(tokenAddress: string, walletAddress: string) { return akkaFetch<{ allowance: string }>( `/swap/v1/${CHAIN_ID}/approve/allowance`, { tokenAddress, walletAddress }, ); } export async function getApproveTransaction(tokenAddress: string) { return akkaFetch<{ data: string; to: string; value: string; gasPrice: string }>( `/swap/v1/${CHAIN_ID}/approve/transaction`, { tokenAddress }, ); } export function isNativeToken(address: string) { return address.toLowerCase() === NATIVE_TOKEN; } ``` ## 3. Connect Wallet + Execute Swap Wire the API client into wagmi hooks: ```tsx SwapButton.tsx theme={null} import { useAccount, useSendTransaction, useWaitForTransactionReceipt } from 'wagmi'; import { useState } from 'react'; import { getSwap, getAllowance, getApproveTransaction, isNativeToken } from './akka'; interface SwapButtonProps { src: string; dst: string; amount: string; // in wei slippage: number; } export function SwapButton({ src, dst, amount, slippage }: SwapButtonProps) { const { address } = useAccount(); const { sendTransactionAsync } = useSendTransaction(); const [status, setStatus] = useState<'idle' | 'approving' | 'swapping' | 'done' | 'error'>('idle'); const [txHash, setTxHash] = useState(); const [error, setError] = useState(); const handleSwap = async () => { if (!address) return; setError(undefined); try { // Step 1: Check & handle approval (skip for native tokens) if (!isNativeToken(src)) { setStatus('approving'); const { allowance } = await getAllowance(src, address); if (BigInt(allowance) < BigInt(amount)) { const approveTx = await getApproveTransaction(src); const approveHash = await sendTransactionAsync({ to: approveTx.to as `0x${string}`, data: approveTx.data as `0x${string}`, value: BigInt(approveTx.value), }); // Wait for approval to confirm before swapping await waitForReceipt(approveHash); } } // Step 2: Execute swap setStatus('swapping'); const swap = await getSwap(src, dst, amount, address, slippage); const { tx } = swap; const hash = await sendTransactionAsync({ to: tx.to as `0x${string}`, data: tx.data as `0x${string}`, value: BigInt(tx.value), gasPrice: BigInt(tx.gasPrice), gas: BigInt(tx.gas), }); setTxHash(hash); setStatus('done'); } catch (err) { setError(err instanceof Error ? err.message : 'Swap failed'); setStatus('error'); } }; return (
{error &&

{error}

} {txHash && ( View transaction )}
); } async function waitForReceipt(hash: string): Promise { // Simple polling — in production, use wagmi's useWaitForTransactionReceipt const { createPublicClient, http } = await import('viem'); const client = createPublicClient({ transport: http('https://rpc.hyperliquid.xyz/evm') }); await client.waitForTransactionReceipt({ hash: hash as `0x${string}` }); } ``` ## 4. Full Page Example Putting it all together: ```tsx SwapPage.tsx theme={null} import { useAccount, useConnect } from 'wagmi'; import { injected } from 'wagmi/connectors'; import { useState } from 'react'; import { parseUnits } from 'viem'; import { SwapButton } from './SwapButton'; import { useAkkaQuote } from './hooks'; // see React Hooks guide const HYPE = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; const UBTC = '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb'; export function SwapPage() { const { address, isConnected } = useAccount(); const { connect } = useConnect(); const [inputAmount, setInputAmount] = useState(''); const amountWei = inputAmount ? parseUnits(inputAmount, 18).toString() : '0'; const { quote, loading } = useAkkaQuote(HYPE, UBTC, amountWei); if (!isConnected) { return ; } return (
setInputAmount(e.target.value)} /> {loading &&

Fetching quote...

} {quote &&

You'll receive: {(Number(quote.dstAmount) / 1e18).toFixed(6)} UBTC

}
); } ``` See the [React Hooks guide](/guides/react-hooks) for the `useAkkaQuote` and `useAkkaSwap` hooks used above. # Introduction Source: https://docs.akka.finance/introduction AKKA Finance — liquidity aggregation API for optimal token swaps AKKA Finance is a liquidity aggregation protocol that finds the best token swap rates by routing through multiple DEXes simultaneously. The Pathfinder algorithm splits your swap across protocols and market depths to minimize slippage and maximize output. ## What you can do with the API Find the best swap rate for any token pair across all supported DEXes in a single call. Generate ready-to-sign transaction data for token swaps with built-in slippage protection. Check allowances and generate approval transactions for ERC-20 tokens. Get token metadata, verification status, and real-time USD pricing. ## How it works 1. **You request a quote** — AKKA's Pathfinder scans all available liquidity pools and finds the optimal route, potentially splitting across multiple DEXes. 2. **You approve token spending** — If swapping an ERC-20 token, you first approve the AKKA Router contract to spend your tokens. 3. **You execute the swap** — Call the swap endpoint to get a signed transaction object, then submit it to the blockchain. ## Next steps Go from zero to your first swap in 5 steps. # Quickstart Source: https://docs.akka.finance/quickstart Go from zero to your first token swap in 5 steps This guide walks you through a complete token swap on HyperEVM (chain ID `999`) — from checking allowance to executing the swap. ## Prerequisites * An API key ([get one on Telegram](https://t.me/akka_finance)) * A wallet with tokens on HyperEVM * Tokens to swap (this example swaps HYPE for UBTC) Before swapping an ERC-20 token, check if the AKKA Router is allowed to spend it. For native token swaps (HYPE), skip to step 3. ```bash cURL theme={null} curl -H "apikey: YOUR_API_KEY" \ "https://api.akka.finance/swap/v1/999/approve/allowance?tokenAddress=0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb&walletAddress=YOUR_WALLET_ADDRESS" ``` ```javascript JavaScript (viem) theme={null} const response = await fetch( 'https://api.akka.finance/swap/v1/999/approve/allowance?' + new URLSearchParams({ tokenAddress: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb', walletAddress: 'YOUR_WALLET_ADDRESS', }), { headers: { apikey: 'YOUR_API_KEY' } } ); const { allowance } = await response.json(); console.log('Current allowance:', allowance); ``` Response: ```json theme={null} { "allowance": "0" } ``` If `allowance` is `0` or less than your swap amount, proceed to step 2. Otherwise, skip to step 3. Generate and submit an approval transaction so the AKKA Router can spend your tokens. ```bash cURL theme={null} curl -H "apikey: YOUR_API_KEY" \ "https://api.akka.finance/swap/v1/999/approve/transaction?tokenAddress=0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb" ``` ```javascript JavaScript (viem) theme={null} const response = await fetch( 'https://api.akka.finance/swap/v1/999/approve/transaction?' + new URLSearchParams({ tokenAddress: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb', }), { headers: { apikey: 'YOUR_API_KEY' } } ); const approveTx = await response.json(); // approveTx = { data, gasPrice, to, value } // Sign and send the approval transaction with your wallet const hash = await walletClient.sendTransaction({ to: approveTx.to, data: approveTx.data, value: BigInt(approveTx.value), }); // Wait for confirmation await publicClient.waitForTransactionReceipt({ hash }); ``` Response: ```json theme={null} { "data": "0x095ea7b3...", "gasPrice": "100000000", "to": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb", "value": "0" } ``` Submit this transaction to the blockchain and wait for it to be confirmed before proceeding. Check the expected output amount before executing the swap. ```bash cURL theme={null} curl -H "apikey: YOUR_API_KEY" \ "https://api.akka.finance/swap/v1/999/quote?src=0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee&dst=0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb&amount=1000000000000000000&includeTokensInfo=true" ``` ```javascript JavaScript (viem) theme={null} const response = await fetch( 'https://api.akka.finance/swap/v1/999/quote?' + new URLSearchParams({ src: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', dst: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb', amount: '1000000000000000000', // 1 HYPE includeTokensInfo: 'true', }), { headers: { apikey: 'YOUR_API_KEY' } } ); const quote = await response.json(); console.log('Expected output:', quote.dstAmount); ``` Response: ```json theme={null} { "dstAmount": "205340622987446484992", "srcToken": { "address": "0x5555555555555555555555555555555555555555", "symbol": "WHYPE", "name": "Wrapped HYPE", "decimals": 18, "logoUri": null }, "dstToken": { "address": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb", "symbol": "UBTC", "name": "Universal BTC", "decimals": 18, "logoUri": null } } ``` Generate the swap transaction data and submit it to the blockchain. ```bash cURL theme={null} curl -H "apikey: YOUR_API_KEY" \ "https://api.akka.finance/swap/v1/999/swap?src=0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee&dst=0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb&amount=1000000000000000000&from=YOUR_WALLET_ADDRESS&slippage=1" ``` ```javascript JavaScript (viem) theme={null} const response = await fetch( 'https://api.akka.finance/swap/v1/999/swap?' + new URLSearchParams({ src: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', dst: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb', amount: '1000000000000000000', // 1 HYPE from: 'YOUR_WALLET_ADDRESS', slippage: '1', // 1% slippage tolerance }), { headers: { apikey: 'YOUR_API_KEY' } } ); const swap = await response.json(); console.log('Expected output:', swap.dstAmount); ``` Response: ```json theme={null} { "dstAmount": "12723902882990271", "tx": { "from": "0xYOUR_WALLET_ADDRESS", "to": "0xcce7452db4392b40aa0e1592a7c486e13bf69654", "data": "0x...", "value": "1000000000000000000", "gasPrice": "1000000000", "gas": "231973" }, "encodedTx": "0x..." } ``` Submit the transaction object from step 4 to the blockchain. ```javascript JavaScript (viem) theme={null} const { tx } = swap; const hash = await walletClient.sendTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value), gasPrice: BigInt(tx.gasPrice), gas: BigInt(tx.gas), }); const receipt = await publicClient.waitForTransactionReceipt({ hash }); console.log('Swap confirmed:', receipt.transactionHash); ``` The `tx` object is ready to use directly — no ABI encoding required. Just pass it to your wallet's `sendTransaction` method. ## Next steps Complete TypeScript implementation you can copy and run. Explore all endpoints with the interactive playground. # Smart Contracts Source: https://docs.akka.finance/smart-contracts AKKA Router contract addresses ## Deployed Contracts | Chain | Chain ID | AKKA Router Address | | --------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | HyperEVM | `999` | [`0xcce7452db4392b40aa0e1592a7c486e13bf69654`](https://hyperevmscan.io/address/0xcce7452db4392b40aa0e1592a7c486e13bf69654) | | Robinhood Chain | `4663` | [`0x0B00004Ccc39408Fa289e9F6853BFE4eac3E52c8`](https://robinhoodchain.blockscout.com/address/0x0B00004Ccc39408Fa289e9F6853BFE4eac3E52c8) | Contract addresses for Ethereum, Arbitrum, and Base will be published when those chains launch. ## What is the AKKA Router? The AKKA Router is the smart contract that executes token swaps on your behalf. When you call the `/swap` endpoint, the API returns a transaction that targets this contract. Before swapping ERC-20 tokens, you must approve the router to spend your tokens. Use the [`/approve/spender`](/api-reference/get-spender) endpoint to get the router address for any chain, or the [`/approve/transaction`](/api-reference/approve-transaction) endpoint to generate the approval transaction. Native tokens (e.g. HYPE on HyperEVM, ETH on Robinhood Chain) do not require approval. Only ERC-20 tokens need to be approved before swapping. # Supported Chains Source: https://docs.akka.finance/supported-chains Blockchain networks supported by AKKA Finance ## Live | Chain | Chain ID | Native Token | Wrapped Native | | ---------------------- | -------- | ------------ | ---------------------------------------------------- | | HyperEVM (Hyperliquid) | `999` | HYPE | WHYPE (`0x5555555555555555555555555555555555555555`) | | Robinhood Chain | `4663` | ETH | WETH (`0x0bd7d308f8e1639fab988df18a8011f41eacad73`) | ## Coming Soon | Chain | Chain ID | Native Token | | -------- | -------- | ------------ | | Ethereum | `1` | ETH | | Arbitrum | `42161` | ETH | | Base | `8453` | ETH | ## Native Token Address When swapping the chain's native token (e.g., HYPE on HyperEVM), use the sentinel address as the `src` or `dst` parameter: ``` 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee ``` The API automatically wraps/unwraps native tokens during the swap. You do not need to wrap manually.