Hook Executor

The HookExecutor is a helper contract deployed by Escrow to execute a sequence of on-chain hooks (typically DEX swaps) before locking funds for bridging. This lets the user convert their ERC20 tokens into a stable asset upfront so the Market Maker (MM) who fronts liquidity on the destination chain is not exposed to volatility risk.

Hooks are precomputed off-chain by calling the Most public API and are passed into Escrow.swapAndCreateOrder, which deploys a fresh HookExecutor via CREATE2, funds it, and triggers execution. When the swap completes, the executor returns the swapped tokens to Escrow, which then creates the order using the swapped token and amount.

Key Interfaces

  • Struct Hook:

    • target: address to call

    • callData: ABI-encoded calldata for the target

Execution Lifecycle

  1. Escrow.swapAndCreateOrder(...) deploys HookExecutor with CREATE2 (using hookExecutorSalt), and transfers the user’s _srcAmount of _srcToken to the executor.

  2. Escrow calls HookExecutor.execute(swapId, hooks, _srcToken, _expectedOutToken, address(this)).

  3. The executor:

    • Reads its tokenIn balance and approves each hooks[i].target to spend that balance.

    • Iterates through hooks and performs target.call(callData) in order.

    • Checks the resulting tokenOut balance; reverts if zero

    • Transfers all tokenOut to escrow and invokes onPreBridgeSwapReturn(swapId, tokenOut, amountOut) on Escrow

    • Verifies no residual tokenIn or tokenOut remain; reverts if any are left

    • Self-destructs to escrow (safe under EIP-6780 since creation and destruction occur in the same transaction)

If any hook call fails, the executor reverts the entire transaction (HookFailed). If tokenOut balance is zero at the end, it reverts (ZeroOutputTokens).

How Escrow Uses the Result

  • In swapAndCreateOrder, after execute returns, Escrow expects the executor to have called onPreBridgeSwapReturn

  • Escrow validates that the executor returned and provided a non-zero tokenOut address. It then sets the order’s source token/amount to the returned values and proceeds to create the order as usual

  • Escrow emits SwapCompleted with the swap details

Parameters and Constraints

  • hooks: Ordered list of calls to perform the swap route. Provided by the Most public API and passed through by the client.

  • tokenIn: ERC20 to be swapped. Swaps require ERC20; native ETH is not supported in the hook flow.

  • tokenOut: The expected output token address used by the executor to determine the balance to forward back to Escrow.

  • swapId: Unique identifier binding the executor run to a specific swapAndCreateOrder call.

Security and Safety Considerations

  • The executor only holds funds explicitly sent for this swap and destroys itself at the end; it reverts if any tokens remain unreturned, limiting any potential attack vectors.

  • Approvals are set per-hook target for the current executor tokenIn balance only.

  • Hooks are external calls and may be unsafe if crafted maliciously, however the risk is minimized with the creation and destruction of the HookExecutor with each call. In practice, they are generated by the Most public API; clients should validate slippage and route off-chain. In the near future the hooks passed will be computed and checked on the client side to prevent the need for any trust.

  • The flow is atomic: a failure in any hook or post-conditions reverts the entire swapAndCreateOrder call.

Minimal Flow

  1. User calls swapAndCreateOrder with _srcToken, _srcAmount, hooks, _expectedOutToken, and hookExecutorSalt.

  2. Escrow deploys HookExecutor, sends it _srcAmount, and calls execute.

  3. HookExecutor performs the swap route, sends tokenOut back, calls onPreBridgeSwapReturn, and self-destructs.

  4. Escrow records the swapped token/amount and creates the order.

Last updated