* Add EIP 2020: Ethereum Provider * Incorporate changes into EIP 1102 (thanks Paul) * Update discussions-to link * Clarify intentions * Proper property names * Updates * Requires EIP 1102 * Updates * Updates * Merge EIP 1102 updates * Update postMessage types to align with EIP 1102 * Remove meta provider information, since all the data is accessible through the JSON-RPC API * Updates * Usage => Examples * Update example console msg * Fix subheadings * Use console.error instead of console.log in error instances * Updates * Updates * Add params for subscriptions * Clarifying subscription response * Update subscriptions spec * Fix * More clear example headings * Better wording for `close` event spec * Updates * Remove unnecessary spacing * Updates * Better grammar * Formatting * Updates * Better unsubscribe documentation * Updates * Typo (pluralize) * Better wording * periods * Use pull number * Update discussions-to link * wording
10 KiB
eip | title | author | discussions-to | status | type | category | created | requires |
---|---|---|---|---|---|---|---|---|
1193 | Ethereum Provider API | Ryan Ghods (@ryanio), Marc Garreau (@marcgarreau) | https://ethereum-magicians.org/t/eip-1193-ethereum-provider/640 | Draft | Standards Track | Interface | 2018-06-30 | 1102 |
Summary
This proposal formalizes an Ethereum Provider API.
The provider is designed to be minimal, containing 3 methods: send
, subscribe
, and unsubscribe
. It emits 4 types of events: connect
, close
, networkChanged
, and accountsChanged
.
API
Send
ethereum.send(method: String, params?: Array<any>): Promise<any>;
Promise resolves with result
or rejects with Error
.
See the available methods.
Subscriptions
Subscribe
ethereum.subscribe(subscriptionType: String, params?: Array<any>): Promise<any>;
Promise resolves with subscriptionId: String
or rejects with Error
.
See the types of subscriptions.
Results emit on subscriptionId
using EventEmitter. Attach listeners with:
ethereum.on(subscriptionId, listener: (result: any) => void): this;
The event emits with result
, the subscription result
or an Error
object.
Unsubscribe
ethereum.unsubscribe(subscriptionId: String): Promise<Boolean|Error>;
Promise resolves with success: Boolean
or rejects with Error
.
All EventEmitter listeners on subscriptionId
will also be removed.
Events
Events are emitted using EventEmitter.
connect
The provider emits connect
on connect to a network.
ethereum.on('connect', listener: () => void): this;
You can detect which network by sending net_version
:
const network = await ethereum.send('net_version');
> '1'
close
The provider emits close
on disconnect from a network.
ethereum.on('close', listener: (code: Number, reason: String) => void): this;
The event emits with code
and reason
. The code follows the table of CloseEvent
status codes.
networkChanged
The provider emits networkChanged
on connect to a new network.
ethereum.on('networkChanged', listener: (networkId: String) => void): this;
The event emits with networkId
, the new network returned from net_version
.
accountsChanged
The provider emits accountsChanged
if the accounts returned from the provider (eth_accounts
) changes.
ethereum.on('accountsChanged', listener: (accounts: Array<String>) => void): this;
The event emits with accounts
, an array of the accounts' public keys.
Constructor
ethereum.constructor.name;
> 'EthereumProvider'
Examples
// Request Ethereum Provider (EIP 1102)
window.addEventListener('message', event => {
if (event.data && event.data.type === 'ETHEREUM_PROVIDER_SUCCESS') {
start(window.ethereum);
}
});
window.postMessage({ type: 'ETHEREUM_PROVIDER_REQUEST' }, this.origin);
function start(ethereum) {
// A) Primary use case - set provider in web3.js
web3.setProvider(ethereum);
// B) Secondary use case - use provider object directly
// Example: Log accounts
ethereum
.send('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: Log last block
ethereum
.send('eth_getBlockByNumber', ['latest', 'true'])
.then(block => {
console.log(`Block ${block.number}:\n${block}`);
})
.catch(error => {
console.error(
`Error fetching last block: ${error.message}.
Code: ${error.code}. Data: ${error.data}`
);
});
// Example: Log new blocks
let subId;
ethereum
.subscribe('newHeads')
.then(subscriptionId => {
subId = subscriptionId;
ethereum.on(subscriptionId, block => {
if (result instanceOf Error) {
const error = result;
console.error(
`Error from newHeads subscription: ${error.message}.
Code: ${error.code}. Data: ${error.data}`
);
} else {
console.log(`New block ${block.number}:\n${block}`);
}
});
})
.catch(error => {
console.error(
`Error making newHeads subscription: ${error.message}.
Code: ${error.code}. Data: ${error.data}`
);
});
// to unsubscribe
ethereum
.unsubscribe(subId)
.then(result => {
console.log(`Unsubscribed newHeads subscription ${subscriptionId}`);
})
.catch(error => {
console.error(
`Error unsubscribing newHeads subscription: ${error.message}.
Code: ${error.code}. Data: ${error.data}`
);
});
// Example: 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: Log if connection ends
ethereum.on('close', (code, reason) => {
console.log(
`Ethereum provider connection closed: ${reason}. Code: ${code}`
);
});
}
Specification
Send
The send
method MUST send a properly formatted JSON-RPC request.
If the Ethereum JSON-RPC API returns a response object with no error, then the Promise MUST resolve with the response.result
object untouched by the implementing Ethereum Provider.
If the Ethereum JSON-RPC API returns response object that contains an error property then the Promise MUST be rejected with an Error object containing the response.error.message
as the Error message, response.error.code
as a code property on the error and response.error.data
as a data property on the error.
If an error occurs during processing, such as an HTTP error or internal parsing error then the Promise MUST be rejected with an Error object containing a human readable string message describing the error and SHOULD populate code and data properties on the error object with additional error details.
If the implementing Ethereum Provider is not talking to an external Ethereum JSON-RPC API provider then it MUST resolve with an object that matches the JSON-RPC API object as specified in the Ethereum JSON-RPC documentation. In case of an error, ensure that the Promise is rejected with an Error that matches the above shape.
Subscriptions
The subscribe
method MUST send a properly formatted JSON-RPC request with method eth_subscribe
and params [subscriptionType: String, {...params: Array<any>}]
and MUST return a Promise that resolves with subscriptionId: String
or rejected with an Error object containing a human readable string message describing the error and SHOULD populate code and data properties on the error object with additional error details.
The unsubscribe
method MUST send a properly formatted JSON-RPC request with method eth_unsubscribe
and params [subscriptionId: String]
and MUST return a Promise that resolves with result: Boolean
or rejected with an Error object containing a human readable string message describing the error and SHOULD populate code and data properties on the error object with additional error details.
If the unsubscribe
method returns successfully with a True
result, the implementing provider MUST remove all listeners on the subscriptionId
using ethereum.removeAllListeners(subscriptionId);
.
If an error occurs during processing of the subscription, such as an HTTP error or internal parsing error then the Promise MUST return with an Error object containing a human readable string message describing the error and SHOULD populate code and data properties on the error object with additional error details.
The implementing Ethereum Provider MUST emit every subscription response result
with the eventName subscriptionId
.
If an error occurs during the listening of the subscription, the Ethereum Provider MUST emit an Error object to the eventName subscriptionId
containing a human readable string message describing the error and SHOULD populate code and data properties on the error object with additional error details.
If the implementing provider does not support subscriptions, then it MUST leave the subscribe
and unsubscribe
methods undefined.
Events
If the network connects, the Ethereum Provider MUST emit an event named connect
.
If the network connection closes, the Ethereum Provider MUST emit an event named close
with args code: Number, reason: String
using the status codes for CloseEvent
and a short human readable reason.
If the network the Ethereum Provider is connected to changes, the Ethereum Provider MUST emit an event named networkChanged
with args networkId: String
containing the ID of the new network (using the Ethereum JSON-RPC call net_version
).
If the accounts connected to the Ethereum Provider change, the Ethereum Provider MUST send an event with the name accountsChanged
with args accounts: Array<String>
containing the accounts' public key(s).
Class
The name of the constructor of the Ethereum Provider MUST be EthereumProvider
.
Topics
Multiple chain support
As per discussion in ethereum/interfaces#16, to handle support of changing networks we recommend introducing a new RPC method eth_changeNetwork
. In the future depending on the implementation of sharding, an additional method could be eth_changeShard
.
Copyright
Copyright and related rights waived via CC0.