disconnected
docs/protocol/bonding-curve

Bonding Curve Mechanics

NAKA uses a single deterministic exponential bonding curve. There is one curve, one mathematical relationship between cumulative ETH input and supply minted, and two equivalent state directions (buy advances, sell retreats). The curve math lives in NakaCurve.sol as a pure library. The hook layers fees, entropy, deprecation and reactivation on top of it.

Formula

  • Marginal (spot) price at virtual cumulative ETH eth:

    p(eth) = (S / K) · e^(eth / S)

  • Cumulative minted supply at virtual cumulative ETH eth:

    minted(eth) = K · (1 − e^(−eth / S))

  • Inverse — virtual ETH required to reach a given supply m:

    eth(m) = −S · ln(1 − m / K) = S · ln(K / (K − m))

With S = 100 and K = 21,000,000 (1e18-scaled internally):

QuantityValue
Initial price p(0)S/K = 100 / 21,000,000 ≈ 4.76 × 10⁻⁶ ETH/token
50% of Kreached at S · ln(2) ≈ 69.3 ETH
95% of Kreached at S · ln(20) ≈ 299.6 ETH
99% of Kreached at S · ln(100) ≈ 460.5 ETH

The 99% point is the deprecation trigger. The 95% point is the reactivation threshold.

Virtual ETH (totalMintedFair)

The hook does not track its real ETH balance as the curve's X axis. Instead it tracks totalMintedFair, a virtual cumulative ETH level that advances only by the fair-curve component of each buy and retreats proportionally on each sell. This decouples the curve from:

  • Direct ETH transfers to the hook (which receive nothing in return).
  • Entropy multipliers in the first 100 blocks, which mint extra tokens but do not move the curve.
  • Rounding drift from the prb-math fixed-point library.

actualEthBalance() (real reserve) and the curve position can therefore differ — the curve's source of truth is supply, not balance.

Buy Path

  1. User submits buyNaka(minTokensOut) on NakaSwapRouter with attached ETH.
  2. The router pre-settles the ETH to the V4 PoolManager and triggers swap.
  3. The hook's beforeSwap runs _executeBuyV4, which:
    • Reverts if selfDeprecated is true (SelfDeprecatedNoBuys).
    • Reverts if ethIn < 1 gwei or ethIn > 5 ETH.
    • Computes fairTokens from the curve at the current totalMintedFair.
    • If still inside the entropy window (first 100 blocks), multiplies mintAmount by a uniformly random factor in [0.9, 1.1] keyed on block.prevrandao + msg.sender + GENESIS_HASH.
    • Splits 0.30% of mintAmount into a DEAD-mint (tokensLocked) and 99.70% into a user-mint (tokensUser).
    • Mints both portions; advances totalMintedFair by fairTokens (NOT by mintAmount).
    • Records lastBuyBlock[tx.origin] = block.number for the cooldown.
    • If circulating ≥ 99% × K, flips selfDeprecated = true and emits SelfDeprecated(circulating).
  4. If tokensOut < minTokensOut, the entire transaction reverts and no state changes.

Sell Path

  1. User approves the router for tokensIn, then calls sellNaka(tokensIn, minEthOut).
  2. The router pre-settles NAKA into the PoolManager and triggers swap.
  3. The hook's beforeSwap runs _executeSellV4, which:
    • Reverts on the per-EOA cooldown (COOLDOWN_BLOCKS = 1) if the same tx.origin bought in the same block.
    • Reverts if tokensIn < 1 gwei or the curve is fully drained (totalMintedFair == 0 or totalSupply() == 0).
    • Converts real tokens to fair-curve units: fairIn = tokensIn × totalMintedFair / totalSupply() (proportional projection — the entropy bonus distributed in early blocks is shared pro-rata across all sellers).
    • Computes ethOutGross from the curve, capped at the actual ETH balance.
    • Burns 0.30% of tokensIn outright (tokensLocked) then mints those to DEAD; burns the remaining 99.70% (tokensRedeem) outright.
    • Decrements totalMintedFair by fairIn.
    • If selfDeprecated was set and circulating now drops below 95% × K, clears the flag and emits Reactivated(circulating, deadBalance) in the same transaction.
  4. ETH is paid back to the PoolManager and forwarded to the user. If ethOut < minEthOut, the whole transaction reverts.

Properties

  • Path-independent on the curve: the relationship between totalMintedFair and minted supply depends only on the current value of totalMintedFair, never on the order of trades that produced it.
  • Proportional sell unwind: selling x real tokens reduces totalMintedFair by x × totalMintedFair / totalSupply(). Early-window entropy bonuses are shared, not isolated to the original recipient.
  • Floor-only-up: every trade burns 0.30% of token-side flow to DEAD. Across cycles this monotonically grows DEAD and shrinks circulating, ratcheting floor = reserve / circulating upward.
  • Cap on simultaneously-circulating supply0.99 × K. Total ever-existing supply has no bound.