EIP-7702 enables smart account behavior for EOAs by allowing them to execute arbitrary calls via an authorization signature. This is especially useful for cross-chain transactions where the origin chain funds the destination chain execution, but the destination-side call must still reflect the user’s EOA as the msg.sender.

🚀 Support for EIP-7702 is live on testnets (e.g., Base Sepolia → Sepolia) and will be rolled out to mainnets soon.

When to use EIP-7702?

By default, the Solver is the sender (msg.sender) of destination chain transactions. This works well for simple “buy” use cases where the action can be routed to the user. But in many other scenarios (e.g. minting, selling, approvals), the contract logic relies on the caller being the user’s EOA.

EIP-7702 solves this by turning any EOA into a smart wallet, allowing relayed calls to preserve the original msg.sender. This unlocks new capabilities like:

  • Delegated execution: destination chain transactions that require the user as msg.sender
  • Cross-chain payment routing: use gas from one chain (e.g., Base) to pay for transactions on another (e.g., Sepolia)
  • Batched actions: approvals, minting, or function calls that must originate from the user

Relaying on the destination chain using EIP-7702

You can use EIP-7702 by passing an authorizationList inside the txs array during your /quote API call. The Solver will relay these transactions on the destination chain by passing the authorizationList while sending a type-4 transaction.

Here’s a complete example:

import { encodeFunctionData, parseEther, privateKeyToAccount } from "viem";
import axios from "axios";

// Step 1: Setup signer and smart account
const eoa7702 = privateKeyToAccount("EOA_PRIVATE_KEY");
const smartAccountImplementation = "0x000100abaad02f1cfC8Bbe32bD5a564817339E72"; // Replace with your smart account implementation

// Step 2: Sign EIP-7702 authorization
const authorizationHash = await sepoliaWalletClient.signAuthorization({
  account: eoa7702,
  contractAddress: smartAccountImplementation,
});

// Workaround for viem and RPC compatibility 
delete authorizationHash.v;
(authorizationHash as any).address = authorizationHash.contractAddress;

// Step 3: Encode batched destination chain calls
const executeCallData = encodeFunctionData({
  abi,
  functionName: "executeBatch",
  args: [
    [
      {
        target: eoa7702.address,
        value: parseEther("0.00001"),
        data: "0x",
      },
      {
        target: eoa7702.address,
        value: parseEther("0.00002"),
        data: "0x",
      },
    ],
  ],
});

// Step 4: Construct and send quote request
const requestData = {
  user: eoa7702.address,
  originChainId: baseSepolia.id,
  destinationChainId: sepolia.id,
  originCurrency: "0x0000000000000000000000000000000000000000",
  destinationCurrency: "0x0000000000000000000000000000000000000000",
  recipient: eoa7702.address,
  tradeType: "EXACT_OUTPUT",
  amount: "1000000000000000",
  useExternalLiquidity: false,
  txs: [
    {
      to: eoa7702.address,
      value: "0",
      data: executeCallData,
      authorizationList: [authorizationHash],
    },
  ],
};

const response = await axios.post(
  "https://api.testnets.relay.link/quote",
  requestData,
  {
    headers: {
      "Content-Type": "application/json",
    },
  }
);