Skip to content

feat: NAV snapshots, recipient allowlist, timelock status+retry, backstop seeding - #504

Merged
techisigu merged 4 commits into
Refract-Protocol:mainfrom
abikedaniel22:feat/issues-242-243-244-245
Oct 24, 2026
Merged

techisigu merged 4 commits into
Refract-Protocol:mainfrom
abikedaniel22:feat/issues-242-243-244-245

Conversation

@abikedaniel22

Copy link
Copy Markdown
Contributor

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, computes asset_nav = balance × price / 1e7, persists a NavSnapshot with per-asset breakdown and total NAV.
  • Read-only views: total_nav(), asset_nav_breakdown(), asset_price_staleness(token) — staleness in seconds relative to oracle reading timestamp.
  • Oracle failures degrade gracefully (asset gets nav = 0, snapshot still complete).
  • New OraclePriceClient typed 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), AllowlistKey storage type, TTL bump on every read/write. Includes 5 unit tests.
  • Bounty: allow_recipient / block_recipient / remove_recipient / recipient_status / is_recipient_allowed; new RecipientNotAllowed = 12 error; check applied in award() and create_payout().
  • Grants: same pattern — RecipientNotAllowed = 20; check applied in create_grant().
  • Treasury: same pattern applied to withdraw().

Issue #242 — Timelock observable status and retry (timelock/src/lib.rs)

  • OperationStatus gains Failed = 3 and Expired = 4.
  • TimelockOperation gains failure_code, attempt_count, last_failed_at fields.
  • execute() and execute_due() persist Failed status with the callee's error code; emit tl_failed event.
  • retry(id) — permissionless re-attempt of a Failed op.
  • cancel_failed(id) and expire(id) — governance cleanup paths.
  • New errors: NotFailed = 11, RetryTooSoon = 12.
  • 6 new tests.

Issue #243 — Backstop seeding (backstop/src/lib.rs, treasury/src/lib.rs)

  • Backstop: record_seed(treasury, amount) — mints shares to SeedShares counter (junior, separate from staker shares). recall_seed(caller, amount) — validates caller is original seeder, guards against recalling more than the current share value.
  • Treasury: seed_backstop() + recall_seed() + seeded_capital() — governance-gated; tracks capital in SeededCapital counter.

Testing

  • timelock/src/test.rs: 6 new tests
  • backstop/src/lib.rs: 4 inline tests
  • treasury/src/lib.rs: 5 inline tests
  • common/src/allowlist.rs: 5 unit tests

Closes #242
Closes #243
Closes #244
Closes #245

abikedaniel22 and others added 4 commits October 24, 2026 00:09
…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>
@techisigu
techisigu merged commit 49bbfa9 into Refract-Protocol:main Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants