Crosschain API - Lamina’s forward-facing API interface. Protocols talk to the Crosschain API by sending transaction calldata and target information (chain, address, cost). Crosschain does the heavy lifting on the backend, wrapping userops and calculating the overall transaction cost, then returns data for the protocol to sign before forwarding said signed data as a blob to the Crosschain Client.
Crosschain Client - Lamina's backend infrastructure responsible for lock request execution and userop validation. This client currently comprises of a private bundler and relayer but is expected to scale by offering a reward-based model to bring new bundlers and relayers into the fold.
Crosschain Mempool - Lamina’s Crosschain Mempool is a currently a private mempool with custom blobs of data. These blobs include a proposed bid, execution cost, and userop. Solvers digest these blobs and execute an array of userops on the destination chain’s ERC4337 EntryPoint contract.
Crosschain Paymaster - Lamina's userop paymaster. During preOp the paymaster validates the userop and digests the paymasterAndData field. Then constructs the Hyperlane message for later authentication on the origin chain. Extra data from the paymasterAndData field will be appended with the Solver's address. During postOp the paymaster will pay for the Hyperlane IGP and redeposit used funds to it's own stake and send residual funds back to the Solver.
// PaymasterAndData Field (generated by Crosschain API):structPaymasterAndData {address paymaster;address owner;uint256 chainId;address asset;uint256 amount;}// preOp execution:function_validatePaymasterUserOp(UserOperationcalldata userOp,bytes32,uint256 requiredPreFund ) internaloverridereturns (bytesmemory context,uint256 validationResult) {unchecked {bytescalldata data = userOp.paymasterAndData;uint256 paymasterAndDataLength = data.length;// 124 == crosschain non-payableif (paymasterAndDataLength !=124&& paymasterAndDataLength !=176) {revertInvalidDataLength(paymasterAndDataLength); }address paymaster_ =address(bytes20(data[:20]));address owner_ =address(bytes20(data[20:40]));uint256 chainId_ =uint256(bytes32(data[40:72]));address paymentAsset_ =address(bytes20(data[72:92]));uint256 paymentAmount_ =uint256(bytes32(data[92:124]));bytes32 messageId_;uint256 gasAmount_ =100000;uint32 destinationDomain_ =uint32(chainId_);if (!acceptedChain[destinationDomain_]) {revertInvalidChainId(destinationDomain_); }// enabled only for MVP; tbh we don't care about the assets used, network is P2Pif (!acceptedAsset[destinationDomain_][paymentAsset_]) {revertInvalidAsset(destinationDomain_, paymentAsset_); }// withdraw funds for oracle call to paymaster// nope, let it fail if the paymaster has insufficent funds, solver should know better// entryPoint.withdrawTo(payable(address(this)), 0.1 ether);// the bundler/ solver that submits the tx from the uomempool// in reality we don't care who executes, but they are burdened with refinding the paymaster and tx costaddress receiver = tx.origin;bytes32 recipientAddress_ =bytes32(uint256(uint160(receiver)));IMailbox(hyperlane_mailbox).dispatch( destinationDomain_, recipientAddress_, abi.encode(userOp, receiver) );uint256 igpQuote_ =IIGP(hyperlane_igp).quoteGasPayment( destinationDomain_, gasAmount_ ); context = abi.encode( receiver, messageId_, destinationDomain_, gasAmount_, igpQuote_ ); } }// postOp refundfunction_postOp(PostOpMode mode,bytescalldata context,uint256 actualGasCost ) internaloverride {// don't care about the mode, solver fronts the gas (mode);bytes32 messageId_;uint32 destinationDomain_;uint256 gasAmount_;uint256 igpQuote_;address refundAddress_; ( refundAddress_, messageId_, destinationDomain_, gasAmount_, igpQuote_ ) = abi.decode(context, (address,bytes32,uint32,uint256,uint256));IIGP(hyperlane_igp).payForGas{value:address(this).balance}( messageId_, destinationDomain_, gasAmount_,address(this) ); entryPoint{ value: gasAmount_ }.addStake(0);// shouldn't revert, but doesn't matterpayable(refundAddress_).call{ value:address(this).balance }(""); }
Hyperlane
Hyperlane Mailbox - The mailbox, for Hyperlane messages, acts as either the receiver contract on destination chains, or the sender contract on origin chains. Hyperlane messages transmitted or received include: target chain, target address, value, and message. When a valid message received on the origin chain it will be added to the Hyperlane network with a pending state until payment is accepted by the Hyperlane IGP. When a valid message is received on the destination chain it will use the message data to call the target contract. Learn more here.
Hyperlane IGP (Interchain Gas Paymaster) - The gas paymaster estimates this native currency cost required to process the submitted Hyperlane message. The gas requirements must be quoted after the Hyperlane message is submitted. Crosschain Paymaster quotes the cost of a Hyperlane message during preOp and submits payment during postOp. This approach ensures that the Hyperlane message is triggered only if the userop is executed successfully. Learn more here.
Hyperlane Validator - The Hyperlane network on any chain includes a series of validators that process transactions on destination chains. Learn more here.
Hyperlane Handler - The handle function on the target contract accepting a message from the Hyperlane Mailbox on the destination chain. Learn more here.
Escrow
Escrow - Every signer has a create2 escrow address. The Escrow is a lightweight ERC1967 proxy that supports tracking of any lock or unlocked token. Only the signers locked funds are used for paying solvers. When receiving a Hyperlane message to handle it will validate and then execute the Solver payout.
Escrow Factory - Factory contract for initializing a signer’s ERC1967 Escrow.