# How Does It Work?

Pikachu explains...

{% embed url="<https://x.com/whoiskevin/status/1793374559137341870>" %}
Work of Art \[1]
{% endembed %}


# Liquidity Sources

A list of all live and soon-to-be-live integrated liquidity sources.

Berachain:\
\
All liquidity sources can be selectively enabled and disabled on the frontend as well as through the API.\
\
\*CP = Constant Product, CL = Concentrated Liquidity

## Live:

<table><thead><tr><th>Liquidity Source</th><th width="155">Integration Type</th><th>X</th></tr></thead><tbody><tr><td>Kodiak V2</td><td>CP AMM</td><td><a href="https://x.com/KodiakFi">https://x.com/KodiakFi</a></td></tr><tr><td>Kodiak V3</td><td>CL AMM</td><td><a href="https://x.com/KodiakFi">https://x.com/KodiakFi</a></td></tr><tr><td>Bex</td><td>CP AMM</td><td>N/A (Berachain enshrined dApp)</td></tr><tr><td>Honeypot</td><td>CP AMM</td><td><a href="https://x.com/honeypotfinance">https://x.com/honeypotfinance</a></td></tr><tr><td>Beradrome</td><td>Restaking Protocol</td><td><a href="https://x.com/beradrome">https://x.com/beradrome</a></td></tr><tr><td>Grizzly</td><td>CL + Hooks  AMM</td><td><a href="https://x.com/GrizzlyFinance_">https://x.com/GrizzlyFinance_</a></td></tr><tr><td>Izumi</td><td>CL + Limit Order AMM</td><td><a href="https://x.com/izumi_Finance">https://x.com/izumi_Finance</a></td></tr><tr><td>Honeyswap</td><td>Stablecoin Wrapper</td><td>N/A (Berachain enshrined dApp)</td></tr><tr><td>Berps</td><td>Perpetuals Protocol</td><td>N/A (Berachain enshrined dApp)</td></tr><tr><td>Bend</td><td>Lending Protocol</td><td>N/A (Berachain enshrined dApp)</td></tr><tr><td>Marginal</td><td>Perpetuals + CP AMM</td><td><a href="https://x.com/MarginalDEX">https://x.com/MarginalDEX</a></td></tr><tr><td>Memeswap</td><td>Launchpad + CP AMM</td><td><a href="https://x.com/memeswapfi">https://x.com/memeswapfi</a></td></tr><tr><td>Bulla</td><td>CL + Hooks AMM</td><td><a href="https://x.com/BullaExchange">https://x.com/BullaExchange</a></td></tr><tr><td>Burr Bear - Multi Stable Pools</td><td>StableSwap AMM</td><td><a href="https://x.com/moneygoesburr">https://x.com/moneygoesburr</a></td></tr><tr><td>Burr Bear  - Generalized Pools</td><td>CP + Multi-Token AMM</td><td><a href="https://x.com/moneygoesburr">https://x.com/moneygoesburr</a></td></tr><tr><td>Burr Bear - Burr Pools</td><td>Bonding Curve AMM</td><td><a href="https://x.com/moneygoesburr">https://x.com/moneygoesburr</a></td></tr><tr><td>Twin Finance</td><td>CP AMM</td><td><a href="https://x.com/TwinFinance">https://x.com/TwinFinance</a></td></tr><tr><td>WeBera</td><td>Yield Protocol</td><td><a href="https://x.com/WeberaFinance">https://x.com/WeberaFinance</a></td></tr><tr><td>WBERA</td><td>Native Wrapper</td><td>N/A</td></tr></tbody></table>

## Coming Soon:

<table><thead><tr><th>Liquidity Source</th><th width="154">Integration Type</th><th>X</th></tr></thead><tbody><tr><td>Beraborrow</td><td>Lending Protocol</td><td><a href="https://x.com/beraborrow">https://x.com/beraborrow</a></td></tr><tr><td>Gummi</td><td>Lending Protocol</td><td><a href="https://x.com/GummiFi">https://x.com/GummiFi</a></td></tr><tr><td>Dolomite</td><td>Lending Protocol</td><td><a href="https://x.com/Dolomite_io">https://x.com/Dolomite_io</a></td></tr><tr><td>Goldilocks</td><td>Bonding Curve AMM</td><td><a href="https://x.com/goldilocksmoney">https://x.com/goldilocksmoney</a></td></tr><tr><td>Velocimeter</td><td>Bonding Curve AMM</td><td><a href="https://x.com/VelocimeterDEX">https://x.com/VelocimeterDEX</a></td></tr><tr><td>MantisSwap</td><td>StableSwap AMM</td><td><a href="https://x.com/MantisSwap">https://x.com/MantisSwap</a></td></tr><tr><td>BeraBook</td><td>Order Book DEX</td><td><a href="https://x.com/BeraBook">https://x.com/BeraBook</a></td></tr><tr><td>Infrared</td><td>Restaking Protocol</td><td><a href="https://x.com/InfraredFinance">https://x.com/InfraredFinance</a></td></tr><tr><td>Exponents</td><td>Perpetuals + AMM DEX</td><td><a href="https://x.com/Exponents_Fi">https://x.com/Exponents_Fi</a></td></tr><tr><td>Arbera</td><td>Yield Protocol</td><td><a href="https://x.com/ArbitrageBera">https://x.com/ArbitrageBera</a></td></tr><tr><td>Peapods</td><td>Yield Protocol</td><td><a href="https://x.com/PeapodsFinance">https://x.com/PeapodsFinance</a></td></tr><tr><td>Kodiak Panda Factory</td><td>Launchpad + Bonding Curve AMM</td><td><a href="https://x.com/KodiakFi">https://x.com/KodiakFi</a></td></tr><tr><td>IVX</td><td>Options AMM</td><td><a href="https://x.com/ivx_fi">https://x.com/ivx_fi</a></td></tr></tbody></table>


# Fee Model

Berachain:\
\
Ooga Booga only charges a fee if both Bex and Kodiak’s quotes are beaten. See image below:

<figure><img src="/files/wcHCwdtRSndxT8ZThU9F" alt=""><figcaption></figcaption></figure>

Put simply, a quote is pulled from Bex, a quote is pulled from Kodiak, and then a quote is pulled from Ooga Booga. If Ooga Booga is able to beat both Bex’s and Kodiak’s price by at least 0.15%, a 0.069% fee is charged on the output token. This guarantees a betterment of at least 0.081% to the swapper if a fee is charged. \
\
This model is better than charging a blanket flat fee on the aggregator, which defeats the entire thesis of “finding the best price”.\
\
HyperEVM:\
\
Ooga Booga currently does not charge a fee, and only takes in positive slippage.


# Meta Aggregator

Currently on live on HyperEVM, coming to Berachain soon!

A meta aggregator, is an aggregator which aggregates aggregators!\
\
Ooga Booga takes no fees on the meta aggregator. Ooga Booga only takes in fees from aggregators which offer kickbacks, rebates, or positive slippage for referring flow to them. This does not affect your quotes whatsoever, as you'd be charged at exactly the same price.


# Tokenomics

The token resides on Berachain.

### `OOGA` Token

`OOGA` token is the liquid, transferrable utility token for Ooga Booga.

### `sOOGA` Token

`sOOGA` token is the non-transferrable staked version of `OOGA`.

Those that choose to allocate their `sOOGA` to the relevant modules can earn fees from Ooga Booga, participate in governance, and further.


# Staking and Allocating

{% stepper %}
{% step %}

### Obtain `OOGA`

Through markets or otherwise.
{% endstep %}

{% step %}

### Stake `OOGA`

Stake `OOGA` through the staking page to recieve `sOOGA`.
{% endstep %}

{% step %}

### Allocate `sOOGA`

Allocate `sOOGA` to an allocation module such as the rewards or governance module to start earning that vault's benefits.
{% endstep %}
{% endstepper %}

`OOGA` must be staked into `sOOGA` first before being able to do anything with it. After staking into `sOOGA`, an allocation module can be chosen to receive the relevant benefits associated with it.

### `OOGA` to `sOOGA`

`OOGA` can be staked to receive `sOOGA`, and the conversion is 1:1.

{% hint style="info" %}
Staking 1,000 OOGA will return 1,000 sOOGA.
{% endhint %}

### `sOOGA` to `OOGA`

Conversion times represent the period required for `sOOGA` to fully convert into `OOGA`. Redeeming before the full conversion time results in a conversion tax, which decreases linearly as the conversion progresses towards the maximum.

On Berachain bArtio testnet, the minimum and maximum conversion times are set to 3 days and 7 days.&#x20;

On Berachain mainnet, the minimum and maximum conversion times will differ significantly.&#x20;

{% hint style="info" %}
Selecting the minimum conversion time (3 days on bArtio), and unstaking 1,000 `sOOGA` will return 500 `OOGA` after 3 days.\
\
Selecting the maximum conversion time (7 days on bArtio) and unstaking 1,000 `sOOGA` will return 1,000 `OOGA` after 7 days.
{% endhint %}

{% hint style="success" %}
All `OOGA` collected from the conversion taxes will be burned and permanently removed from circulation. &#x20;
{% endhint %}


# Distribution

Coming soon..


# Swap API

`OBRouter` is the primary contract which is interacted with in day-to-day use, including those that engage through calldata retrieved from the Swap API.

`pathDefinition` is generated by the API.  This is fed into`OBExecutor` to carry out the swap route. This value should never be tampered as it can cause to loss of funds.

`OBExecutor` is ephemeral and may change often (to include new liquidity sources). Therefore, it should never be hardcoded. It should always be returned from the Swap API. It is also not recommended to call `OBExecutor` directly.

{% hint style="info" %}
API responses are limited to 1000 requests per minute.&#x20;

If you require a higher rate limit, please ping us on telegram @beranoulli or @whoiskevinn.
{% endhint %}

<br>


# Guide

