npm install viem
Reusable client
akka-client.ts
export type PartnerQuote = {
quoteId: string;
chainId: number;
sellToken: `0x${string}`;
buyToken: `0x${string}`;
sellAmount: string;
buyAmount: string;
minAmountOut: string;
allowanceTarget: `0x${string}` | null;
expiresAt: string;
issues: Array<{ code: string; message: string }>;
validation: Record<'balance' | 'allowance' | 'gas', { status: string }>;
simulation: { status: string; gas: string };
tx: {
to: `0x${string}`;
data: `0x${string}`;
value: string;
gas: string;
gasPrice: string;
type?: 'legacy' | 'eip1559';
maxFeePerGas?: string;
maxPriorityFeePerGas?: string;
};
};
export class AkkaPartnerClient {
constructor(
private readonly apiKey: string,
private readonly baseUrl = 'https://api.akka.finance',
) {}
private async request<T>(path: string, init?: RequestInit): Promise<T> {
const response = await fetch(`${this.baseUrl}${path}`, {
...init,
headers: { apikey: this.apiKey, ...init?.headers },
signal: AbortSignal.timeout(10_000),
});
const body = await response.json();
if (!response.ok)
throw new Error(`AKKA ${response.status}: ${body.message}`);
return body;
}
quote(input: {
chainId: number;
src: string;
dst: string;
amount: bigint;
payer: string;
recipient?: string;
slippage?: number;
}) {
const params = new URLSearchParams({
src: input.src,
dst: input.dst,
amount: input.amount.toString(),
payer: input.payer,
recipient: input.recipient ?? input.payer,
slippage: String(input.slippage ?? 1),
});
return this.request<PartnerQuote>(
`/partner/v1/${input.chainId}/quote?${params}`,
);
}
chains() {
return this.request<
Array<{
chainId: number;
routerAddress: string;
routerCodeHash: string | null;
operationalStatus: string;
}>
>('/partner/v1/chains');
}
sources(chainId: number) {
return this.request<Array<{ key: string; status: string }>>(
`/partner/v1/${chainId}/sources`,
);
}
async report(input: {
quoteId: string;
chainId: number;
transactionHash: string;
status: 'SUBMITTED' | 'CONFIRMED' | 'REVERTED';
reason?: string;
}) {
await this.request('/partner/v1/executions', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(input),
}).catch(() => undefined); // Reporting must not block receipt processing.
}
}
Usage
const akka = new AkkaPartnerClient(process.env.AKKA_API_KEY!);
const quote = await akka.quote({
chainId: 999,
src: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
dst: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
amount: 1_000_000_000_000_000_000n,
payer: account.address,
slippage: 1,
});
if (quote.issues.length) throw new Error(quote.issues[0].message);
if (
Object.values(quote.validation).some((check) => check.status === 'UNKNOWN')
) {
throw new Error('Validate payer state through your RPC before execution');
}
const feeFields =
quote.tx.type === 'eip1559'
? {
maxFeePerGas: BigInt(quote.tx.maxFeePerGas!),
maxPriorityFeePerGas: BigInt(quote.tx.maxPriorityFeePerGas!),
}
: { gasPrice: BigInt(quote.tx.gasPrice) };
const hash = await walletClient.sendTransaction({
to: quote.tx.to,
data: quote.tx.data,
value: BigInt(quote.tx.value),
gas: BigInt(quote.tx.gas),
...feeFields,
});
await akka.report({
quoteId: quote.quoteId,
chainId: 999,
transactionHash: hash,
status: 'SUBMITTED',
});
