Swap API Guide
The following guide will explain how to use the Ooga Booga API to carry out a swap on Berachain Testnet, displaying the functionalities that the API will be able to provide.
To carry out the swap is as simple as the following steps:
- Get an Ooga Booga API key
- Checking Allowances
- Setting allowance with approval transaction
- Making a Swap
The full source code of the guide can be found on Github
0. Get an Ooga Booga API key
Currently the API is only available upon request. Please reach out to the team on TG for the API keys: @whoiskevinn or @beranoulli.
1. Checking Allowances
Before starting to trade using the Ooga Booga API, it is essential to approve the ERC20 token that we intend to swap with against the router. Thus, we need verify if there is enough allowance to the Ooga Booga Routing contract. You can also manually check the allowance by getting the routing contract and calling allowance
directly to the ERC20 contract on-chain.
1.1 Set up environment
The example source code is written using bun
and viem
. But it should be equally simple to integrate using other runtimes such as node.js
and other EVM libraries such as ether.js
import {
http,
type Address,
createWalletClient,
maxUint256,
parseEther,
publicActions,
zeroAddress,
} from "viem"; // Main library used to interface with the blockchain
import { privateKeyToAccount } from "viem/accounts";
import { berachainTestnetbArtio } from "viem/chains";
if (!process.env.PRIVATE_KEY) throw new Error("PRIVATE_KEY is required");
if (!process.env.PUBLIC_API_URL) throw new Error("PUBLIC_API_URL is required");
if (!process.env.API_KEY) throw new Error("API_KEY is required");
const PRIVATE_KEY = process.env.PRIVATE_KEY as Address; // Private key of the account to make the trade
const PUBLIC_API_URL = process.env.PUBLIC_API_URL;
const API_KEY = process.env.API_KEY;
1.2 Set account and initialize EVM libraries
const account = privateKeyToAccount(PRIVATE_KEY);
const client = createWalletClient({
chain: berachainTestnetbArtio,
transport: http(),
account,
}).extend(publicActions);
1.3 Define Swap Parameters
In this guide we will be swapping 0.01 HONEY to BERA to show case the capabilities of the API.
// Bartio token addresses
const NATIVE_TOKEN: Address = zeroAddress; // Default address for Bera native token
const HONEY: Address = "0x0E4aaF1351de4c0264C5c7056Ef3777b41BD8e03"; //
const swapParams = {
tokenIn: HONEY, // Address of the token swapping from (HONEY)
tokenOut: NATIVE_TOKEN, // Address of the token swapping to (BERA)
amount: parseEther("0.02"), // Amount of tokenIn to swap
to: account.address, // Address to send tokenOut to (optional and defaults to `from`)
slippage: 0.01, // Range from 0 to 1 to allow for price slippage
};
type SwapParams = typeof swapParams;
If you're planning to test the swapping with the same parameters make sure you have enough HONEY to make the trade. We encourage you to also test with other parameters
1.4 Main Function
Our API also allows developers to query the allowances directly instead of doing on-chain. This minimizes the developers reliance on an on-chain connection.
Alternative, you can retrieve the router contract directly from the API Reference
IMPORTANT
Do also note that if you are trading the native token no allowance is required. For simplicity we've set the allowance to maxUint256
in case it is the native token.
const headers = {
Authorization: `Bearer ${API_KEY}`,
};
const getAllowance = async (token: Address, from: Address) => {
// Native token does not require approvals for allowance
if (token === NATIVE_TOKEN) return maxUint256;
const publicApiUrl = new URL(`${PUBLIC_API_URL}/v1/approve/allowance`);
publicApiUrl.searchParams.set("token", token);
publicApiUrl.searchParams.set("from", from);
const res = await fetch(publicApiUrl, {
headers,
});
const json = await res.json();
return json.allowance;
};
WARNING
Everytime the Ooga Booga API is queried, the API_KEY
has to be provided on the fetch
call. Make sure to not forget this.
1.5 Execution
This getAllowance
would then fit in the main execution body like such:
async function main() {
// Check allowance
const allowance = await getAllowance(swapParams.tokenIn, swapParams.from);
console.log("Allowance", allowance);
// Approve if necessary
if (allowance < swapParams.amount) {
await approveAllowance(
swapParams.tokenIn,
swapParams.from,
swapParams.amount - allowance, // Only approve amount remaining
);
}
// Swap
await swap(swapParams);
}
2. Approving allowance
2.1 Main function
Allowances have to be approved if it was not previously done before.
NOTE
The amount
parameter can be left out and it would generate a transaction to approve unlimited amounts for the given token to the router. This is useful to save gas on subsequent swap requests
const approveAllowance = async (
token: Address,
amount: bigint,
) => {
const publicApiUrl = new URL(`${PUBLIC_API_URL}/v1/approve`);
publicApiUrl.searchParams.set("token", token);
publicApiUrl.searchParams.set("amount", amount.toString());
const res = await fetch(publicApiUrl, { headers });
const { tx } = await res.json();
console.log("Submitting approve...");
const hash = await client.sendTransaction({
from: tx.from as Address,
to: tx.to as Address,
data: tx.data as `0x${string}`,
});
const rcpt = await client.waitForTransactionReceipt({
hash,
});
console.log("Approval complete", rcpt.transactionHash, rcpt.status);
};
2.2 Execution
Approving should only be run if there is a necessity for it
async function main() {
// Check allowance
const allowance = await getAllowance(swapParams.tokenIn, swapParams.from);
console.log("Allowance", allowance);
// Approve if necessary
if (allowance < swapParams.amount) {
await approveAllowance(
swapParams.tokenIn,
swapParams.from,
swapParams.amount - allowance, // Only approve amount remaining
);
}
// Swap
await swap(swapParams);
}
3. Making a swap
Once we have the necessary allowances to make the trade we can all the final API endpoint to generate a quote. And if we like the quote then we can execute it.
3.1 Main function
The query being done on the swap also serves as a quote. The quote contains crucial information about the trade being carried out. The full details of the quote can be found in API Reference.
The quote endpoint also directly generates the transaction body required to sign and submit the transaction on-chain directly.
const swap = async (swapParams: SwapParams) => {
const publicApiUrl = new URL(`${PUBLIC_API_URL}/v1/swap`);
publicApiUrl.searchParams.set("tokenIn", swapParams.tokenIn);
publicApiUrl.searchParams.set("amount", swapParams.amount.toString());
publicApiUrl.searchParams.set("tokenOut", swapParams.tokenOut);
publicApiUrl.searchParams.set("to", swapParams.to);
publicApiUrl.searchParams.set("slippage", swapParams.slippage.toString());
const res = await fetch(publicApiUrl, { headers });
const { tx } = await res.json();
console.log("Submitting swap...");
const hash = await client.sendTransaction({
from: tx.from as Address,
to: tx.to as Address,
data: tx.data as `0x${string}`,
value: tx.value ? BigInt(tx.value) : 0n,
});
console.log("hash", hash);
const rcpt = await client.waitForTransactionReceipt({
hash,
});
console.log("Swap complete", rcpt.status);
};
Note that value
has to be passed in if the tokenIn
is the native token. This will also automatically wrap the token into WBERA
to be traded.
Do also note if BERA
is the tokenOut
then it will also return it unwrapped.
Feel free to also print the res
object to see the full routing path and details of the swap being made. For full details of the response check the reference.
3.1 Execution
async function main() {
// Check allowance
const allowance = await getAllowance(swapParams.tokenIn, account.address);
console.log("Allowance", allowance);
// Approve if necessary
if (allowance < swapParams.amount) {
await approveAllowance(
swapParams.tokenIn,
swapParams.amount - allowance, // Only approve amount remaining
);
}
// Swap
await swap(swapParams);
}
The source code of the full guide can be found on Github