fix(L1/I1): request-slot auth + drain per-epoch redemption dust - #21
Merged
Conversation
L1: requestDeposit/requestRedeem now require the caller to be the controller or its operator, not just able to move owner_'s assets. This blocks a third party from seeding a dust request into a foreign controller's slot to grief its next deposit/redeem (PendingRequestFromEarlierEpoch DoS). I1: track reserved payout and outstanding redeem shares per settlement epoch. The aggregate payout reserved at settle is floor(sumShares * price) while each claimant is paid floor(userShares * price); with multiple fractional claimants the per-user floors sum to less than the aggregate, leaving a few wei frozen in totalReservedPayoutsWad (and thus subtracted from shareholderNav forever). The last claimant of an epoch now drains that residue. Tests: two L1 griefing/operator cases and an I1 case that leaves 2 wei of rounding dust and asserts it is fully drained after the last claim.
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.
Batch PR E of the CPPI vault audit remediation (follows PR A–D: revert-resilience #17, oracle-robustness #18, execution-mev-bounds #19, floor-correctness #20).
L1 — foreign controller-slot griefing DoS (Low)
requestDeposit/requestRedeempreviously only authorized the caller againstowner_(whose assets move). The caller could still write an arbitrary controller's request slot, seeding a dust request there. Because a slot with a pending request from an earlier epoch reverts (PendingRequestFromEarlierEpoch), an attacker could block a victim controller's next deposit/redeem.Fix: both entrypoints now also require the caller to be the controller or its operator (
_authControllerOrOperator(controller)), so no one can write a foreign slot.I1 — reserved-payout dust frozen forever (Informational)
At settlement the vault reserves
floor(sumShares * price)aggregate, but each claimant is paidfloor(userShares * price). With more than one fractional claimant the per-user floors sum to strictly less than the aggregate, leaving a few wei permanently stuck intotalReservedPayoutsWad— which is subtracted fromshareholderNav, so it is lost to holders forever.Fix: track reserved payout and outstanding redeem shares per epoch (
epochReservedWad/epochRedeemRemaining). The last claimant of an epoch drains the residue back out oftotalReservedPayoutsWad.Tests
test_l1_cannotGriefForeignControllerSlot— attacker funding from self cannot seed a victim's slot; victim's slot still works.test_l1_operatorCanStillWriteControllerSlot— a legitimate operator is unaffected.test_i1_reservedDustDrainedOnLastClaim— three fractional holders redeem in one epoch, leaving 2 wei of rounding dust; asserts it is fully drained after the last claim. Verified to fail (2 != 0) when the drain branch is removed.Full suite: 141 passing.