IntentSource
(source chain operations) and Inbox
(destination chain operations).
Architecture
Intent Lifecycle
1. Publishing (Source Chain)
Users create intents specifying execution instructions for the destination chain and rewards for solvers. Direct Publishing:IntentPublished
event.
Atomic Publishing with Funding:
2. Funding (Source Chain)
Intents can be funded separately after creation:3. Fulfillment (Destination Chain)
Solvers execute intent instructions on the destination chain:intentHash
: Unique identifier of the intentroute
: Execution instructions and token requirementsrewardHash
: Hash of reward structure for verificationclaimant
: Cross-VM compatible identifier for reward recipient (bytes32)
sourceChainDomainID
is NOT the chain ID. Each bridge uses its own domain ID system:
- Hyperlane: Custom domain IDs
- LayerZero: Endpoint IDs
- Metalayer: Domain IDs specific to routing
4. Proving (Destination Chain)
Generate proofs for fulfilled intents:5. Claiming Rewards (Source Chain)
After proof verification, solvers claim rewards:6. Refunds (Source Chain)
Creators can reclaim rewards after expiry:- Intent has expired (
block.timestamp >= reward.deadline
) - Intent was not fulfilled on the correct destination chain
ERC-7683 Compatibility
The Portal implements both ERC-7683 origin and destination settler interfaces.Origin Functions
Direct Order Opening:- Signature matches
order.user
openDeadline
not passedoriginSettler
matches contract addressoriginChainId
matches current chain
Destination Functions
ERC-7683 Fulfillment:orderId
: Intent hash from origin chainoriginData
: Encoded(bytes route, bytes32 rewardHash)
fillerData
: Encoded(address prover, uint64 source, bytes32 claimant, bytes proverData)
fulfillAndProve()
internally.
Vault System
The Portal uses deterministic CREATE2 deployment for intent vaults.Computing Vault Address
Vault States
Vaults track intent lifecycle through status enum:Initial
: Intent created but not fundedFunded
: Fully funded and ready for fulfillmentWithdrawn
: Rewards claimed by solverRefunded
: Rewards returned to creator
Funding Validation
Token Recovery
Recover tokens mistakenly sent to vaults:- Cannot recover zero address
- Cannot recover any token in
reward.tokens
- Intent must have zero native rewards OR already be claimed/refunded
Intent Hashing
The Portal uses a deterministic hashing scheme:Execution Model
Source Chain Execution
The Portal transfers tokens from users to vaults:- Native tokens via
payable
function calls - ERC20 tokens via
SafeERC20.safeTransferFrom
- Excess ETH refunded automatically
Destination Chain Execution
The Portal delegates call execution to anExecutor
contract:
- Transfers tokens from solver to Executor
- Executor performs calls with delegated tokens
- Executor has no persistent state between transactions
- Portal storage is protected during arbitrary calls
- Failed calls don’t corrupt Portal state
- Executor can be upgraded independently
Security Features
Replay Protection
- Intent hashes are unique (include salt in route)
- Fulfilled intents cannot be fulfilled again
- Withdrawn/refunded intents cannot be withdrawn/refunded again
- ERC-7683 gasless orders use nonces
Validation
Publishing:- Cannot republish withdrawn/refunded intents
- Validates reward structure consistency
- Verifies intent hash matches route and reward
- Checks portal address in route matches contract
- Validates deadline hasn’t passed
- Prevents zero claimant address
- Requires minimum native token amount
- Validates intent is proven on correct destination
- Challenges proofs for incorrect destinations
- Prevents withdrawal before proof
- Only after deadline expiry
- Only if not proven on correct destination
- Prevents refund of claimed intents
Reentrancy Protection
All external calls are made through:SafeERC20
for token transfers- Isolated
Executor
for user-specified calls - State updates before external interactions
Cross-VM Compatibility
The Portal supports both EVM and non-EVM chains:Address Conversion
Claimant Identifiers
On destination chains, claimants are stored asbytes32
:
- EVM addresses (20 bytes, left-padded)
- Solana addresses (32 bytes)
- Other blockchain address formats
Events
IntentPublished
IntentFunded
IntentFulfilled
IntentProven
IntentWithdrawn
IntentRefunded
IntentTokenRecovered
Open (ERC-7683)
OrderFilled (ERC-7683)
Error Handling
ArrayLengthMismatch()
: Array parameters have mismatched lengthsChainIdTooLarge(uint256)
: Chain ID exceeds uint64 maximumInsufficientFunds(bytes32)
: Incomplete funding when partial not allowedInsufficientNativeAmount(uint256, uint256)
: Insufficient native tokens for executionIntentAlreadyExists(bytes32)
: Cannot republish existing intentIntentAlreadyFulfilled(bytes32)
: Intent already fulfilledIntentExpired()
: Past route deadlineIntentNotClaimed(bytes32)
: Cannot refund claimed intentIntentNotFulfilled(bytes32)
: Intent not in fulfilled stateInvalidClaimant()
: Zero address claimantInvalidHash(bytes32)
: Computed hash doesn’t match provided hashInvalidOriginChainId(uint256, uint256)
: Chain ID mismatch in ERC-7683 orderInvalidOriginSettler(address, address)
: Settler address mismatch in ERC-7683 orderInvalidPortal(address)
: Route portal doesn’t match contractInvalidRecoverToken(address)
: Cannot recover specified tokenInvalidSignature()
: EIP-712 signature verification failedInvalidStatusForFunding(Status)
: Cannot fund withdrawn/refunded intentInvalidStatusForRefund(Status, uint256, uint256)
: Invalid refund conditionsInvalidStatusForWithdrawal(Status)
: Cannot withdraw non-funded intentOpenDeadlinePassed()
: ERC-7683 order opening deadline exceededTypeSignatureMismatch()
: ERC-7683 orderDataType mismatchZeroClaimant()
: Claimant cannot be zero