Kodiak Finance
  • OVERVIEW
    • 🐻‍❄️Introducing Kodiak
    • 🐻Kodiak x Berachain
    • ✉️Contact Us
    • 🍯Kodiak Contracts
  • 🅱️Kodiak-Boyco
  • PROTOCOL
    • 🔃DEX
      • Swaps
      • Liquidity Provision
      • Trading Fees
    • 🏝️Islands
      • Island Liquidity Provision
      • Sweetened Islands
      • Island Mechanics
        • Auto-BGT
        • Real-time Security
        • Rebalancing
        • Strategies
    • 🐼Panda Factory
    • 💱Baults
      • Bault analytics
  • 🪙Tokenomics
    • Kodiak Pre-TGE Rewards
  • 🧠User Guide
    • Launch a Token Launch on Panda Factory
    • Trading on Panda Factory
    • Swap
    • Create a V2 Position
    • Create a V3 Position
    • Add/Stake Islands Liquidity
    • Baults (Auto-Compound)
    • Migrating to a Reward Vault
    • Deploying new Permissonless Islands
    • Deploying and Configuring a Kodiak Farm
    • Add your token
  • Add Your Project to the Ecosystem
  • 👨‍💻Developers
    • 🐼Panda
      • Technical Integration Guide
      • Subgraph
        • Entity Reference
        • Query Guide
        • Advanced Usage Guide
      • Smart Contract Reference
        • Panda Factory
        • Panda Pool
        • Panda Token
      • Api
    • Farms
      • Technical Integration Guide
      • Smart Contract Reference
    • 🌴Kodiak Islands
      • Technical Integration Guide
        • Understanding Token Deposit Ratio
      • Subgraph
        • Entity Reference
        • Query Guide
        • Advanced Usage Guide
      • Smart Contract Reference
        • Kodiak Island Factory
        • Kodiak Island
        • Kodiak Island Router
      • Api
    • 💱Compounding Baults
    • 💰Pricing with Subgraph
    • 💱Quotes
    • Backend
  • 🛡️SECURITY
    • 🔍Audits
    • Page
  • ℹ️Informational
    • 📜Terms of Use
    • 🔏Privacy Policy
    • TradingView Advanced License
Powered by GitBook
On this page
  • Bault API
  • Bault Compounding Guide
  • How Compounding Works
  • The Bounty Mechanism
  • Cost-Effective Compounding
  • Previewing Potential Claims
  • Performing Compounding
  • Compounding Algorithm Overview using the BountyHelper
  • Step 1: Check if Bault is Ready to Compound
  • Step 2: Check Profitability
  • Step 3: Execute Compound Transaction
  • Key Points
  1. Developers

Compounding Baults

PreviousApiNextPricing with Subgraph

Last updated 4 days ago

Bault API

Get a list of all the Baults, their TVL and APY here:

Bault Compounding Guide

This guide explains how compounding works in Baults, including the BGT auction mechanism, optimal usage patterns, and integration with the BountyHelper contract which is designed to make compounding free and effectively available for anyone to call.

How Compounding Works

Baults are ERC4626-compliant vaults that stake tokens in reward vaults to earn BGT rewards. Over time, these BGT rewards accumulate but remain unclaimed in the reward vault. Compounding is the process of claiming these BGT rewards and either:

  1. Receiving them directly as BGT tokens

  2. Converting them to wrapped BGT tokens (like iBGT, yBGT, LBGT etc.)

The Bounty Mechanism

Baults use a bounty-based auction system that:

  1. Allows anyone to trigger the compounding process

  2. Requires the caller to provide the configured "bounty" in bault asset (the staking tokens)

  3. Gives the caller all the accumulated BGT rewards as either BGT or wrappedBGT of choice.

How the Bounty System Works

  1. The caller pays a fixed amount of staking tokens (the bounty)

  2. A small portion of the bounty (set by compoundFeeBps) goes to the protocol treasury

  3. The rest of the bounty is staked in the reward vault, benefiting all vault users effectively increasing the share price for each user.

  4. The caller receives all accumulated BGT rewards or a wrapped version

