A Fare is a voluntary offer on a dead token: the payer deposits a budget, commits a Roll, and sets the rules under which holders who burn their bags are paid.
Parameters#
| Parameter | Meaning |
|---|---|
target | The dead token holders burn. Must be dead per the oracle when the Fare opens. |
payoutToken | What holders are paid in: any ERC-20, or WHYPE. Cannot be the target. |
budget | Gross budget, fee included. Pulled from the payer at opening. |
snapshotBlock | The Elysium block of the Roll. |
snapshotTime | The timestamp of snapshotBlock. Must be in the past. The Roll check compares it with the real block timestamp. |
maxRate | At most this many payout units per 1e18 wei (1 HYPE) of loss. |
maxLossPerWallet | Cap on the loss counted for one wallet, in wei. |
window | How long holders can cross, after the dispute period. |
vesting | How long each payout is streamed after settlement. |
stay | Enables the Stay clause. |
rollURI | How to rebuild the Roll, for example danake:roll:v1:minAge=0. |
rollRoot | The Merkle root of the Roll, passed next to the parameters. Must not be zero. |
Contract time is measured with block.timestamp only. On Elysium, block.number inside Solidity returns the parent chain's block, not the Elysium block, so it is never used for logic.
Paying in HYPE#
A payer can fund a WHYPE Fare in native HYPE: send budget as the transaction value with payoutToken set to WHYPE, and the market wraps it. Any other payout token is pulled with transferFrom after an approval. Tokens that take a fee on transfer are refused, because the market must receive exactly the budget.
Fee#
FEE_BPS = 300: 3% of the budget goes to the FeeVault at opening. The rest is the net budget, the amount shared between holders. The vault has no owner and no withdrawal function. On testnet the fees stay there; they are meant to buy $DANAKE once it exists (see $DANAKE token). The fee only leaves the vault if the payer cancels during the dispute period, in which case it returns to the payer.
Lifecycle#
| Status | When | What can happen |
|---|---|---|
| Pending | From opening until the dispute period ends | Anyone checks the Roll. The payer may cancel() and get the whole budget back, fee included. |
| Open | During the window | Holders cross(). |
| Ended | After the window, before settlement | Anyone may settle(). |
| Settled | From settlement until the end of vesting | Holders claim(). The payer withdraws surplus. |
| Closed | After vesting | Everything has vested. Claims and withdrawals still work. |
| Cancelled | After a cancel during Pending | Nothing. The budget is back with the payer. |
Durations#
| Duration | Mainnet target | Testnet value |
|---|---|---|
| Dead after (no trade, or 95% below ATH) | 7d | 10m 0s |
| Dispute period (Pending) | 1d | 2m 0s |
| Minimum window (Open) | 3d | 10m 0s |
| Maximum window | 30d | 30d |
| Minimum vesting | Set per deployment | 5m 0s |
The testnet values are shortened so the whole loop fits in under an hour. They are constructor parameters of the deployed contracts, so mainnet uses its own values without code changes.
Settlement math#
Settlement is callable by anyone once the window is over.
netBudget = budget − floor(budget × 300 / 10,000)
rate = min(maxRate, floor(netBudget × 1e18 / totalCountedLoss))
allocated = floor(totalCountedLoss × rate / 1e18)
surplus = netBudget − allocated
payout_i = floor(countedLoss_i × rate / 1e18)
The rate is the same for every wallet. Each wallet's payout is its counted loss times the rate. Because each payout is floored, the sum of payouts can be a few units below allocated; that dust stays in the market, at most one unit per wallet.
Two cases:
- Budget-limited. If the budget is small compared with the losses,
netBudget × 1e18 / totalCountedLossis belowmaxRate, so the whole net budget is shared pro rata. - Rate-limited. If the budget is large, the rate stops at
maxRate. Each wallet getsmaxRateper HYPE lost and the rest of the budget is surplus.
Example: budget 1,000,000 $LIVE, so the net budget is 970,000. Max rate 5,000 $LIVE per HYPE.
- If holders cross with 300 HYPE of counted loss:
970,000 / 300 ≈ 3,233.33is below 5,000, so the rate is about 3,233.33 and nearly all of the 970,000 is allocated. - If holders cross with 150 HYPE:
970,000 / 150 ≈ 6,466.67is above 5,000, so the rate is 5,000, 750,000 is allocated and 220,000 is surplus.
If nobody crossed, the rate is 0 and the whole net budget is surplus.
Surplus#
The surplus, plus any stream forfeited under the Stay clause, returns to the payer through withdrawSurplus(). Only the payer can call it, as often as new forfeits arrive.
Cancellation#
During Pending, and only then, the payer can cancel(). The net budget and the fee both return to the payer. Nobody can cross a Pending Fare, so nobody has burned anything yet. This is how a payer withdraws an offer whose Roll was challenged.
Estimating a payout before crossing#
previewRate(fareId, extraLoss) returns the rate the Fare would settle at now, if extraLoss more counted loss were added. The app uses it to show "estimated payout". It changes until settlement, as more holders cross.