Skip to main content

Call Abstraction Protocol

New Protocol Primitive

Call Abstraction is the distilled core of CrossCall — the minimal specification that makes crosschain execution possible without bridges. Everything in the CrossCall stack is built on top of this primitive.

What Is Call Abstraction?

Call Abstraction separates who signs a transaction from who executes it and where.

In a normal EVM flow, the signer must have funds on the chain where they want to execute. Call Abstraction breaks that requirement: a signer on Chain A can authorize a transaction on Chain B, and a solver on Chain B executes it — while the signer's funds on Chain A pay for it, deterministically, via a crosschain message.

The result: native execution on any chain, funded from anywhere.


The Three Roles

Signer

The user or protocol authorizing a transaction. The signer:

  • Holds funds on their origin chain (locked in their Escrow contract)
  • Signs a call intent specifying what should execute and where
  • Never needs to hold funds on the destination chain

Solver

A permissionless actor that executes on behalf of signers. The solver:

  • Monitors the CrossCall mempool for call intents
  • Fronts the liquidity required for execution on the destination chain
  • Is deterministically repaid from the signer's escrow via Hyperlane

CrossCall Protocol

The infrastructure layer that:

  • Validates intents and manages the mempool
  • Routes solver payout through the CrossCall Paymaster + Hyperlane
  • Guarantees atomicity — the solver is only paid if execution succeeded

The Call Intent

A call intent is the signed payload a signer produces. It contains everything a solver needs to execute and be paid.

// The execution specification
type ExecutionData struct {
DestinationChain string `json:"destinationChain"` // where to execute
TargetAddress string `json:"targetAddress"` // what contract
Asset string `json:"asset"` // payment asset
Amount string `json:"amount"` // locked amount
Calldata string `json:"calldata"` // what to call
}

// The ERC-4337 userop for execution on the destination chain
type UserOperation struct {
Sender string `json:"sender"`
Nonce string `json:"nonce"`
InitCode string `json:"initCode"`
CallData string `json:"callData"`
CallGasLimit string `json:"callGasLimit"`
VerificationGasLimit string `json:"verificationGasLimit"`
PreVerificationGas string `json:"preVerificationGas"`
MaxFeePerGas string `json:"maxFeePerGas"`
MaxPriorityFeePerGas string `json:"maxPriorityFeePerGas"`
PaymasterAndData string `json:"paymasterAndData"`
Signature string `json:"signature"`
}

// The complete blob submitted to the mempool
type ExecutableBlob struct {
ExecutionRequest ExecutionData `json:"execution"`
UserOp UserOperation `json:"userop"`
}

The PaymasterAndData field is generated by the CrossCall API and encodes the crosschain payment instruction:

struct PaymasterAndData {
address paymaster; // CrossCall Paymaster address
address owner; // signer identity
uint256 chainId; // origin chain (where escrow lives)
address asset; // asset locked in escrow
uint256 amount; // amount authorized for solver payout
}

Execution Flow

 Signer (Origin Chain)
├── Locks funds in Escrow
└── Signs: ExecutionData + UserOperation


CrossCall API
├── Simulates transaction
├── Estimates costs (gas, validation, solver bid)
└── Returns: lock request + userop


CrossCall Client
├── Validates lock on-chain (origin RPC)
├── Simulates userop (with paymaster pre-execution)
└── Admits blob to Mempool


Solver (Destination Chain)
├── [1] Pays CrossCall Paymaster (Hyperlane costs)
├── [2] Funds Signer's SCW (gas + execution)
└── [3] Executes Signer's UserOp ◄── ATOMIC


CrossCall Paymaster
├── preOp: validates PaymasterAndData, builds Hyperlane message
└── postOp: pays Hyperlane IGP, redeposits stake, returns residual to solver


Hyperlane Network
└── Delivers message to Origin Chain


Signer's Escrow (Origin Chain)
├── Validates message hash
└── Pays solver: execution costs + bid ✓

Atomicity Guarantee

The entire execution bundle is atomic at two levels:

Bundle atomicity (destination chain): The solver's three-step bundle — fund paymaster, fund SCW, execute userop — is submitted as a single atomic ERC-4337 bundle. If the userop fails, the paymaster is never funded and the Hyperlane message is never sent.

Payout atomicity (crosschain): The CrossCall Paymaster only submits the Hyperlane payout message in postOp, which only fires if preOp and execution both succeeded. This means the solver payout is cryptographically guaranteed to occur if and only if execution succeeded.

There is no state where:

  • Execution happens but the solver isn't paid
  • The solver is paid but execution didn't happen
  • Partial execution leaves funds stranded

Escrow Contract

Every signer has a deterministic Escrow address derived via create2. The Escrow is a lightweight ERC-1967 proxy.

function createEscrow(
bytes memory _initializer,
bytes32 _salt
) external returns (address proxy) {
bytes memory deploymentData = abi.encodePacked(
type(EscrowProxy).creationCode,
_ESCROWIMPL
);
bytes32 salt = _calcSalt(_initializer, _salt);
assembly ("memory-safe") {
proxy := create2(0x0, add(deploymentData, 0x20), mload(deploymentData), salt)
}
if (proxy == address(0)) revert();
assembly ("memory-safe") {
let succ := call(gas(), proxy, 0, add(_initializer, 0x20), mload(_initializer), 0, 0)
if eq(succ, 0) { revert(0, 0) }
}
return proxy;
}

The Escrow:

  • Tracks locked and unlocked token balances per signer
  • Validates incoming Hyperlane messages against the original lock hash
  • Executes solver payout on successful validation
  • Is non-custodial — only the signer's locked funds are ever used for payouts

Security Properties

PropertyGuarantee
Signer can't be drainedOnly locked amounts (specified by signer) are ever paid out
Solver can't be stiffedPayout is atomic with execution — if execution happened, payout happens
No bridge pool to hackNo centralized liquidity pool exists in the flow
Deterministic payoutHyperlane message is constructed deterministically in preOp; solver address is bound at execution time
Full revert on failureAny step failing reverts the entire bundle; no partial state

Relationship to ERC-4337

Call Abstraction is built on ERC-4337 Account Abstraction. The CrossCall Paymaster is a standard ERC-4337 paymaster that extends the _validatePaymasterUserOp and _postOpHandler hooks to add crosschain payout logic.

This means CrossCall is composable with any ERC-4337-compatible smart contract wallet, EntryPoint deployment, or bundler infrastructure — with CrossCall-specific behavior activated only via the paymasterAndData field.