This creates a market-driven incentive for compounding - when the value of unclaimed BGT exceeds the bounty cost, someone will claim it.

This is a significant improvement over traditional compounding methods where the rewards are claimed and swapped for the asset, which can lead to slippage and loss of value while compounding. Additionally the swap system requires gatekeeping the compounding process and integration of swap routers for effective and secured compounding which limits the flexibility and accessibility of the compounding process. The bounty system allows anyone to compound and benefit from the compounding process while also giving the bault users maximal compounding value.

Cost-Effective Compounding

With the introduction of the bounty system, you can benefit from the compounding process and claim the rewards. To compound cost-effectively:

  1. Monitor BGT accrual: Wait until enough BGT has accumulated to justify the bounty cost

  2. Calculate break-even point: Compare the value of claimable BGT against the bounty cost

  3. Choose the right wrapper: Different wrappers have different valuations for BGT and are generally a better choice against BGT itself. So find the best wrapper that maximizes the value of the BGT rewards.

  4. Executing Claims: Once the breakeven point has been reached, execute the claim transaction to receive the rewards as soon as possible to benefit from any excess rewards that accumulate.

Remember you are racing against other bots for the bounty, so act quickly while keeping a minimal profit margin to claim the rewards before someone else does.

Previewing Potential Claims

Before executing a compound transaction, you can preview the expected outcome:

// Preview the amount of BGT that would be claimed
uint256 bgtAmount = bault.earned();

// Preview the amount of wrapped BGT tokens that would be minted
uint256 wrappedAmount = bault.previewClaimBgtWrapper(wrapperAddress);
import { createPublicClient, http } from 'viem';
import { berachain } from 'viem/chains';
import { BAULT_ABI } from './abis'; // Import your ABI

const client = createPublicClient({
  chain: berachain,
  transport: http()
});

// Preview the amount of BGT that would be claimed
const earnedBgt = await client.readContract({
  address: baultAddress,
  abi: BAULT_ABI,
  functionName: 'earned',
});

// Preview the amount of wrapped BGT tokens that would be minted
const wrappedAmount = await client.readContract({
  address: baultAddress,
  abi: BAULT_ABI,
  functionName: 'previewClaimBgtWrapper',
  args: [wrapperAddress],
});

const client = createPublicClient({
  chain: berachain,
  transport: http()
});

// Preview the amount of BGT that would be claimed
const earnedBgt = await client.readContract({
  address: baultAddress,
  abi: BAULT_ABI,
  functionName: 'earned',
});

// Preview the amount of wrapped BGT tokens that would be minted
const wrappedAmount = await client.readContract({
  address: baultAddress,
  abi: BAULT_ABI,
  functionName: 'previewClaimBgtWrapper',
  args: [wrapperAddress],
});

Performing Compounding

Always correctly set the minAmountOut after previewing to ensure you do not get frontrun.

Direct BGT Claim

// Simple TypeScript with Viem - Direct BGT claim
import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { berachain } from 'viem/chains';
import { BAULT_ABI, ERC20_ABI } from './abis';

// Setup account and client
const account = privateKeyToAccount(PRIVATE_KEY);
const client = createWalletClient({
  account,
  chain: berachain,
  transport: http()
});

// Basic claim process
async function claimBgt(baultAddress) {
  // 1. Get staking token and bounty
  const stakingToken = await client.readContract({
    address: baultAddress,
    abi: BAULT_ABI,
    functionName: 'stakingToken',
  });

  const bounty = await client.readContract({
    address: baultAddress,
    abi: BAULT_ABI,
    functionName: 'bounty',
  });

  // 2. Approve the bounty transfer
  await client.writeContract({
    address: stakingToken,
    abi: ERC20_ABI,
    functionName: 'approve',
    args: [baultAddress, bounty],
  });
  
  // 3. Preview the amount of BGT that would be claimed
  // and make sure you pass it in as minAmountOut while claiming
  // to avoid getting frontrun
  const minAmountOut = await client.readContract({
    address: baultAddress,
    abi: BAULT_ABI,
    functionName: 'earned',
  });

  // 4. Execute the claim
  await client.writeContract({
    address: baultAddress,
    abi: BAULT_ABI,
    functionName: 'claimBgt',
    args: [account.address, minAmountOut],
  });
}

