BondingCurveTemplate

Manages bonding curve trading, quadratic pricing, graduation trigger, and the refund safety net. Deployed as a minimal proxy per token.

Contract Type

Minimal Proxy (EIP-1167) — one instance per deployed token. Initialized by the Factory.

State Variables

NameTypeDescription
statePackedStatePacked struct: flags, current_supply_lots, deployment_timestamp, fees_collected
refund_per_lotuint256Fixed refund amount per lot (set when refund mode activates)
tokenaddressThe token this curve manages
deployeraddressThe address that deployed this token pair

Write Functions

initialize(_token: address) payable external

Initialize the bonding curve with a token address. Called by the Factory during deployment. msg.value must equal DEPLOYER_INITIAL_PAYMENT (0.0006 ETH / 0.0012 BNB). Sets deployer = tx.origin.

Reverts
  • "Already initialized" — flags ≠ 0
  • "Must send 0.0006 ETH" / "Must send 0.0012 BNB" — wrong value
  • "Invalid token" — zero address
buy(token_lots: uint256) payable nonreentrant

Buy token lots on the bonding curve. Mints token_lots * LOT_SIZE tokens to msg.sender. If this purchase fills the supply to MAX_SUPPLY_LOTS, triggers graduation automatically.

Parameters
NameTypeDescription
token_lotsuint256Number of lots to buy (≥ 1)
Value Required

msg.value must equal exactly the total returned by quote_buy_price(token_lots).

Reverts
  • "Below minimum" — token_lots < 1
  • "Not initialized" / "Invalid state" — wrong lifecycle state
  • "Supply exceeded" — new supply > 800,000
  • "User limit exceeded" — user would hold > 36,000 lots
  • "Incorrect payment" — msg.value ≠ quoted total
Emits

Buy(buyer, lots, eth_sent, base_price, tax)

If graduating: Graduated(token, deployer)

sell(token_lots: uint256) external nonreentrant

Sell token lots back to the curve. Burns the tokens and sends ETH proceeds to msg.sender. Deployer cannot call this function.

Parameters
NameTypeDescription
token_lotsuint256Number of lots to sell (≥ 1)
Reverts
  • "Deployer locked" — msg.sender is deployer
  • "Below minimum" — token_lots < 1
  • "Insufficient tokens" — balance < token_lots * LOT_SIZE
  • "Cannot sell at floor" — supply at INITIAL_SUPPLY_LOTS
  • "Insufficient contract balance" — shouldn't happen normally
Emits

Sell(seller, lots, eth_returned, base_price, tax)

initiate_refund() external

Activate refund mode after the 3-day bonding period expires without graduation. Calculates and locks refund_per_lot. Anyone can call.

Reverts
  • "Period not over" — bonding period hasn't expired
  • "Invalid state" — already graduated or in refund mode
  • "No refunds" — zero balance or no eligible lots
refund_claim(token_lots: uint256) external nonreentrant

Claim ETH refund by burning tokens. Only available in refund mode. Deployer cannot claim.

Parameters
NameTypeDescription
token_lotsuint256Number of lots to refund
Reverts
  • "Not refund mode" — refund not activated
  • "Deployer cannot refund" — msg.sender is deployer
  • "Insufficient tokens" — balance too low
Emits

RefundClaimed(user, lots, eth_received)

View Functions

quote_buy_price(token_lots) → (uint256, uint256, uint256) view

Get the price quote for buying lots. Returns (base, tax, total) where total = base + tax. Use the total as msg.value for buy().

quote_sell_price(token_lots) → (uint256, uint256, uint256) view

Get the price quote for selling lots. Returns (base, tax, proceeds) where proceeds = base - tax.

get_supply_lots() → uint32 view

Current supply in lots (includes deployer's initial 60,000).

get_sales_balance() → uint256 view

ETH balance minus collected fees.

get_fees_collected() → uint80 view

Total accumulated fees in the bonding curve (before graduation split).

is_graduated() → bool view

Whether the curve has graduated (FLAG_GRADUATED is set).

is_refund_mode() → bool view

Whether refund mode is active (FLAG_REFUND_MODE is set).

get_user_token_balance(user) → uint256 view

Returns user's token balance in lots (balanceOf / LOT_SIZE).