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
      • Auto-BGT
    • 🐼Panda Factory
  • 🪙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
    • 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
    • 💰Pricing with Subgraph
    • 💱Quotes
    • Backend
  • 🛡️SECURITY
    • 🔍Audits
  • ℹ️Informational
    • 📜Terms of Use
    • 🔏Privacy Policy
    • TradingView Advanced License
Powered by GitBook
On this page
  • Overview
  • 1. Usage with existing/Deployed Islands
  • 2. Deploying new Islands
  1. Developers
  2. Kodiak Islands

Technical Integration Guide

Smart contract integration guide and examples

Overview

Kodiak Islands are concentrated liquidity management vaults built on top of Kodiak V3 pools. This guide covers the technical aspects of integrating with Kodiak Islands from a smart contract perspective.

1. Usage with existing/Deployed Islands

What can be achieved

  1. Depositing into existing Islands

  2. Withdrawing from existing Islands

  3. Checking current island position

  4. Checking current fee earned

  5. Calling rebalance to invest any pending fees

Prerequisites

Before integrating with Kodiak Islands, you should understand:

  1. Kodiak V3 concentrated liquidity concepts

  2. ERC20 token standards and approvals

  3. Basic understanding of what's slippage and slippage protection mechanisms

  4. Deployed contract addresses

  5. Understanding of token ratio that is needed to deposit tokens into the island.

  6. Finding the correct deposit params for double sided token deposits.

  7. Finding the correct deposit and swap params for single sided token deposits.

Core Contracts

The main contracts involved for integration with existing islands are:

  1. Island Router Contract: Handles complex operations like zaps and slippage protection

  2. Island Contract: The actual vault contract managing the Kodiak V3 position

Integration Examples

1. Basic Position Information

interface IKodiakIsland {
    function getUnderlyingBalances() external view returns (uint256 amount0Current, uint256 amount1Current);
    function token0() external view returns (IERC20);
    function token1() external view returns (IERC20);
    function pool() external view returns (IUniswapV3Pool);
    function lowerTick() external view returns (int24);
    function upperTick() external view returns (int24);
}

2. Depositing with Both Tokens

interface IKodiakIslandRouter {
    function addLiquidity(
        IKodiakIsland island,
        uint256 amount0Max,
        uint256 amount1Max,
        uint256 amount0Min,
        uint256 amount1Min,
        uint256 amountSharesMin,
        address receiver
    ) external returns (uint256 amount0, uint256 amount1, uint256 mintAmount);
}

contract IslandDepositor {
    IKodiakIslandRouter public immutable router;
    
    constructor(address _router) {
        router = IKodiakIslandRouter(_router);
    }
    
    function deposit(
        IKodiakIsland island,
        uint256 amount0,
        uint256 amount1,
        uint256 slippageBPS,
        uint minShares
    ) external returns (uint256 mintAmount) {
        // Transfer tokens to this contract
        IERC20(island.token0()).transferFrom(msg.sender, address(this), amount0);
        IERC20(island.token1()).transferFrom(msg.sender, address(this), amount1);
        
        // Approve router
        IERC20(island.token0()).approve(address(router), amount0);
        IERC20(island.token1()).approve(address(router), amount1);
        
        // Calculate minimum amounts with slippage
        uint256 amount0Min = amount0 * (10000 - slippageBPS) / 10000;
        uint256 amount1Min = amount1 * (10000 - slippageBPS) / 10000;
        
        // Add liquidity
        (,, mintAmount) = router.addLiquidity(
            island,
            amount0,
            amount1,
            amount0Min,
            amount1Min,
            minShares, // Min shares, can be calculated based on simulation before calling this
            msg.sender
        );
    }
}

3. Single Token Deposits (Zaps)

For single token deposits, the swap calldata needs to be prepared off-chain using the Kodiak Quoter API. The process involves:

  1. Getting the optimal swap amount using the formula:

