test(amm): LP reward regression coverage for the 2026-07-21 findings - #4
Open
OxToF wants to merge 3 commits into
Open
test(amm): LP reward regression coverage for the 2026-07-21 findings#4OxToF wants to merge 3 commits into
OxToF wants to merge 3 commits into
Conversation
Isolated rewards-enabled pool (two throwaway mints). Covers, in-epoch: - happy path: a real depositor claims continuous oSOLA (was uncovered) - Finding B guard: a fresh wallet holding TRANSFERRED LP reverts NothingToClaim - Finding A guard: a fresh wallet banks zero checkpoint weight Full epoch-emission path (emit_pool_rewards -> claim_lp_emissions) needs a 7-day epoch warp this mocha/validator harness can't do — documented gap (bankrun). 37 passing on localnet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
The mocha suite runs against a live cluster (Anchor.toml pins devnet), so it is stuck with the real clock and could only cover the in-epoch half of the LP reward system. The per-epoch half (checkpoint_lp -> emit_pool_rewards -> claim_lp_emissions) needs a 7-day boundary crossed, which is the documented gate on arming configure_emissions with initial > 0 on mainnet. bankrun's setClock() moves the epoch on demand. 7 tests, ~1s, no validator: - full cycle across a real epoch boundary: allocation is the undecayed emission in epoch 0, then decayed 1% in epoch 1, which pins decayed_emission too - replay of the same (user, pool, epoch) rejected. Worth noting the LpEpochClaim `init` is an ACCOUNT CONSTRAINT, so it fires during validation, before the body's NothingToClaim. The opposite assumption was made and disproved by the test. - invariant sum(claims) <= osola_allocated over a 2-LP epoch. The clamp itself does not bind: two honest LPs under-subscribe the pot, which is the safe direction. - a late depositor cannot bank a full epoch of weight (Finding A) - withdrawal decrements lp_amount, so it shrinks the reward basis - reward_basis follows the wallet balance DOWN, the reverse leg of Finding B that nothing covered: high recorded deposit but LP moved out must bank zero weight - a position recorded at lp_amount = 0 (legacy or transfer-acquired) can still withdraw Verified load-bearing by mutation: putting window_start back to epoch_start in checkpoint_lp makes the late-depositor test fail (weight/LP 1114620 vs 1114560, equality being the back-credit signature) while the other 6 stay green. A cycle test asserting only "gained > 0" passes on the bug. Tooling trap: bankrun cannot load an SBPFv3 binary. cargo build-sbf --arch v3, required for a devnet deploy, yields a .so rejected with the misleading "Program is not deployed". Build plain to test, re-add --arch v3 to deploy. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…sync found Two entries. The missing per-epoch coverage is written (bankrun), and a delivery defect was found on the way: the committed IDL carried lp_user_info for add_liquidity, claim_lp_rewards and remove_liquidity but NOT for checkpoint_lp, precisely the subject of 8e4454d. The production bundle was inspected and serves checkpoint_lp with 9 accounts while the deployed program expects 10. Nothing caught it because LpEmissions.tsx passes lpUserInfo through an `as any` cast, and the component is not mounted in page.tsx, so no tester could reach the path. Same failure mode as the "always rebuild the IDL" rule, one notch more devious: the IDL had been regenerated and partially committed. Check the IDL that is SERVED, not the local one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #3 — adds the test coverage that was entirely missing on the AMM LP-reward paths.
Isolated rewards-enabled pool (two throwaway mints, no interference with the existing SOLA/USDC / curve / POL / invariant tests). Covers, in-epoch:
claim_lp_rewards→ must revertNothingToClaim. This encodes the exact confirmed devnet exploit as a permanent regression test.checkpoint_lp→ banks zero weight, so the same LP walked through N wallets can no longer inflate the epoch pot.Documented gap
The full epoch-emission cycle (
emit_pool_rewards→claim_lp_emissions, incl. theosola_claimedcap) requires crossing a 7-day epoch boundary, which this mocha/validator harness can't warp. That path stays uncovered here and needs a bankrun-style clock — flagged before mainnet emission arming.Verification
anchor test --provider.cluster localnet→ 37 passing, 0 failing. Must run on localnet: the tests callconfigure_continuous_emissions, which writes global state and would clobber the live devnet config.🤖 Generated with Claude Code