Loading
Loading
A harvest moves a token's accrued fees into the vault as stock and starts a reward stream. Nothing reaches stakers until someone harvests.
Anyone. harvest() has no access control. The Pons fee escrow only ever pays a vault's balance to that vault, so the caller cannot redirect anything; they only pay the gas. A launcher, a staker, or a keeper bot can all do it.
There is no reward for calling it. If you are staked, your incentive is that harvests are what fill the stream you earn from.
On a token page, Waiting to be harvested shows two wells:
Then two buttons:
NothingToHarvest.IndexFactory as the app fee.Any ETH that reaches the vault by other means (someone sending it to the vault address) is treated as a donation and swapped in step 4. A stock-priced vault has no swap, so ETH sent to it sits there.
Whenever the escrow balance is worth more than the gas. Harvesting a few wei of fees still works, but the app fee and the stream math round in the vault's favour at tiny amounts, and you pay full gas for it.
A harvest right after fees accrue on a graduated token can pick up less than the "unswept" figure suggests, because fees collected in the memecoin itself wait for the Pons operator to convert them. Harvest again later and the rest comes through.
The TWAP check reads the Uniswap v3 pool's observation buffer. A pool that has never had its buffer grown has cardinality 1 and cannot serve a TWAP; the harvest reverts with OracleTooShallow.
Press Warm oracle. It calls increaseObservationCardinalityNext(64) on the pool, which grows the buffer so the pool starts recording price history. It costs gas once per pool and never needs repeating; a later call is a no-op if the buffer is already that size or larger. Any vault pointed at the same pool benefits.
After warming, the pool needs trades over at least 15 minutes before a TWAP covering that window exists. If a harvest still reverts with OracleTooShallow right after warming, wait for the pool to see some activity and retry.
Before swapping, the vault compares the pool's current tick to its 15-minute TWAP tick. If they differ by more than 200 ticks (about 2%), the harvest reverts with PriceOutOfBand. Someone is moving the pool right now, or it has moved on its own in the last quarter hour. Wait and retry.
This check replaces a caller-supplied minimum output. Because anyone can call harvest(), a minimum the caller chooses would be worthless; an attacker would pass zero. The band is fixed into the vault at launch and cannot be loosened.
A successful harvest emits Harvested(caller, ethClaimed, stockClaimed, stockGained, appFee) and RewardAdded(stock, periodFinish). On the token page, the "Harvests" stat increments, "Last harvest" updates, and the stake section's note tells you how much is streaming and until when. The page re-renders every 15 seconds, so give it a moment.
A keeper that calls harvest() on every vault every so often is the simplest way to keep streams flowing. Read pendingFees() first and skip vaults with nothing claimable. The public RPC rate-limits by IP; a keeper doing sustained reads wants its own node. See Contract reference for the calls.