Documentation Index
Fetch the complete documentation index at: https://akkafinance-4d5a30d3.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
This is a complete, copy-paste-ready TypeScript script that swaps tokens on HyperEVM using the AKKA API and viem.
Prerequisites
Create a .env file:
WALLET_ADDRESS=0xYourWalletAddress
PRIVATE_KEY=0xYourPrivateKey
RPC_URL=https://rpc.hyperliquid.xyz/evm
API_KEY=your_akka_api_key
Full Script
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<string, string>) {
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<bigint> {
// 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
What this script does
Checks allowance
If the source token is native (HYPE), skips approval entirely. For ERC-20 tokens, checks if the AKKA Router already has sufficient spending approval.
Approves if needed
If allowance is insufficient, generates and submits an unlimited approval transaction, then waits for confirmation.
Executes the swap
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:
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.