This guide outlines how to use the Swap API to execute a swap.\
\
The full source code of this guide can be found in this [Github](https://github.com/0xoogabooga/ooga-booga-api-example) repository.

Follow these steps to complete a swap:

{% stepper %}
{% step %}

### Obtain API Key

Get an API key by reaching out to a member of our team.
{% endstep %}

{% step %}

### Check Allowances

Check the current allowances for the tokens involved in the swap.
{% endstep %}

{% step %}

### Set Allowances

Use an approval transaction to set the required allowances for the swap.
{% endstep %}

{% step %}

### Execute Swap

Initiate the swap transaction.
{% endstep %}
{% endstepper %}

## 1. Obtain an API Key

The API is currently available by request only. To obtain API keys, contact the team directly on Telegram: [@whoiskevinn](https://t.me/whoiskevinn) or [@beranoulli](https://t.me/beranoulli).

## 2. Check Allowances

Before initiating trades with the Swap API, it is crucial to approve the ERC20 token intended for the swap (the input token) against the router. Ensure there is sufficient allowance granted to `OBRouter`. You can verify this programmatically or manually by calling the `allowance` function directly on the ERC20's contract on-chain.

The example 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`

Setting up the environment:

```typescript
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;
```

Setting the account and initializing the EVM libraries:

```typescript
const account = privateKeyToAccount(PRIVATE_KEY);
const client = createWalletClient({
	chain: berachainTestnetbArtio,
	transport: http(),
	account,
}).extend(publicActions);
```

Defining the swap parameters (this example uses a 0.01 HONEY to BERA swap):

```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;
```

The Swap API also allows developers to query the allowances directly instead of doing on-chain.

{% hint style="info" %}
If you are trading the native token no allowance is required. In this example, for simplicity, the allowance is set to `maxUint256` in the native token case.
{% endhint %}

```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;
};
```

{% hint style="warning" %}
Everytime the Swap API is queried, the `API_KEY` has to be provided on the `fetch` call.&#x20;
{% endhint %}

`getAllowance` fits into the main execution body likeso:

```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. Approving Allowances

{% hint style="info" %}
The `amount` parameter can be left out, generating a transaction to approve unlimited amounts for the given token to the router. This is useful to save gas on subsequent swap requests.
{% endhint %}

```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);
};
```

Approving if neccesary:

```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);
}
```

## 4. Execute Swap

Once the necessary allowances are in place, you can call the final API endpoint to generate a quote. If the quote meets your expectations, proceed to execute the trade.

The swap query doubles as a quote, providing essential details about the trade. Comprehensive information about the quote can be found in the API reference.

Additionally, the quote endpoint generates the complete transaction body, ready to be signed and submitted directly on-chain.

```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);
};
```

{% hint style="info" %}
If the `tokenIn` is the native token, ensure that a `value` is passed. This will automatically wrap the native token into WBERA, enabling it to be traded.

If `BERA` is the `tokenOut` then it will be returned unwrapped.
{% endhint %}

{% hint style="success" %}
The`res` object can be printed to view the complete routing path and detailed information about the swap. For a comprehensive breakdown of the response, refer to the API Reference.
{% endhint %}

Executing:

```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);
}
```


# Reference

{% openapi src="<https://mainnet.api.oogabooga.io/docs/json>" path="/v1/swap" method="get" %}
<https://mainnet.api.oogabooga.io/docs/json>
{% endopenapi %}

{% openapi src="<https://mainnet.api.oogabooga.io/docs/json>" path="/v1/tokens" method="get" %}
<https://mainnet.api.oogabooga.io/docs/json>
{% endopenapi %}

{% openapi src="<https://mainnet.api.oogabooga.io/docs/json>" path="/v1/liquidity-sources" method="get" %}
<https://mainnet.api.oogabooga.io/docs/json>
{% endopenapi %}


# Troubleshooting

## Debugging Transaction Failures

EVM execution environments often provide limited ways to figure how exactly a transaction failed to execute.&#x20;

[Foundry](https://book.getfoundry.sh/getting-started/installation) provides a useful command:

```bash
cast run 0x8e14deeb46f1757b21a0fcb4badb0a5296c7a2d20ec3963732214ed74cb3c03e --rpc-url https://bartio.rpc.berachain.com
```

This shows a breakdown of the transaction execution and the different contract interactions.

Assuming the transaction failed, the most probable error signature would be `0x71c4efed` (`SlippageExceeded`).&#x20;

You can look up the full list of errors in the `OBRouter` Reference.

Alternatively if the error is not found on the table, foundry also provides [cast-4byte](https://book.getfoundry.sh/reference/cast/cast-4byte?highlight=4byte#cast-4byte) which can decode the error if it is already present in their lookup table:

```bash
cast 4byte 0x71c4efed
```

***

## OutOfGas Transactions

We've identified that bArtio's gas estimation for transactions can sometimes be inaccurate, leading to failures due to insufficient gas. When reviewing such transactions on a block explorer or using debugging methods (described above), you'll notice that the failures are attributed to inadequate gas provision.

By default, viem and wagmi will always try to estimate gas from the RPC if no gas limit is set to the transaction. This gas estimation often leads to incorrect estimates that lead to transactions failing with`OutOfGas`.&#x20;

> \[OutOfGas] EvmError: OutOfGas

To address this issue, we’ve implemented a solution in our frontend and recommend other integrators do the same. The approach involves manually estimating the transaction gas using the RPC, then submitting the swap transaction with an additional buffer added to the estimated gas value.

We suggest applying a buffer of **10%-20%** on top of the RPC's returned gas estimate. This method has proven effective in mitigating `OutOfGas` errors and ensuring smoother transaction execution.

Below is an example of through viem:

```typescript
const gas = await publicClient.estimateGas({
  account: tx.from as Address,
  to: tx.to as Address,
  data: tx.data as `0x${string}`,
  value: tx.value ? BigInt(tx.value) : 0n,
});

// Add 10% gas buffer
const gasWithBuffer = (gas * 11) / 10;

await client.sendTransaction({
  account: tx.from as Address,
  to: tx.to as Address,
  data: tx.data as `0x${string}`,
  value: tx.value ? BigInt(tx.value) : 0n,
  gas: gasWithBuffer,
});
```

***

## Transaction Calldata Missing on Swap API[​](https://docs.oogabooga.io/api/troubleshooting#tx-calldata-missing-on-the-swap-api) <a href="#tx-calldata-missing-on-the-swap-api" id="tx-calldata-missing-on-the-swap-api"></a>

If the `swap` endpoint on the API does not return the transaction calldata. This is because a `to` parameter needs to be provided in order for the calldata to be constructed, otherwise `OBRouter` does not know where to send outputted tokens.


# Meta API

{% hint style="info" %}
API responses are limited to 1500 requests per minute.&#x20;

If you require a higher rate limit, please ping us on telegram @beranoulli or @whoiskevinn.
{% endhint %}

<br>


# Streaming vs Polling

The Meta API provides two ways to obtain swap quotes:

* **Polling** — via the `/meta/swap` endpoint
* **Streaming** — via the `/meta/stream/swap` endpoint

***

**`/meta/stream/swap` — Streaming Quotes**

Establishes a Server-Sent Events (SSE) stream that returns quotes in real time.

* Quotes are delivered on a **first-come, first-served** basis.
* Aggregators that respond sooner will be sent to the client immediately.
* Events include connection status, quotes, errors, heartbeats, and completion notifications.
* Intended to be directly integrated on frontend code.
* No authentication required only sensible IP based rate limits.

***

**`/meta/swap` — Polling Quotes**

Fetches swap quotes for one or more aggregators in a single response.

* The `aggregators` query parameter defines which aggregators to query.
* If omitted, the API defaults to **all available aggregators**.
* The response **always includes `oogaBooga`** as a baseline aggregator.
* Quotes from other aggregators are subject to a **500ms cutoff** window; slower responses are excluded.
* The cutoff is based on observed averages and may be tuned in future releases.
* More suitable for backend usage.
* Requires an API key for authentication. Request key from <david@oogabooga.io>

***


# Frontend Integration Guide

A **Next.js** tutorial demonstrating how to connect to and stream real-time data from the **Ooga Booga Meta Dex Aggregator API** using Server-Sent Events (SSE).

[Github](https://github.com/0xoogabooga/meta-agg-fe-tutorial)

[Live demo](https://meta-agg-fe-tutorial.vercel.app/?tab=quotes)


# Key Concepts

### ⚠️ Important: Quotes simulation  <a href="#important-wallet-connection" id="important-wallet-connection"></a>

> **🔒 Connect your wallet to get real, pre-simulated pricing from the Ooga Booga backend.**
>
> **Without wallet connection, quotes may be spoofed or manipulated by aggregators.** Connected wallets receive verified quotes that reflect actual execution prices.

#### 🌐 Quote Stream API <a href="#quote-stream-api" id="quote-stream-api"></a>

The application connects to a streaming API for real-time swap quotes:

```typescript
const AGGREGATOR_BASE_URL = 'https://hyperevm.api.oogabooga.io/meta/stream/swap'
```

**Supported Parameters**

| Parameter     | Type      | Description                                 |
| ------------- | --------- | ------------------------------------------- |
| `tokenIn`     | string    | Input token address                         |
| `tokenOut`    | string    | Output token address                        |
| `amount`      | string    | Amount to swap (in token units)             |
| `maxSlippage` | string    | Maximum acceptable slippage (default: 0.01) |
| `to`          | string    | Recipient address                           |
| `aggregators` | string\[] | Specific aggregators to query               |

#### 📡 Event Types <a href="#event-types" id="event-types"></a>

The SSE stream emits the following events:

* **`connected`** - Initial connection established
* **`quote`** - New quote data received
* **`error`** - Error occurred during streaming
* **`heartbeat`** - Keep-alive signal

#### 📊 Quote Data Structure <a href="#quote-data-structure" id="quote-data-structure"></a>

Each quote contains comprehensive swap information:

```typescript
interface QuoteResponse {
  aggregator: string;
  quote: {
    status: string;
    amountIn: string;
    amountOut: string;
    fee: string;
    value: string;
    aggregator: string;
    routerAddr: string;
    calldata: string;
    gas: string;
    simulationAmountOut: string;
    priceImpact: number;
  };
  timestamp: number;
}
```

### 🔧 Usage Examples <a href="#usage-examples" id="usage-examples"></a>

#### Basic Quote Stream Implementation <a href="#basic-quote-stream-implementation" id="basic-quote-stream-implementation"></a>

```typescript
import { useQuoteStream } from '@/hooks/use-quote-stream'

const QuoteStreamComponent = () => {
  const { isConnected, latestQuote, error } = useQuoteStream({
    chainId: 999, // HyperEVM chain ID
    params: {
      tokenIn: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb', // USDT
      tokenOut: '0x0000000000000000000000000000000000000000', // HYPE
      amount: '10000000', // 10 USDT
      maxSlippage: '0.5',
    },
    enabled: true
  })

  if (!isConnected) {
    return <div>🔄 Connecting to quote stream...</div>
  }
  
  if (error) {
    return <div>❌ Error: {error.message}</div>
  }
  
  return (
    <div>
      <h3>📊 Latest Quote</h3>
      <pre>{JSON.stringify(latestQuote, null, 2)}</pre>
    </div>
  )
}
```


# Meta Aggregator Quote Streaming

[Github](https://github.com/0xoogabooga/meta-agg-fe-tutorial)&#x20;

[Live demo](https://meta-agg-fe-tutorial.vercel.app/?tab=quotes)

<figure><img src="/files/3Db6ntHddlbQ0CMnoWeI" alt=""><figcaption></figcaption></figure>

This example shows how to stream real-time swap quotes from multiple aggregators simultaneously.

**Architecture Overview**

**🏗️ Backend Infrastructure**

* **Ooga Booga Meta Dex Aggregator**: Service providing real-time swap quotes
* **Server-Sent Events**: Streaming infrastructure for live updates

**📁 Frontend Components**

1. **API Layer** (`src/api/meta-stream-api.ts`)
   * Manages SSE connections to the aggregator API
   * Handles quote stream parameters and events
2. **Connection Management** (`src/hooks/use-quote-stream.ts`)
   * React hook for managing quote streams
   * Event subscription and cleanup lifecycle
3. **Business Logic** (`src/hooks/use-aggregators-quote.ts`)
   * Preconfigured hook for USDT/HYPE quotes
   * Built on top of `useQuoteStream`
4. **UI Components** (`src/components/`)
   * React components for displaying quote data

> **✅ That's everything you need to get started with streaming quotes!**


# Dynamic Token List

[Github](https://github.com/0xoogabooga/meta-agg-fe-tutorial)&#x20;

[Live demo](https://meta-agg-fe-tutorial.vercel.app/?tab=aggregators)

<figure><img src="/files/3foJiOwSlnIiJWarDSQq" alt=""><figcaption></figcaption></figure>

Demonstrates how to fetch and display available aggregators and their supported token pairs in real-time.

**Architecture Overview**

**🏗️ Backend Infrastructure**

* **Aggregators Registry**: Service providing real-time aggregator information
* **Token Pair Discovery**: Availability across different DEX protocols

**📁 Frontend Components**

1. **API Layer** (`src/api/api.ts`)
   * HTTP requests to the aggregators registry endpoint
   * Data fetching and caching
2. **Data Management** (`src/hooks/use-aggregators-list.ts`)
   * React hook for fetching aggregator data
   * Real-time updates and error handling
3. **UI Components** (`src/components/aggregators-list/`)
   * Interactive aggregator information display
   * Token pair selection and filtering

<br>


# Send Transaction

[Github](https://github.com/0xoogabooga/meta-agg-fe-tutorial)&#x20;

[Live demo](https://meta-agg-fe-tutorial.vercel.app/?tab=transactions)

<figure><img src="/files/9xc1TMQTChV8J4r3dkpc" alt=""><figcaption></figcaption></figure>

Complete end-to-end swap implementation using Meta Aggregator quotes with wallet connection, token approval, and transaction execution.

**Architecture Overview**

**📁 Main Components** (`src/components/transaction-example/`)

**🔧 Core Components**

* `transaction-example.tsx` - Root wrapper with wallet provider
* `transaction-example-content.tsx` - Main logic and state management
* `wallet-provider.tsx` - Wagmi and RainbowKit configuration
* `wagmi-config.ts` - HyperEVM chain configuration and wallet setup

**🎨 UI Components**

* `header.tsx` - Connection status and wallet connect button
* `quote-display.tsx` - Quote data and action buttons
* `approval-status.tsx` - Token approval status and progress


# Reference

## GET /meta/swap

>

```json
{"openapi":"3.0.3","info":{"title":"Meta API","version":"1.0.0"},"tags":[],"paths":{"/meta/swap":{"get":{"parameters":[{"description":"The tokenIn address","schema":{"type":"string","title":"EVM Address","pattern":"^0x(.*)$"},"in":"query","name":"tokenIn","required":true},{"description":"The tokenOut address","schema":{"type":"string","title":"EVM Address","pattern":"^0x(.*)$"},"in":"query","name":"tokenOut","required":true},{"description":"The amount of tokenIn used in the swap","schema":{"exclusiveMinimum":0,"anyOf":[{"format":"numeric","type":"string"},{"exclusiveMinimum":0,"description":"The amount of tokenIn used in the swap","type":"number"}]},"in":"query","name":"amount","required":true},{"description":"The address to send the output to","schema":{"type":"string","title":"EVM Address","pattern":"^0x(.*)$"},"in":"query","name":"to","required":false},{"description":"The maximum slippage allowed in the swap as a decimal fraction, for example 0.005 for 0.5% slippage. 0 < maxSlippage < 1","schema":{"minimum":0,"maximum":1,"default":0.01,"anyOf":[{"format":"numeric","default":0,"type":"string"},{"minimum":0,"maximum":1,"default":0.01,"description":"The maximum slippage allowed in the swap as a decimal fraction, for example 0.005 for 0.5% slippage. 0 < maxSlippage < 1","type":"number"}]},"in":"query","name":"maxSlippage","required":true},{"description":"The aggregators to use in the swap","schema":{"type":"array","items":{"anyOf":[{"const":"hyperBloom","type":"string"},{"const":"openOcean","type":"string"},{"const":"liquidSwap","type":"string"},{"const":"kyberSwap","type":"string"},{"const":"oogaBooga","type":"string"},{"const":"lifi","type":"string"},{"const":"bebop","type":"string"},{"const":"gluex","type":"string"},{"const":"enso","type":"string"},{"const":"eisen","type":"string"},{"const":"hyperflow","type":"string"},{"const":"fibrous","type":"string"},{"const":"nordstern","type":"string"}]}},"in":"query","name":"aggregators","required":false},{"description":"The aggregators to not use in the swap","schema":{"type":"array","items":{"anyOf":[{"const":"hyperBloom","type":"string"},{"const":"openOcean","type":"string"},{"const":"liquidSwap","type":"string"},{"const":"kyberSwap","type":"string"},{"const":"oogaBooga","type":"string"},{"const":"lifi","type":"string"},{"const":"bebop","type":"string"},{"const":"gluex","type":"string"},{"const":"enso","type":"string"},{"const":"eisen","type":"string"},{"const":"hyperflow","type":"string"},{"const":"fibrous","type":"string"},{"const":"nordstern","type":"string"}]}},"in":"query","name":"aggregatorsBlacklist","required":false},{"description":"Whether to simulate the quotes","schema":{"type":"boolean"},"in":"query","name":"simulate","required":false},{"description":"The referral code to use in the swap","schema":{"anyOf":[{"format":"numeric","default":0,"type":"string"},{"description":"The referral code to use in the swap","type":"number"}]},"in":"query","name":"referralCode","required":false}],"responses":{"200":{"items":{"type":"object","properties":{"amountIn":{"description":"The amount of tokenIn used in the swap","type":"bigint"},"aggregator":{"description":"The aggregator used in the swap","type":"string"},"amountOut":{"description":"The amount of tokenOut quoted by the dex-aggregator provider","type":"bigint"},"minAmountOut":{"description":"The minimum amount of tokenOut that will be received in the swap calculated from the simulationAmountOut and maxSlippage provided","type":"bigint"},"simulationAmountOut":{"description":"The amount of tokenOut received in the on-chain simulation and encoded in the transaction","type":"bigint"},"priceImpact":{"nullable":true,"anyOf":[{"description":"The price impact of the swap, in basis points, for example 0.0004 for 0.04%","type":"number"},{"type":"null"}]},"fee":{"description":"The fee paid in the swap denominated in outputToken wei","type":"bigint"},"gas":{"description":"The gas used in the swap","type":"bigint"},"value":{"description":"The value sent in the swap","type":"bigint"},"routerAddr":{"description":"The router address used in the swap. Only shown if recipient is provided","title":"EVM Address","type":"string","pattern":"^0x(.*)$"},"calldata":{"description":"The calldata used in the swap. Only shown if recipient is provided","type":"string"},"status":{"description":"The status of the swap","const":"Success","type":"string"}},"required":["amountIn","aggregator","amountOut","minAmountOut","priceImpact","fee","value","status"]},"content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"amountIn":{"description":"The amount of tokenIn used in the swap","type":"bigint"},"aggregator":{"description":"The aggregator used in the swap","type":"string"},"amountOut":{"description":"The amount of tokenOut quoted by the dex-aggregator provider","type":"bigint"},"minAmountOut":{"description":"The minimum amount of tokenOut that will be received in the swap calculated from the simulationAmountOut and maxSlippage provided","type":"bigint"},"simulationAmountOut":{"description":"The amount of tokenOut received in the on-chain simulation and encoded in the transaction","type":"bigint"},"priceImpact":{"nullable":true,"anyOf":[{"description":"The price impact of the swap, in basis points, for example 0.0004 for 0.04%","type":"number"},{"type":"null"}]},"fee":{"description":"The fee paid in the swap denominated in outputToken wei","type":"bigint"},"gas":{"description":"The gas used in the swap","type":"bigint"},"value":{"description":"The value sent in the swap","type":"bigint"},"routerAddr":{"description":"The router address used in the swap. Only shown if recipient is provided","title":"EVM Address","type":"string","pattern":"^0x(.*)$"},"calldata":{"description":"The calldata used in the swap. Only shown if recipient is provided","type":"string"},"status":{"description":"The status of the swap","const":"Success","type":"string"}},"required":["amountIn","aggregator","amountOut","minAmountOut","priceImpact","fee","value","status"]}}},"multipart/form-data":{"schema":{"type":"array","items":{"type":"object","properties":{"amountIn":{"description":"The amount of tokenIn used in the swap","type":"bigint"},"aggregator":{"description":"The aggregator used in the swap","type":"string"},"amountOut":{"description":"The amount of tokenOut quoted by the dex-aggregator provider","type":"bigint"},"minAmountOut":{"description":"The minimum amount of tokenOut that will be received in the swap calculated from the simulationAmountOut and maxSlippage provided","type":"bigint"},"simulationAmountOut":{"description":"The amount of tokenOut received in the on-chain simulation and encoded in the transaction","type":"bigint"},"priceImpact":{"nullable":true,"anyOf":[{"description":"The price impact of the swap, in basis points, for example 0.0004 for 0.04%","type":"number"},{"type":"null"}]},"fee":{"description":"The fee paid in the swap denominated in outputToken wei","type":"bigint"},"gas":{"description":"The gas used in the swap","type":"bigint"},"value":{"description":"The value sent in the swap","type":"bigint"},"routerAddr":{"description":"The router address used in the swap. Only shown if recipient is provided","title":"EVM Address","type":"string","pattern":"^0x(.*)$"},"calldata":{"description":"The calldata used in the swap. Only shown if recipient is provided","type":"string"},"status":{"description":"The status of the swap","const":"Success","type":"string"}},"required":["amountIn","aggregator","amountOut","minAmountOut","priceImpact","fee","value","status"]}}},"text/plain":{"schema":{"type":"array","items":{"type":"object","properties":{"amountIn":{"description":"The amount of tokenIn used in the swap","type":"bigint"},"aggregator":{"description":"The aggregator used in the swap","type":"string"},"amountOut":{"description":"The amount of tokenOut quoted by the dex-aggregator provider","type":"bigint"},"minAmountOut":{"description":"The minimum amount of tokenOut that will be received in the swap calculated from the simulationAmountOut and maxSlippage provided","type":"bigint"},"simulationAmountOut":{"description":"The amount of tokenOut received in the on-chain simulation and encoded in the transaction","type":"bigint"},"priceImpact":{"nullable":true,"anyOf":[{"description":"The price impact of the swap, in basis points, for example 0.0004 for 0.04%","type":"number"},{"type":"null"}]},"fee":{"description":"The fee paid in the swap denominated in outputToken wei","type":"bigint"},"gas":{"description":"The gas used in the swap","type":"bigint"},"value":{"description":"The value sent in the swap","type":"bigint"},"routerAddr":{"description":"The router address used in the swap. Only shown if recipient is provided","title":"EVM Address","type":"string","pattern":"^0x(.*)$"},"calldata":{"description":"The calldata used in the swap. Only shown if recipient is provided","type":"string"},"status":{"description":"The status of the swap","const":"Success","type":"string"}},"required":["amountIn","aggregator","amountOut","minAmountOut","priceImpact","fee","value","status"]}}}}},"400":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"const":"error","type":"string"},"error":{"description":"The error message if the swap failed","type":"string"}},"required":["status","error"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"status":{"const":"error","type":"string"},"error":{"description":"The error message if the swap failed","type":"string"}},"required":["status","error"]}},"text/plain":{"schema":{"type":"object","properties":{"status":{"const":"error","type":"string"},"error":{"description":"The error message if the swap failed","type":"string"}},"required":["status","error"]}}}}},"operationId":"getMetaSwap","tags":["Meta Aggregator"]}}}}
```

## GET /meta/aggregators

>

```json
{"openapi":"3.0.3","info":{"title":"Meta API","version":"1.0.0"},"tags":[],"paths":{"/meta/aggregators":{"get":{"responses":{"200":{"description":"List of available aggregators","items":{"type":"object","properties":{"id":{"description":"The unique identifier of the aggregator","type":"string"},"displayName":{"description":"The display name of the aggregator","type":"string"},"logoUrl":{"description":"The URL to the aggregator logo","type":"string"}},"required":["id","displayName","logoUrl"]},"content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"description":"The unique identifier of the aggregator","type":"string"},"displayName":{"description":"The display name of the aggregator","type":"string"},"logoUrl":{"description":"The URL to the aggregator logo","type":"string"}},"required":["id","displayName","logoUrl"]}}},"multipart/form-data":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"description":"The unique identifier of the aggregator","type":"string"},"displayName":{"description":"The display name of the aggregator","type":"string"},"logoUrl":{"description":"The URL to the aggregator logo","type":"string"}},"required":["id","displayName","logoUrl"]}}},"text/plain":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"description":"The unique identifier of the aggregator","type":"string"},"displayName":{"description":"The display name of the aggregator","type":"string"},"logoUrl":{"description":"The URL to the aggregator logo","type":"string"}},"required":["id","displayName","logoUrl"]}}}}}},"operationId":"getMetaAggregators","tags":["Meta Aggregator"]}}}}
```

## Stream real-time swap quotes

> Establishes a Server-Sent Events (SSE) stream that provides real-time swap quotes from multiple aggregators. The stream emits various event types including connection status, quotes, errors, heartbeats, and completion notifications.

```json
{"openapi":"3.0.3","info":{"title":"Meta API","version":"1.0.0"},"tags":[],"paths":{"/meta/stream/swap":{"get":{"parameters":[{"description":"The tokenIn address","schema":{"type":"string","title":"EVM Address","pattern":"^0x(.*)$"},"in":"query","name":"tokenIn","required":true},{"description":"The tokenOut address","schema":{"type":"string","title":"EVM Address","pattern":"^0x(.*)$"},"in":"query","name":"tokenOut","required":true},{"description":"The amount of tokenIn used in the swap","schema":{"exclusiveMinimum":0,"anyOf":[{"format":"numeric","type":"string"},{"exclusiveMinimum":0,"description":"The amount of tokenIn used in the swap","type":"number"}]},"in":"query","name":"amount","required":true},{"description":"The address to send the output to","schema":{"type":"string","title":"EVM Address","pattern":"^0x(.*)$"},"in":"query","name":"to","required":false},{"description":"The maximum slippage allowed in the swap as a decimal fraction, for example 0.005 for 0.5% slippage. 0 < maxSlippage < 1","schema":{"minimum":0,"maximum":1,"default":0.01,"anyOf":[{"format":"numeric","default":0,"type":"string"},{"minimum":0,"maximum":1,"default":0.01,"description":"The maximum slippage allowed in the swap as a decimal fraction, for example 0.005 for 0.5% slippage. 0 < maxSlippage < 1","type":"number"}]},"in":"query","name":"maxSlippage","required":true},{"description":"The aggregators to use in the swap","schema":{"type":"array","items":{"anyOf":[{"const":"hyperBloom","type":"string"},{"const":"openOcean","type":"string"},{"const":"liquidSwap","type":"string"},{"const":"kyberSwap","type":"string"},{"const":"oogaBooga","type":"string"},{"const":"lifi","type":"string"},{"const":"bebop","type":"string"},{"const":"gluex","type":"string"},{"const":"enso","type":"string"},{"const":"eisen","type":"string"},{"const":"hyperflow","type":"string"},{"const":"fibrous","type":"string"},{"const":"nordstern","type":"string"}]}},"in":"query","name":"aggregators","required":false},{"description":"The aggregators to not use in the swap","schema":{"type":"array","items":{"anyOf":[{"const":"hyperBloom","type":"string"},{"const":"openOcean","type":"string"},{"const":"liquidSwap","type":"string"},{"const":"kyberSwap","type":"string"},{"const":"oogaBooga","type":"string"},{"const":"lifi","type":"string"},{"const":"bebop","type":"string"},{"const":"gluex","type":"string"},{"const":"enso","type":"string"},{"const":"eisen","type":"string"},{"const":"hyperflow","type":"string"},{"const":"fibrous","type":"string"},{"const":"nordstern","type":"string"}]}},"in":"query","name":"aggregatorsBlacklist","required":false},{"description":"Whether to simulate the quotes","schema":{"type":"boolean"},"in":"query","name":"simulate","required":false},{"description":"The referral code to use in the swap","schema":{"anyOf":[{"format":"numeric","default":0,"type":"string"},{"description":"The referral code to use in the swap","type":"number"}]},"in":"query","name":"referralCode","required":false}],"operationId":"getMetaStreamSwap","tags":["Meta Aggregator"],"summary":"Stream real-time swap quotes","description":"Establishes a Server-Sent Events (SSE) stream that provides real-time swap quotes from multiple aggregators. The stream emits various event types including connection status, quotes, errors, heartbeats, and completion notifications.","responses":{"200":{"description":"SSE stream of quote events","content":{"text/event-stream":{"schema":{"type":"string","description":"Server-Sent Events formatted string containing quote data"}}}}}}}}}
```


# Price API


# Guide (WIP)

Coming soon.


# Reference

{% openapi src="<https://mainnet.api.oogabooga.io/docs/json>" path="/v1/prices" method="get" %}
<https://mainnet.api.oogabooga.io/docs/json>
{% endopenapi %}

{% openapi src="<https://mainnet.api.oogabooga.io/docs/json>" path="/v1/tokens" method="get" %}
<https://mainnet.api.oogabooga.io/docs/json>
{% endopenapi %}


# Endpoints

| Chain             | Url                                                                     |
| ----------------- | ----------------------------------------------------------------------- |
| Berachain (80094) | <https://mainnet.api.oogabooga.io>                                      |
| HyperEvm (999)    | [https://hyperevm.api.oogabooga.io](https://hyperevm.api.oogabooga.io/) |
| Botanix (3637)    | [https://botanix.api.oogabooga.io](https://botanix.api.oogabooga.io/)   |
| Monad (143)       | [https://monad.api.oogabooga.io](https://monad.api.oogabooga.io/)       |

{% hint style="info" %}
API key is currently necessarily for access. Please ping us on telegram @beranoulli or @whoiskevinn.
{% endhint %}


# Audit

OBRouter Audit:

{% file src="/files/Q7bVrHVVlh7RWcJXGA4m" %}

bOoga and OogaRewards Audit:

{% embed url="<https://reports.electisec.tech/reports/04-2025-Ooga-Booga>" %}


# Media

{% file src="/files/9RgF85VKaUvDbiRKQTbi" %}

{% file src="/files/BvRERK7xWHVo89qlfVI0" %}

{% file src="/files/EdiSUnfwgwUwtNLLqcJj" %}

{% file src="/files/utH61yCgxfsOS2WcX3Tf" %}

{% file src="/files/E952P2EuCvaMdfp6TsfD" %}

{% file src="/files/sIvH68UTo3bRW4OMD39o" %}

{% file src="/files/uycNLXvv5BXzJ0RwZ6SJ" %}

{% file src="/files/rqZEA1yyFwVys5sRWXR7" %}

***

{% file src="/files/N8osXQ4RKiinO9tsCt2v" %}

{% file src="/files/IcXDUxlfMN2oPArp1VoU" %}

{% file src="/files/qYaEqk1tvbNpTiX9vtng" %}

{% file src="/files/ZNKlR291JMLCnWem57ug" %}

{% file src="/files/MZ2XBkYbpcvVDcN7FISy" %}

{% file src="/files/W6jYdo994VxzsVa0K8ne" %}

{% file src="/files/7nCd8HZIoujjCvuyzJcW" %}

{% file src="/files/KfzrJgwBeuPBn32iLH2H" %}

{% file src="/files/SjuzihoCqKjSCaOxD1Rz" %}

{% file src="/files/Yt0kObjk5SKbvbnocvVe" %}

{% file src="/files/DDxeJa2SIYit2jFI9CsA" %}

{% file src="/files/3FT4f2YuGhsmRsAFV90g" %}

{% file src="/files/KPPOssrUbOz1KjBx6coW" %}

{% file src="/files/wk0u7VyO9PIIy0iwIQ9J" %}

{% file src="/files/EbRh9sFtNOGRq7Md8m6O" %}

{% file src="/files/GKRNpmnwvUcru3gLs4EF" %}

{% file src="/files/JRNgFpYXbOB2PEZGyaLI" %}

{% file src="/files/nYu1yAnn5ywVcqZuCadk" %}

{% file src="/files/aW0rtfnRjB9NsRa8OTTA" %}

{% file src="/files/KIJepl73LFdn98aGADED" %}

{% file src="/files/YysICPsqszzmEBB6kaiJ" %}


# Community Made Resources

Super Bera made resources!

Ooga Bucks Analysis by: <https://x.com/RaveniumNFT>

{% embed url="<https://dune.com/ravenium/oogabucks-by-oogabooga>" %}

Swap API Python Wrapper by: <https://x.com/1220Moritz>

{% @github-files/github-code-block url="<https://github.com/1220moritz/Ooga_Booga_Python>" %}


# Aggregator

Deployments for OBRouter can be found here:

{% tabs %}
{% tab title="Berachain (80094)" %}
[0xFd88aD4849BA0F729D6fF4bC27Ff948Ab1Ac3dE7](https://berascan.com/address/0xfd88ad4849ba0f729d6ff4bc27ff948ab1ac3de7)
{% endtab %}

{% tab title="HyperEvm (999)" %}
[0x5fbd1b5aa82d09359c05428647871fe9add3f411](https://hyperevmscan.io/address/0x5fbd1b5aa82d09359c05428647871fe9add3f411)
{% endtab %}

{% tab title="Botanix (3637)" %}
[0x417fBC387fa853AEd674d62Ca1b21E3cE54C0F85](https://botanixscan.io/address/0x417fBC387fa853AEd674d62Ca1b21E3cE54C0F85)
{% endtab %}

{% tab title="Monad (143)" %}
0x5fbD1B5AA82d09359C05428647871fe9aDd3F411
{% endtab %}
{% endtabs %}


# OBRouter Reference

## Functions

The swap function is the primary function interface for making swaps through Ooga Booga.

```solidity
function swap(
  swapTokenInfo memory tokenInfo,
  bytes calldata pathDefinition,
  address executor,
  uint32 referralCode
) external payable returns (uint256 amountOut)
```

| Name             | Type            | Description                                  |
| ---------------- | --------------- | -------------------------------------------- |
| `tokenInfo`      | `swapTokenInfo` | Specifies the inputs and outputs of the swap |
| `pathDefinition` | `bytes`         | Encoded path parameters of the swap path     |
| `executor`       | `address`       | External contract that will execute the path |
| `referralCode`   | `uint32`        | Referral code to note the source of the swap |

{% hint style="info" %}
When `inputAmount` is set to 0 then the senders' full balance will be sent. This can be used to fully swap tokens that rebase.
{% endhint %}

{% hint style="warning" %}
Do not modify the calldata provided by the swap endpoint. It could lead to **loss of funds**. The calldata provided should allow direct execution on-chain.
{% endhint %}

The structure of the data returned is:

| Name        | Type      | Description                                  |
| ----------- | --------- | -------------------------------------------- |
| `amountOut` | `uint256` | Actual outputToken amount received from swap |

The `swapTokenInfo` struct looks like:

| Name             | Type      | Description                                                                                        |
| ---------------- | --------- | -------------------------------------------------------------------------------------------------- |
| `inputToken`     | `address` | Token starting the swap, the native token (BERA) is `0x0000000000000000000000000000000000000000`   |
| `inputAmount`    | `uint256` | Amount of `inputToken` to swap                                                                     |
| `outputToken`    | `address` | Token returning from swap, the native token (BERA) is `0x0000000000000000000000000000000000000000` |
| `outputQuote`    | `uint256` | Expected amount returned                                                                           |
| `outputMin`      | `uint256` | Minimum amount returned derived from slippage and quote                                            |
| `outputReceiver` | `address` | The destination address to receive output tokens                                                   |

## Events

An event is emitted from any swaps carried out on `OBRouter`:

```solidity
event Swap(
    address sender,
    uint256 inputAmount,
    address inputToken,
    uint256 amountOut,
    address outputToken,
    int256 slippage,
    uint32 referralCode
);
```

The structure of the data within the event emitted looks like this:

| Name           | Type      | Description                                                                                                                                                                                                                                                          |
| -------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sender`       | `address` | Address that called the swap                                                                                                                                                                                                                                         |
| `inputAmount`  | `uint256` | Amount of `inputTokens` used                                                                                                                                                                                                                                         |
| `inputToken`   | `address` | Token that started the swap. The native token (BERA) is `0x0000000000000000000000000000000000000000`                                                                                                                                                                 |
| `amountOut`    | `uint256` | Actual amountOut transferred after potential fees                                                                                                                                                                                                                    |
| `outputToken`  | `address` | Token that returned from the swap. The native token (BERA) is `0x0000000000000000000000000000000000000000`                                                                                                                                                           |
| `slippage`     | `int256`  | The difference between the expected `outputQuote` and actual `amountOut` returned (`slippage = amountOut - outputQuote`). When `< 0` means **negative slippage** (swap returned less than expected) and > 0 **positive slippage** (swap returned more than expected) |
| `referralCode` | `uint32`  | Used to identify the source of the swap                                                                                                                                                                                                                              |

## Errors

These are the errors that can occur:

| Selector     | Signature                                        | Description                                                                                                |
| ------------ | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
| `0x71c4efed` | `SlippageExceeded(uint256,uint256)`              | `amountOut` resulted lower than `outputMin` during swap execution                                          |
| `0xfa463c69` | `SameTokenInAndOut(address)`                     | Cannot provide same `inputToken` and `outputToken`                                                         |
| `0x6da58071` | `MinimumOutputGreaterThanQuote(uint256,uint256)` | `outputMin` is set greater than `outputQuote`                                                              |
| `0xf067d762` | `MinimumOutputIsZero()`                          | `outputMin` is set to 0                                                                                    |
| `0xdb4d141c` | `NativeDepositValueMismatch(uint256,uint256)`    | `value` provided to function call does not match `amountIn` provided when `inputToken` is the native token |
| `0x9996b315` | `AddressEmptyCode(address)`                      | Calling a contract that has no bytecode                                                                    |
| `0xcd786059` | `AddressInsufficientBalance(address)`            | Attempting to send native token with insufficient balance                                                  |
| `0xd93c0665` | `EnforcedPause()`                                | Function can only be called when the contract is unpaused                                                  |
| `0x8dfc202b` | `ExpectedPause()`                                | Function can only be called when the contract is paused                                                    |
| `0x1425ea42` | `FailedInnerCall()`                              | A call to an address target failed. The target may have reverted.                                          |
| `0x79feaaea` | `InvalidNativeTransfer()`                        | Native token transfer has failed                                                                           |
| `0x5274afe7` | `SafeERC20FailedOperation(address)`              | An operation with an ERC-20 token failed.                                                                  |

## ABI

Finally, this is the ABI for `OBRouter`:

```
[
  {
    "type": "constructor",
    "inputs": [
      {
        "name": "_owner",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "type": "receive",
    "stateMutability": "payable"
  },
  {
    "type": "function",
    "name": "FEE_DENOM",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "REFERRAL_WITH_FEE_THRESHOLD",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "owner",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "pause",
    "inputs": [],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "paused",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "referralLookup",
    "inputs": [
      {
        "name": "",
        "type": "uint32",
        "internalType": "uint32"
      }
    ],
    "outputs": [
      {
        "name": "referralFee",
        "type": "uint64",
        "internalType": "uint64"
      },
      {
        "name": "beneficiary",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "registered",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "registerReferralCode",
    "inputs": [
      {
        "name": "_referralCode",
        "type": "uint32",
        "internalType": "uint32"
      },
      {
        "name": "_referralFee",
        "type": "uint64",
        "internalType": "uint64"
      },
      {
        "name": "_beneficiary",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "renounceOwnership",
    "inputs": [],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "swap",
    "inputs": [
      {
        "name": "tokenInfo",
        "type": "tuple",
        "internalType": "struct IOBRouter.swapTokenInfo",
        "components": [
          {
            "name": "inputToken",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "inputAmount",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "outputToken",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "outputQuote",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "outputMin",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "outputReceiver",
            "type": "address",
            "internalType": "address"
          }
        ]
      },
      {
        "name": "pathDefinition",
        "type": "bytes",
        "internalType": "bytes"
      },
      {
        "name": "executor",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "referralCode",
        "type": "uint32",
        "internalType": "uint32"
      }
    ],
    "outputs": [
      {
        "name": "amountOut",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "payable"
  },
  {
    "type": "function",
    "name": "swapERC20Permit",
    "inputs": [
      {
        "name": "permit",
        "type": "tuple",
        "internalType": "struct IOBRouter.erc20PermitInfo",
        "components": [
          {
            "name": "value",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "deadline",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "v",
            "type": "uint8",
            "internalType": "uint8"
          },
          {
            "name": "r",
            "type": "bytes32",
            "internalType": "bytes32"
          },
          {
            "name": "s",
            "type": "bytes32",
            "internalType": "bytes32"
          }
        ]
      },
      {
        "name": "tokenInfo",
        "type": "tuple",
        "internalType": "struct IOBRouter.swapTokenInfo",
        "components": [
          {
            "name": "inputToken",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "inputAmount",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "outputToken",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "outputQuote",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "outputMin",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "outputReceiver",
            "type": "address",
            "internalType": "address"
          }
        ]
      },
      {
        "name": "pathDefinition",
        "type": "bytes",
        "internalType": "bytes"
      },
      {
        "name": "executor",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "referralCode",
        "type": "uint32",
        "internalType": "uint32"
      }
    ],
    "outputs": [
      {
        "name": "amountOut",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "swapPermit2",
    "inputs": [
      {
        "name": "permit2",
        "type": "tuple",
        "internalType": "struct IOBRouter.permit2Info",
        "components": [
          {
            "name": "contractAddress",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "nonce",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "deadline",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "signature",
            "type": "bytes",
            "internalType": "bytes"
          }
        ]
      },
      {
        "name": "tokenInfo",
        "type": "tuple",
        "internalType": "struct IOBRouter.swapTokenInfo",
        "components": [
          {
            "name": "inputToken",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "inputAmount",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "outputToken",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "outputQuote",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "outputMin",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "outputReceiver",
            "type": "address",
            "internalType": "address"
          }
        ]
      },
      {
        "name": "pathDefinition",
        "type": "bytes",
        "internalType": "bytes"
      },
      {
        "name": "executor",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "referralCode",
        "type": "uint32",
        "internalType": "uint32"
      }
    ],
    "outputs": [
      {
        "name": "amountOut",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "transferOwnership",
    "inputs": [
      {
        "name": "newOwner",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "transferRouterFunds",
    "inputs": [
      {
        "name": "tokens",
        "type": "address[]",
        "internalType": "address[]"
      },
      {
        "name": "amounts",
        "type": "uint256[]",
        "internalType": "uint256[]"
      },
      {
        "name": "dest",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "unpaused",
    "inputs": [],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "type": "event",
    "name": "OwnershipTransferred",
    "inputs": [
      {
        "name": "previousOwner",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "newOwner",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "Paused",
    "inputs": [
      {
        "name": "account",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "Swap",
    "inputs": [
      {
        "name": "sender",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "inputAmount",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "inputToken",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "amountOut",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "outputToken",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "slippage",
        "type": "int256",
        "indexed": false,
        "internalType": "int256"
      },
      {
        "name": "referralCode",
        "type": "uint32",
        "indexed": false,
        "internalType": "uint32"
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "Unpaused",
    "inputs": [
      {
        "name": "account",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "type": "error",
    "name": "AddressEmptyCode",
    "inputs": [
      {
        "name": "target",
        "type": "address",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "error",
    "name": "AddressInsufficientBalance",
    "inputs": [
      {
        "name": "account",
        "type": "address",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "error",
    "name": "EnforcedPause",
    "inputs": []
  },
  {
    "type": "error",
    "name": "ExpectedPause",
    "inputs": []
  },
  {
    "type": "error",
    "name": "FailedInnerCall",
    "inputs": []
  },
  {
    "type": "error",
    "name": "FeeTooHigh",
    "inputs": [
      {
        "name": "fee",
        "type": "uint64",
        "internalType": "uint64"
      }
    ]
  },
  {
    "type": "error",
    "name": "InvalidFeeForCode",
    "inputs": [
      {
        "name": "fee",
        "type": "uint64",
        "internalType": "uint64"
      }
    ]
  },
  {
    "type": "error",
    "name": "InvalidNativeTransfer",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidRouterFundsTransfer",
    "inputs": []
  },
  {
    "type": "error",
    "name": "MinimumOutputGreaterThanQuote",
    "inputs": [
      {
        "name": "outputMin",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "outputQuote",
        "type": "uint256",
        "internalType": "uint256"
      }
    ]
  },
  {
    "type": "error",
    "name": "MinimumOutputIsZero",
    "inputs": []
  },
  {
    "type": "error",
    "name": "NativeDepositValueMismatch",
    "inputs": [
      {
        "name": "expected",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "received",
        "type": "uint256",
        "internalType": "uint256"
      }
    ]
  },
  {
    "type": "error",
    "name": "NullBeneficiary",
    "inputs": []
  },
  {
    "type": "error",
    "name": "OwnableInvalidOwner",
    "inputs": [
      {
        "name": "owner",
        "type": "address",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "error",
    "name": "OwnableUnauthorizedAccount",
    "inputs": [
      {
        "name": "account",
        "type": "address",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "error",
    "name": "ReferralCodeInUse",
    "inputs": [
      {
        "name": "referralCode",
        "type": "uint32",
        "internalType": "uint32"
      }
    ]
  },
  {
    "type": "error",
    "name": "SafeERC20FailedOperation",
    "inputs": [
      {
        "name": "token",
        "type": "address",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "error",
    "name": "SameTokenInAndOut",
    "inputs": [
      {
        "name": "token",
        "type": "address",
        "internalType": "address"
      }
    ]
  },
  {
    "type": "error",
    "name": "SlippageExceeded",
    "inputs": [
      {
        "name": "amountOut",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "outputMin",
        "type": "uint256",
        "internalType": "uint256"
      }
    ]
  }
]
```


# Token

Berachain (80094) Deployments

{% tabs %}
{% tab title="OOGA" %}
[0x009af46df68db0e76bfe9ea35663f6ed17877956](https://berascan.com/address/0x009af46df68db0e76bfe9ea35663f6ed17877956)
{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="bOOGA" %}
[0xFa663E26B34EC3A45f5e1d3484CFBF3cF10f42af](https://berascan.com/address/0xFa663E26B34EC3A45f5e1d3484CFBF3cF10f42af)
{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="OogaRewards (DEPRECATED)" %}
[0x74289002D52e767B7528B82450ba56dC6Aa37fcd](https://berascan.com/address/0x74289002d52e767b7528b82450ba56dc6aa37fcd)
{% endtab %}
{% endtabs %}


# Ooga Bucks

All Ooga Bucks related deployments are deployed on Arbitrum One Mainnet.

{% tabs %}
{% tab title="OOGABUCK" %}
[0xbbe52eb5e079cd2e9b31ffd21d677cf24f7cb925](https://arbiscan.io/token/0xbbe52eb5e079cd2e9b31ffd21d677cf24f7cb925)
{% endtab %}

{% tab title="OogaBuckConverter" %}
[0x93412Da46AbfC6C09D87870DFab81Cb993372304](https://arbiscan.io/address/0x93412Da46AbfC6C09D87870DFab81Cb993372304)
{% endtab %}

{% tab title="OogaBuckDistributer" %}
[0xb4911232b9594fceda7f01a0dbc6ffb3d252f6c4](https://arbiscan.io/address/0xb4911232b9594fceda7f01a0dbc6ffb3d252f6c4)
{% endtab %}
{% endtabs %}


# Benefits

TWAP is particularly useful for executing large orders without causing significant market impact. By splitting an order into smaller parts and executing them over time, traders can aim to achieve a price close to the TWAP, potentially reducing trading costs. The service offers a strategic, automated approach based on predefined intervals.

TWAP enables users to trade over a set time frame. The time frame is customizable, allowing flexibility for various trading strategies. Execution is powered by Brahma.


# Architecture

To understand how TWAP automation operates, it’s important to first examine how Brahma accounts function under the hood. For a full technical breakdown, refer to the official Brahma documentation: [https://docs.brahma.fi](<https://docs.brahma.fi&#xA;>)

Brahma Accounts are at the core of all automated actions within TWAP. These accounts are unique smart contracts derived from a user’s primary EOA wallet, enabling secure asset management and automated execution.

#### Execution&#x20;

TWAP uses Brahma to allow users to define and automate complex execution logic. It enables trades to be split across multiple orders over a chosen time frame, with customizable parameters such as duration, number of splits, and slippage thresholds. Once configured, these actions can be executed autonomously without further user interaction.

This system is fully self-custodial. Assets remain in the user’s Safe Account throughout the entire automation process and no funds are ever deposited into contracts controlled by Brahma.

#### Safe Smart Accounts

A Safe Smart Account is a programmable smart contract wallet that replaces traditional seed-based EOAs with enhanced security features. These include multi-sig support and transaction guards. For each TWAP automation, a dedicated Safe is created and tied to the specific execution. This Safe manages all trade logic and execution parameters without user intervention.

Users grant permission to a dedicated Automation SubAccount, owned by their Safe, to carry out the trades. This SubAccount handles the input token, executes the predefined swap route, and returns the output token to the primary Safe. Brahma handles these executions under the hood, batching multi-step logic into a single transaction where possible.

#### Balance Requirements

Users must maintain a sufficient balance of the chosen input token within their Brahma wallet to complete the entire value of the TWAP execution.

#### Supported Tokens

The native gas asset of BERA is not supported as and input token due to limitations in the multi-call process. Any other ERC20 token is supported, as long as a valid swap route exists. Tokens can be added by name search or contract address.

#### Automation Initiation

TWAP automation is initiated through a single signed multicall transaction, which handles the following:

* **SubAccount Configuration**:\
  For new users, a dedicated Automation SubAccount is created—a Safe owned by the user’s main Brahma Safe, restricted by a custom policy tied to the automation parameters. Existing users reuse their current SubAccount for new automations.
* **Token Approval and Authorization**:\
  On-chain approval is granted to the SubAccount, allowing it to manage the input token, perform the swap, and return the output in one atomic transaction.

#### Routing Through Ooga Booga

All TWAP trades are executed through Ooga Booga.


# Miscellaneous

**Funds Access:**\
Users maintain full control over their assets throughout the process. TWAPs can be cancelled at any time before completion, allowing users to withdraw unexecuted funds back to their wallet.

**Backend Infrastructure:**\
All infrastructure, including Safe deployment, strategy execution, and transaction management, is handled by Brahma behind the scenes.

**Withdrawals Without TWAP Setup:**\
If funds are deposited into the console account but a TWAP is not created, users can withdraw those funds at any time via the withdraw button on the UI. Alternatively, these console accounts can also be accessed at <https://console.brahma.fi/>

**Slippage Configuration:**\
Users can define a slippage threshold to guide execution. If a trade fails at the specified slippage, Brahma will retry by gradually increasing the threshold until the execution succeeds.&#x20;

**Risk Management:**\
If a TWAP fails, Brahma will automatically return the remaining funds to the user's externally owned account from the Safe. There is no risk of funds becoming stuck. Users can also manually withdraw any available balance from their console account at any time.

**Execution Fees:**

* **Automation Setup Fee:** Setting up a TWAP will incur a one-time gas fee when creating a new Automation SubAccount. This cost is paid directly to the blockchain and not charged by Brahma.
* **Per Trade Fee:** Fees are applied on each individual trade, not the total order. For example, if each trade executes 3 HONEY to USDC, the effective amount per interval will be 3 HONEY minus the trade fee.

**Residual Fund Sweeps:**\
At the end of a TWAP, any remaining input tokens left in the user's Brahma Safe will be automatically refunded. Brahma performs a final sweep transaction to send unused funds back to the wallet. This refund will always be in the original input asset and may show up as an additional transaction following the final trade.


# Trade Execution Logic and Retry Behavior

When executing TWAP orders, Brahma uses a structured approach to maximize the chances of successful execution while staying within user-defined parameters. Below is a breakdown of how trade execution and retries are handled:

**Slippage Handling and Retry Mechanism**

When a TWAP order is triggered, Brahma attempts execution using the following process:

1. **Initial Quote & Simulation (Try 1):**
   * Brahma begins by attempting execution using a slippage **lower than** the user-defined maximum, if possible.
   * The service progressively increases slippage through a preset ladder (e.g. 0.05%, 0.10%, 0.50%, up to the user-defined max).
   * At each step, it fetches a quote, simulates the trade, and checks if the quote would succeed.
   * Once a working quote is found within the defined slippage, it is submitted on-chain.
2. **Fallback Attempt (Try 2):**
   * If the first transaction fails *after* submission (i.e. the quote was valid during simulation but reverted during mining), a second attempt is made.
   * This second attempt uses the **user-defined maximum slippage** directly without incremental steps.
   * A new quote is fetched, simulated, and submitted for execution.
3. **Failure Condition:**
   * If the second attempt also fails (either in simulation or after submission), the order is marked as failed and no further retries are made.
   * If simulation fails even at the user-defined maximum slippage, no transaction is submitted and the order is marked as failed.

> **Important:** For Try 2 to trigger, the transaction must revert *after* passing the simulation step but *before* or during mining. This is rare and typically occurs only when slippage is extremely tight.

**Timing and Interval Execution**

* The **first order** in the TWAP sequence is executed immediately after setup.
* Subsequent orders are scheduled at fixed intervals, based on the time of the initial execution.
* For example, with a 1-minute interval:
  * Order 1 executes at time `T`
  * Order 2 is scheduled for `T + 1m`
  * Order 3 is scheduled for `T + 2m`, and so on
* While Brahma aims to initiate execution exactly at the scheduled interval, the **actual on-chain transaction** may land slightly after the target time due to retries or network delay.


# Frontrunning Considerations and Parameter Confidentiality

TWAP strategies, especially when executed on fixed, predictable intervals (e.g. every 1 minute), can be vulnerable to frontrunning or anticipatory trading—particularly in illiquid markets. An external observer monitoring the chain might attempt to front-run a known pattern by entering positions shortly before the TWAP executes and exiting afterward.

**What Can Be Seen On-Chain**

When a TWAP executes, each transaction is broadcast and mined like any other on-chain action. This means:

* Observers **can see** the transaction payload (e.g. token pair, amount, swap route, and timestamp)
* Observers **cannot see** the full scope of the automation (e.g. how long it will run or how many intervals are left)

**What Remains Private**

Critical parameters such as:

* **Total duration**
* **Number of total orders**
* **Interval between trades**
* **Randomization logic (if enabled)**\
  are **not stored on-chain**, nor embedded in any public contract.

Instead, these parameters are kept **off-chain in Brahma’s backend database**, and are linked to each user’s TWAP via a **Policy Hash**, which is used to match and execute the automation. This policy hash is not the transaction hash—it is a backend identifier tied to the user's specific automation settings.

Because these settings aren’t on-chain, an external observer cannot know whether a trade is the first, last, or one of many in a series—**unless the user shares this information publicly**.

**Randomization as a Future Mitigation (v1.1)**

Randomization of execution—such as:

* Varying the time interval between trades slightly
* Varying the size of each order
* Introducing controlled jitter to execution timing

...is the **most effective defense** against predictable execution patterns and frontrunning. These features are currently in development for v1.1 and would obscure predictable trade behavior even further, making it materially harder for adversaries to anticipate execution schedules.

> **Note:** This level of protection is not present in many on-chain TWAP systems, including those used by major providers like Jupiter.

**Practical Takeaway**

While the current system ensures that **key parameters remain private**, users should still understand that **predictability of execution timing** can be a vector for frontrunning—especially in thin markets. Until randomization is deployed, users are advised to:

* Avoid using TWAP for extremely large orders on low-liquidity assets with exact intervals
* Break up orders across broader timeframes
* Monitor impact manually or combine with other execution strategies where necessary


