Skip to content

Instantly share code, notes, and snippets.

@jordaniza
Created September 16, 2025 10:00
Show Gist options
  • Select an option

  • Save jordaniza/3b568a09b3651ccbb4b9b0152f78760d to your computer and use it in GitHub Desktop.

Select an option

Save jordaniza/3b568a09b3651ccbb4b9b0152f78760d to your computer and use it in GitHub Desktop.
Taikodrome Bonding Contract Specification

Specification: Bonding.sol

1. Overview

Bonding.sol is the core smart contract responsible for bootstrapping the Taikodrome economy. Its primary function is to facilitate the one-way conversion of the native $TAIKO token into max-locked veTD governance positions.

The contract is designed to create a powerful incentive for early, large-scale participation by offering significant, competitive discounts. It also serves as the primary mechanism for accumulating Protocol-Owned Liquidity (POL), which will be used to establish deep liquidity for the foundational $TAIKO/$TD pair on the Taikodrome DEX.


2. Core Mechanics

The contract's logic is built around three primary functions: the user-facing bonding process, a dynamic pricing engine, and administrative treasury management.

2.1. The Bonding Process

The user experience is designed to be seamless. A user approves the Bonding.sol contract to spend their $TAIKO and calls a single function, bond(). The contract then handles the entire process atomically:

  1. It calculates the amount of $TD the user is entitled to based on the dynamic pricing engine.
  2. It pulls the required $TAIKO from the user.
  3. It mints the corresponding amount of $TD.
  4. It automatically deposits this new $TD into the VotingEscrow.sol contract on behalf of the user, creating a max-locked veTD NFT.
  5. The veTD NFT is minted directly to the user's wallet.

2.2. Pricing Engine

The amount of $TD minted for a given amount of $TAIKO is determined by a multi-factor pricing formula. This ensures both security and powerful incentives.

a. Base Price Calculation

The base conversion rate between $TAIKO and $TD is determined by one of two phases:

  • Bootstrap Phase: At launch, a 1:1 exchange rate is used. This is necessary because no on-chain market exists yet. This phase is controlled by a boolean flag, isBootstrapPhase.
  • Market Phase: Once the bootstrap phase is manually concluded by the admin, the contract switches to using the on-chain price from the Taikodrome $TAIKO/$TD AMM pool. Crucially, this must be a Time-Weighted Average Price (TWAP) to prevent flash loan manipulation.

b. Discount Calculation

