EIP 1193: Ethereum Provider JavaScript API Source

AuthorFabian Vogelsteller, Ryan Ghods, Victor Maia, Marc Garreau
Discussions-Tohttps://github.com/ethereum/EIPs/issues/2319
StatusDraft
TypeStandards Track
CategoryInterface
Created2018-06-30
Requires 155, 695, 1102, 1474, 1767

Summary

This EIP formalizes a JavaScript Ethereum Provider API for consistency across clients and applications.

The Provider is intended to be available as globalThis.ethereum (i.e. window.ethereum in browsers), so that JavaScript dapps can be written once and function in perpetuity.

The Provider’s interface is designed to be minimal, preferring that features are introduced in the API layer (e.g. see eth_requestAccounts), and agnostic of transport and RPC protocols.

The events connect, close, chainChanged, and accountsChanged are provided as a convenience to help enable reactive dapp UIs.

API

request

Makes an Ethereum RPC method call.

type RequestParams = Array<any> | { [key: string]: any };

ethereum.request(method: string, params?: RequestParams): Promise<unknown>;

The Promise resolves with the method’s result or rejects with an Error. For example:

ethereum
  .request('eth_accounts')
  .then((accounts) => console.log(accounts))
  .catch((error) => console.error(error));

Consult each Ethereum RPC method’s documentation for its return type. You can find a list of common methods here.

The Promise rejects with errors of the following form:

{
  message: string,
  code: number,
  data?: any
}

See the RPC Errors section for more details.

RPC Protocols

Multiple RPC protocols may be available.

EIP 1474 specifies the Ethereum JSON-RPC API.

EIP 1767 specifies the Ethereum GraphQL schema.

sendAsync (DEPRECATED)

Submits a JSON-RPC request to the Provider. As ethereum.request, but with JSON-RPC objects and a callback.

ethereum.sendAsync(request: Object, callback: Function): Object;

The interfaces of request and response objects are not specified here. Historically, they have followed the Ethereum JSON-RPC specification.

send (DEPRECATED)

Due to conflicting implementations and specifications, this method is unreliable and should not be used.

ethereum.send(...args: Array<any>): unknown;

Events

Events follow the Node.js EventEmitter API.

connect

The Provider emits connect when it:

  • first connects to a chain after being initialized.
  • first connects to a chain, after the close event was emitted.
interface ProviderConnectInfo {
  chainId: string;
  [key: string]: unknown;
}

ethereum.on('connect', listener: (connectInfo: ProviderConnectInfo) => void): ethereum;

The event emits an object with a hexadecimal string chainId per the eth_chainId Ethereum RPC method, and other properties as determined by the Provider.

close

The Provider emits close when it becomes disconnected from all chains.

ethereum.on('close', listener: (code: number, reason: string) => void): ethereum;

This event emits with code and reason. The code follows the table of CloseEvent status codes.

chainChanged

The Provider emits chainChanged when connecting to a new chain.

ethereum.on('chainChanged', listener: (chainId: string) => void): ethereum;

The event emits a hexadecimal string chainId per the eth_chainId Ethereum RPC method.

networkChanged (DEPRECATED)

The event networkChanged is deprecated in favor of chainChanged. For details, see EIP 155: Simple replay attack protection and EIP 695: Create eth_chainId method for JSON-RPC.

accountsChanged

The Provider emits accountsChanged if the accounts returned from the Provider (eth_accounts) change.

ethereum.on('accountsChanged', listener: (accounts: Array<string>) => void): ethereum;

The event emits with accounts, an array of account addresses, per the eth_accounts Ethereum RPC method.

message

The Provider emits message to communicate arbitrary messages to the consumer. Messages may include JSON-RPC notifications, GraphQL subscriptions, and/or any other event as defined by the Provider.

interface ProviderMessage {
  type: string;
  data: unknown;
}

ethereum.on('message', listener: (notification: ProviderMessage) => void): Provider;
Subscriptions

Some clients like Geth and Parity support Publish-Subscribe (Pub-Sub) using JSON-RPC notifications. This lets you subscribe and wait for events instead of polling for them. See the eth_ subscription methods and shh_ subscription methods for details.

For e.g. eth_subscribe subscription updates, ProviderMessage.type will equal the string 'eth_subscription'.

notification (DEPRECATED)

This event should not be relied upon, and may not be implemented.

Historically, it has returned e.g. eth_subscribe subscription updates of the form { subscription: string, result: unknown }.

Examples

const ethereum = window.ethereum;

// A) Set Provider in web3.js
var web3 = new Web3(ethereum);
// web3.eth.getBlock('latest', true).then(...)

// B) Use Provider object directly
// Example 1: Log chainId
ethereum
  .request('eth_chainId')
  .then((chainId) => {
    console.log(`hexadecimal string: ${chainId}`);
    console.log(`decimal number: ${parseInt(chainId, 16)}`);
  })
  .catch((error) => {
    console.error(`Error fetching chainId: ${error.code}: ${error.message}`);
  });

// Example 2: Log last block
ethereum
  .request('eth_getBlockByNumber', ['latest', 'true'])
  .then((block) => {
    console.log(`Block ${block.number}:`, block);
  })
  .catch((error) => {
    console.error(
      `Error fetching last block: ${error.message}.
       Code: ${error.code}. Data: ${error.data}`
    );
  });

// Example 3: Log available accounts
ethereum
  .request('eth_accounts')
  .then((accounts) => {
    console.log(`Accounts:\n${accounts.join('\n')}`);
  })
  .catch((error) => {
    console.error(
      `Error fetching accounts: ${error.message}.
       Code: ${error.code}. Data: ${error.data}`
    );
  });

// Example 4: Log new blocks
ethereum
  .request('eth_subscribe', ['newHeads'])
  .then((subscriptionId) => {
    ethereum.on('notification', (notification) => {
      if (notification.type === 'eth_subscription') {
        const { data } = notification;
        if (data.subscription === subscriptionId) {
          if (typeof data.result === 'string' && data.result) {
            const block = data.result;
            console.log(`New block ${block.number}:`, block);
          } else {
            console.error(`Something went wrong: ${data.result}`);
          }
        }
      }
    });
  })
  .catch((error) => {
    console.error(
      `Error making newHeads subscription: ${error.message}.
       Code: ${error.code}. Data: ${error.data}`
    );
  });

// Example 5: Log when accounts change
const logAccounts = (accounts) => {
  console.log(`Accounts:\n${accounts.join('\n')}`);
};
ethereum.on('accountsChanged', logAccounts);
// to unsubscribe
ethereum.removeListener('accountsChanged', logAccounts);

// Example 6: Log if connection ends
ethereum.on('close', (code, reason) => {
  console.log(`Ethereum Provider connection closed: ${reason}. Code: ${code}`);
});

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.

Definitions

This section is non-normative.

  • Provider
    • A JavaScript object made available to a dapp, that provides access to Ethereum by means of a Client
  • Client
    • An endpoint accessed by a Provider, that receives Remote Procedure Call (RPC) requests and returns their results
  • Remote Procedure Call (RPC)
    • A Remote Procedure Call (RPC), is any request submitted to a Provider for some procedure that is to be processed by a Provider or its Client.

Availability

In a browser environment, the Provider MUST be made available as the ethereum property on the global window object.

In a non-browser environment, the Provider SHOULD be made available as the ethereum property on the globalThis object.

API

The Provider MUST expose the API defined in this section. All API entities MUST adhere to the types and interfaces defined in this section.

The Provider MAY expose methods and properties not specified in this document.

request

type RequestParams = Array<any> | { [key: string]: any };

ethereum.request(method: string, params?: RequestParams): Promise<unknown>;

The request method is intended as a transport- and protocol-agnostic wrapper function for Remote Procedure Calls (RPCs).

The request method MUST send a properly formatted request to the Provider’s Ethereum client. Requests MUST be handled such that, for a given set of arguments, the returned Promise either resolves with a value per the RPC method’s specification, or rejects with an error.

If present, the params argument MUST be structured value, either by-position as an Array or by-name as an Object.

If resolved, the Promise MUST NOT resolve with any RPC protocol-specific response objects, unless the RPC method’s return type is so defined by its specification.

If resolved, the Promise MUST resolve with a result per the RPC method’s specification.

If the returned Promise rejects, it MUST reject with an Error of the form specified in the RPC Errors section below.

The returned Promise MUST reject if any of the following conditions are met:

  • The client returns an error for the RPC request
    • If error returned from the client is compatible with the ProviderRpcError interface, the Promise MAY reject with that error directly
  • The Provider encounters an fails for any reason
  • The request requires access to an unauthorized account, per EIP 1102
    • In this case, the Promise rejection error code MUST be 4100

Supported RPC Methods

A “supported RPC method” is any RPC method that may be called via the Provider.

All supported RPC methods MUST be identified by unique strings.

Providers MAY support whatever RPC methods required to fulfill their purpose, standardized or otherwise.

If a Provider supports a method defined in a finalized EIP, the Provider’s implementation of this method MUST adhere to the method’s specification.

If an RPC method defined in a finalized EIP is not supported, it SHOULD be rejected with an appropriate error per EIP 1474.

RPC Errors

interface ProviderRpcError extends Error {
  message: string;
  code: number;
  data?: any;
}
  • message
    • MUST be a human-readable string
    • SHOULD adhere to the specifications in the Error Standards section below
  • code
    • MUST be an integer number
    • SHOULD adhere to the specifications in the Error Standards section below
  • data
    • SHOULD contain any other useful information about the error
Error Standards

ProviderRpcError codes and messages SHOULD follow these conventions, in order of priority:

  1. The errors in the Provider Errors section below

  2. The Ethereum JSON-RPC API error codes

  3. The CloseEvent status codes

Provider Errors

Status code Name Description
4001 User Rejected Request The user rejected the request.
4100 Unauthorized The requested method and/or account has not been authorized by the user.
4200 Unsupported Method The requested method is not supported by the given Ethereum Provider.

Events

The Provider SHOULD extend the Node.js EventEmitter to provide dapps flexibility in listening to events. In place of full EventEmitter functionality, the Provider MAY provide as many methods as it can reasonably provide, but MUST provide at least on, emit, and removeListener.

message

The Provider MAY emit the event named message, for any reason.

If the Provider supports Ethereum RPC subscriptions, e.g. eth_subscribe, the Provider MUST emit the message event when it receives a subscription notification.

When emitted, the message event MUST be emitted with an object argument of the following form:

interface ProviderMessage {
  type: string;
  data: unknown;
}
Converting a Subscription Message to a ProviderMessage

If the Provider receives a subscription message from e.g. an eth_subscribe subscription, the Provider MUST emit a message event with a ProviderMessage object of the following form:

interface EthSubscription extends ProviderMessage {
  type: 'eth_subscription';
  data: {
    subscription: string;
    result: any;
  };
}

connect

If the Provider becomes connected, the Provider MUST emit the event named connect.

The Provider “becomes connected” when:

  • it first connects to a chain after initialization.
  • it connects to a chain after the close event was emitted.

This event MUST be emitted with an object of the following form:

interface ProviderConnectInfo {
  chainId: string;
  [key: string]: unknown;
}

chainId MUST specify the integer ID of the connected chain as a hexadecimal string, per the eth_chainId Ethereum RPC method.

The ProviderConnectInfo object MAY contain any other string properties with values of any type.

close

If the Provider becomes disconnected from all chains, the Provider MUST emit the event named close with ordered values code: number, reason: string following the status codes for CloseEvent.

chainChanged

If the chain the Provider is connected to changes, the Provider MUST emit the event named chainChanged with value chainId: string, specifying the integer ID of the new chain as a hexadecimal string, per the eth_chainId Ethereum RPC method.

accountsChanged

If the accounts available to the Provider change, the Provider MUST emit the event named accountsChanged with value accounts: Array<string>, containing the account addresses per the eth_accounts Ethereum RPC method.

The “accounts available to the Provider” change when the return value of eth_accounts changes.

References

Copyright and related rights waived via CC0.