Skip to content

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:

  1. Get an Ooga Booga API key
  2. Checking Allowances
  3. Setting allowance with approval transaction
  4. 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

javascript
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

typescript
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.

typescript
// 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.

typescript
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:

typescript
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

typescript
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

typescript
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.

typescript
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

typescript
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