EIP.tools

EIP.tools

⚠️ DraftStandards Track: Interface

ERC-7882: Wallet Call Simulation API

Adds a JSON-RPC method for simulating execution of calls on a Wallet

Authors
Created2025-02-10
Discussion Linkhttps://ethereum-magicians.org/t/new-erc-wallet-call-simulation-api/22818
Requires

Markdown

https://raw.githubusercontent.com/ethereum/ERCs/re...
Pull Request#892PR open

EIP-GPT summary

Contents
AbstractMotivationSpecificationwalletsimulateCallsRequestResponseExampletraceAssetChanges CapabilitytraceMalicious CapabilityRationaleethsimulateV1 vs walletsimulateCallsBackwards CompatibilitySecurity ConsiderationsCopyright

Abstract

This ERC proposes a new JSON-RPC method for simulating the execution of calls on a Wallet. The method is designed to be used by Wallets to simulate the execution of calls before sending them to the network, allowing for gas estimation, log extraction, and call validation.

Motivation

Applications are reliant on JSON-RPC communication to Wallets in order to execute actions. A seemingly core functionality for "offline" Applications (Servers, etc) is the ability to simulate if an action will succeed or fail and/or estimate the total fee and/or calculate balance changes, prior to signing and broadcasting to the network.

Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

wallet_simulateCalls

Instructs a Wallet to simulate execution of a set of calls, and return metadata such as: the gas used, logs, status, and failure reason (if applicable).

Request

type Request = {
  method: 'wallet_simulateCalls',
  params: [{
    // Calls to simulate.
    calls: {
      to: `0x${string}`,
      data?: `0x${string}`,
      value?: `0x${string}`,
      capabilities?: Record<string, any>;
    }[],
    // Target chain ID to simulate calls on.
    chainId: `0x${string}`,
    // ERC-5792 Capabilities request.
    capabilities?: Record<string, any>;
    // Sender address.
    from?: `0x${string}`;
    // Key (hint) that will be used to sign the call bundle.
    key?: {
      // Whether the digest will be prehashed by the key (default behavior of WebCrypto APIs).
      prehash?: boolean,
      // Public key.
      publicKey: `0x${string}`,
      // Key type.
      type: 'secp256k1' | 'p256' | 'webauthn-p256'
    };
    // Version.
    version: string;
  }]
}

Response

type Response = {
  // Chain ID the calls were simulated on.
  chainId: `0x${string}`;
  // Estimated total gas used by the calls.
  gasUsed: `0x${string}`;
  // Logs emitted by the calls.
  logs: {
    address: `0x${string}`;
    data: `0x${string}`;
    topics: `0x${string}`[];
  }[];
  // ERC-5792 Capabilities results.
  capabilities?: Record<string, any>;
  // Error that occurred during simulation.
  error?: {
    message: string;
    data?: `0x${string}`;
    details?: string;
  },
  // Status code of the simulation. 
  status: number;
}

Example

Successful Simulation
const response = await provider.request({
  method: 'wallet_simulateCalls',
  params: [{
    calls: [{
      to: '0xcafebabecafebabecafebabecafebabecafebabe',
      data: '0xdeadbeef',
    }],
    chainId: '0x1',
    from: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
    version: '1',
  }],
});

console.log(response);
/**
 * {
 *  chainId: '0x1',
 *  gasUsed: '0xe208',
 *  logs: [{
 *    address: '0xcafebabecafebabecafebabecafebabecafebabe',
 *    data: '0x0000000000000000000000000000000000000000000000000000000000069420',
 *    topics: [
 *      '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
 *      '0x000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
 *      '0x000000000000000000000000cafebabecafebabecafebabecafebabecafebabe',
 *    ],
 *  }],
 *  status: 200,
 * }
 */
Failed Simulation (Onchain Failure)
const response = await provider.request({
  method: 'wallet_simulateCalls',
  params: [{
    calls: [{
      to: '0xba11ba11ba11ba11ba11ba11ba11ba11ba11ba11',
      data: '0xbabebabe0000000000000000000000000000000000000000000000000000000000000001',
    }],
    chainId: '0x1',
    from: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
    version: '1',
  }],
});

console.log(response);
/**
 * {
 *  chainId: '0x1',
 *  gasUsed: '0xe208',
 *  error: {
 *    message: 'Token ID is taken.',
 *    details: 'execution reverted: TokenIdUnavailable()',
 *    data: '0x08c379a0',
 *  },
 *  status: 500,
 * }
 */
Failed Simulation (Offchain Failure)
const response = await provider.request({
  method: 'wallet_simulateCalls',
  params: [{
    calls: [{
      to: '0xba11ba11ba11ba11ba11ba11ba11ba11ba11ba11',
      data: '0xbabebabe0000000000000000000000000000000000000000000000000000000000000001',
    }],
    chainId: '0x1',
    from: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
    version: '1',
  }],
});

console.log(response);
/**
 * {
 *  chainId: '0x1',
 *  gasUsed: '0xe208',
 *  error: {
 *    message: 'Paymaster balance is insufficient.',
 *    details: 'useroperation reverted during simulation with reason: aa26',
 *  },
 *  status: 400,
 * }
 */

traceAssetChanges Capability

Capability to trace ERC20 & Native asset changes. Needs discussion.

traceMalicious Capability

Capability to trace malicious calls. Needs discussion.

Rationale

eth_simulateV1 vs wallet_simulateCalls

The eth_simulateV1 Execution API method is very similar to wallet_simulateCalls in that they both simulate the execution of calls on a Wallet. However, the fundamental differences are that eth_simulateV1: is not account agnostic, is an Execution API method (not a Wallet API method), and assumes that regular transactions will be executed. It does not have knowledge of the implementation details of how the Wallet constructs transactions (ie. they could be wrapped as an ERC-4337 User Operation with a Paymaster, or wrapped as another type of abstraction, which consequently would affect the simulation results).

wallet_simulateCalls is account agnostic, meaning that it is aware of the implementation details of how the Wallet constructs transactions. As the Wallet handles wallet_simulateCalls and returns a response to the Application, this means that the Wallet can simulate the calls with the full context of its implementation details (ie. simulate as a regular transaction, a ERC-4337 User Operation, or something else entirely).

It is very well possible that a Wallet can "build" the transaction with their preferred account implementation, use eth_simulateV1 internally to simulate the calls, and use it to build the response for wallet_simulateCalls.

Backwards Compatibility

Needs discussion.

Security Considerations

Needs discussion.

Copyright and related rights waived via CC0.

EIP.tools

EIP.tools

Search, read, and map Ethereum improvement proposals, ERCs, RIPs, and CAIPs from one focused interface.

Farcaster
by @apoorveth