Refund System
A curve that does not reach full supply within the bonding period can be wound down. Holders reclaim the native asset pro-rata; the remainder is swept to the protocol after a fixed claim window.
Opening refund mode
initiate_refund() is permissionless and requires:
- 259,200 s (3 days) elapsed since curve initialization
- The curve has neither graduated nor already entered refund mode
- A non-zero balance and at least one eligible lot above the floor
- The curve is not the protocol curve —
FLAG_PROTOCOLrejects it
It takes 10% of collected fees for the protocol, then fixes the payout rate:
eligible_lots = current_supply_lots - INITIAL_SUPPLY_LOTS
protocol_share = fees_collected / 10 → creditProtocolBalance()
refund_per_lot = balance / eligible_lots // after the protocol share leaves
refund_per_lot is computed once and stored. It does not move as claims are made, so the first and last claimant receive the same rate per lot.
Claiming
Holders call refund_claim(lots) within 604,800 s (7 days) of refund mode opening. The call burns the tokens and pays lots × refund_per_lot.
| Rule | Detail |
|---|---|
| Window | 604,800 s (7 days) from initiate_refund() |
| Minimum | 1 lot |
| Deployer | Excluded — cannot claim |
| Eligibility | By live token balance, not by purchase history |
| Partial claims | Allowed — claim any number of lots you hold |
There is no per-address record of who bought what. Eligibility is checked against the current balance, so refund rights transfer with the tokens — which is what makes the curve's storage-free design possible in the first place.
Query the deadline with refund_claim_deadline(), which returns the unix timestamp after which claiming closes, or 0 if the curve is not in refund mode.
Sweeping
After the window closes, anyone may call sweep_unclaimed_refunds(). It moves the entire remaining balance to protocolBalance and sets FLAG_SWEPT, a terminal state that can only be reached once.
assert FLAG_REFUND_MODE set
assert FLAG_SWEPT not set
assert block.timestamp >= refund_initiated_timestamp + REFUND_CLAIM_PERIOD
→ flags |= FLAG_SWEPT
→ raw_call(HOOK, "creditProtocolBalance()", value=remaining)
Unclaimed refunds are forfeited to the protocol after 604,800 s (7 days). There is no extension, no recovery path and no discretion. Integrations displaying a refundable position should surface the deadline prominently.
State after refund
Refund mode is permanent. buy() and sell() both reject FLAG_REFUND_MODE, the token never graduates, transfers stay locked, and no DEX pool is ever created. The token's totalSupply falls as claims burn tokens, and whatever remains unclaimed stays outstanding but worthless against the curve.