// Pseudo-code for swap amount calculation
function calculateSwapAmount(
    uint256 totalAmount,
    uint256 price,
    uint256 ratio0,
    uint256 ratio1
) pure returns (uint256) {
    // If depositing token0
    return (ratio1 * totalAmount * 1e18) / (ratio0 * price + (ratio1 * 1e18));
    
    // If depositing token1
    // return (ratio0 * totalAmount * 1e18) / (ratio1 * price + ratio0 * 1e18);
}
  1. Implementing the deposit:

interface IKodiakIslandRouter {
    struct RouterSwapParams {
        bool zeroForOne;
        uint256 amountIn;
        uint256 minAmountOut;
        bytes routeData;
    }
    
    function addLiquiditySingle(
        IKodiakIsland island,
        uint256 totalAmountIn,
        uint256 amountSharesMin,
        uint256 maxStakingSlippageBPS,
        RouterSwapParams calldata swapData,
        address receiver
    ) external returns (uint256 amount0, uint256 amount1, uint256 mintAmount);
}

contract IslandZapper {
    IKodiakIslandRouter public immutable router;
    
    constructor(address _router) {
        router = IKodiakIslandRouter(_router);
    }
    
    function zapIn(
        IKodiakIsland island,
        uint256 amountIn,
        RouterSwapParams calldata swapData,
        uint256 slippageBPS,
        uint256 minShares
    ) external returns (uint256 mintAmount) {
        // Transfer input token
        IERC20 inputToken = swapData.zeroForOne ? island.token0() : island.token1();
        inputToken.transferFrom(msg.sender, address(this), amountIn);
        
        // Approve router
        inputToken.approve(address(router), amountIn);
        
        // Execute zap
        (,, mintAmount) = router.addLiquiditySingle(
            island,
            amountIn,
            minShares, // Min shares, should be calculated based on simulation
            slippageBPS, // This ensures the target pool's price does not move dramatically before your deposit goes through
            swapData,
            msg.sender
        );
    }
}

4. Withdrawing Liquidity

interface IKodiakIslandRouter {
    function removeLiquidity(
        IKodiakIsland island,
        uint256 burnAmount,
        uint256 amount0Min,
        uint256 amount1Min,
        address receiver
    ) external returns (uint256 amount0, uint256 amount1, uint128 liquidityBurned);
}

contract IslandWithdrawer {
    IKodiakIslandRouter public immutable router;
    
    constructor(address _router) {
        router = IKodiakIslandRouter(_router);
    }
    
    function withdraw(
        IKodiakIsland island,
        uint256 burnAmount,
        uint256 slippageBPS
    ) external returns (uint256 amount0, uint256 amount1) {
        // Get expected amounts
        (uint256 expectedAmount0, uint256 expectedAmount1) = island.getUnderlyingBalances();
        expectedAmount0 = expectedAmount0 * burnAmount / island.totalSupply();
        expectedAmount1 = expectedAmount1 * burnAmount / island.totalSupply();
        
        // Calculate minimum amounts with slippage
        uint256 amount0Min = expectedAmount0 * (10000 - slippageBPS) / 10000;
        uint256 amount1Min = expectedAmount1 * (10000 - slippageBPS) / 10000;
        
        // Transfer LP tokens and approve router
        IERC20(address(island)).transferFrom(msg.sender, address(this), burnAmount);
        IERC20(address(island)).approve(address(router), burnAmount);
        
        // Remove liquidity
        (amount0, amount1,) = router.removeLiquidity(
            island,
            burnAmount,
            amount0Min,
            amount1Min,
            msg.sender
        );
    }
}

5. Rebalancing and Fee Collection

contract IslandRebalancer {
    function rebalanceIsland(IKodiakIsland island) external {
        // Anyone can call rebalance to reinvest fees
        island.rebalance();
    }
    
    function collectManagerFees(IKodiakIsland island) external {
        // Only manager can collect fees
        require(island.manager() == msg.sender, "Not manager");
        island.withdrawManagerBalance();
    }
}

2. Deploying new Islands