Wrapped BGT Claim (iBGT, LBGT, yBGT)

// Simple TypeScript with Viem - Claim wrapped BGT
import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { berachain } from 'viem/chains';
import { BAULT_ABI, ERC20_ABI } from './abis';

// Setup account and client
const account = privateKeyToAccount(PRIVATE_KEY);
const client = createWalletClient({
  account,
  chain: berachain,
  transport: http()
});

// Function to claim wrapped BGT tokens
async function claimWrappedBgt(baultAddress, wrapperAddress) {
  // 1. Get required data from the bault
  const stakingToken = await client.readContract({
    address: baultAddress,
    abi: BAULT_ABI,
    functionName: 'stakingToken',
  });

  const bounty = await client.readContract({
    address: baultAddress,
    abi: BAULT_ABI,
    functionName: 'bounty',
  });

  // 2. Preview expected amount of wrapper tokens
  const minAmountOut = await client.readContract({
    address: baultAddress,
    abi: BAULT_ABI,
    functionName: 'previewClaimBgtWrapper',
    args: [wrapperAddress],
  });

  // 3. Approve and claim
  await client.writeContract({
    address: stakingToken,
    abi: ERC20_ABI,
    functionName: 'approve',
    args: [baultAddress, bounty],
  });

  const amountMinted = await client.writeContract({
    address: baultAddress,
    abi: BAULT_ABI,
    functionName: 'claimBgtWrapper',
    args: [wrapperAddress, account.address, minAmountOut],
  });

  return amountMinted;
}

BountyHelper: Zero-Capital Compounding (Recommended)

The BountyHelper is a specialized contract that enables anyone to compound Baults without needing the bounty payment upfront. It uses a clever mechanism to make compounding easy and accessible for everyone without need of the bounty.

How BountyHelper Works

  1. Pre-funding mechanism: The helper maintains a balance of staking tokens that can be used for bounties

  2. Swap integration: When using bounty helper, the claimed wrappers must be swapped for the staking token to return the bounty amount back to the contract. You can use any contract that can swap/exchange the bgtWrapper for the underlying staking token. We recommend using the Enso Router for swapping directly from the liquid wrapper to the underlying staking token.

  3. Refund system: Returns any excess tokens to the caller after returning the free bounty amount accessed by the compounder and additionally rewards the compounder by transferring any amount of remaining staking token/bgt wrapper back to the user.

Compounding Algorithm Overview using the BountyHelper

The compounding process follows these key steps:

  1. Discovery: Find baults that are ready to compound

  2. Wrapper Selection: Determine the best BGT wrapper (iBGT, YBGT, LBGT) for maximum value

  3. Quote Generation: Get swap quote to convert wrapper to underlying staking token

  4. Profitability Check: Ensure the swap output covers the required bounty

  5. Execution: Send the compound transaction via BountyHelper

Step 1: Check if Bault is Ready to Compound

import { createPublicClient, http, getContract, parseAbi } from "viem";

const BAULT_ABI = parseAbi([
  "function bounty() external view returns (uint256)",
  "function earned() external view returns (uint256)",
  "function previewClaimBgtWrapper(address wrapper) external view returns (uint256)"
]);

async function checkBault(baultAddress: string) {
  const bault = getContract({
    address: baultAddress,
    abi: BAULT_ABI,
    client: publicClient
  });

  // Get current bounty requirement
  const bounty = await bault.read.bounty();

  // Get earned BGT available to claim
  const earnedBGT = await bault.read.earned();

  // Preview how much wrapper we'd get (using iBGT as example)
  const wrapperAmount = await bault.read.previewClaimBgtWrapper([wrapperOfChoice]); // ibgt for example

  console.log(`Bounty required: ${bounty}`);
  console.log(`BGT earned: ${earnedBGT}`);
  console.log(`Wrapper amount: ${wrapperAmount}`);

  return { bounty, earnedBGT, wrapperAmount };
}

