Mechanism
Where the ETH comes from,
and what the lever does with it.
The short version is on the front page. This page is the long one:
the accounting, the caps, the exact order of operations inside a pull, and the
places it can fail. Everything below describes code in
PressHook.sol, PressStaking.sol and
PressToken.sol.
01 · Intake — two taps, one pool
Intake: where the ETH comes from
A cut of the ETH leg of buys
The pool is ETH/PRESS. A buy is ETH going in; a sell is ETH coming out. The hook
looks at the direction of the swap and only acts on the first one. On a buy it
keeps feeBps of the ETH the buyer supplied. On a sell it returns a
zero delta and does nothing at all.
Both shapes of buy are covered: an exact-input buy is cut before the swap, where the ETH amount is already known, and an exact-output buy is cut after it, once the ETH actually spent is known.
Anyone can top it up
depositRevenue() is payable and unrestricted, and plain ETH sent to
the hook is credited the same way. Both land in the same pool the lever spends.
There is no separate treasury and no second queue.
The fee is a claim, not a transfer
The cut is minted to the hook as an ERC-6909 claim against the Uniswap PoolManager rather than pulled out as real ETH during the swap. That is deliberate: a swap cannot fail on a transfer that never happens. The claim is only redeemed for real ETH later, inside a pull, where a failure reverts the pull and nothing else.
Diagram of the code path, not of any deployment.
02 · The pull — what print() actually does
One transaction, in this order.
print() takes no arguments and has no access control. Everything it
spends and everything it pays out is derived on chain from the state at the moment
of the call.
The buy happens inside a single poolManager.unlock, so the redemption
of the fee claim, the swap and the settlement are one atomic unit. If any part of
it fails, the whole pull reverts and the ETH stays in the press for the next one.
- 1 · Cooldown
- Reverts if the last pull was too recent
- 2 · Liquidity
- Reverts if the pool holds none
- 3 · Size the order
- spend = min(pooled ETH, cap per pull)
- 4 · Quote the floor
- minOut from spot, less the slippage bound
- 5 · Redeem
- Fee claim → real ETH, inside the unlock
- 6 · Buy
- Exact-input ETH → PRESS, on the open book
- 7 · Check
- Bought < minOut reverts the whole thing
- 8 · Tip
- A slice of the purchase to whoever called
- 9 · Deliver
- The rest to the staking pot, credited pro-rata
03 · Caps and bounds — fixed at construction
Nothing here has a setter.
Every value in the table is either a constant or an
immutable assigned in a constructor. There is no owner function
anywhere in these contracts that changes any of them after deployment, and the
constructor rejects anything outside the hard limit.
The right-hand column is the value the deploy script uses unless the operator overrides it at deployment. Until $PRESS is actually deployed these are intended settings, not facts about a live contract — the hard limits in the middle column are what the code enforces regardless.
| What | In code | Hard limit enforced on chain | Deploy-script default |
|---|---|---|---|
| Cut on the ETH leg of a buy | feeBps | > 0 and ≤ 500 bps (5%) | 200 bps (2%) |
| Tip to whoever pulls the lever | keeperTipBps | ≤ 500 bps (5%) of the PRESS bought | 50 bps (0.5%) |
| Slippage bound on a pull | slippageBps | > 0 and ≤ 5,000 bps | 300 bps (3%) |
| Maximum ETH spent per pull | maxPrintEth | Must be non-zero | 0.5 ETH |
| Minimum gap between pulls | printCooldown | — | 1 hour |
| Lock on staked principal | minStakeLock | Must be ≥ printCooldown, checked when the pot is wired to the hook | 2 hours |
| Total supply | SUPPLY | Constant · 1,000,000,000 PRESS, minted once | — |
| Pool tick spacing | SPACING | Constant · 60 | — |
The cap per pull is the important one. It is what keeps a single pull from being a large enough order to be worth trading around, and it is why the press makes many small buys rather than one big one.
04 · The pot — who gets the sheets
The staking pot
A plain pro-rata book
Stake $PRESS in the pot and your share of every subsequent print is exactly your share of the staked total. No multipliers, no tiers, no lock-length curve, no boost for being early. One accumulator, one debt per address.
Delivery is permissionless too
The pot credits whatever token balance has arrived beyond what it already owes. The hook calls that after a print, but anyone can call it, and tokens simply donated to the pot are credited to stakers the same way. Nothing can be credited twice, because the accounted floor rises with every credit.
The lock
Principal is locked for minStakeLock from your most recent stake —
adding to a position refreshes the lock on the whole position, so every token in
it serves a full period. Claiming rewards is not locked;
only withdrawing principal waits.
The lock is required to be at least as long as the print cooldown, so a stake and a print can never be composed inside one cycle. That constraint is checked on chain when the pot is wired to the hook, not left to configuration.
Worked example
- Staked total
- 1,000,000 PRESS
- Your stake
- 50,000 PRESS · 5%
- A pull buys
- 100,000 PRESS
- Caller's tip at 0.5%
- 500 PRESS
- To the pot
- 99,500 PRESS
- Your credit
- 4,975 PRESS
Arithmetic on invented round numbers, to show the shape of the split. It is not a projection, a yield, or a claim about what any pull will buy — that depends entirely on how much ETH is in the press and what the market price is at the moment of the pull.
05 · Failure modes — when a pull reverts
A pull that cannot be done
safely is not done at all.
Every one of these reverts the entire transaction. The caller pays gas and gets nothing; the pooled ETH is untouched and the next caller can try again.
Cooldown- Called too soon after the last pull
NothingToPrint- No ETH pooled, or no pool yet
NoLiquidity- The pool has no liquidity to buy from
SlippageNotMet- The buy would fill below the bound
Reentrancy- A pull is already in progress
The slippage floor is checked twice — once inside the unlock, so a breach reverts the swap itself rather than being unwound afterwards, and once again after it.
06 · Limits and dependencies — read this part
Limits and dependencies
The press runs on other people's buys
No buying, no ETH, nothing to print. The mechanism converts volume; it does not create it. A quiet market produces a quiet press.
A pull is a real order, with real impact
It buys into the same book as everyone else and moves the price the way any buy of that size would. That is the point — but it is not free money appearing from nowhere. It is ETH that buyers paid, being spent on the book.
Only staked tokens are paid
Holding $PRESS in a wallet earns nothing from a print. The purchase goes to the pot, and the pot pays the addresses staked in it.
Liquidity is not contract-locked
The market is seeded at launch as a Uniswap v4 position held by the deploying wallet. It is not held by a timelock or a locker contract. That is a discretionary position, and you should price it as one.
It depends on Uniswap v4
The press is a v4 hook. It reads the pool's price to set its own slippage floor and buys through the PoolManager. Its behaviour is bounded by that pool.
Unaudited
67 internal tests, including mainnet-fork runs and a stateful invariant suite, and no independent external audit. That is a real risk, not a formality.