FREEZE
freeze(tokenId)
Put a coin in the vault. It leaves your wallet and the vault opens a position against its id.
Rule: Starts at 1.00×. The vault needs setApprovalForAll first, or a plain safeTransferFrom straight in.
A coin that stays still earns. A coin that moves pays.
Freeze a coin in the vault and it starts collecting a share of every fee the project takes in. The longer it sits untouched, the colder it gets and the bigger its share. Pull it out early and you leave heat behind — half of it burned, half handed to everyone still frozen. Melt two coins into one and the supply drops for good.
Everything the vault does, and the exact rule attached to each one.
freeze(tokenId)
Put a coin in the vault. It leaves your wallet and the vault opens a position against its id.
Rule: Starts at 1.00×. The vault needs setApprovalForAll first, or a plain safeTransferFrom straight in.
chill(tokenId)
Promote a position into the tier its age has already earned.
Rule: Nothing promotes itself. Anyone may call it, for any coin — it can only ever help the owner.
fund(amount)
Pay rewards into the vault. Royalties, trading fees and treasury top-ups all come in here.
Rule: Split by weight at the instant it lands. No retroactive drip, and nothing frozen means it waits in carry.
claim(tokenId)
Take the rewards and leave the coin where it is.
Rule: The clock does not reset. Temperature keeps climbing as if you had never touched it.
thaw(tokenId)
Take the coin back out.
Rule: Seven days or more is a clean exit. Under seven days, 50% of the pending rewards are forfeited — the coin itself is never at risk.
melt(keepId, burnId)
Burn one frozen coin to make another one permanently stronger.
Rule: +0.25× each, four melts maximum, both coins yours and both frozen. The burned coin's rewards are paid out first.
handoff(tokenId, to)
Give a whole frozen position to someone else in one transaction.
Rule: The temperature, the melt bonus and the unclaimed rewards all travel with it. Nothing resets, nothing is lost.
Drag the slider. The tier, the multiplier and the size of the slice all move with it.
30DAYS
NOW: FROZEN · 1.50×
60 more days until this position can be chilled into ABSOLUTE ZERO at 2.00×.
SAME DEPOSIT, SAME MOMENT
ROOM TEMP · 1.00×
100 units
THIS POSITION · 1.50×
150 units
Out of one deposit this position takes 50% more than a room-temp coin. Same pot, bigger slice — the extra comes out of everyone else's.
The clock is frozenAt and it never resets while the coin stays frozen. Claiming does not reset it. Melting into it does not reset it. Nothing promotes itself either: someone has to call chill() — and anyone may, for any coin.
A permanent trade: one coin's existence for another coin's weight. The only thing that moves the supply.
TOTAL WEIGHT
2.50×
ABSOLUTE ZERO is 2.00×. 2 melts add 0.50× on top — 0.25× each, permanently.
Costs 2 coins, burned for good. 3 coins in, 1 coin out.
Both coins must be frozen and both must be yours. The burned coin's unclaimed rewards are paid out to you first — the coin is destroyed, the rewards it already earned are not.
9,000LIVE
1,000 coins gone, 9,000 still on the chain. MELT is the only thing that moves this number, and it only moves one way.
The cap stays 10,000 whatever happens here. totalMinted is an id counter that never decreases, so a burn can never free up a mint slot — it just means fewer coins exist.
The vault is fee-agnostic. One reward asset, one entry point, and anyone may pay into it.
Change any weight and watch the other two move. That is the entire mechanic.
ONE DEPOSIT LANDS
1,000UNITS

WEIGHT 2.50×
52.6%
526 units

WEIGHT 1.25×
26.3%
263 units

WEIGHT 1.00×
21.1%
211 units
TOTAL WEIGHT: 4.75×
This is a share of fees, not a rate. Nothing here pays a percentage of anything — raise one position's weight and its slice grows by taking the growth off the other two. The pot is whatever came in.
A position frozen after a deposit landed gets none of it. There is no retroactive drip, and the rounding dust stays in the accumulator to go out with the next one.
THE ACCOUNTING
totalWeight = Σ weight of every frozen position accPerWeight += amount × 1e18 / totalWeight on every fund() position.pending = weight × accPerWeight / 1e18 − rewardDebt
Whenever a weight changes — a tier promotion, a melt — the position's pending amount is banked first, then the weight moves, then its debt is recomputed against the current accumulator. The invariant totalWeight == Σ weights holds at the end of every single call. No function loops over positions, so a deposit costs the same whether one coin is frozen or 10,000.
The part we would rather you read twice.
Not audited. The vault is written defensively, it is tested and it has been reasoned about — but no third party has reviewed it. Do not put meaningful money through it until one has.
Not an APR. There is no fixed rate here, no emission schedule and no reward token minted out of thin air. The vault only ever pays out what the project actually earned. A quiet month is a quiet month.
Risk: Re-entrancy through the reward transfer or the NFT callback
Guard: nonReentrant on every state-changing external function, checks-effects-interactions throughout, payouts last.
Risk: A fee-on-transfer or rebasing reward token breaking the books
Guard: The credited amount is the balance actually received, never the amount argument.
Risk: Someone thawing a coin that is not theirs
Guard: Every position stores its owner. thaw, claim, melt and handoff all check it.
Risk: The collection being swapped underneath the vault
Guard: collection and rewardToken are immutable. They are set once, at deploy.
Risk: An admin draining the vault
Guard: There is no admin withdrawal of the reward asset. rescueERC721 only reaches a different NFT sent in by mistake, and can never touch a frozen coin.
Risk: A deposit landing when nothing is frozen
Guard: Held in carry and folded into the next deposit that has someone to pay.
Risk: Division by zero when the total weight is zero
Guard: Explicitly branched before every division.
Risk: Precision loss draining dust over time
Guard: Remainders stay in the accumulator and go out with the next deposit.
Two additions to the collection make all of this possible, both from OpenZeppelin and both in before any deployment: ERC-721 Enumerable, so a wallet's coins can be listed without calling ownerOf 10,000 times, and ERC-721 Burnable, so a melt is a real burn that lowers the live supply instead of a transfer to a dead address that leaves the count untouched.