№ V · Particulars
The technical sheet.
Written against the contracts as they stand today, before deployment. Every constant below is a value in the source; every parameter marked at deployment is a value chosen by the deploy script and settable thereafter only within the limits stated.
System
Five contracts, no proxiesNothing here is upgradeable. There is no proxy, no implementation pointer, and no delegatecall to code that could be swapped later. The addresses that need to know about each other are wired exactly once, at deployment, by an address that becomes unable to wire anything again the moment it has.
| Contract | Responsibility |
|---|---|
| RentToken | $RENT itself. ERC-20 with permit and vote checkpoints. Fixed supply minted once in the constructor; no mint path afterwards. Accepts a burn instruction from the hook, applied only to the hook's own balance. |
| RentHook | The Uniswap v4 hook. Holds the lease state, charges rent, splits it, returns the active fee to the pool on every swap, and redeems the three shares. |
| RentStaking | Single-asset vault: stake $RENT, earn the staker share of rent. Funded only by the hook, which can only add. |
| RentGovernor | Snapshot voting over three bounded parameters. The only address the hook accepts those changes from. |
| RentLauncher | The only address permitted to bring the pool into existence, and it does so seeded, in one transaction. One-shot. |
The hook
Two hook points · beforeInitialize, beforeSwapThe hook subscribes to two v4 callbacks and no others. It takes no share of any swap: it returns no swap delta, and it never mints, takes or settles a currency on the swap path.
beforeInitialize refuses every caller except the launcher,
and refuses any pool key that is not the canonical ETH/RENT dynamic-fee
pool at tick spacing 200. It can succeed once.
beforeSwap settles any rent that has accrued since the last
time the lease was touched, then returns the currently active fee as a
dynamic-fee override — the leaseholder's fee if there is one, the
default if the board is vacant.
// lease bid(uint256 rentPerBlock, uint256 deposit) take or retain the board deposit(uint256 amount) top up, holder only setFee(uint24 fee) holder only, within the band pokeRent() anyone: settle a quiet pool withdrawRefund() collect an escrowed refund // redemption — anyone may call distributeToLPs() donate the LP share into the pool distributeToStakers() push the staker share to the vault burnAccrued() burn the burn share // views currentFee() manager() rentPerBlock() managerDeposit() pendingRent() isVacant() lpBucket() stakerBucket() burnBucket()
Rent accounting
Lazy accrual · exact splitRent owed is rentPerBlock × (current block − last settled block). Settlement happens inside whatever transaction next touches the lease, and the settled-to block always advances to the current block, so an arbitrarily long quiet period is charged exactly once and never twice.
If the amount owed is at least the whole remaining deposit, the whole deposit is charged and the lease ends with nothing to return. Otherwise the amount owed is charged, and if what is left cannot cover one more block the lease ends and the remainder is returned.
The charged amount is divided into three balances. The staker and burn shares are computed by basis points; the liquidity share is the remainder, which is what makes the identity exact: the three balances always sum to precisely what was charged, with no dust left unassigned and nothing over-credited.
Refunds owed to a leaseholder are attempted as a direct transfer and, if that transfer does not succeed for any reason, credited to them to withdraw later. This is deliberate: it means a refund can never be the thing that reverts a swap or blocks a takeover.
Staking vault
Single asset · no lock-up · no ownerstake(uint256 amount) unstake(uint256 amount) claim() pending(address user)
Rewards are tracked with an accumulator over total staked, which is the standard shape for this: crediting is O(1) per distribution regardless of how many stakers there are, and each staker's entitlement is computed from the accumulator's movement since they last touched it. Rounding always leaves dust in the vault rather than promising more than it holds.
A distribution that arrives while nobody is staked is held aside and folded into the next one. Someone who stakes after a distribution receives no part of it.
Governor
Snapshot · quorum · re-clamped on arrivalproposeFeeBand(uint24 minFee, uint24 maxFee, uint24 defaultFee) proposeSplit(uint16 lpBps, uint16 stakerBps) proposeMinOutbid(uint16 outbidBps) vote(uint256 id, bool support) execute(uint256 id)
A proposal records a snapshot timepoint strictly earlier than the block it was created in, and every vote is weighed at that timepoint. A balance that did not exist at the snapshot has no weight, which is what makes a borrowed balance useless here.
Execution is possible only after the window closes, only once, only if the votes in favour reach the quorum measured against the supply at the snapshot, and only if there are more for than against. The hook then re-checks every value against its own fixed limits before storing it, so a governor that passed something out of range would simply be rejected.
Changing the fee band also re-clamps a sitting leaseholder's fee into the new band, so a band change cannot leave an out-of-band fee live.
Launch
One transaction, seededThe pool is created by the launcher and by nothing else. In a single transaction it initialises the pool at the chosen price and mints the initial liquidity position, so there is no moment at which the pool exists unseeded or at a price somebody else chose. Any attempt to initialise the canonical pool from any other caller is rejected by the hook.
The board is vacant at the first block. Until somebody bids, the pool charges the default fee.
Constants and parameters
Fixed in code vs. chosen at deployment| Value | Setting |
|---|---|
| Lowest fee the pool can ever charge | 0.01 % |
| Highest fee the pool can ever charge | 3.00 % |
| Liquidity share floor | 50 % |
| Burn share ceiling | 20 % |
| Outbid increment ceiling | 50 % |
| Total supply | 1 000 000 000 |
| Pool tick spacing | 200 |
| Parameter | At deployment |
|---|---|
| Fee band, low | 0.01 % |
| Fee band, high | 3.00 % |
| Default fee when vacant | 0.30 % |
| Rent share — liquidity providers | 70 % |
| Rent share — stakers | 25 % |
| Rent share — burn | 5 % |
| Minimum outbid increment | 5 % |
| Governor voting window | 3 days |
| Governor quorum | 4 % of supply |
Trust and limits
The things worth knowing before you decide anything- The liquidity share is paid in $RENT, on one side. It is donated to the pool and accrues like a fee, but it is not a balanced payout, and an LP whose range is not covering the current price at the moment of a donation receives no part of that donation.
- A donation needs liquidity in range. If there is none at that instant the share waits in the hook rather than being paid. It is not lost, but it is not paid either until somebody calls again with liquidity in range.
- A well-funded holder can sit at the top of the band. Nothing stops a leaseholder with deep pockets from setting the fee to 3.00 % and continuing to pay for it. They are paying rent to the pool the entire time, and anyone may outbid them at any block, but they cannot be forced out for free.
- The initial liquidity position is an NFT held by the deploying address. It is not locked by a contract and not burned.
- Rent volume is unknown. All three shares are shares of a quantity nobody can size in advance. The contracts fix the proportions, not the amount.
- External dependencies. The pool relies on Uniswap v4's PoolManager and PositionManager. A defect there is a defect here.
Status
As of this page- Mainnet contracts
- not deployed
- Contract address
- does not exist yet
- Pool
- not initialised
- Test suite
- 101 tests passing
- Independent external audit
- none
- Token sale
- none — there is no sale
The test suite covers the auction arithmetic, the exactness of the rent split under randomised sequences, the lapse and takeover paths, the vault's accounting, the governor's snapshot behaviour, and the pool behaviour against a fork of live Uniswap v4. That is internal work by the people who wrote it. It is not an audit, and this page does not claim it is one.