What can be achieved

  1. Deploying new managed Islands

  2. Deploying new Permissionless Islands

  3. Enabling mint for everyone for deployed Islands

  4. Managing deployed Island parameters and position

  5. Collecting Fees

  6. Giving up ownership of deployed Islands

Prerequisites

Before deploying new Islands, you should understand:

  1. Kodiak V3 concentrated liquidity concepts

  2. Openzeppelin Minimal Proxy Contracts

  3. Island management parameters and fee structures

Core Contracts

The main contracts involved in deployment are:

  1. Island Factory Contract: Creates new Island instances

  2. Island Implementation Contract: The base contract that gets cloned

Deployment Examples

1. Deploying a Managed Island

interface IKodiakIslandFactory {
    function deployVault(
        address tokenA,
        address tokenB,
        uint24 uniFee,
        address manager,
        address managerTreasury,
        uint16 managerFee,
        int24 lowerTick,
        int24 upperTick
    ) external returns (address island);
}

contract IslandDeployer {
    IKodiakIslandFactory public immutable factory;
    
    constructor(address _factory) {
        factory = IKodiakIslandFactory(_factory);
    }
    
    function deployManagedIsland(
        address tokenA,
        address tokenB,
        uint24 uniFee,
        address manager,
        address treasury,
        uint16 managerFeeBPS,
        int24 lowerTick,
        int24 upperTick
    ) external returns (address) {
        // Validate parameters
        require(manager != address(0), "Invalid manager"); // this is address zero for permissionless islands only
        require(treasury != address(0), "Invalid treasury"); // You need to set a treasury for managed islands to collect fees
        require(managerFeeBPS <= 10000, "Invalid fee"); // Manager fee cannot exceed 10000 BPS (100%)
        
        // Deploy island
        return factory.deployVault(
            tokenA,
            tokenB,
            uniFee,
            manager,
            treasury,
            managerFeeBPS,
            lowerTick,
            upperTick
        );
    }
}

2. Deploying a Permissionless Island

contract PermissionlessIslandDeployer {
    IKodiakIslandFactory public immutable factory;
    
    constructor(address _factory) {
        factory = IKodiakIslandFactory(_factory);
    }
    
    function deployPermissionlessIsland(
        address tokenA,
        address tokenB,
        uint24 uniFee,
        int24 lowerTick,
        int24 upperTick
    ) external returns (address) {
        // For permissionless islands:
        // - manager must be address(0)
        // - treasury must be address(0)
        // - managerFee must be 0
        return factory.deployVault(
            tokenA,
            tokenB,
            uniFee,
            address(0), // No manager
            address(0), // No treasury
            0, // No manager fee
            lowerTick,
            upperTick
        );
    }
}

Important Notes

  1. Tick Spacing: Ensure ticks align with pool's tick spacing otherwise an error will be thrown

  2. Token Ordering: Factory handles token ordering internally

  3. Fee Limits: Manager fees cannot exceed 10000 BPS (100%)

  4. Permissionless vs Managed: Understand the differences in parameters to deploy managed vs permissionless islands

  5. Enabling Minting: You need to enable minting for everyone for managed islands

  6. Rebalance: You need to call rebalance on the island for compounding earned fee back into the position.

  7. Permissionless Islands Frontend listing: You need to contact the Kodiak team to get your permissionless island listed on the kodiak frontend.

Security Considerations

  1. Always use the router for deposits/withdrawals to ensure proper slippage protection

  2. Validate all parameters before deployment

  3. Test with small amounts first

  4. Be cautious with manager permissions, use islands only from trusted managers.

  5. Implement proper access control in integrating contracts

  6. Monitor gas costs, especially for operations involving swaps

PreviousKodiak IslandsNextUnderstanding Token Deposit Ratio

Last updated 3 months ago

Refer the section on for in dept guide.

Using the Kodiak Quoter API to get the swap calldata (refer to the

👨‍💻
🌴
Understanding Token Deposit Ratio
Kodiak API Documentation)