Skip to main content
The Executor is an isolated contract that executes intent calls on the destination chain. It provides security isolation by separating arbitrary call execution from the Portal’s storage and balance.

Purpose

The Executor serves as a security boundary for intent execution: Without Executor:
With Executor:

Architecture

Key Properties:
  • One executor per Portal deployment
  • Stateless (no storage between transactions)
  • Only Portal can trigger execution
  • Receives tokens from solver before execution
  • Returns unused tokens/ETH to solver after execution

Access Control

The executor can only be called by the Portal that deployed it. This prevents:
  • Direct execution of arbitrary calls
  • Bypassing intent validation
  • Unauthorized token access

Execution Flow

Call Execution

Process:
  1. Portal validates intent and transfers tokens to executor
  2. Portal calls executor with intent’s call array
  3. Executor validates and executes each call sequentially
  4. Executor returns results to Portal
  5. Portal refunds unused ETH to solver

Single Call

Each call is executed with:
  • Target: Contract address to call
  • Value: Native token amount to send
  • Data: Encoded function call data
Validation:
  • Checks if call targets EOA with calldata (security check)
  • Uses low-level call() for execution
  • Reverts entire transaction if any call fails

Security Features

EOA Protection

Prevents calls to externally owned accounts (EOAs) when calldata is present:
Why this matters:
  • EOAs cannot execute code, so calldata is meaningless
  • Calldata to EOA might indicate misconfiguration
  • Prevents potential phishing where calldata appears to be a function call
Allowed:
  • Native token transfers to EOAs (zero calldata)
  • Calls to contracts (non-zero code length)
Blocked:
  • Calls to EOAs with calldata (suspicious pattern)

Storage Isolation

The Executor has no state variables except immutable portal:
  • Cannot be manipulated through reentrancy
  • No persistent state to corrupt
  • Fresh execution context for each intent

Atomic Execution

All calls execute atomically:
  • If any call fails, entire transaction reverts
  • No partial execution of intent
  • Solver either succeeds completely or loses only gas

Token Handling

Token Flow

Native Tokens

The Executor accepts ETH via:
Portal transfers route.nativeAmount to Executor before execution:

ERC20 Tokens

Portal transfers ERC20s to Executor before execution:
Executor then uses these tokens during call execution.

Call Structure

Example Calls

Token Swap:
Native Token Transfer:
Contract Interaction:

Error Handling

CallToEOA

Thrown when attempting to call an EOA with calldata. Resolution:
  • Remove calldata for simple transfers
  • Use correct contract address if calling contract
  • Verify target address is not an EOA

CallFailed

Thrown when any call execution fails. Contains:
  • Full call data (target, value, data)
  • Revert reason from failed call
Common Causes:
  • Insufficient token balance in executor
  • Reverted function on target contract
  • Out of gas
  • Invalid function selector

NonPortalCaller

Thrown when non-Portal address attempts execution. Resolution:
  • Only Portal can call executor
  • Use Portal’s fulfill methods instead of direct executor calls

Execution Patterns

Simple Transfer

Intent that sends tokens to recipient:
Executor transfers tokens that were sent to it by Portal.

Swap and Transfer

Intent that swaps tokens and sends result:

Multi-Step DeFi

Intent executing complex DeFi operations:

Gas Considerations

Per-Call Overhead

Each call incurs:
  • Call validation: ~2,000 gas (EOA check)
  • Low-level call: ~2,600 gas base, plus execution
  • Result handling: ~1,000 gas

Batch Optimization

Multiple calls in one intent are more efficient than separate intents:
  • Shared validation costs
  • Single token transfer from solver
  • Atomic execution reduces failure risk

Failed Call Costs

When a call fails:
  • Gas consumed up to failure point
  • Full transaction reverts (no state changes)
  • Solver pays gas but receives no reward

Integration Patterns

For Intent Creators

Encoding Calls:
Testing Calls:

For Solvers

Pre-Execution Validation:
Token Preparation:

Security Best Practices

For Intent Creators

  1. Test Thoroughly: Simulate all calls before publishing intent
  2. Minimal Privileges: Only include necessary calls in route
  3. Verify Targets: Ensure all target addresses are correct contracts
  4. Amount Validation: Verify all token amounts and values are correct
  5. Deadline Safety: Set appropriate route deadline for execution window

For Solvers

  1. Validate Before Fulfilling: Simulate execution to avoid wasted gas
  2. Check Token Balances: Ensure sufficient tokens to provide route amounts
  3. Gas Estimation: Estimate execution costs accurately
  4. Slippage Protection: Account for price changes in DEX calls
  5. Revert Analysis: Understand why calls might fail before executing

For Protocol Integrators

  1. Immutable Executor: Executor address never changes per Portal
  2. No Direct Calls: Never call executor directly, always through Portal
  3. Result Handling: Process execution results appropriately
  4. Error Recovery: Handle call failures gracefully in UI/SDK

Limitations

No Persistent State

Executor cannot:
  • Store data between transactions
  • Accumulate tokens across intents
  • Maintain allowances or permissions
Each execution starts fresh.

No Token Retention

After execution:
  • All tokens should be transferred to final destinations
  • Executor should have zero balance
  • Any remaining tokens are stuck until next execution
Best Practice: Include cleanup call to sweep any dust.

Sequential Execution

Calls execute in order:
  • Cannot parallelize
  • Later calls depend on earlier ones
  • Any failure reverts all
Design Consideration: Order calls carefully for dependencies.

Comparison to Alternatives

Direct Portal Execution

Executor Pattern (Current)

External Executor

The single stateless executor provides optimal balance of security, gas efficiency, and simplicity.