Overview
Build contracts/access-control/ as the shared role/permission source of truth for every other contract in this repo (analytics, escrow, governance, etc.). Establish, as a hard rule from the first dependent contract onward, that authorization is always checked live — never cached.
Why this is hard
A security review of access-control in isolation would find nothing wrong even if this bug exists, since revocation there works perfectly correctly — the bug, if present, lives in every dependent contract's choice of when to re-check. A complete audit requires walking every privileged entry point across every dependent contract and confirming each performs a fresh cross-contract call rather than trusting a cached result, which is easy to get right in the first contract and inconsistently wrong in a later one written without this specific hazard in mind.
What to build
Suggested layout:
contracts/access-control/
src/lib.rs
src/roles.rs
src/grant_revoke.rs
tests/
cross_contract_revocation_test.rs # revoke, then immediately retry in each dependent
Implementation steps:
- As each dependent contract (
analytics, escrow, governance, governance-voting, multi-sig-wallet, time-locked-transactions, token-swap, upgrade) is built, require every privileged entry point to call access-control live — write this as an explicit rule in each crate's README, not just tribal knowledge.
- If a cross-contract call cost genuinely requires caching for performance, require an explicit cache invalidation tied to
access-control's revocation event, with a test proving the cache can't outlive a revocation.
- Write
cross_contract_revocation_test.rs covering every dependent contract, not just one representative case: grant a role, use it successfully, revoke it, immediately retry, assert failure.
Acceptance criteria
- Every dependent contract's privileged entry points check
access-control live (or have a provably-invalidated cache).
cross_contract_revocation_test.rs passes for every dependent contract.
Overview
Build
contracts/access-control/as the shared role/permission source of truth for every other contract in this repo (analytics,escrow,governance, etc.). Establish, as a hard rule from the first dependent contract onward, that authorization is always checked live — never cached.Why this is hard
A security review of
access-controlin isolation would find nothing wrong even if this bug exists, since revocation there works perfectly correctly — the bug, if present, lives in every dependent contract's choice of when to re-check. A complete audit requires walking every privileged entry point across every dependent contract and confirming each performs a fresh cross-contract call rather than trusting a cached result, which is easy to get right in the first contract and inconsistently wrong in a later one written without this specific hazard in mind.What to build
Suggested layout:
Implementation steps:
analytics,escrow,governance,governance-voting,multi-sig-wallet,time-locked-transactions,token-swap,upgrade) is built, require every privileged entry point to callaccess-controllive — write this as an explicit rule in each crate's README, not just tribal knowledge.access-control's revocation event, with a test proving the cache can't outlive a revocation.cross_contract_revocation_test.rscovering every dependent contract, not just one representative case: grant a role, use it successfully, revoke it, immediately retry, assert failure.Acceptance criteria
access-controllive (or have a provably-invalidated cache).cross_contract_revocation_test.rspasses for every dependent contract.