Step 2: Check Profitability

async function isProfitable(baultAddress: string) {
  const { bounty, wrapperAmount } = await checkBault(baultAddress);

  // Get staking token address
    const stakingToken = await client.readContract({
      address: baultAddress,
      abi: BAULT_ABI,
      functionName: 'stakingToken',
    });

  // Get swap quote: wrapper -> staking token (enso router preffered)
  const quote = await getSwapQuote(
    iBGT_ADDRESS,
    stakingToken,
    wrapperAmount.toString()
  );

  // Check if swap output covers the bounty
  const isReady = BigInt(quote.amountOut) >= bounty;

  console.log(`Swap will give us: ${quote.amountOut}`);
  console.log(`Bounty required: ${bounty}`);
  console.log(`Ready to compound: ${isReady}`);

  return { isReady, quote };
}

// Helper function for getting swap quotes in desired format
async function getSwapQuote(fromToken: string, toToken: string, amount: string) {
  // This is where you'd integrate with:
  // - Enso Router (recommended)
  // - Your custom routing functions.
  // - Any other swap router
  // Your goal is to swap/exchange the claimed bgt wrapper into the underlying staking token (Kodiak island tokens)

  const quote = await fetch('/api/swap-quote', {
    method: 'POST',
    body: JSON.stringify({
      fromToken,    // iBGT address
      toToken,      // Staking token address
      amount,       // Wrapper amount to swap
      slippage: 500 // 5%
    })
  });

  return await quote.json(); // { amountOut, calldata, to }
}

Step 3: Execute Compound Transaction

const BOUNTY_HELPER_ABI = parseAbi([
  `function claimBgtWrapper(
    address bault,
    address bgtWrapper,
    address swapTarget,
    bytes calldata swapData,
    uint256 wrapperAmount,
    address bountyReceiver
  ) external`
]);

async function compoundBault(baultAddress: string) {
  // Get all the data we need
  const { wrapperAmount } = await checkBault(baultAddress);
  const { quote, isProfitable } = await isProfitable(baultAddress);

  const BOUNTY_HELPER_ADDRESS = "0x..."; // BountyHelper contract
  const PROFIT_RECEIVER = "0x..."; // Any address that should get the excess bgt claimed/staking token left after repaying bounty

  // Execute the compound transaction
  const txHash = await walletClient.writeContract({
    address: BOUNTY_HELPER_ADDRESS,
    abi: BOUNTY_HELPER_ABI,
    functionName: 'claimBgtWrapper',
    args: [
      baultAddress,        // Which bault to compound
      iBGT_ADDRESS,        // BGT wrapper to use
      quote.to,            // Swap router address
      quote.calldata,      // Swap transaction data
      wrapperAmount,       // Amount of wrapper to claim
      PROFIT_RECEIVER         // Where to send the bounty profit
    ]
  });

  console.log(`Compound transaction sent: ${txHash}`);
  return txHash;
}

Key Points

What You Need

  • A wallet with some BERA for gas

  • Access to a swap router (Enso recommended).

    • Get your enso api key here (https://shortcuts.enso.finance/developers)

    • Look at how to use the api here (https://docs.enso.build/api-reference/defi-shortcuts/optimal-route-between-two-tokens)

  • RPC endpoint for Berachain (https://rpc.kodiak.finance)

How You Profit

  • You earn the excess bounty (mostly in staking tokens) for each successful compound

  • No upfront capital required - BountyHelper funds the bounty

  • Profit = stakingTokenSwapOutput - baultBounty

BGT Wrappers

Choose the best wrapper for maximum value:

  • iBGT: Infrared liquid staking token

  • YBGT: Yeet liquid staking token

  • LBGT: Another liquid staking option

When to Compound

  • stakingTokenSwapOutput >= baultBounty (profitable)

  • Gas costs(generally dust) < expected profit

This simple flow shows how anyone can participate in bault compounding and earn rewards by helping optimize DeFi yields!

👨‍💻
💱
https://backend.kodiak.finance/baults