Skip to content

Restructure TP flow with onlyRouter access - #850

Open
krebernisak wants to merge 6 commits into
feat/tp-get-ccvs-feesfrom
feat/tp-only-router
Open

Restructure TP flow with onlyRouter access#850
krebernisak wants to merge 6 commits into
feat/tp-get-ccvs-feesfrom
feat/tp-only-router

Conversation

@krebernisak

@krebernisak krebernisak commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

Reworks the Token Pool (TP) access-control model so that all inbound/outbound token operations are authenticated solely by the Router, rather than by per-pool onRamp/offRamp mappings. The pool no longer performs ramp authentication — the Router becomes the single chokepoint that verifies the sender is the correct OnRamp/OffRamp and applies its own RMN curse policy before dispatching to the pool. The pool keeps only an independent, owner-managed local curse policy.

Motivation

Previously each token pool stored a mirroredPolicy with onRamps/offRamps maps and ran ensureOutboundAccess/ensureInboundAccess guards (with overridable hooks) to authenticate callers. This duplicated ramp authentication that the Router already owns, and the overridable access hooks let a custom pool bypass the Router boundary if it mishandled the check. Centralizing authentication in the Router removes this class of bug and simplifies pool storage/config.

Key changes

Access control (entrypoint.tolk)

  • onLockOrBurn and onReleaseOrMint now call a new onlyRouter(sender) guard before invoking any overridable operation hook, so a custom pool cannot bypass the Router boundary.
  • New onlyAdvancedPoolHooks(sender) guards the four async hook continuations (onPreflightCheckFinished/Failed, onPostflightCheckFinished/Failed), preventing a forger from injecting a fake success/failure continuation after the Router-authenticated op returns to the async flow.
  • Removed the ensureOutboundAccess / ensureInboundAccess hooks and their base ramp-lookup implementations.
  • ensureNotCursed now always enforces the pool's local curse policy first (hooks may add restriction but cannot bypass it).
  • rmnProxy becomes nullable (address?); the owner can now disable RMN-proxy updates by setting addr_none. setRMNProxy/getRMNProxy and onlyOwnerOrRMNProxy updated accordingly.

Storage/types (types.tolk, concrete pools)

  • Replaced TokenPool_MirroredPolicy (onRamps + offRamps + cursedSubjects) with a slimmer TokenPool_LocalPolicy (cursedSubjects only). Removed TokenPool_RampUpdate and the TokenPool_UpdateRampAccess message/flow, its RampAccessUpdated event, and the onRamp/offRamp/getMirroredPolicy getters.
  • Concrete pools (burn_mint, lock_release, lock_release_lockbox) updated: removed null access hooks and ramp getters, switched storage init to localPolicy.
  • setDynamicConfig now asserts the router address is non-zero.

Router (contract.tolk, messages.tolk, errors.tolk)

  • Outbound: Router_LockOrBurn now performs a Router-side curse check (isCursed on the destination selector) and returns a structured Router_TokenPoolLockOrBurnFailed to the executor when rejected.
  • New inbound path: Router_RelayReleaseOrMint — the registered OffRamp relays the release-or-mint request to the Router, which asserts the sender is that OffRamp, binds details.remoteChainSelector == sourceChainSelector (new SourceChainSelectorMismatch error), applies its RMN curse policy, and forwards a TokenPool_ReleaseOrMint to the pool.
  • New Router_RichBouncedMessage handling in onBouncedMessage: pre-admission pool bounces (via RichBounce) are caught and surfaced as canonical Router_TokenPool…Failed messages.

Send executor (ccipsend_executor)

  • Handles new TokenPool_LockOrBurnFailure (structured pool failure, may arrive before or during withdrawal) and Router_TokenPoolLockOrBurnFailed (Router policy rejection / pre-admission bounce), both driving exitWithError (new TokenPoolBounce error). Validates sender is the pool/router and that tokenPool matches state.

Tests & wrappers

  • Behavior specs updated to the Router-only model (e.g. "reverts releaseOrMint when caller is not the configured Router", "does not authorize an OffRamp to call the pool directly", "allows the owner to disable RMN proxy updates with addr_none"); ramp-access test cases removed.
  • Router cursing spec extended for the new relay path; e2e and pool specs adjusted.
  • Generated wrappers regenerated (Router.ts, pools, MockTokenPool, CCIPSendExecutor).

@krebernisak
krebernisak requested a review from a team as a code owner August 25, 2026 11:27
@nicolasgnr nicolasgnr added the Flag label Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants