EIP.tools

EIP.tools

⚠️ DraftStandards Track: ERC

ERC-7989: Ethereum Intent URI (EIURI)

A Universal action URI format for Ethereum (represent and trigger Ethereum JSON-RPC requests)

Authors
Created2025-01-27
Discussion Linkhttps://ethereum-magicians.org/t/eip-7933-ethereum-intent-uri-eiuri-a-universal-action-uri-format-for-ethereum/23554
Requires

Markdown

https://raw.githubusercontent.com/frani/ERCs/refs/...

EIP-GPT summary

Contents
AbstractMotivationSpecificationSpecial ValuesCURRENTACCOUNTZero Address PlaceholderJSON-like Bracket NotationRequired ComponentsOptional ComponentsExamplesethsendTransactionwalletaddEthereumChainmultiRequestRationaleBackwards CompatibilityTest CasesTest Case 1: Basic ethsendTransactionTest Case 2: walletaddEthereumChain with Nested ParametersTest Case 3: Multi-Request with Base64 EncodingReference ImplementationSecurity ConsiderationsSecurity RecommendationsCopyright

Abstract

This ERC introduces a standardized URI format for representing and triggering Ethereum JSON-RPC requests, allowing users to execute blockchain actions directly via URLs or QR codes. It extends the existing ethereum: URI scheme by supporting full RPC methods, optional chain identifiers, and additional semantic metadata such as intent, enhancing Web3 UX and interoperability across wallets.

Motivation

ERC-681 introduced a way to encode Ethereum payment requests via URIs, laying the foundation for user-friendly interactions such as QR-code based payments. However, its scope is limited to eth_sendTransaction and lacks flexibility for more complex interactions, such as multi-call sequences, RPC methods beyond simple transfers, and chain-specific contexts.

As the ecosystem matures, users are increasingly performing a variety of Web3 actions—depositing into vaults, interacting with smart contracts, switching chains, or batch-signing transactions—all of which are not easily represented within the current URI standard.

This proposal aims to extend the URI pattern introduced in ERC-681 to support:

  • Arbitrary RPC calls (e.g., wallet_addEthereumChain, eth_call, eth_signTypedData)
  • Chained or multi-step requests via base64-encoded payloads
  • A clear and consistent way to encode the target chain (via chainId)
  • A more versatile way to encode intent (e.g., "deposit", "swap", "vote", etc.)
  • Seamless QR-based user interactions without requiring wallet connection or dapp session

By standardizing this flexible URI format, wallets can parse and act on requests directly from a link or QR code, enabling smoother real-world interactions and improving onboarding, security, and UX across Ethereum applications.

Specification

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

The URI format extends the current ethereum: scheme:

request                 = schema_prefix [ rpc_method ] [ "-" target_address ] [ "@" chain_id ] [ "?" parameters ]
schema_prefix           = "ethereum" ":" [ "pay-" / rpc_method "-" ]
rpc_method             = STRING
target_address         = ethereum_address / "CURRENT_ACCOUNT"
chain_id               = 1*DIGIT
ethereum_address       = ( "0x" 40*HEXDIG ) / ENS_NAME
parameters             = parameter *( "&" parameter )
parameter              = key "=" value
key                    = STRING
value                  = number / ethereum_address / STRING / base64_string / hex_value / "CURRENT_ACCOUNT"
number                 = [ "-" / "+" ] *DIGIT [ "." 1*DIGIT ] [ ( "e" / "E" ) [ 1*DIGIT ] ]
base64_string          = *( ALPHA / DIGIT / "+" / "/" ) [ "=" [ "=" ] ]
hex_value              = "0x" 1*HEXDIG

ethereum:<rpc_method>-0x0000000000000000000000000000000000000000@<chain_id>[\?<key>=<value>&...]

Special Values

CURRENT_ACCOUNT

The special value CURRENT_ACCOUNT is a placeholder that will be replaced by the wallet implementation with the user's currently selected Ethereum address. When a wallet encounters this placeholder in the URI, it SHOULD substitute the user's current active address before processing the request. This allows URIs to be created that dynamically target the user's active wallet address without needing to know it in advance. The uppercase format follows common convention for symbolic constants.

Zero Address Placeholder

The zero address (0x0000000000000000000000000000000000000000) is used as a placeholder in URIs when calling RPC methods that don't require a target address. This maintains consistency with the URI format while allowing for RPC calls like wallet_addEthereumChain or eth_chainId that operate at the wallet/node level rather than targeting a specific contract. Wallets SHOULD ignore this zero address for methods where it's not relevant to the operation.

JSON-like Bracket Notation

For parameters that represent nested objects or arrays, the URI format supports JSON-like bracket notation:

  • Objects: Use [key] to denote nested object properties
  • Arrays: Use [index] to denote array elements

For example, a nested object parameter like:

{
  "chainId": "0x1",
  "chainName": "Ethereum Mainnet",
  "rpcUrls": ["https://example.com/v3/..."],
  "iconUrls": ["https://example.com/icon.png"],
  "nativeCurrency": {
    "name": "Ether",
    "symbol": "ETH",
    "decimals": 18
  },
  "blockExplorerUrls": ["https://example.com"]
}

Can be represented as:

ethereum:wallet_addEthereumChain-0x0000000000000000000000000000000000000000?chainId=0x1&chainName=Ethereum%20Mainnet&rpcUrls[0]=https%3A%2F%2Fexample.com%2Fv3%2F...&iconUrls[0]=https%3A%2F%2Fexample.com%2Ficon.png&nativeCurrency[name]=Ether&nativeCurrency[symbol]=ETH&nativeCurrency[decimals]=18&blockExplorerUrls[0]=https%3A%2F%2Fexample.com

Required Components

  • rpc_method: any valid Ethereum JSON-RPC method supported by the wallet (e.g. eth_sendTransaction, wallet_addEthereumChain, etc.)
  • chain_id: optional chain identifier (e.g. 1 for Ethereum Mainnet, 324 for ZkSync Era)
  • URL parameters: key-value pairs representing the parameters of the RPC method

Optional Components

  • requests_b64: for multi-request, a base64-encoded array of RPC calls

Examples

eth_sendTransaction

ethereum:eth_sendTransaction-0x0000000000000000000000000000000000000000@324?from=CURRENT_ACCOUNT&to=0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238&gas=0x76c0&gasPrice=0x4a817c800&value=0x0&data=0xa9059cbb000000000000000000000000ffce4d191cb5007ee9ad7226581f7e217b68cafe00000000000000000000000000000000000000000000000000000000000f4240636166656369746f

wallet_addEthereumChain

ethereum:wallet_addEthereumChain-0x0000000000000000000000000000000000000000?chainId=0x64&chainName=Gnosis&rpcUrls[0]=https%3A%2F%2Fexample.com&iconUrls[0]=https%3A%2F%2Fexample.com%2Ficon.svg%2Chttps%3A%2F%2Fexample.com%2Ficon.png&nativeCurrency[name]=xDAI&nativeCurrency[symbol]=xDAI&nativeCurrency[decimals]=18&blockExplorerUrls[0]=https%3A%2F%2Fexample.com

multiRequest

ethereum:multiRequest-0x0000000000000000000000000000000000000000@324?requests_b64=W3sibWV0aG9kIjoid2FsbGV0X3N3aXRjaEV0aGVyZXVtQ2hhaW4iLCJwYXJhbXMiOlt7ImNoYWluSWQiOiIweDE0NCJ9XX0seyJtZXRob2QiOiJldGhfc2VuZFRyYW5zYWN0aW9uIiwicGFyYW1zIjpbeyJmcm9tIjoiMHg4MDgyZGE2NzcxMGMxNGU3ZjY2OGVmYzczYWMyN2FkNmIyZDdjYWZlIiwidG8iOiIweDFjN0Q0QjE5NkNiMEM3QjAxZDc0M0ZiYzYxMTZhOTAyMzc5QzcyMzgiLCJnYXMiOiIweDc2YzAiLCJnYXNQcmljZSI6IjB4NGE4MTdjODAwIiwidmFsdWUiOiIweDAiLCJkYXRhIjoiMHhhOTA1OWNiYjAwMDAwMDAwMDAwMDAwMDAwMDBmZmNlNGQxOTFjYjUwMDdlZTlhZDcyMjY1ODFmN2UyMTdiNjhjYWZlMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwZjQyNDA2MzYxNmY2NjYzNjk3In1dfV0=

Rationale

  • Intents allow wallet interfaces to preemptively guide users through transactions with clear context.
  • Chain-specific targeting improves safety and predictability across networks.
  • Multi-request support allows for batch operations, simplifying advanced workflows (e.g., approval + vault deposit).
  • QR-friendly design enables real-world usage (e.g., payments, POS, offline signing).

Alternate designs such as JSON files or app links introduce complexity and dependency on frontend apps, while EI-URI stays fully compatible with existing URI schemes and QR infrastructure.

Backwards Compatibility

The proposed format extends the existing ethereum: URI standard but remains backward-compatible. Wallets that do not support the extended format will simply ignore unknown parameters.

Test Cases

Test Case 1: Basic eth_sendTransaction

Input:

ethereum:eth_sendTransaction-0x0000000000000000000000000000000000000000@1?from=CURRENT_ACCOUNT&to=0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6&value=0xde0b6b3a7640000

Expected Output:

  • RPC Method: eth_sendTransaction
  • Chain ID: 1 (Ethereum Mainnet)
  • Parameters: from (user's current account), to (0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6), value (1 ETH)

Test Case 2: wallet_addEthereumChain with Nested Parameters

Input:

ethereum:wallet_addEthereumChain-0x0000000000000000000000000000000000000000?chainId=0x89&chainName=Polygon&rpcUrls[0]=https://polygon-rpc.com&nativeCurrency[name]=MATIC&nativeCurrency[symbol]=MATIC&nativeCurrency[decimals]=18

Expected Output:

  • RPC Method: wallet_addEthereumChain
  • Parameters: Properly parsed nested object with chain configuration for Polygon

Test Case 3: Multi-Request with Base64 Encoding

Input:

ethereum:multiRequest-0x0000000000000000000000000000000000000000@1?requests_b64=W3sibWV0aG9kIjoiZXRoX2NoYWluSWQiLCJwYXJhbXMiOltdfV0=

Expected Output:

  • RPC Method: multiRequest
  • Chain ID: 1
  • Decoded requests: [{"method":"eth_chainId","params":[]}]

Reference Implementation

class EthereumIntentURI {
  constructor(uri) {
    this.uri = uri;
    this.parsed = this.parse();
  }

  parse() {
    const regex = /^ethereum:([^-@?]+)(?:-([^@?]+))?(?:@(\d+))?(?:\?(.+))?$/;
    const match = this.uri.match(regex);
    
    if (!match) {
      throw new Error('Invalid Ethereum Intent URI format');
    }

    const [, rpcMethod, targetAddress, chainId, queryString] = match;
    
    return {
      rpcMethod,
      targetAddress: targetAddress || '0x0000000000000000000000000000000000000000',
      chainId: chainId ? parseInt(chainId) : null,
      parameters: this.parseQueryString(queryString)
    };
  }

  parseQueryString(queryString) {
    if (!queryString) return {};
    
    const params = {};
    const pairs = queryString.split('&');
    
    for (const pair of pairs) {
      const [key, value] = pair.split('=');
      const decodedKey = decodeURIComponent(key);
      const decodedValue = decodeURIComponent(value);
      
      // Handle bracket notation for nested objects/arrays
      const bracketMatch = decodedKey.match(/^(.+)\[([^\]]+)\]$/);
      if (bracketMatch) {
        const [, baseKey, index] = bracketMatch;
        if (!params[baseKey]) {
          params[baseKey] = isNaN(index) ? {} : [];
        }
        params[baseKey][isNaN(index) ? index : parseInt(index)] = decodedValue;
      } else {
        params[decodedKey] = decodedValue;
      }
    }
    
    return params;
  }

  toRPCRequest() {
    const { rpcMethod, parameters } = this.parsed;
    
    if (rpcMethod === 'multiRequest') {
      const requestsB64 = parameters.requests_b64;
      if (!requestsB64) {
        throw new Error('multiRequest requires requests_b64 parameter');
      }
      return JSON.parse(atob(requestsB64));
    }
    
    return {
      method: rpcMethod,
      params: [parameters]
    };
  }
}

// Usage example
const uri = new EthereumIntentURI('ethereum:eth_sendTransaction-0x0000000000000000000000000000000000000000@1?from=CURRENT_ACCOUNT&to=0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6&value=0xde0b6b3a7640000');
const rpcRequest = uri.toRPCRequest();
console.log(rpcRequest);

Security Considerations

Wallets MUST validate all parameters before executing actions. Special care must be taken with multi-request, base64 decoding, and default values like gas or value to avoid exploits or phishing vectors.

Security Recommendations

  1. Parameter Validation: All parameters should be validated against expected types and ranges before execution.

  2. Base64 Decoding: When decoding requests_b64, wallets should validate the decoded JSON structure and limit the size of the decoded data.

  3. Chain ID Validation: Wallets should verify that the specified chain ID is supported and matches the user's current network context.

  4. Address Validation: All Ethereum addresses should be validated for proper checksum format and length.

  5. Gas Limit Protection: Wallets should implement reasonable gas limits and warn users about potentially expensive operations.

  6. Phishing Prevention: Wallets should display clear information about the action being performed and allow users to review all parameters before confirmation.

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