Skip to content

[ReceiveExecutor] ref: store data in state machine - #826

Open
duck-types wants to merge 6 commits into
mainfrom
ref/receive-executor/clean-up-state
Open

[ReceiveExecutor] ref: store data in state machine#826
duck-types wants to merge 6 commits into
mainfrom
ref/receive-executor/clean-up-state

Conversation

@duck-types

@duck-types duck-types commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

parse, don't validate

@duck-types
duck-types force-pushed the ref/receive-executor/clean-up-state branch from 65ec078 to 4ff9547 Compare August 10, 2026 17:56
@duck-types
duck-types requested a lite review from Copilot August 10, 2026 17:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors the CCIP ReceiveExecutor contract/state layout to persist token-transfer execution details inside a dedicated state machine, shifting token-transfer initiation to be driven by InitExecute message contents rather than standalone storage fields.

Changes:

  • Replaces ReceiveExecutor_MessageState with ReceiveExecutor_State { tokenTransfer?, messageExecution } and introduces a tagged ReceiveExecutor_TokenTransferState union for token-transfer flow.
  • Extends ReceiveExecutor_InitExecute to optionally carry tokenAdminRegistry, and updates OffRamp to populate this field when available.
  • Restructures ReceiveExecutor tests by extracting shared setup utilities and adding a dedicated execution/token-transfer test suite.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
contracts/wrappers/gen/ccip/ReceiveExecutor.ts Updates generated wrapper types/serialization for new storage + state machine model and InitExecute payload changes.
contracts/wrappers/gen/ccip/OffRamp.ts Updates generated wrapper structs/serialization for the extended ReceiveExecutor_InitExecute.
contracts/tests/ccip/receiveExecutor/ReceiveExecutor.spec.ts Simplifies the core ReceiveExecutor test suite and delegates deployment to shared setup.
contracts/tests/ccip/receiveExecutor/ReceiveExecutor.Setup.ts Adds reusable test deployment + message factory helpers for ReceiveExecutor.
contracts/tests/ccip/receiveExecutor/ReceiveExecutor.execution.spec.ts Adds execution-flow and token-transfer-flow tests, including retry behaviors.
contracts/contracts/lib/utils.tolk Adds Cell<T>?.loadOpt() helper for ergonomic optional cell loading.
contracts/contracts/ccip/receive_executor/types.tolk Defines the new ReceiveExecutor_State and ReceiveExecutor_TokenTransferState union and helpers.
contracts/contracts/ccip/receive_executor/storage.tolk Updates storage layout to use the new state struct and removes old token-transfer fields.
contracts/contracts/ccip/receive_executor/messages.tolk Extends ReceiveExecutor_InitExecute with optional tokenAdminRegistry.
contracts/contracts/ccip/receive_executor/contract.tolk Refactors message handlers to use the new state machine and validates sender based on persisted token-transfer state.
contracts/contracts/ccip/offramp/contract.tolk Populates initExecuteMsg.tokenAdminRegistry and removes embedding token-transfer fields into ReceiveExecutor storage init.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread contracts/contracts/ccip/receive_executor/storage.tolk Outdated
Comment thread contracts/contracts/ccip/receive_executor/contract.tolk Outdated
Comment thread contracts/wrappers/gen/ccip/ReceiveExecutor.ts
Comment thread contracts/tests/ccip/receiveExecutor/ReceiveExecutor.spec.ts Outdated
@duck-types
duck-types force-pushed the ref/receive-executor/clean-up-state branch from 4ff9547 to a82a767 Compare August 10, 2026 18:28
@duck-types
duck-types marked this pull request as ready for review August 10, 2026 18:28
@duck-types
duck-types requested a review from a team as a code owner August 10, 2026 18:28
@duck-types
duck-types force-pushed the ref/receive-executor/clean-up-state branch from a82a767 to 9ad430c Compare August 11, 2026 11:31
Base automatically changed from feat/token-transfer/offramp to main August 13, 2026 14:01
@duck-types
duck-types force-pushed the ref/receive-executor/clean-up-state branch from 9ad430c to 4adfc5b Compare August 13, 2026 14:01
@duck-types
duck-types force-pushed the ref/receive-executor/clean-up-state branch from 4adfc5b to 7f2fd20 Compare August 13, 2026 14:02
Comment on lines +46 to +66
struct ReceiveExecutor_TokenTransferState_Untouched {
tokenAdminRegistry: address;
}

struct ReceiveExecutor_TokenTransferState_TokenAdminRegistryQuery {
tokenAdminRegistry: address;
}

struct ReceiveExecutor_TokenTransferState_TokenAdminRegistryQueryFailed {
tokenAdminRegistry: address;
}

struct ReceiveExecutor_TokenTransferState_ReleaseOrMint {
tokenAdminRegistry: address;
tokenPool: address;
}

struct ReceiveExecutor_TokenTransferState_ReleaseOrMintFailed {
tokenAdminRegistry: address;
tokenPool: address;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that i see the advantage of having all these structs which are basically the same as different types over having an enum that indicates what the state is and a single storage type.

That said I'm okay with it if you feel like it improves the code.

@vicentevieytes vicentevieytes Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like this seems easier to follow to me

struct ReceiveExecutor_State {
    tokenTransfer: Cell<ReceiveExecutor_TokenTransfer>?
    messageExecution: ReceiveExecutor_MessageExecutionState
}
struct ReceiveExecutor_TokenTransfer {
    state: ReceiveExecutor_TokenTransferState
	tokenAdminRegistry: address;
    tokenPool: address;
}
enum ReceiveExecutor_TokenTransferState {
    Untouched
    TokenAdminRegistryQuery
    TokenAdminRegistryQueryFailed
    ReleaseOrMint
    ReleaseOrMintFailed
}

and if tokenTransfer is null then there is no tokenTransfer and that's it

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue with this is that the logic is not represented by the types. Let's take the tokenPool field, for example. It should be an optional in your model, as it is not populated until You passed the token registry query.

  1. Let's say your release or mint failed, so ReceiveExecutor_TokenTransfer.state == ReceiveExecutor_TokenTransferState.ReleaseOrMintFailed.
  2. You receive an initExec message from a manual exec.
  3. You match your state and know you have to retry the ReleaseOrMint, so you try to use ReceiveExecutor_TokenTransfer.tokenPool but it is an optional. As it is an optional, you would need to put an assert (ReceiveExecutor_TokenTransfer.tokenPool != null) throw Unreachable, which means you have lost information. Your type system doesn't keep track of the relation between your knowleged of the TokenPool address and your state ReleaseOrMintFailed which entails the fact that you have already succeeded quering the token registry.

@duck-types duck-types Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reconsider it and I think you got a point. Please take a look at the latest version. I've extracted the tokenAdminRegistry, which was shared across all states, and kept only the tokenPool state dependant

Comment thread contracts/contracts/ccip/receive_executor/storage.tolk Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants