Repository navigation
feat: NAV snapshots, recipient allowlist, timelock status+retry, backstop seeding - #504
Merged
techisigu merged 4 commits intoOct 24, 2026
Conversation
…stop seeding Implements four governance and treasury features: Issue Refract-Protocol#245 — NAV snapshots (treasury/src/lib.rs) - Register SEP-41 asset/feed mappings via register_asset_feed - take_nav_snapshot() fetches 1e7 USD prices from RefractOracle for every tracked asset, computes asset_nav = balance * price / 1e7, persists NavSnapshot with per-asset breakdown and total NAV - Read-only views: total_nav(), asset_nav_breakdown(), asset_price_staleness() - OraclePriceClient trait for typed cross-contract price lookups - Tests: oracle-not-configured guard, feed registration/deregistration, allowlist gate, seeded-capital accounting guards Issue Refract-Protocol#244 — Recipient allowlist (bounty/src/lib.rs, grants/src/contract.rs, treasury/src/lib.rs, common/src/allowlist.rs) - common/src/allowlist.rs: new governance-managed allowlist module with allow/block/remove helpers, require_allowed(), ScreeningStatus type, AllowlistKey storage type, TTL bump on read/write; includes unit tests - bounty: allow_recipient/block_recipient/remove_recipient/recipient_status/ is_recipient_allowed entrypoints; RecipientStatus DataKey; RecipientNotAllowed error; check in award() and create_payout() before funds move - grants: same pattern — allow_recipient/block_recipient/remove_recipient; RecipientNotAllowed = 20 error; check in create_grant() - treasury: same pattern on withdraw(); all three contracts share the ScreeningStatus(Allowed/Blocked) encoding Issue Refract-Protocol#242 — Timelock observable status and retry (timelock/src/lib.rs) - OperationStatus gains Failed = 3 and Expired = 4 variants - TimelockOperation gains failure_code, attempt_count, last_failed_at fields - execute() and execute_due() now persist Failed status with failure_code instead of silently resetting to Pending on callee revert; tl_failed event - retry(id): permissionless re-attempt of a Failed op after eta; same Executed-before-call reentrancy guard as execute() - cancel_failed(id): admin can cancel a Failed op - expire(id): admin can mark a Pending op Expired (irrevocable) - TimelockError gains NotFailed = 11 and RetryTooSoon = 12 - Tests: failed status persisted, retry of non-failed rejected, cancel_failed, expire, expire of executed rejected Issue Refract-Protocol#243 — Backstop seeding (backstop/src/lib.rs, treasury/src/lib.rs) - backstop: record_seed(treasury, amount) mints shares to SeedShares counter, accounted separately from staker deposits (junior accounting) - backstop: recall_seed(caller, amount) verifies caller == SeedTreasury, converts amount to shares at current price, rejects if shares_needed > SeedShares (losses absorbed before recall), transfers token to treasury - treasury: seed_backstop(caller, token, amount) transfers funds to backstop and updates SeededCapital counter; set_backstop() wires the address - treasury: recall_seed(caller, token, amount) guards amount <= SeededCapital, triggers backstop transfer back, decrements SeededCapital - Tests: double-init guards, paused-deposit rejection, recall-exceeds-seed Closes Refract-Protocol#242, Refract-Protocol#243, Refract-Protocol#244, Refract-Protocol#245
…le agent) - backstop/Cargo.toml: merged [markers] — model resolved the conflict markers - backstop/src/lib.rs: merged [markers] — model resolved the conflict markers - bounty/Cargo.toml: merged [markers] — model resolved the conflict markers - bounty/src/lib.rs: merged [markers] — model resolved the conflict markers - grants/Cargo.toml: merged [markers] — model resolved the conflict markers - treasury/Cargo.toml: merged [markers] — model resolved the conflict markers - treasury/src/lib.rs: merged [markers] — model resolved the conflict markers Co-authored-by: Simple Agent <agent@simple.dev>
…le agent) - backstop/src/lib.rs: merged [markers] — model resolved the conflict markers Co-authored-by: Simple Agent <agent@simple.dev>
…le agent) - backstop/src/lib.rs: merged [markers] — model resolved the conflict markers - grants/src/contract.rs: merged [markers] — model resolved the conflict markers - treasury/src/lib.rs: merged [markers] — model resolved the conflict markers Co-authored-by: Simple Agent <agent@simple.dev>
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.
Summary
Implements four governance and treasury features across five crates.
Issue #245 — NAV snapshots (
treasury/src/lib.rs)register_asset_feed(token, feed_id)— admin maps each SEP-41 token to a RefractOracle feed symbol.take_nav_snapshot()— permissionless; fetches 1e7 USD prices from the oracle for every tracked asset, computesasset_nav = balance × price / 1e7, persists aNavSnapshotwith per-asset breakdown and total NAV.total_nav(),asset_nav_breakdown(),asset_price_staleness(token)— staleness in seconds relative to oracle reading timestamp.nav = 0, snapshot still complete).OraclePriceClienttyped trait for cross-contract price lookups.Issue #244 — Recipient allowlist (
bounty,grants,treasury,common/allowlist)common/src/allowlist.rs— new shared module:allow(),block(),remove(),require_allowed(),ScreeningStatus(Allowed/Blocked),AllowlistKeystorage type, TTL bump on every read/write. Includes 5 unit tests.allow_recipient / block_recipient / remove_recipient / recipient_status / is_recipient_allowed; newRecipientNotAllowed = 12error; check applied inaward()andcreate_payout().RecipientNotAllowed = 20; check applied increate_grant().withdraw().Issue #242 — Timelock observable status and retry (
timelock/src/lib.rs)OperationStatusgainsFailed = 3andExpired = 4.TimelockOperationgainsfailure_code,attempt_count,last_failed_atfields.execute()andexecute_due()persistFailedstatus with the callee's error code; emittl_failedevent.retry(id)— permissionless re-attempt of a Failed op.cancel_failed(id)andexpire(id)— governance cleanup paths.NotFailed = 11,RetryTooSoon = 12.Issue #243 — Backstop seeding (
backstop/src/lib.rs,treasury/src/lib.rs)record_seed(treasury, amount)— mints shares toSeedSharescounter (junior, separate from staker shares).recall_seed(caller, amount)— validates caller is original seeder, guards against recalling more than the current share value.seed_backstop()+recall_seed()+seeded_capital()— governance-gated; tracks capital inSeededCapitalcounter.Testing
timelock/src/test.rs: 6 new testsbackstop/src/lib.rs: 4 inline teststreasury/src/lib.rs: 5 inline testscommon/src/allowlist.rs: 5 unit testsCloses #242
Closes #243
Closes #244
Closes #245