Doubloon: separate BURNER from MINTER / enforce allowance on third-party burn (Finding 1 from #131) #132
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:open_issues
agents
agent:security_audit
agent:verify
area
timecurve
arena
arena-v2
audit
block:feature_review
block:security
bug
contracts
design
devops
docs
documentation
enhancement
epic
feature
frontend
indexer
low priority
megaeth
operations
ops
performance
QA
qa checklist
referrals
removal
security
smart-contracts
tech-debt
testing
time-arena
timecurve
visual-qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
code/yieldomega#132
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Parent
Split from pre-deploy security review #131 (Finding 1). Finding 2 deferred per maintainer (“acceptable governance risk”).
Problem
contracts/src/tokens/Doubloon.solexposesburn(address from, uint256 amount)toMINTER_ROLEwithout an allowance path fromfrom. Anyone holdingMINTER_ROLEcan destroy arbitrary holder balances (“god-mode burn”), unlike standardERC20Burnable.burnFromsemantics.Today only RabbitTreasury holds
MINTER_ROLEand only burnsmsg.sender, so live behavior is constrained — but mis-grants, compromised multisig, or future contracts withMINTER_ROLEcreate systemic tail risk distinct from inflation (audit narratives often emphasize mint-only).Recommended fix
Pick one coherent model (prefer split roles OR allowance) and enforce it everywhere
Doubloonis integrated:BURNER_ROLE;mintstaysMINTER_ROLE;burnrequiresBURNER_ROLE; grantBURNER_ROLEonly to RabbitTreasury (document “no further grants”)._spendAllowance(from, msg.sender, amount)then_burn(from, amount)(or deprecate unrestrictedburnand use OZ-alignedburnFrompattern), soMINTER_ROLEalone cannot wipe others.Regardless: add explicit unit tests proving
MINTER_ROLEalone cannot burn a holder who never approved.Acceptance criteria
Verification checklist
forge testforDoubloon+RabbitTreasury(or integration) covers: mint ok; self-burn or Treasury-authorized burn ok; burn other without allowance/role reverts.Doubloon.burn/MINTER_ROLEgrants incontracts/scriptand adjust if needed.docs/onchain/or token section +docs/testing/invariants-and-business-logic.md— new invariant row for separation of mint vs burn authority (link this issue)..cursor/skills/yieldomega-guardrails/SKILL.mdonly if a standing cross-link to DOUB roles is useful (optional, small).Repo touch list
contracts/src/tokens/Doubloon.sol; possiblyRabbitTreasuryburn call sites;AccessControlrole grants in deploy scriptscontracts/test/*.t.solcovering Doubloon + Treasury burn matrixdocs/testing/invariants-and-business-logic.md; token / governance docs as appropriatementioned in issue #131
mentioned in commit
9f07280cf9Fix shipped to
main(GitLab #132)Summary: Doubloon burning is aligned with standard ERC-20 semantics: holders can
burntheir own tokens; third parties must useburnFromwith spender allowance. There is noBURNER_ROLEandMINTER_ROLEdoes not allow burning others' balances without allowance.What changed (high level):
Doubloon:ERC20Burnable+AccessControl;mintremainsonlyRole(MINTER_ROLE); burns only via OZburn/burnFrom.RabbitTreasury.withdraw: usesdoub.burnFrom(msg.sender, amount)— users must approve the treasury for DOUB before withdraw burns.docs/testing/invariants-and-business-logic.md; skills cross-links inskills/play-rabbit-treasury/SKILL.mdand guardrails.Commit on
main:9f07280@brouie — please verify when you have a moment.
Verification checklist
forge test --match-contract "DoubloonTest|RabbitTreasuryTest|RabbitTreasuryInvariantTest"passesmint; cannotburnFromanother wallet without allowance (expect revert)burnown balance; holder B canburnFrom(A, x)only afterA.approve(B, x)approve(treasury, ...); revert without allowanceBURNER_ROLEor privileged burn-only role on DoubloonIssue left open until you've signed off.
mentioned in commit
fc6ba68fccmentioned in commit
7fffcfa242mentioned in issue #135
@PlasticDigits — verification PASS on
9f07280. walked your checklist:forge test --match-contract 'DoubloonTest|RabbitTreasuryTest|RabbitTreasuryInvariantTest'green.DoubloonTest7/7 PASS includingtest_burn_drains_arbitrary_holder_via_secondary_minterregression test. full suite 310/310 ona421ba1.test_mint_onlyMinterPASS,test_minter_cannotBurnFromHolderWithoutAllowancePASS — minter has no special burn surface anymore.test_burn_self_withoutRolePASS (own burn no role needed),test_burnFrom_withAllowancePASS,test_burnFrom_withoutAllowance_revertsPASS.doub.burnFrom(msg.sender, doubAmount). L373-374 docstring spells out the user must approve treasury for DOUB first. clean migration.BURNER_ROLEor privileged burn role on Doubloon —grep -n 'BURNER\|burn' src/tokens/Doubloon.solreturns only the inheritedERC20Burnablereference.MINTER_ROLEis mint-only with explicit NatSpec saying it does not authorize burning others.heads-up for whoever's on frontend: Burrow withdraw flow now needs an explicit
approve(rabbitTreasury, doubAmount)step before calling withdraw, otherwise it revertsERC20InsufficientAllowance. flagging in case the frontend hasn't been updated yet.ready for close on your side.
mentioned in issue #149
mentioned in issue #207
mentioned in issue #341