LAST LIGHT
LAST LIGHT is the programmable liquidity component of the protocol, a Uniswap v4 hook attached to the VSPR/USDC pool.
Responsibilities
- session-aware pool behavior
- dynamic fees
- final-hour activation
- fee normalization after the window
- eligible protocol revenue routing
Normal Session
fee = baseFeeFinal Hour
During the final 60 minutes of the configured equity session:
fee = baseFee + ramp(timeToClose)As timeToClose approaches zero, the fee approaches its configured closing level.
Where the fee goes
The mechanism is deterministic: the Hook reads current session state and applies predefined logic rather than relying on a daily manual trigger. What it takes is paid out inside the swap, to a fixed address outside the protocol. It never reaches the reserve.
Current Schedule
As implemented in hooks/LastLight.sol:
| Session state | Fee |
|---|---|
| Open, 09:30 to 15:00 ET | 30 bps |
| Last light, the final 60 minutes | 30 bps at T-60, rising linearly to 200 bps at T-0 |
| After the close, closed, pre-market | 100 bps |
fee = 30 + 170 x (3600 - secondsToClose) / 3600 (bps)The pool fee is updated only when the schedule has moved at least 5 bps from the last applied fee. Half of every fee (the protocol share, owner-settable) is taken by the hook on the unspecified currency and paid, in the same swap, to feeRecipient.
The opening taper
The session schedule above is about the close. The taper is about the launch: a second cut, measured from the moment the pool was created, that starts high and settles at a flat 2%. The schedule below is what taperSchedule() returns on the deployed hook.
| Time since the pool opened | Buy | Sell |
|---|---|---|
| First 60 seconds | 10% | 15% |
| The next 60 seconds | 5% | 5% |
| From 120 seconds on, permanently | 2% | 2% |
The tiers are constants in the contract and the clock starts in afterInitialize, so nothing can raise them afterwards and no one can burn through the opening tier with a dust swap: it expires on the clock whether anyone traded or not. The taper is paid the same way as the protocol share, in the same call.
Paid inside the swap
There is nothing to settle. In afterSwap the hook takes the protocol share plus the taper on the unspecified currency and hands it at once to feeRecipient, an immutable address set at construction, outside the protocol: the dev wallet. The hook never holds a token, there is no accumulator, no sweep and no keeper. Each paying swap emits Captured(cycleId, currency, amount, feePips) and, when a taper applied, Tapered(cycleId, currency, amount, bps, isBuy); the amounts are also counted per 8-hour cycle (accruedThisCycle, cycles, paidCount, totalPaid0, totalPaid1) for the record only.
The hook books nothing with the Distributor: what it takes is not reserve backing, so it never mints VSPR and never feeds the reserve. The protocol's own revenue is the bond surplus:
reward = min(bond proceeds, excess reserves)If no bond sold above backing, the cycle pays nothing.