Two discounts are applied to the base price to incentivize participation:

  1. Illiquidity Discount: This is a fixed (but potentially adjustable) percentage discount that compensates all users for locking their assets for the max lock. It acknowledges the premium of liquid assets over illiquid ones.
  2. Early Adopter Discount: This is a competitive, dynamic discount that creates a race to bond. The discount is an inverse function of the tokenId from VotingEscrow.sol. The first bonder (tokenId #1) receives the highest possible bonus discount, which then decays with each subsequent bond until a predefined cap (MAX_EARLY_BIRD_BONDS) is reached. This creates maximum urgency and rewards the earliest and most committed participants.

2.3. Protocol-Owned Liquidity (POL) Management

All $TAIKO tokens accepted by the contract are stored in its own balance, effectively removing them from circulating supply. These funds are designated to become POL.

  • Discretionary Control: An admin or DAO address has the exclusive right to call a deployPol() function.
  • Supply Management: This function allows the admin to specify both the amount of $TAIKO to use and the amount of $TD to mint for pairing. This provides the DAO with discretionary control over the $TD monetary supply, which is a critical safety lever in the early stages of the economy.

3. Contract Interface (IBonding.sol)

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title IBonding
 * @notice Interface for the Taikodrome bonding contract, which handles the conversion
 * of TAIKO into max-locked veTD positions.
 */
interface IBonding {
  // --- Events ---

  /**
   * @notice Emitted when a user successfully bonds TAIKO for veTD.
   * @param user The address of the user who initiated the bond.
   * @param taikoAmount The amount of TAIKO bonded.
   * @param tdAmount The amount of TD minted and locked.
   * @param tokenId The ID of the resulting veTD NFT.
   */
  event Bonded(
    address indexed user,
    uint256 taikoAmount,
    uint256 tdAmount,
    uint256 indexed tokenId
  );

  /**
   * @notice Emitted when the treasury deploys Protocol-Owned Liquidity.
   * @param admin The address that initiated the deployment.
   * @param taikoAmount The amount of TAIKO used from the treasury.
   * @param tdAmount The amount of TD minted and paired.
   */
  event PolDeployed(
    address indexed admin,
    uint256 taikoAmount,
    uint256 tdAmount
  );

  // --- User-facing Functions ---

  /**
   * @notice Bonds a specified amount of TAIKO tokens in exchange for a new,
   * 1-year max-locked veTD NFT.
   * @dev User must first approve this contract to spend their TAIKO.
   * @param _taikoAmount The amount of TAIKO to bond.
   * @return tokenId The ID of the newly created veTD NFT.
   */
  function bond(uint256 _taikoAmount) external returns (uint256 tokenId);

  /**
   * @notice A view function to quote the expected amount of TD to be minted for a
   * given amount of TAIKO, based on the current state.
   * @dev This is an estimate, as the early adopter discount can change based on transaction ordering.
   * @param _taikoAmount The amount of TAIKO to quote for.
   * @return tdAmount The estimated amount of TD that will be minted and locked.
   */
  function quoteBond(
    uint256 _taikoAmount
  ) external view returns (uint256 tdAmount);

  // --- Admin Functions ---

  /**
   * @notice Deploys a specified amount of the contract's TAIKO balance and newly minted
   * TD as Protocol-Owned Liquidity on the Taikodrome DEX.
   * @dev Can only be called by the contract owner/admin.
   * @param _taikoAmountToUse The amount of TAIKO from the treasury to use for liquidity.
   * @param _tdAmountToMint The amount of new TD to mint for pairing.
   */
  function deployPol(
    uint256 _taikoAmountToUse,
    uint256 _tdAmountToMint
  ) external;

  /**
   * @notice Sets the bootstrap phase state. When true, a 1:1 price is used.
   * When false, the AMM TWAP price is used.
   * @dev Can only be called by the contract owner/admin. Should only be called once.
   * @param _isBootstrap The new state of the bootstrap phase.
   */
  function setBootstrapPhase(bool _isBootstrap) external;

  /**
   * @notice Updates the illiquidity discount percentage.
   * @dev Can only be called by the contract owner/admin.
   * @param _newDiscountBps The new discount in basis points (e.g., 500 for 5%).
   */
  function setIlliquidityDiscount(uint256 _newDiscountBps) external;
}

4. Pseudocode for Core Pricing Logic

The following pseudocode illustrates the core logic within the bond() function for determining the final $TD mint quantity.

// This is PSEUDOCODE to illustrate the pricing logic.

function getTdMintQty(uint256 _taikoAmount) internal returns (uint256) {
  // 1. Determine Base Price in TAIKO per TD
  uint256 basePriceTaikoPerTd;
  if (isBootstrapPhase) {
    basePriceTaikoPerTd = 1e18; // 1:1
  } else {
    basePriceTaikoPerTd = taikodromeOracle.fetchTwapPrice(TAIKO, TD);
  }

  // 2. Calculate Total Discount
  // Start with the fixed illiquidity discount
  uint256 totalDiscountBps = illiquidityDiscountBps;

  // Add the competitive early adopter bonus
  uint256 nextTokenId = IVotingEscrow(escrow).tokenId() + 1;
  if (nextTokenId <= MAX_EARLY_BIRD_BONDS) {
    totalDiscountBps += getEarlyBirdDiscount(nextTokenId);
  }

  // 3. Apply Discount to Price
  // Note: To apply a discount, we reduce the TAIKO cost per TD
  uint256 finalPriceTaikoPerTd = (basePriceTaikoPerTd *
    (10000 - totalDiscountBps)) / 10000;

  // 4. Calculate Final TD Amount
  // The amount of TD the user gets is their TAIKO divided by the final price
  uint256 tdAmount = (_taikoAmount * 1e18) / finalPriceTaikoPerTd;

  return tdAmount;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment