Removing legacy docs hosted source.

This commit is contained in:
Richard Moore 2020-06-11 16:29:53 -04:00
parent 750ba7ff8c
commit 4c4830670a
No known key found for this signature in database
GPG Key ID: 665176BE8E9DC651
29 changed files with 0 additions and 8964 deletions

@ -1,624 +0,0 @@
Low-Level API
**************
These are advanced, low-level API features that should, for most people not be
necessary to worry about.
They are lightly documented here, and in the future will have more documentation,
but the emphasis at this point is documenting the more :ref:`common methods <api>`.
-----
.. _api-hdnode:
HDNode
======
A *Hierarchical Deterministic Wallet* represents a large tree of private keys
which can reliably be reproduced from an initial seed. Each node in the tree
is represended by an HDNode which can be descended into.
A *mnemonic phrase* represents a simple way to generate the initial seed.
See the `BIP 32 Specification`_ to learn more about HD Wallets and hardened vs
non-hardened nodes.
See the `BIP 39 Specification`_ to learn more about Mnemonic Phrases.
Creating Instances
------------------
:sup:`ethers . HDNode` **. fromMnemonic** ( mnemonic )
Create an HDNode from a *mnemonic* phrase.
:sup:`ethers . HDNode` **. fromSeed** ( seed )
Create an HDNode from a seed.
Prototype
---------
:sup:`prototype` **. privateKey**
The :ref:`hex string <hexstring>` private key for this node.
:sup:`prototype` **. publicKey**
The (compressed) public key for this node.
:sup:`prototype` **. chainCode**
The chain code for this node.
:sup:`prototype` **. index**
The index (from the parent) of this node (0 for the master node).
:sup:`prototype` **. depth**
The depth within th hierarchy of this node.
:sup:`prototype` **. derivePath** ( path )
Derive the path from this node. Path is slash (**/**) delimited path components.
The first component may be "m" for master (which enforces the starting node is
infact a master node) and each subsequent path component should be a positive
integer (up to 31 bits), which can optionally include an apostrophe (**'**) to
indicate hardened derivation for that path components. See below for some examples.
Static Methods
--------------
:sup:`ethers . HDNode` **. mnemonicToEntropy** ( mnemonic )
Convert a *mnemonic* to its binary entropy. (throws an error if the checksum
is invalid)
:sup:`ethers . HDNode` **. entropyToMnemonic** ( entropy )
Convert the binary *entropy* to the mnemonic phrase.
:sup:`ethers . HDNode` **. mnemonicToSeed** ( mnemonic )
Compute the BIP39 seed from *mnemonic*.
:sup:`ethers . HDNode` **. isValidMnemonic** ( string )
Returns true if and only if the string is a valid mnemonic (including
the checksum)
*Examples*
----------
::
var HDNode = require('ethers').HDNode;
var mnemonic = "radar blur cabbage chef fix engine embark joy scheme fiction master release";
var masterNode = HDNode.fromMnemonic(mnemonic);
var standardEthereum = masterNode.derivePath("m/44'/60'/0'/0/0");
-----
.. _api-interface:
Interface
=========
The Interface Object is a meta-class that accepts a Solidity (or compatible)
Application Binary Interface (ABI) and populates functions to deal with encoding
and decoding the parameters to pass in and results returned.
Creating an Instance
--------------------
new :sup:`ethers` . Interface ( abi )
Returns a new instance and populates the properties with the ABI constructor,
methods and events. The *abi* may be either a JSON string or the parsed JSON
Object.
Prototype
---------
:sup:`prototype` . abi
A **copy** of the ABI is returned, modifying this object will not alter the ABI.
:sup:`prototype` . functions
An object of the functions available in the ABI, by name. (collissions are dropped)
:sup:`prototype` . events
An object of the events available in the ABI, by name. (collisions are dropped)
:sup:`prototype` . deployFunction ( bytecode [ , params... ])
The function to deploy the contract (compiled to *bytecode*) to the network, passing
*params* into the ABI constructor. If the ABI does not have a constructor, a default
one is generated.
*Examples*
----------
**Creating an Interface Instance** ::
var Interface = require('ethers').Interface;
var abi = [
{
constant: true,
inputs:[],
name: "getValue",
outputs:[ { name: "value", type: "string"} ],
type: "function"
},
{
constant: false,
inputs: [ { name: "value", type: "string" } ],
name: "setValue",
outputs: [],
type: "function"
},
{
anonymous: false,
inputs:[
{ indexed:false, name: "oldValue", type: "string" },
{ indexed:false, name: "newValue", type: "string" }
],
name: "valueChanged",
type: "event"
}
];
// NOTE: "interface" is a reserved keyword in JavaScript
var iface = new Interface(abi)
**Call (Constant) Functions** ::
var getValueInfo = iface.functions.getValue();
console.log(getValueInfo);
// {
// name: "getValue",
// signature: "getValue()",
// data: "0x20965255",
// parse: function(result),
// type: "call"
// }
// Here is the result of:
// provider.call({
// to: "0x954De93D9f1Cd1e2e3AE5964F614CDcc821Fac64",
// data: getValue.data,
// }).then(function(result) {
// console.log(result);
// });
var getDataResult = "0x0000000000000000000000000000000000000000000000000000000000000020" +
"000000000000000000000000000000000000000000000000000000000000000b" +
"48656c6c6f20576f726c64000000000000000000000000000000000000000000"
console.log(getValueInfo.parse(getDataResult));
// {
// 0: "Hello World",
// value: "Hello World",
// length: 1
// }
**Transaction (Non-Constant) Functions** ::
var setValueInfo = iface.functions.setValue("Foobar!");
console.log(setValueInfo);
// {
// name: "setValue",
// signature: "setValue(string)",
// data: "0x93a09352" +
// "0000000000000000000000000000000000000000000000000000000000000020" +
// "0000000000000000000000000000000000000000000000000000000000000007" +
// "466f6f6261722100000000000000000000000000000000000000000000000000"
// type: "transaction"
// }
// To send this to the network, you would sign and send the transaction:
// {
// to: "0x954De93D9f1Cd1e2e3AE5964F614CDcc821Fac64",
// data: setValueInfo.data,
// gasLimit: someGasLimit,
// gasPrice: someGasPrice,
// nonce: yourTransactionCountForYourAddress
// }
**Events** ::
var ethers = require('ethers');
var Interface = ethers.Interface;
var abi = [
{
anonymous: false,
inputs:[
{ indexed:true, name: "from", type: "address" },
{ indexed:true, name: "to", type: "address" },
{ indexed:false, name: "value", type: "uint256" }
],
name: "Transfer",
type: "event"
}
];
// NOTE: "interface" is a reserved keyword in JavaScript
var iface = new Interface(abi)
var transferInfo = iface.events.Transfer();
console.log(transferInfo);
// EventDescription {
// inputs:
// [ { indexed: true, name: 'from', type: 'address' },
// { indexed: true, name: 'to', type: 'address' },
// { indexed: false, name: 'value', type: 'uint256' } ],
// name: 'Transfer',
// signature: 'Transfer(address,address,uint256)',
// topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' ],
// parse: [Function] }
// To listen for this event:
var provider = ethers.providers.getDefaultProvider();
provider.on(transferInfo.topics, function(log) {
// Parse event data (only returns the non-indexed entries)
var result = transferInfo.parse(log.data);
console.log('non-indexed entries: ', result);
// non-indexed entries: Result {
// '0': Indexed { indexed: true, hash: null },
// '1': Indexed { indexed: true, hash: null },
// '2': BigNumber { _bn: <BN: 1db3c5934d11e3c0000> },
// from: Indexed { indexed: true, hash: null },
// to: Indexed { indexed: true, hash: null },
// value: BigNumber { _bn: <BN: 1db3c5934d11e3c0000> },
// length: 3 }
// Parse event topics and data (returns all entries)
// Note: Any indexed entry which is not a 32 byte value is hashed.
// Dynamic arrays are hashed as a static sized array.
result = transferInfo.parse(log.topics, log.data);
console.log('all entries: ', result);
// all entries: Result {
// '0': '0x0000000000000000000000000000000000000000',
// '1': '0x92239D0512c313E1b001b3996707F822a76C0901',
// '2': BigNumber { _bn: <BN: 1db3c5934d11e3c0000> },
// from: '0x0000000000000000000000000000000000000000',
// to: '0x92239D0512c313E1b001b3996707F822a76C0901',
// value: BigNumber { _bn: <BN: 1db3c5934d11e3c0000> },
// length: 3 }
});
-----
ABI Coder
=========
Creating Instances
------------------
new :sup:`ethers . utils` **. AbiCoder** ( [ coerceFunc ] )
Create a new ABI Coder object, which calls *coerceFunc* for each parsed value
during decoding. The *coerceFunc* should have the signature: ``function(type, value)``.
Static Properties
-----------------
:sup:`ethers . utils` **. defaultAbiCoder**
A default instance of the coder which can be used, which has a *coerceFunc*
which will call ``toNumber()`` on BigNumbers whose **type** is less than
53 bits and is safe for JavaScript Number instances.
Prototype
---------
:sup:`prototype` . encode ( [ names , ] types , values )
Returns a :ref:`hex string <hexstring>` of the *values* encoded as the *types*.
If names is provided, *values* may contain named keys for tuples, otherwise
each tuple expects an Array. Throws if a value is invalid for the type.
:sup:`prototype` . decode ( [ names , ] types , data )
Returns an Object by parsing *data* assuming *types*, with each parameter
accessible as apositional parameters. If *names* is provided, each
parameter is also accessible by its name. Throws if *data* is invalid
for the *types*.
-----
Provider (Sub-Classing)
=======================
See the :ref:`Provider API <api-provider>` for more common usage. This documentation
is designed for developers that are sub-classing Provider.
Static Methods
--------------
:sup:`Provider` . inherits ( childProvider )
Set up *childProvider* as an provider, inheriting the parent prototype and
set up a prototype.inherits on the *childProvider*.
:sup:`Provider` . fetchJSON ( url , body , processFunc )
Convenience method for returning a :ref:`Promise <promise>` with the result of fetching JSON
from a *url* with an optional *body*. The optional *processFunc* is called on
the parsed JSON before being passed to the Promise's resolve. (throwing an error
in the *processFunc* will cause the Promise to reject)
Prototype
---------
:sup:`prototype` . perform ( method , params )
The only method needed to override in a subclass. All values are sanitized
and defaults populated in params and the result is sanitized before returning.
Returns a :ref:`Promise <promise>`, see the example below for overview of
*method* and *params*.
*Examples*
----------
::
var ethers = require('ethers');
var utils = ethers.utils;
var Provider = ethers.providers.Provider;
// The new provider Object
function DemoProvider(testnet, somethingElse) {
Provide.call(this, testnet);
utils.defineProperty(this, 'somethingElse', somethingElse);
}
// Inherit the Provider
Provider.inherits(DemoProvider);
// Override perform
utils.defineProperty(DemoProvider.prototype, 'perform', function(method, params) {
switch (method) {
case 'getBlockNumber':
// Params:
// { }
case 'getGasPrice':
// Params:
// { }
case 'getBalance':
// Params:
// {
// address: address,
// blockTag: blockTag
// }
case 'getTransactionCount':
// Params:
// {
// address: address,
// blockTag: blockTag
// }
case 'getCode':
// Params:
// {
// address: address,
// blockTag: blockTag
// }
case 'getStorageAt':
// Params:
// {
// address: address,
// position: hexString,
// blockTag: blockTag
// }
case 'sendTransaction':
// Params:
// {
// signedTransaction: hexString
// }
case 'getBlock':
// Params:
// Exactly one of the following will be specified, the other will be absent
// {
// blockHash: blockHash,
// blockTag: blockTag
// }
case 'getTransaction':
// Params:
// {
// transactionHash: hexString
// }
case 'getTransactionReceipt':
// Params:
// {
// transactionHash: hexString
// }
case 'call':
// Params:
// {
// transaction: See Transaction Requests (on Providers API)
// }
case 'estimateGas':
// Params:
// {
// transaction: See Transaction Requests (on Providers API)
// }
case 'getLogs':
// Params:
// {
// address: address,
// fromBlock: blockTag,
// toBlock: blockTag,
// topics: array (possibly nested) of topics
// }
default:
break;
}
return Promise.reject(new Error('not implemented - ' + method));
});
-----
Signing Key
===========
The SigningKey interface provides an abstraction around the
*secp256k1 elliptic curve cryptography* library, which signs digests,
computes public keys from private keys and performs *ecrecover* which
computes a public key from a digest and a signature.
Creating Instances
------------------
new :sup:`ethers` . SigningKey ( privateKey )
Create a new SigningKey and compute the corresponding public key and address.
A private key may be a any :ref:`hex string <hexstring>` or an
:ref:`Arrayish <api-arrayish>` representing 32 bytes.
Static Methods
--------------
:sup:`SigningKey` . recover ( digest, r, s, recoveryParam )
Given a message *digest* and the signature parameters *r*, *s*
and *recoveryParam* compute the the address that signed the
message.
:sup:`SigningKey` . getPublicKey ( publicOrPrivateKey [, compressed] )
Given a *publicOrPrivateKey*, return the public key, optionally *compressed*.
**default:** *compressed*\ =false
:sup:`SigningKey` . publicKeyToAddress ( publicOrPrivateKey )
Convert a *publicOrPrivateKey* to an Ethereum address.
Prototype
---------
:sup:`prototype` . privateKey
The private key.
:sup:`prototype` . publicKey
The compressed public key.
:sup:`prototype` . address
The Ethereum address for this key pair.
:sup:`prototype` . signDigest ( messageDigest )
The compressed public key
*Examples*
----------
::
var ethers = require('ethers');
var SigningKey = ethers._SigningKey;
var privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
var signingKey = new SigningKey(privateKey);
console.log('Address: ' + signingKey.address);
// "Address: 0x14791697260E4c9A71f18484C9f997B308e59325"
var message = "Hello World";
var messageBytes = ethers.utils.toUtf8Bytes(message);
var messageDigest = ethers.utils.keccak256(messageBytes);
console.log("Digest: " + messageDigest);
// "Digest: 0x592fa743889fc7f92ac2a37bb1f5ba1daf2a5c84741ca0e0061d243a2e6707ba"
var signature = signingKey.signDigest(messageDigest);
console.log(signature);
// {
// recoveryParam: 0,
// r: "0x79f56f3422dc67f57b2aeeb0b20295a99ec90420b203177f83d419c98beda7fe",
// s: "0x1a9d05433883bdc7e6d882740f4ea7921ef458a61b2cfe6197c2bb1bc47236fd"
// }
var recovered = SigningKey.recover(messageDigest, signature.r,
signature.s, signature.recoveryParam);
console.log("Recovered: " + recovered);
// "Recovered: 0x14791697260E4c9A71f18484C9f997B308e59325"
var publicKey = signingKey.publicKey;
console.log('Public Key: ' + publicKey);
// "Public Key: 0x026655feed4d214c261e0a6b554395596f1f1476a77d999560e5a8df9b8a1a3515"
var compressedPublicKey = SigningKey.getPublicKey(publicKey, true);
var uncompressedPublicKey = SigningKey.getPublicKey(publicKey, false);
console.log('Compressed: ' + compressedPublicKey);
// "Compressed: 0x026655feed4d214c261e0a6b554395596f1f1476a77d999560e5a8df9b8a1a3515"
console.log('Uncompressed: ' + uncompressedPublicKey);
// "Uncompressed: 0x046655feed4d214c261e0a6b554395596f1f1476a77d999560e5a8df9b8a1a35" +
// "15217e88dd05e938efdd71b2cce322bf01da96cd42087b236e8f5043157a9c068e"
var address = SigningKey.publicKeyToAddress(publicKey);
console.log('Address: ' + address);
// "Address: 0x14791697260E4c9A71f18484C9f997B308e59325"
-----
Recursive-Length Prefixed Encoding (RLP)
========================================
This encoding method is used internally for several aspects of Ethereum, such as
encoding transactions and determining contract addresses. For most developers this
should not be necessary to use.
RLP can encode nested arrays, with data as :ref:`hex strings <hexstring>` and Uint8Array (or other non-Array
:ref:`arrayish <api-arrayish>` objects). A decoded object will always have data represented as :ref:`hex strings <hexstring>` and
Arrays.
See: https://github.com/ethereum/wiki/wiki/RLP
Static Methods
--------------
:sup:`ethers . utils . RLP` . encode( object )
Encodes an object as an RLP :ref:`hex string <hexstring>`. (throws an Error if the object contains
invalid items)
:sup:`ethers . utils . RLP` . decode( hexStringOrArrayish )
Decode *hexStringOrArrayish* into the encoded object. (throws an Error if
invalid RLP-coded data)
*Examples*
----------
::
var rlp = require('ethers').utils.RLP;
var object = [ ["0x42"], "0x1234", [ [], [] ] ];
var encoded = rlp.encode(object);
console.log(encoded);
// 0xc8c142821234c2c0c0
var decoded = rlp.decode(encoded);
console.log(decoded);
// [ [ '0x42' ], '0x1234', [ [], [] ] ]
-----
.. _BIP 32 Specification: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
.. _BIP 39 Specification: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
.. EOF

@ -1,485 +0,0 @@
.. _api-contract:
Contracts
*********
This API provides a graceful connection to a contract deployed on the blockchain,
simplifying calling and querying its functions and handling all the binary
protocol and conversion as necessarily.
The Contract object is a meta-class, so many of the functions it will have are
not defined until it is instantiated with an application binary interface (ABI)
which is usually generated by a compiler, such as Solidity.
To better see this demonstrated, see the `example`_ below.
::
var Contract = ethers.Contract;
-----
Connecting to a Contract
========================
new :sup:`ethers` . Contract ( addressOrName , interface , providerOrSigner )
Connects to the contract at *addressOrName* defined by *interface*, which
may be a JSON string or the parsed object.
The *providerOrSigner* may be any instance of the following:
:ref:`Wallet <api-wallet>`
The wallet will be used to sign and send transactions, and
estimates and calls will use the wallet address.
:ref:`Provider <api-provider>`
Gas estimates and constant functions can be called (but without an
address) and event callbacks may be registered.
`Custom Signer`_
For much more control over how and when signing and sending
transaction occurs and to defer address behaviour.
-----
Prototype
=========
The prototype will contain all the methods and events defined in the
**interface**.
The result of all contant methods are a :ref:`Promise <promise>` which
resolve to the result as a tuple, optionally with the parameters
accessible by name, if named in the ABI.
The result of all non-constant methods are a :ref:`Promise <promise>`
which resolve to the :ref:`transaction <transactionrequest>` that
was sent to the network.
Name collisions with the built-in properties (below) will not be overwritten.
Instead, they must be accessed through the **functions** or **events**
property.
Due to signature overloading, multiple functions can have the same name. The
first function specifed in the ABI will be bound to its name. To access
overloaded functions, use the full typed signature of the functions (e.g.
``contract["foobar(address,uint256)"]``).
:sup:`prototype` . address
The address (or ENS name) of the contract.
:sup:`prototype` . interface
The :ref:`Interface <api-interface>` meta-class of the parsed
ABI. Generally, this should not need to be accessed directly.
:sup:`prototype` . functions . *functionName*
An object that maps each ABI function name to a function that will
either call (for contant functions) or sign and send a transaction
(for non-constant functions)
:sup:`prototype` . estimate . *functionName*
An object that maps each ABI function name to a function that will
estimate the cost the provided parameters.
:sup:`prototype` . events . on\ *eventname*
An object that maps each ABI event name (lower case, with the "on"
prefix) to a callback that is triggered when the event occurs.
:sup:`prototype` . connect ( providerOrSigner )
Create a new instance of the Contract connected as the new *providerOrSigner*.
.. _example:
Examples
--------
*Example Contract and Interface* ::
/**
* contract SimpleStore {
*
* event valueChanged(address author, string oldValue, string newValue);
*
* address _author;
* string _value;
*
* function setValue(string value) public {
* _author = msg.sender;
* valueChanged(_author, _value, value);
* _value = value;
* }
*
* function getValue() constant public returns (string value) {
* return _value;
* }
*
* function getAuthorAndValue() constant public returns (address author, string value) {
* return (_author, _value);
* }
* }
*/
// The interface from the Solidity compiler
var ethers = require('ethers');
var abi = [
{
"constant":true,
"inputs":[],
"name":"getValue",
"outputs":[{"name":"value","type":"string"}],
"payable":false,
"type":"function"
},
{
"constant":true,
"inputs":[],
"name":"getAuthorAndValue",
"outputs":[
{"name":"author","type":"address"},
{"name":"value","type":"string"}
],
"payable":false,
"type":"function"
},
{
"constant":false,
"inputs":[{"name":"value","type":"string"}],
"name":"setValue",
"outputs":[],
"payable":false,
"type":"function"
},
{
"anonymous":false,
"inputs":[
{"indexed":false,"name":"oldValue","type":"string"},
{"indexed":false,"name":"newValue","type":"string"}
],
"name":"valueChanged",
"type":"event"
}
];
var address = '0x2BA27534A8814765795f1Db8AEa01d5dbe4112d9';
var provider = ethers.providers.getDefaultProvider('ropsten');
var contract = new ethers.Contract(address, abi, provider);
*Example Constant Function* -- **getAuthorAndValue ( ) returns ( address author , string value )** ::
var callPromise = contract.getValue();
callPromise.then(function(result) {
console.log('Positional argument [0]; author: ' + result[0]);
console.log('Positional argument [1]; value: ' + result[1]);
console.log('Keyword argument [author]; author: ' + result.author);
console.log('Keyword argument [value]; value: ' + result.value);
});
// These are identical to the above call
// var callPromise = contract.functions.getValue();
// var callPromise = contract['getValue()']();
// var callPromise = contract.functions['getValue()']();
// var callPromise = contract['getValue()']();
*Example Constant Function with Single Return Value* -- **getValue ( ) returns ( string value )** ::
var callPromise = contract.getValue();
callPromise.then(function(value) {
console.log('Single Return Value:' + value);
});
*Example Non-Constant Function* -- **setValue ( string value )** ::
// to call a non-constant function, the contract needs to be
// initialized with a wallet or a customSigner
var provider = ethers.providers.getDefaultProvider('ropsten');
var address = '0x2BA27534A8814765795f1Db8AEa01d5dbe4112d9';
var privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
var wallet = new ethers.Wallet(privateKey, provider);
var contract = new ethers.Contract(address, abi, wallet);
var sendPromise = contract.setValue("Hello World");
sendPromise.then(function(transaction) {
console.log(transaction);
});
// This is identical to the above send
// var sendPromise = contract.functions.setValue("Hello World");
// Overriding parameters; any of these are optional and get passed
// as an additional parameter after all function parameters.
var overrideOptions = {
gasLimit: 250000,
gasPrice: 9000000000,
nonce: 0,
value: ethers.utils.parseEther('1.0')
};
var sendPromise = contract.setValue("Hello World", overrideOptions);
*Example Event Registration* -- **valueChanged ( author , value )** ::
// Register for events
contract.onvaluechanged = function(oldValue, newValue) {
console.log('oldValue: ' + oldValue);
console.log('newValue: ' + newValue);
};
// This is identical to the above event registry
// contract.events.onvaluechanged = function(author, value) { ...
*Example Non-Constant Gas Estimate* ::
// to get the gas estimate, the contract needs to be
// initialized with a wallet or a customSigner
var provider = ethers.providers.getDefaultProvider('ropsten');
var privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
var wallet = new ethers.Wallet(privateKey, provider);
var contract = new ethers.Contract(address, abi, wallet);
var estimatePromise = contract.estimate.setValue("Hello World");
estimatePromise.then(function(gasCost) {
// gasCost is returned as BigNumber
console.log('Estimated Gas Cost: ' + gasCost.toString());
});
-----
Result Types
============
There are many variable types avaiable in Solidity, some which work well
in JavaScript and others that do not. Here are some note regarding passing
and returning values in Contracts.
Integers
--------
Integers in solidity are a fixed number of bits (aligned to the nearest byte)
and are available in signed and unsigned variants.
For example, a **uint256** is 256 bits (32 bytes) and unsigned. An **int8**
is 8 bits (1 byte) and signed.
When the type is 48 bits (6 bytes) or less, values are returned as a JavaScript
Number, since Javascript Numbers are safe to use up to 53 bits.
Any types with 56 bits (7 bytes) or more will be returned as a BigNumber,
even if the *value* is within the 53 bit safe range.
When passing numeric values in, JavaScript Numbers, hex strings or any BigNumber
is acceptable (however, take care when using JavaScript Numbers amd performing
mathematic operations on them).
The **uint** and **int** types are aliases for **uint256** and **int256**,
respectively.
Strings
-------
Strings work fine and require no special care.
To convert between strings and bytes, which may occasionally come up, use the
:ref:`utils.toUtf8Bytes() <api-utf8-strings>` and :ref:`utils.toUtf8String() <api-utf8-strings>`
utility functions.
Bytes
-----
Bytes are available in fixed-length or dynamic-length variants. In both cases, the
values are returned as a hex string and may be passed in as either a hex string or
as an :ref:`arrayish <api-arrayish>`.
To convert the string into an array, use the :ref:`utils.arrayify() <api-arrayish>` utility function.
Arrays
------
Arrays work fine and require no special care.
-----
Deploying a Contract
====================
To deploy a contract to the Ethereum network, you must have its bytecode
and its application binary interface (ABI), usually generated from the
Solidity compiler.
:sup:`Contract` . getDeployTransaction ( bytecode , interface , ... )
Generate the transaction needed to deploy the contract specified by
*bytecode* and *interface*. Any additional parameters the constructor
take should also be passed in.
*Examples*
----------
::
/**
* contract Example {
*
* string _value;
*
* // Constructor
* function Example(string value) {
* _value = value;
* }
* }
*/
var ethers = require('ethers');
// The interface from Solidity
var abi = '[{"inputs":[{"name":"value","type":"string"}],"type":"constructor"}]';
// The bytecode from Solidity
var bytecode = "0x6060604052341561000c57fe5b60405161012d38038061012d83398101604052" +
"8080518201919050505b806000908051906020019061003f929190610047565b" +
"505b506100ec565b828054600181600116156101000203166002900490600052" +
"602060002090601f016020900481019282601f1061008857805160ff19168380" +
"011785556100b6565b828001600101855582156100b6579182015b8281111561" +
"00b557825182559160200191906001019061009a565b5b5090506100c3919061" +
"00c7565b5090565b6100e991905b808211156100e55760008160009055506001" +
"016100cd565b5090565b90565b6033806100fa6000396000f30060606040525b" +
"fe00a165627a7a72305820041f440021b887310055b6f4e647c2844f4e1c8cf1" +
"d8e037c72cd7d0aa671e2f0029";
// Notice we pass in "Hello World" as the parameter to the constructor
var deployTransaction = ethers.Contract.getDeployTransaction(bytecode, abi, "Hello World");
console.log(deployTransaction);
// {
// data: "0x6060604052341561000c57fe5b60405161012d38038061012d83398101604052" +
// "8080518201919050505b806000908051906020019061003f929190610047565b" +
// "505b506100ec565b828054600181600116156101000203166002900490600052" +
// "602060002090601f016020900481019282601f1061008857805160ff19168380" +
// "011785556100b6565b828001600101855582156100b6579182015b8281111561" +
// "00b557825182559160200191906001019061009a565b5b5090506100c3919061" +
// "00c7565b5090565b6100e991905b808211156100e55760008160009055506001" +
// "016100cd565b5090565b90565b6033806100fa6000396000f30060606040525b" +
// "fe00a165627a7a72305820041f440021b887310055b6f4e647c2844f4e1c8cf1" +
// "d8e037c72cd7d0aa671e2f002900000000000000000000000000000000000000" +
// "0000000000000000000000002000000000000000000000000000000000000000" +
// "0000000000000000000000000b48656c6c6f20576f726c640000000000000000" +
// "00000000000000000000000000"
// }
// Connect to the network
var provider = ethers.providers.getDefaultProvider();
// Create a wallet to deploy the contract with
var privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
var wallet = new ethers.Wallet(privateKey, provider);
// Send the transaction
var sendPromise = wallet.sendTransaction(deployTransaction);
// Get the transaction
sendPromise.then(function(transaction) {
console.log(transaction);
});
-----
.. _custom-signer:
Custom Signer
=============
The simplest way to specify a signer is to simply use an instance of a wallet.
However, if more fine-grained control is required, a custom signer allow
deferring the address, signing and sending transactions.
A signer can be any object with:
:sup:`object` . getAddress()
*Required.*
Which must return a valid address or a :ref:`Promise <promise>` which will resolve to a valid
address or reject an error.
:sup:`object` . provider
*Required.*
A provider that will be used to connect to the Ethereum blockchain to issue
calls, listen for events and possibly send transaction.
:sup:`object` . estimateGas ( transaction )
*Optional.*
If this is not defined, the provider is queries directly, after populating
the address using *getAddress()*.
The result must be a :ref:`Promise <promise>` which resolves to the
:ref:`BigNumber <bignumber>` estimated gas cost.
:sup:`object` . sendTransaction ( transaction )
*Optional.*
If this is defined, it is called instead of sign and is expected to
populate *nonce*, *gasLimit* and *gasPrice*.
The result must be a :ref:`Promise <promise>` which resolves to the sent transaction, or
rejects on failure.
:sup:`object` . sign ( transaction )
*Optional.*
If this is defined, it is called to sign a transaction before using the
provider to send it to the network.
The result may be a valid :ref:`hex string <hexstring>` or a promise which will resolve to a valid
:ref:`hex string <hexstring>` signed transaction or reject on failure.
*Examples*
----------
::
var privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
var wallet = new ethers.Wallet(privateKey);
function getAddress() {
return new Promise(function(resolve, reject) {
// Some asynchronous method; some examples
// - request which account from the user
// - query a database
// - wait for another contract to be mined
var address = wallet.address;
resolve(address);
});
}
function sign(transaction) {
return new Promise(function(resolve, reject) {
// Some asynchronous method; some examples
// - prompt the user to confirm or decline
// - check available funds and credits
// - request 2FA over SMS
var signedTransaction = wallet.sign(transaction);
resolve(signedTransaction);
});
}
var customSigner = {
getAddress: getAddress,
provider: ethers.providers.getDefaultProvider(),
sign: sign
}
-----
.. EOF

@ -1,845 +0,0 @@
.. _api-provider:
Providers API
*************
A Provider abstracts a connection to the Ethereum blockchain, for issuing queries
and sending state changing transactions.
Unlike the Web3 provider, there is no concept of accounts or signing entities in
an Ethers Provider. It is simply a connection to the network, and cannot unlock
accounts or sign and is unaware of your Ethereum addresses.
To manage state changing operations, you must use a :ref:`Wallet <api-wallet>`
to sign transactions. If you pass a wallet in as a signer to
a :ref:`Contract <api-contract>`, this is managed for you by the contract.
-----
Connecting to Ethereum
======================
There are several ways to connect to the Ethereum blockchain:
new :sup:`ethers . providers` . EtherscanProvider( [ network ] [ , apiToken ] )
Connect to the `Etherscan`_ blockchain `web service API`_.
**default:** *network*\ ='homestead', *apiToken*\ =null
new :sup:`ethers . providers` . JsonRpcProvider( [ url ] [ , network ] )
Connect to the `JSON-RPC API`_ *url* of an Ethereum node, such as `Parity`_ or `Geth`_.
**default:** *url*\ ="http://localhost:8545/", *network*\ ='homestead'
new :sup:`ethers . providers` . InfuraProvider( [ network ] [ , apiAccessToken ] )
Connect to the `INFURA`_ hosted network of Ethereum nodes.
**default:** *network*\ ='homestead', *apiAccessToken*\ =null
new :sup:`ethers . providers` . Web3Provider( web3Provider [ , network ] )
Connect to an existing Web3 provider (e.g. `web3Instance.currentProvider`).
**default:** *network*\ ='homestead'
new :sup:`ethers . providers` . FallbackProvider( providers )
Improves reliability by attempting each provider in turn, falling back to the
next in the list if an error was encountered.
:sup:`ethers . providers` . getDefaultProvider( [ network ] )
This automatically creates a FallbackProvider backed by INFURA and Etherscan; recommended
**default:** *network*\ ='homestead'
*Examples*
----------
::
var providers = require('ethers').providers;
// Connect to Ropsten (the test network)
// You may specify any of:
// - boolean; true = ropsten, false = homestead
// - object; { name: 'ropsten', chainId: 3 } (see ethers.networks);
// - string; e.g. 'homestead', 'ropsten', 'rinkeby', 'kovan'
var network = providers.networks.ropsten;
// Connect to INFUA
var infuraProvider = new providers.InfuraProvider(network);
// Connect to Etherscan
var etherscanProvider = new providers.EtherscanProvider(network);
// Creating a provider to automatically fallback onto Etherscan
// if INFURA is down
var fallbackProvider = new providers.FallbackProvider([
infuraProvider,
etherscanProvider
]);
// This is equivalent to using the getDefaultProvider
var provider = providers.getDefaultProvider(network)
// Connect to a local Parity instance
var provider = new providers.JsonRpcProvider('http://localhost:8545', network);
// Connect to an injected Web3's provider (e.g. MetaMask)
var web3Provider = new providers.Web3Provider(web3.currentProvider, network);
-----
Prototype
=========
All properties are immutable, and reflect their default value if not specified, or if
indirectly populated by child Objects.
.. _provider:
Provider
--------
:sup:`prototype` . name
The name of the network the provider is connected to (e.g. 'homestead', 'ropsten', 'rinkeby', 'kovan')
:sup:`prototype` . chainId
The chain ID (or network ID) this provider is connected as; this is used by
signers to prevent `replay attacks`_ across compatible networks
FallbackProvider :sup:`( inherits from Provider )`
--------------------------------------------------
:sup:`prototype` . providers
A **copy** of the array of providers (modifying this variable will not affect
the providers attached)
JsonRpcProvider :sup:`( inherits from Provider )`
-------------------------------------------------
:sup:`prototype` . url
The JSON-RPC URL the provider is connected to
:sup:`prototype` . send ( method , params )
Send the JSON-RPC *method* with *params*. This is useful for calling
non-standard or less common JSON-RPC methods. A :ref:`Promise <promise>` is
returned which will resolve to the parsed JSON result.
EtherscanProvider :sup:`( inherits from Provider )`
---------------------------------------------------
:sup:`prototype` . apiToken
The Etherscan API Token (or null if not specified)
InfuraProvider :sup:`( inherits from JsonRpcProvider )`
-------------------------------------------------------
:sup:`prototype` . apiAccessToken
The INFURA API Access Token (or null if not specified)
Web3Provider :sup:`( inherits from JsonRpcProvider )`
-------------------------------------------------------
:sup:`prototype` . provider
The underlying Web3-compatible provider from the Web3 library, for example
an `HTTPProvider`_ or `IPCProvider`_. The only required method on a Web3 provider
is:
*sendAsync ( method , params , callback )*
-----
Account Actions
===============
:sup:`prototype` . getBalance ( addressOrName [ , blockTag ] )
Returns a :ref:`Promise <promise>` with the balance (as a :ref:`BigNumber <bignumber>`) of
*addressOrName* at *blockTag*. (See: :ref:`Block Tags <blocktag>`)
**default:** *blockTag*\ ="latest"
:sup:`prototype` . getTransactionCount ( addressOrName [ , blockTag ] )
Returns a :ref:`Promise <promise>` with the number of sent transactions (as a Number) from
*addressOrName* at *blockTag*. This is also the nonce required to send a new
transaction. (See: :ref:`Block Tags <blocktag>`)
**default:** *blockTag*\ ="latest"
:sup:`prototype` . lookupAddress ( address )
Returns a :ref:`Promise <promise>` which resolves to the ENS name (or null) that *address* resolves
to.
:sup:`prototype` . resolveName ( ensName )
Returns a :ref:`Promise <promise>` which resolves to the address (or null) of that the *ensName*
resolves to.
*Examples*
----------
::
var ethers = require('ethers');
var providers = ethers.providers;
var provider = providers.getDefaultProvider('ropsten');
var address = "0x02F024e0882B310c6734703AB9066EdD3a10C6e0";
provider.getBalance(address).then(function(balance) {
// balance is a BigNumber (in wei); format is as a sting (in ether)
var etherString = ethers.utils.formatEther(balance);
console.log("Balance: " + etherString);
});
provider.getTransactionCount(address).then(function(transactionCount) {
console.log("Total Transactions Ever Send: " + transactionCount);
});
provider.resolveName("test.ricmoose.eth").then(function(address) {
console.log("Address: " + address);
});
-----
Blockchain Status
=================
:sup:`prototype` . getBlockNumber ( )
Returns a :ref:`Promise <promise>` with the latest block number (as a Number).
:sup:`prototype` . getGasPrice ( )
Returns a :ref:`Promise <promise>` with the current gas price (as a :ref:`BigNumber <bignumber>`).
:sup:`prototype` . getBlock ( blockHashOrBlockNumber )
Returns a :ref:`Promise <promise>` with the block at *blockHashorBlockNumber*. (See: :ref:`Block Responses <blockresponse>`)
:sup:`prototype` . getTransaction ( transactionHash )
Returns a :ref:`Promise <promise>` with the transaction with *transactionHash*. (See: :ref:`Transaction Responses <transactionresponse>`)
:sup:`prototype` . getTransactionReceipt ( transactionHash )
Returns a :ref:`Promise <promise>` with the transaction receipt with *transactionHash*.
(See: :ref:`Transaction Receipts <transactionReceipt>`)
*Examples*
----------
**Current State**\ ::
var provider = providers.getDefaultProvider();
provider.getBlockNumber().then(function(blockNumber) {
console.log("Current block number: " + blockNumber);
});
provider.getGasPrice().then(function(gasPrice) {
// gasPrice is a BigNumber; convert it to a decimal string
gasPriceString = gasPrice.toString();
console.log("Current gas price: " + gasPriceString);
});
**Blocks**\ ::
var provider = providers.getDefaultProvider();
// Block Number
provider.getBlock(3346773).then(function(block) {
console.log(block);
});
// Block Hash
var blockHash = "0x7a1d0b010393c8d850200d0ec1e27c0c8a295366247b1bd6124d496cf59182ad";
provider.getBlock(blockHash).then(function(block) {
console.log(block);
});
**Transactions**\ ::
var provider = providers.getDefaultProvider();
var transactionHash = "0x7baea23e7d77bff455d94f0c81916f938c398252fb62fce2cdb43643134ce4ed";
provider.getTransaction(transactionHash).then(function(transaction) {
console.log(transaction);
});
provider.getTransactionReceipt(transactionHash).then(function(transactionReceipt) {
console.log(transactionReceipt);
});
-----
Ethereum Name Resolution
========================
The Ethereum Naming Service (ENS) allows easy to remember and use names to be
assigned to Ethereum addresses. Any provider operation which takes an address
may also take an ENS name.
It is often useful to resolve a name entered by a user or perform a reverse lookup
of an address to get a more human readbale name.
**Resolving Names**\ ::
var providers = require('ethers').providers;
var provider = providers.getDefaultProvider();
provider.resolveName('registrar.firefly.eth').then(function(address) {
console.log(address);
// '0x6fC21092DA55B392b045eD78F4732bff3C580e2c'
});
**Looking up Addresses**\ ::
provider.lookupAddress('0x6fC21092DA55B392b045eD78F4732bff3C580e2c').then(function(name) {
console.log(name);
// 'registrar.firefly.eth'
});
-----
Contract Execution
==================
These are relatively low-level calls. The :ref:`Contracts API <api-contract>` should
usually be used instead.
:sup:`prototype` . call ( transaction )
Send the **read-only** (constant) *transaction* to a single Ethereum node and
return a :ref:`Promise <promise>` with the result (as a :ref:`hex string <hexstring>`) of executing it.
(See :ref:`Transaction Requests <transactionrequest>`)
This is free, since it does not change any state on the blockchain.
:sup:`prototype` . estimateGas ( transaction )
Send a *transaction* to a single Ethereum node and return a :ref:`Promise <promise>` with the
estimated amount of gas required (as a :ref:`BigNumber <bignumber>`) to send it.
(See :ref:`Transaction Requests <transactionrequest>`)
This is free, but only an estimate. Providing too little gas will result in a
transaction being rejected (while still consuming all provided gas).
:sup:`prototype` . sendTransaction ( signedTransaction )
Send the *signedTransaction* to the **entire** Ethereum network and returns a :ref:`Promise <promise>`
with the transaction hash.
**This will consume gas** from the account that signed the transaction.
*Examples*
----------
**Call (Constant) Functions** ::
var ethers = require('ethers');
var provider = ethers.providers.getDefaultProvider();
// setup a transaction to call the CryptoKitties.symbol() function
// CryptoKitties contract address
var address = "0x06012c8cf97BEaD5deAe237070F9587f8E7A266d";
// first 8 nibbles of the hash of symbol()
var data = ethers.utils.id('symbol()').substring(0,10);
var transaction = {
to: address,
data: data
}
provider.call(transaction).then(function(result) {
console.log(result);
// '0x000000000000000000000000000000000000000000000000000000000000002'+
// '00000000000000000000000000000000000000000000000000000000000000002'+
// '434b000000000000000000000000000000000000000000000000000000000000'
});
**sendTransaction** ::
var ethers = require('ethers');
var privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
var wallet = new ethers.Wallet(privateKey);
wallet.provider = ethers.providers.getDefaultProvider('ropsten');
var transaction = {
to: "0x88a5C2d9919e46F883EB62F7b8Dd9d0CC45bc290",
value: ethers.utils.parseEther("0.1")
};
var estimateGasPromise = wallet.estimateGas(transaction);
estimateGasPromise.then(function(gasEstimate) {
console.log(gasEstimate.toString());
transaction.gasLimit = gasEstimate;
// Send the transaction
var sendTransactionPromise = wallet.sendTransaction(transaction);
sendTransactionPromise.then(function(transactionHash) {
console.log(transactionHash);
});
});
-----
Contract State
==============
:sup:`prototype` . getCode ( addressOrName )
Returns a :ref:`Promise <promise>` with the bytecode (as a :ref:`hex string <hexstring>`)
at *addressOrName*.
:sup:`prototype` . getStorageAt ( addressOrName , position [ , blockTag ] )
Returns a :ref:`Promise <promise>` with the value (as a :ref:`hex string <hexstring>`) at
*addressOrName* in *position* at *blockTag*. (See :ref:`Block Tags <blocktag>`)
default: *blockTag*\ = "latest"
:sup:`prototype` . getLogs ( filter )
Returns a :ref:`Promise <promise>` with an array (possibly empty) of the logs that
match the *filter*. (See :ref:`Filters <filter>`)
*Examples*
----------
**getCode** ::
var ethers = require('ethers');
var provider = ethers.providers.getDefaultProvider();
var contractAddress = '0x6fC21092DA55B392b045eD78F4732bff3C580e2c';
var contractEnsName = 'registrar.firefly.eth';
var codePromise = provider.getCode(contractEnsName);
codePromise.then(function(result){
console.log('getCode by ENS name:');
console.log(result);
});
var codeByAddressPromise = provider.getCode(contractAddress);
codeByAddressPromise.then(function(result){
console.log('getCode by contract address:');
console.log(result);
});
**getStorageAt** ::
var ethers = require('ethers');
var provider = ethers.providers.getDefaultProvider();
var contractEnsName = 'registrar.firefly.eth';
var storagePromise = provider.getStorageAt(contractEnsName, 0);
storagePromise.then(function(result){
console.log(result);
});
**getLogs** ::
var ethers = require('ethers');
var provider = ethers.providers.getDefaultProvider();
var cryptoKittiesContractAddress = '0x06012c8cf97BEaD5deAe237070F9587f8E7A266d';
var topic = '0x241ea03ca20251805084d27d4440371c34a0b85ff108f6bb5611248f73818b80';
var filter = {
fromBlock: 5044502,
address: cryptoKittiesContractAddress,
topics: [ topic ]
}
var filterPromise = provider.getLogs(filter);
filterPromise.then(function(result){
console.log(result);
});
-----
Events
======
These methods allow management of callbacks on certain events on the blockchain
and contracts. They are largely based on the `EventEmitter API`_.
:sup:`prototype` . on ( eventType , callback )
Register a callback for any future *eventType*; see below for callback parameters
:sup:`prototype` . once ( eventType , callback)
Register a callback for the next (and only next) *eventType*; see below for callback parameters
:sup:`prototype` . removeListener ( eventType , callback )
Unregister the *callback* for *eventType*; if the same callback is registered
more than once, only the first registered instance is removed
:sup:`prototype` . removeAllListeners ( eventType )
Unregister all callbacks for *eventType*
:sup:`prototype` . listenerCount ( [ eventType ] )
Return the number of callbacks registered for *eventType*, or if ommitted, the
total number of callbacks registered
:sup:`prototype` . resetEventsBlock ( blockNumber )
Begin scanning for events from *blockNumber*. By default, events begin at the
block number that the provider began polling at.
Event Types
-----------
"block"
Whenever a new block is mined
``callback( blockNumber )``
any address
When the balance of the corresponding address changes
``callback( balance )``
any transaction hash
When the corresponding transaction is mined; also see
:ref:`Waiting for Transactions <waitForTransaction>`
``callback( transaction )``
an array of topics
When any of the topics are triggered in a block's logs; when using the
:ref:`Contract API <api-contract>`, this is automatically handled;
``callback( log )``
.. _waitForTransaction:
Waiting for Transactions
------------------------
:sup:`prototype` . waitForTransaction ( transactionHash [ , timeout ] )
Return a :ref:`Promise <promise>` which returns the transaction once *transactionHash* is
mined, with an optional *timeout* (in milliseconds)
*Examples*
----------
::
// Get notified on every new block
provider.on('block', function(blockNumber) {
console.log('New Block: ' + blockNumber);
});
// Get notified on account balance change
provider.on('0x46Fa84b9355dB0708b6A57cd6ac222950478Be1d', function(balance) {
console.log('New Balance: ' + balance);
});
// Get notified when a transaction is mined
provider.once(transactionHash, function(transaction) {
console.log('Transaction Minded: ' + transaction.hash);
console.log(transaction);
);
// OR equivalently the waitForTransaction() returns a Promise
provider.waitForTransaction(transactionHash).then(function(transaction) {
console.log('Transaction Mined: ' + transaction.hash);
console.log(transaction);
});
// Get notified when a contract event is logged
var eventTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
provider.on([ eventTopic ], function(log) {
console.log('Event Log');
console.log(log);
});
-----
Objects
=======
There are several common objects and types that are commonly used as input parameters or
return types for various provider calls.
.. _blocktag:
Block Tag
---------
A block tag is used to uniquely identify a block's position in the blockchain:
a Number or :ref:`hex string <hexstring>`:
Each block has a block number (eg. ``42`` or ``"0x2a``.
"latest":
The most recently mined block.
"pending":
The block that is currently being mined.
.. _blockresponse:
Block Responses
---------------
::
{
parentHash: "0x3d8182d27303d92a2c9efd294a36dac878e1a9f7cb0964fa0f789fa96b5d0667",
hash: "0x7f20ef60e9f91896b7ebb0962a18b8defb5e9074e62e1b6cde992648fe78794b",
number: 3346463,
difficulty: 183765779077962,
timestamp: 1489440489,
nonce: "0x17060cb000d2c714",
extraData: "0x65746865726d696e65202d20555331",
gasLimit: utils.bigNumberify("3993225"),
gasUsed: utils.bigNuberify("3254236"),
miner: "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8",
transactions: [
"0x125d2b846de85c4c74eafb6f1b49fdb2326e22400ae223d96a8a0b26ccb2a513",
"0x948d6e8f6f8a4d30c0bd527becbe24d15b1aba796f9a9a09a758b622145fd963",
... [ 49 more transaction hashes ] ...
"0xbd141969b164ed70388f95d780864210e045e7db83e71f171ab851b2fba6b730"
]
}
.. _transactionrequest:
Transaction Requests
--------------------
Any property which accepts a number may also be specified as a :ref:`BigNumber <bignumber>`
or :ref:`hex string <hexstring>`.
::
// Example:
{
// Required unless deploying a contract (in which case omit)
to: addressOrName, // the target address or ENS name
// These are optional/meaningless for call and estimateGas
nonce: 0, // the transaction nonce
gasLimit: 0, // the maximum gas this transaction may spend
gasPrice: 0, // the price (in wei) per unit of gas
// These are always optional (but for call, data is usually specified)
data: "0x", // extra data for the transaction, or input for call
value: 0, // the amount (in wei) this transaction is sending
chainId: 3 // the network ID; usually added by a signer
}
.. _transactionresponse:
Transaction Response
--------------------
::
// Example:
{
// Only available for mined transactions
blockHash: "0x7f20ef60e9f91896b7ebb0962a18b8defb5e9074e62e1b6cde992648fe78794b",
blockNumber: 3346463,
transactionIndex: 51,
// Exactly one of these will be present (send vs. deploy contract)
creates: null,
to: "0xc149Be1bcDFa69a94384b46A1F91350E5f81c1AB",
// The transaction hash
hash: "0xf517872f3c466c2e1520e35ad943d833fdca5a6739cfea9e686c4c1b3ab1022e",
// See above (Transaction Requests) for these explained
data: "0x",
from: "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8",
gasLimit: utils.bigNumberify("90000"),
gasPrice: utils.bigNumberify("21488430592"),
nonce: 0,
value: utils.parseEther(1.0017071732629267),
// The network ID (or chain ID); 0 indicates replay-attack vulnerable
// (eg. 1 = Homestead mainnet, 3 = Ropsten testnet)
networkId: 1,
// The signature of the transaction
r: "0x5b13ef45ce3faf69d1f40f9d15b0070cc9e2c92f3df79ad46d5b3226d7f3d1e8",
s: "0x535236e497c59e3fba93b78e124305c7c9b20db0f8531b015066725e4bb31de6",
v: 37,
// The raw transaction
raw: "0xf87083154262850500cf6e0083015f9094c149be1bcdfa69a94384b46a1f913" +
"50e5f81c1ab880de6c75de74c236c8025a05b13ef45ce3faf69d1f40f9d15b0" +
"070cc9e2c92f3df79ad46d5b3226d7f3d1e8a0535236e497c59e3fba93b78e1" +
"24305c7c9b20db0f8531b015066725e4bb31de6"
}
.. _transactionReceipt:
Transaction Receipts
--------------------
::
// Example
{
transactionHash: "0x7dec07531aae8178e9d0b0abbd317ac3bb6e8e0fd37c2733b4e0d382ba34c5d2",
// The block this transaction was mined into
blockHash: "0xca1d4d9c4ac0b903a64cf3ae3be55cc31f25f81bf29933dd23c13e51c3711840",
blockNumber: 3346629,
// The index into this block of the transaction
transactionIndex: 1,
// The address of the contract (if one was created)
contractAddress: null,
// Gas
cumulativeGasUsed: utils.bigNumberify("42000"),
gasUsed: utils.bigNumberify("21000"),
// Logs
log: [ ],
logsBloom: "0x00" ... [ 256 bytes of 0 ] ... "00",
// Post-Byzantium hard-fork
byzantium: false
////////////
// Pre-byzantium blocks will have a state root:
root: "0x8a27e1f7d3e92ae1a01db5cce3e4718e04954a34e9b17c1942011a5f3a942bf4",
////////////
// Post-byzantium blocks will have a status (0 indicated failure during execution)
// status: 1
}
.. _filter:
Filters
-------
Filtering on topics supports a `somewhat complicated`_ specification, however,
for the vast majority of filters, a single topic is usually sufficient (see the example below).
The *EtherscanProvider* only supports a single topic.
::
// Example
{
// Optional; The range of blocks to limit querying (See: Block Tags above)
fromBlock: "latest",
toBlock: "latest",
// Optional; An address (or ENS name) to filter by
address: addressOrName,
// Optional; A (possibly nested) list of topics
topics: [ topic1 ]
}
-----
Provider Specific Extra API Calls
=================================
Etherscan
---------
:sup:`prototype` . getEtherPrice ( )
Returns a :ref:`Promise <promise>` with the price of ether in USD.
:sup:`prototype` . getHistory ( addressOrName [ , startBlock [ , endBlock ] ] )
Returns a :ref:`Promise <promise>` with an array of :ref:`Transaction Responses <transactionresponse>`
for each transaction to or from *addressOrName* between *startBlock* and *endBlock* (inclusive).
**Examples**
::
var provider = new ethers.providers.EtherscanProvider();
// Getting the current Ethereum price
provider.getEtherPrice().then(function(price) {
console.log("Ether price in USD: " + price);
});
// Getting the transaction history of an address
var address = '0xb2682160c482eB985EC9F3e364eEc0a904C44C23';
var startBlock = 3135808;
var endBlock = 5091477;
provider.getHistory(address, startBlock, endBlock).then(function(history) {
console.log(history);
// [
// {
// hash: '0x327632ccb6d7bb47b455383e936b2f14e6dc50dbefdc214870b446603b468675',
// blockHash: '0x0415f0d2741de45fb748166c7dc2aad9b3ff66bcf7d0a127f42a71d3e286c36d',
// blockNumber: 3135808,
// transactionIndex: 1,
// from: '0xb2682160c482eB985EC9F3e364eEc0a904C44C23',
// gasPrice: ethers.utils.bigNumberify('0x4a817c800'),
// gasLimit: ethers.utils.bigNumberify('0x493e0'),
// to: '0xAe572713CfE65cd7033774170F029B7219Ee7f70',
// value: ethers.utils.bigNumberify('0xd2f13f7789f0000'),
// nonce: 25,
// data: '0x',
// creates: null,
// networkId: 0
// },
// {
// hash: '0x7c10f2e7125a1fa5e37b54f5fac5465e8d594f89ff97916806ca56a5744812d9',
// ...
// }
// ]
});
Web3Provider
------------
:sup:`prototype` . listAccounts ( )
Returns a :ref:`Promise <promise>` with a list of all accounts the node connected
to this Web3 controls.
:sup:`prototype` . getSigner( [ address ] )
Returns a :ref:`Signer <custom-signer>` that uses an account on the node
the Web3 object is connected to. If no address is specified, the first
account on the node is used.
**Examples**
::
web3Provider.listAccounts().then(function(accounts) {
var signer = web3Provider.getSigner(accounts[1]);
console.log(signer);
});
-----
.. _Etherscan: https://etherscan.io/apis
.. _web service API: https://etherscan.io/apis
.. _INFURA: https://infura.io
.. _Parity: https://ethcore.io/parity.html
.. _Geth: https://geth.ethereum.org
.. _JSON-RPC API: https://github.com/ethereum/wiki/wiki/JSON-RPC
.. _EventEmitter API: https://nodejs.org/dist/latest-v6.x/docs/api/events.html
.. _replay attacks: https://github.com/ethereum/EIPs/issues/155
.. _somewhat complicated: https://github.com/ethereum/wiki/wiki/JSON-RPC#a-note-on-specifying-topic-filters
.. _HTTPProvider: https://github.com/ethereum/web3.js/blob/develop/lib/web3/httpprovider.js
.. _IPCProvider: https://github.com/ethereum/web3.js/blob/develop/lib/web3/ipcprovider.js
.. EOF

@ -1,440 +0,0 @@
Utilities
*********
The utility functions exposed in both the *ethers* umbrella package and the *ethers-utils*::
var utils = require('ethers').utils;
-----
.. _bignumber:
Big Numbers
===========
A BigNumber is an immutable object which allow math operations to be carried
out on numbers far larger than :ref:`JavaScript can accurately handle <ieee754>`.
Many functions return these, so it is important to understand how to work with these.
:sup:`prototype` . add ( otherValue )
Return a new BigNumber of this plus *otherValue*
:sup:`prototype` . sub ( otherValue )
Return a new BigNumber of this minus *otherValue*
:sup:`prototype` . mul ( otherValue )
Return a new BigNumber of this times *otherValue*
:sup:`prototype` . div ( otherValue )
Return a new BigNumber of this divided by *otherValue*
:sup:`prototype` . mod ( otherValue )
Return a new BigNumber of this modulo *otherValue*
:sup:`prototype` . eq ( otherValue )
Return true if this is equal to *otherValue*
:sup:`prototype` . lt ( otherValue )
Return true if this is less than *otherValue*
:sup:`prototype` . lte ( otherValue )
Return true if this is less or equal to *otherValue*
:sup:`prototype` . gt ( otherValue )
Return true if this is greater than *otherValue*
:sup:`prototype` . gte ( otherValue )
Return true if this is greater than or equal to *otherValue*
:sup:`prototype` . isZero ( )
Return true if this is equal to zero
:sup:`prototype` . toNumber ( )
Return a JavaScript number representation; an error is thrown if the value is
outside the safe range for JavaScript IEEE 754 64-bit floating point numbers
:sup:`prototype` . toString ()
Return a decimal string representation
:sup:`prototype` . toHexString ( )
Return a **0x prefixed** hexidecimal representation
Creating Instances
------------------
:sup:`utils` **. bigNumberify** ( value )
Returns a BigNumber instance of *value*. The *value* may be anything which can be
reliably converted into a BigNumber:
*Decimal String*
A string consisting of the decimal digits 0 through 9, optionally with a leading
negative sign.
**examples:** utils.bigNumberify("42")
*Hex String*
A :ref:`hex string <hexstring>`, witch has aa **prefix of 0x** and consisting
of the hexidecimal digits 0 through 9 and a through f, case-insensitive. Must
be non-negative.
**examples:** utils.bigNumberify("0x2a")
*JavaScript Numbers*
Numbers must be within the `safe range`_ for JavaScript.
**examples:** utils.bigNumberify(42)
*Arrayish*
Treats the :ref:`arrayish <api-arrayish>` as a big-endian encoded bytes representation.
**examples:** utils.bigNumberify([ 42 ])
*BigNumber*
Returns *value*, since a BigNumber is immutable.
.. _safe range: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isSafeInteger
*Examples*
----------
::
var utils = require('ethers').utils;
var gasPriceWei = utils.bigNumberify("20902747399");
var gasLimit = utils.bigNumberify(3000000);
var maxCostWei = gasPriceWei.mul(gasLimit)
console.log("Max Cost: " + maxCostWei.toString());
// "Max Cost: 62708242197000000"
console.log("Number: " + maxCostWei.toNumber());
// throws an Error, the value is too large for JavaScript to handle safely
-----
Ether Strings and Wei
=====================
:sup:`utils` . etherSymbol
The ethereum symbol (the Greek letter *Xi* )
.. _parseEther:
:sup:`utils` . parseEther ( etherString )
Parse the *etherString* representation of ether into a BigNumber instance
of the amount of wei.
.. _formatEther:
:sup:`utils` . formatEther ( wei [ , options ] )
Format an amount of *wei* into a decimal string representing the amount of ether. The
*options* object supports the keys ``commify`` and ``pad``. The output will always
include at least one whole number and at least one decimal place.
.. _parseUnits:
:sup:`utils` . parseUnits ( valueString , decimalsOrUnitName )
Parse the *valueString* representation of units into a BigNumber instance
of the amount of wei. The *decimalsOrUnitsName* may be a number of decimals between
3 and 18 (multiple of 3) or a name, such as `gwei`.
.. _formatUnits:
:sup:`utils` . formatUnits ( wei , decimalsOrUnitName [ , options ] )
Format an amount of *wei* into a decimal string representing the amount of units. The
*options* object supports the keys ``commify`` and ``pad``. The output will always
include at least one whole number and at least one decimal place. The *decimalsOrUnitsName*
may be a number of decimals between 3 and 18 (multiple of 3) or a name, such as `gwei`.
*Examples*
----------
::
var utils = require('ethers').utils;
var wei = utils.parseEther('1000.0');
console.log(wei.toString(10));
// "1000000000000000000000"
console.log(utils.formatEther(0));
// "0.0"
var wei = utils.bigNumberify("1000000000000000000000");
console.log(utils.formatEther(wei));
// "1000.0"
console.log(utils.formatEther(wei, {commify: true}));
// "1,000.0"
console.log(utils.formatEther(wei, {pad: true}));
// "1000.000000000000000000" (18 decimal places)
console.log(utils.formatEther(wei, {commify: true, pad: true}));
// "1,000.000000000000000000" (18 decimal places)
-----
Addresses
=========
There are :ref:`several formats <checksum-address>` available on the Ethereum network for
addresses, and it is often useful to be able to convert between them.
.. _api-getAddress:
:sup:`utils` . getAddress ( address [ , generateIcap ] )
Normalize an address to a :ref:`checksum address <checksum-address>`, or as an
:ref:`ICAP <icap-address>` address if *generateIcap* is true.
*Examples*
----------
::
var utils = require('ethers').utils;
var address = "0xd115bffabbdd893a6f7cea402e7338643ced44a6";
var icapAddress = "XE93OF8SR0OWI6F4FO88KWO4UNNGG1FEBHI";
console.log(utils.getAddress(address));
// "0xD115BFFAbbdd893A6f7ceA402e7338643Ced44a6"
console.log(utils.getAddress(icapAddress));
// "0xD115BFFAbbdd893A6f7ceA402e7338643Ced44a6"
console.log(utils.getAddress(address, true));
// "XE93OF8SR0OWI6F4FO88KWO4UNNGG1FEBHI"
console.log(utils.getAddress(icapAddress, true));
// "XE93OF8SR0OWI6F4FO88KWO4UNNGG1FEBHI"
-----
.. _api-utf8-strings:
UTF-8 Strings
=============
.. _api-utf8-to-bytes:
:sup:`utils` . toUtf8Bytes ( string )
Converts a UTF-8 string to a Uint8Array.
.. _api-utf8-to-string:
:sup:`utils` . toUtf8String ( hexStringOrArrayish )
Converts a hex-encoded string or array to its UTF-8 representation.
*Examples*
----------
::
var utils = require('ethers').utils;
var text = "Hello World";
var bytes = utils.toUtf8Bytes(text);
console.log(bytes);
// Uint8Array [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
console.log(utils.toUtf8String(bytes));
// "Hello World"
var hexString = "0x48656c6c6f20576f726c64";
console.log(utils.toUtf8String(hexString));
// "Hello World"
-----
.. _api-utils-crypto:
Cryptographic Functions
=======================
:sup:`utils` . keccak256 ( hexStringOrArrayish )
Compute the keccak256 cryptographic hash of a value, returned as a hex string. (Note:
often Ethereum refers to this, **incorrectly**, as SHA3)
:sup:`utils` . id ( utf8String )
Compute the keccak256 cryptographic hash of a UTF-8 string, returned as a hex string.
:sup:`utils` . sha256 ( hexStringOrArrayish )
Compute the SHA2-256 cryptographic hash of a value, returned as a hex string.
:sup:`utils` . randomBytes ( length )
Return a Uint8Array of cryptographically secure random bytes
*Examples*
----------
**Hashing Binary Data** ::
var utils = require('ethers').utils;
console.log(utils.keccak256([ 0x42 ]));
// '0x1f675bff07515f5df96737194ea945c36c41e7b4fcef307b7cd4d0e602a69111'
console.log(utils.keccak256("0x42"));
// '0x1f675bff07515f5df96737194ea945c36c41e7b4fcef307b7cd4d0e602a69111'
console.log(utils.sha256([ 0x42 ]));
// '0xdf7e70e5021544f4834bbee64a9e3789febc4be81470df629cad6ddb03320a5c'
console.log(utils.sha256("0x42"));
// '0xdf7e70e5021544f4834bbee64a9e3789febc4be81470df629cad6ddb03320a5c'
**Hashing UTF-8 Strings** ::
var utils = require('ethers').utils;
// Convert the string to binary data
var utf8Bytes = utils.toUtf8Bytes('Hello World');
console.log(utils.keccak256(utf8Bytes));
// '0x592fa743889fc7f92ac2a37bb1f5ba1daf2a5c84741ca0e0061d243a2e6707ba'
console.log(utils.sha256(utf8Bytes));
// '0xa591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e'
console.log(utils.id("Hello World"));
// '0x592fa743889fc7f92ac2a37bb1f5ba1daf2a5c84741ca0e0061d243a2e6707ba'
console.log(utils.id("addr(bytes32)"));
// '0x3b3b57de213591bb50e06975ea011e4c8c4b3e6de4009450c1a9e55f66e4bfa4'
**Random Bytes** ::
var utils = require('ethers').utils;
console.log(utils.randomBytes(3));
// Uint8Array [ 194, 22, 140 ]
-----
Solidity Cryptographic Functions
================================
Solidity uses a `non-standard packed mode`_ to encode parameters that are passed
into its hashing functions. The parameter types and values can be used to compute
the result of the hash functions as would be performed by Solidity.
:sup:`utils` . solidityKeccak256 ( types, values )
Compute the keccak256 cryptographic hash using the Solidity non-standard (tightly)
packed data for *values* given the *types*.
:sup:`utils` . soliditySha256 ( types, values )
Compute the SHA256 cryptographic hash using the Solidity non-standard (tightly)
packed data for *values* given the *types*.
:sup:`utils` . solidityPack ( types, values )
Compute the Solidity non-standard (tightly) packed data for *values* given the *types*.
*Examples*
----------
::
var utils = require('ethers').utils;
var result = utils.solidityKeccak256([ 'int8', 'bytes1', 'string' ], [ -1, '0x42', 'hello' ]);
console.log(result);
// '0x52d7e6a62ca667228365be2143375d0a2a92a3bd4325dd571609dfdc7026686e'
result = utils.soliditySha256([ 'int8', 'bytes1', 'string' ], [ -1, '0x42', 'hello' ]);
console.log(result);
// '0x1eaebba7999af2691d823bf0c817e635bbe7e89ec7ed32a11e00ca94e86cbf37'
result = utils.solidityPack([ 'int8', 'bytes1', 'string' ], [ -1, '0x42', 'hello' ]);
console.log(result);
// '0xff4268656c6c6f'
-----
.. _api-arrayish:
Arrayish
========
An arrayish object is any such that it:
* has a *length* property
* has a value for each index from 0 up to (but excluding) *length*
* has a valid byte for each value; a byte is an integer in the range [0, 255]
* is **NOT** a string
:sup:`utils` . isArrayish ( object )
Returns true if *object* can be treated as an arrayish object.
:sup:`utils` . arrayify ( hexStringOrBigNumberOrArrayish )
Returns a Uint8Array of a hex string, BigNumber or of an `Arrayish`_ object.
:sup:`utils` . concat ( arrayOfHexStringsAndArrayish )
Return a Uint8Array of all *arrayOfHexStringsAndArrayish* concatenated.
:sup:`utils` . padZeros ( typedUint8Array, length )
Return a Uint8Array of *typedUint8Array* with zeros prepended to *length* bytes.
:sup:`utils` . stripZeros ( hexStringOrArrayish )
Returns a Uint8Array with all leading zero **bytes** striped.
-----
.. _hexstring:
Hex Strings
===========
A hex string is **always** prefixed with "0x" and consists of the characters
0 -- 9 and a -- f. It is always returned lower case with even-length, but any hex
string passed into a function may be any case and may be odd-length.
:sup:`utils` . hexlify ( numberOrBigNumberOrHexStringOrArrayish )
Converts any number, :ref:`BigNumber <bignumber>`, hex string or
`Arrayish`_ to a hex string. (otherwise, throws an error)
-----
Contract Addresses
==================
Every contract deployed on the Ethereum network requires an address (you can think
of this as the memory address which the running application lives at). The address
is generated from a cryptographic hash of the address of the creator and the nonce
of the transaction.
:sup:`utils` . getContractAddress ( transaction )
Computes the contract address a contract would have if this transaction
created a contract. (transaction requires only ``from`` and ``nonce`` be
defined)
*Examples*
----------
::
var utils = require('ethers').utils;
// Ropsten: 0x5bdfd14fcc917abc2f02a30721d152a6f147f09e8cbaad4e0d5405d646c5c3e1
var transaction = {
from: '0xc6af6e1a78a6752c7f8cd63877eb789a2adb776c',
nonce: 0
};
console.log(utils.getContractAddress(transaction));
// "0x0CcCC7507aEDf9FEaF8C8D731421746e16b4d39D"
-----
.. _non-standard packed mode: http://solidity.readthedocs.io/en/develop/abi-spec.html#non-standard-packed-mode
.. EOF

@ -1,405 +0,0 @@
.. _api-wallet:
Wallets
*******
A **wallet** manages a private/public key pair which is used to cryptographically sign
transactions and prove ownership on the Ethereum network.
-----
Creating Instances
==================
new :sup:`ethers` . Wallet( privateKey [ , provider ] )
Creates a new instance from *privateKey* and optionally connect a provider
:sup:`ethers . Wallet` . createRandom ( [ options ] )
Creates a new random wallet; *options* may specify ``extraEntropy`` to stir into
the random source (make sure this wallet is stored somewhere safe; if lost there
is no way to recover it)
:sup:`ethers . Wallet` . fromEncryptedWallet ( json, password [ , progressCallback ] )
Decrypt an encrypted Secret Storage JSON Wallet (from Geth, or that was
created using *prototype.encrypt* )
:sup:`ethers . Wallet` . fromMnemonic ( mnemonic [ , path ] )
Generate a BIP39 + BIP32 wallet from a *mnemonic* deriving path
**default:** *path*\ ="m/44'/60'/0'/0/0"
:sup:`ethers . Wallet` . fromBrainWallet ( username , password [ , progressCallback ] )
Generate a wallet from a username and password
*Examples*
----------
**Private Key** ::
var privateKey = "0x0123456789012345678901234567890123456789012345678901234567890123";
var wallet = new Wallet(privateKey);
console.log("Address: " + wallet.address);
// "Address: 0x14791697260E4c9A71f18484C9f997B308e59325"
**Random Wallet** ::
var wallet = Wallet.createRandom();
console.log("Address: " + wallet.address);
// "Address: ... this will be different every time ..."
**Secret Storage Wallet** (e.g. Geth or Parity) ::
var data = {
id: "fb1280c0-d646-4e40-9550-7026b1be504a",
address: "88a5c2d9919e46f883eb62f7b8dd9d0cc45bc290",
Crypto: {
kdfparams: {
dklen: 32,
p: 1,
salt: "bbfa53547e3e3bfcc9786a2cbef8504a5031d82734ecef02153e29daeed658fd",
r: 8,
n: 262144
},
kdf: "scrypt",
ciphertext: "10adcc8bcaf49474c6710460e0dc974331f71ee4c7baa7314b4a23d25fd6c406",
mac: "1cf53b5ae8d75f8c037b453e7c3c61b010225d916768a6b145adf5cf9cb3a703",
cipher: "aes-128-ctr",
cipherparams: {
iv: "1dcdf13e49cea706994ed38804f6d171"
}
},
"version" : 3
};
var json = JSON.stringify(data);
var password = "foo";
Wallet.fromEncryptedWallet(json, password).then(function(wallet) {
console.log("Address: " + wallet.address);
// "Address: 0x88a5C2d9919e46F883EB62F7b8Dd9d0CC45bc290"
});
**Mnemonic Phrase** ::
var mnemonic = "radar blur cabbage chef fix engine embark joy scheme fiction master release";
var wallet = Wallet.fromMnemonic(mnemonic);
console.log("Address: " + wallet.address);
// "Address: 0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9"
**Brain Wallet** ::
var username = "support@ethers.io";
var password = "password123";
Wallet.fromBrainWallet(username, password).then(function(wallet) {
console.log("Address: " + wallet.address);
// "Address: 0x7Ee9AE2a2eAF3F0df8D323d555479be562ac4905"
});
-----
Prototype
=========
.. _address:
:sup:`prototype` . address
The public address of a wallet
:sup:`prototype` . privateKey
The private key of a wallet; keep this secret
:sup:`prototype` . provider
Optional; a connected :ref:`provider` which allows the wallet to connect to
the Ethereum network to query its state and send transactions
:sup:`prototype` . getAddress ( )
A function which returns the address; for Wallet, this simply returns the
`address`_ property
:sup:`prototype` . sign ( transaction )
Signs *transaction* and returns the signed transaction as a :ref:`hex string <hexstring>`.
See :ref:`Transaction Requests <transactionrequest>`.
:sup:`prototype` . signMessage ( message )
Signs *message* and returns the signature as a :ref:`hex string <hexstring>`.
:sup:`prototype` . encrypt ( password [ , options ] [ , progressCallback ] )
Returns a Promise with the wallet encrypted as a Secret Storage JSON Wallet;
*options* may include overrides for the scrypt parameters.
*Examples*
----------
**Signing Transactions** ::
var ethers = require('ethers');
var Wallet = ethers.Wallet;
var utils = ethers.utils;
var providers = ethers.providers;
var privateKey = "0x0123456789012345678901234567890123456789012345678901234567890123";
var wallet = new Wallet(privateKey);
console.log('Address: ' + wallet.address);
// "Address: 0x14791697260E4c9A71f18484C9f997B308e59325".
var transaction = {
nonce: 0,
gasLimit: 21000,
gasPrice: utils.bigNumberify("20000000000"),
to: "0x88a5C2d9919e46F883EB62F7b8Dd9d0CC45bc290",
value: utils.parseEther("1.0"),
data: "0x",
// This ensures the transaction cannot be replayed on different networks
chainId: providers.networks.homestead.chainId
};
var signedTransaction = wallet.sign(transaction);
console.log(signedTransaction);
// "0xf86c808504a817c8008252089488a5c2d9919e46f883eb62f7b8dd9d0cc45bc2" +
// "90880de0b6b3a7640000801ca0d7b10eee694f7fd9acaa0baf51e91da5c3d324" +
// "f67ad827fbe4410a32967cbc32a06ffb0b4ac0855f146ff82bef010f6f2729b4" +
// "24c57b3be967e2074220fca13e79"
// This can now be sent to the Ethereum network
var provider = providers.getDefaultProvider();
provider.sendTransaction(signedTransaction).then(function(hash) {
console.log('Hash: ' + hash);
// Hash:
});
**Encrypting** ::
var password = "password123";
function callback(percent) {
console.log("Encrypting: " + parseInt(percent * 100) + "% complete");
}
var encryptPromise = wallet.encrypt(password, callback);
encryptPromise.then(function(json) {
console.log(json);
});
-----
Blockchain Operations
=====================
These operations require the wallet have a provider attached to it.
:sup:`prototype` . getBalance ( [ blockTag ] )
Returns a Promise with the balance of the wallet (as a :ref:`BigNumber <bignumber>`,
in **wei**) at the :ref:`blockTag <blocktag>`.
**default:** *blockTag*\ ="latest"
:sup:`prototype` . getTransactionCount ( [ blockTag ] )
Returns a Promise with the number of transactions this account has ever sent
(also called the *nonce*) at the :ref:`blockTag <blocktag>`.
**default:** *blockTag*\ ="latest"
:sup:`prototype` . estimateGas ( transaction )
Returns a Promise with the estimated cost for *transaction* (in **gas**, as a
:ref:`BigNumber <bignumber>`)
:sup:`prototype` . sendTransaction ( transaction )
Sends the *transaction* to the network and returns a Promise with the transaction
details. It is highly recommended to omit *transaction.chainId*, it will be
filled in by *provider*.
:sup:`prototype` . send ( addressOrName, amountWei [ , options ] )
Sends *amountWei* to *addressOrName* on the network and returns a Promise with the
transaction details.
*Examples*
----------
**Query the Network** ::
var privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
var wallet = new ethers.Wallet(privateKey);
wallet.provider = ethers.providers.getDefaultProvider();
var balancePromise = wallet.getBalance();
balancePromise.then(function(balance) {
console.log(balance);
});
var transactionCountPromise = wallet.getTransactionCount();
transactionCountPromise.then(function(transactionCount) {
console.log(transactionCount);
});
**Transfer Ether** ::
var privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
var wallet = new ethers.Wallet(privateKey);
wallet.provider = ethers.providers.getDefaultProvider();
// We must pass in the amount as wei (1 ether = 1e18 wei), so we use
// this convenience function to convert ether to wei.
var amount = ethers.utils.parseEther('1.0');
var address = '0x88a5c2d9919e46f883eb62f7b8dd9d0cc45bc290';
var sendPromise = wallet.send(address, amount);
sendPromise.then(function(transactionHash) {
console.log(transactionHash);
});
// These will query the network for appropriate values
var options = {
//gasLimit: 21000
//gasPrice: utils.bigNumberify("20000000000")
};
var promiseSend = wallet.send(address, amount, options);
promiseSend.then(function(transaction) {
console.log(transaction);
});
**Sending (Complex) Transactions** ::
var privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
var wallet = new ethers.Wallet(privateKey);
wallet.provider = ethers.providers.getDefaultProvider('ropsten');
var transaction = {
// Recommendation: omit nonce; the provider will query the network
// nonce: 0,
// Gas Limit; 21000 will send ether to another use, but to execute contracts
// larger limits are required. The provider.estimateGas can be used for this.
gasLimit: 1000000,
// Recommendations: omit gasPrice; the provider will query the network
//gasPrice: utils.bigNumberify("20000000000"),
// Required; unless deploying a contract (in which case omit)
to: "0x88a5C2d9919e46F883EB62F7b8Dd9d0CC45bc290",
// Optional
data: "0x",
// Optional
value: ethers.utils.parseEther("1.0"),
// Recommendation: omit chainId; the provider will populate this
// chaindId: providers.networks.homestead.chainId
};
// Estimate the gas cost for the transaction
//var estimateGasPromise = wallet.estimateGas(transaction);
//estimateGasPromise.then(function(gasEstimate) {
// console.log(gasEstimate);
//});
// Send the transaction
var sendTransactionPromise = wallet.sendTransaction(transaction);
sendTransactionPromise.then(function(transactionHash) {
console.log(transactionHash);
});
-----
Parsing Transactions
====================
:sup:`Wallet` . parseTransaction ( hexStringOrArrayish )
Parses a raw *hexStringOrArrayish* into a Transaction.
*Examples*
----------
::
// Mainnet:
var ethers = require('ethers');
var Wallet = ethers.Wallet;
var utils = ethers.utils;
var privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
var wallet = new ethers.Wallet(privateKey);
var raw = "0xf87083154262850500cf6e0083015f9094c149be1bcdfa69a94384b46a1f913" +
"50e5f81c1ab880de6c75de74c236c8025a05b13ef45ce3faf69d1f40f9d15b007" +
"0cc9e2c92f"
var transaction = {
nonce: 1393250,
gasLimit: 21000,
gasPrice: utils.bigNumberify("20000000000"),
to: "0xc149Be1bcDFa69a94384b46A1F91350E5f81c1AB",
value: utils.parseEther("1.0"),
data: "0x",
// This ensures the transaction cannot be replayed on different networks
chainId: ethers.providers.networks.homestead.chainId
};
var signedTransaction = wallet.sign(transaction);
var transaction = Wallet.parseTransaction(signedTransaction);
console.log(transaction);
// { nonce: 1393250,
// gasPrice: BigNumber { _bn: <BN: 4a817c800> },
// gasLimit: BigNumber { _bn: <BN: 5208> },
// to: '0xc149Be1bcDFa69a94384b46A1F91350E5f81c1AB',
// value: BigNumber { _bn: <BN: de0b6b3a7640000> },
// data: '0x',
// v: 38,
// r: '0x3cf1f5af8bd11963193451096d86635aed589572c184ac8696dd99c9c044ded3',
// s: '0x08c52dbf1383492c72598511bb135179ec93b062032d2a0d002214644ba39a2c',
// chainId: 1,
// from: '0x14791697260E4c9A71f18484C9f997B308e59325' }
-----
Verifying Messages
==================
:sup:`ethers . Wallet` . verifyMessage ( message , signature )
Returns the address that signed *message* with *signature*.
*Examples*
----------
::
var signature = "0xddd0a7290af9526056b4e35a077b9a11b513aa0028ec6c9880948544508f3c63" +
"265e99e47ad31bb2cab9646c504576b3abc6939a1710afc08cbf3034d73214b8" +
"1c";
var address = Wallet.verifyMessage('hello world', signature);
console.log(address);
// '0x14791697260E4c9A71f18484C9f997B308e59325'
-----
.. EOF

@ -1,16 +0,0 @@
.. _api:
Application Programming Interface (API)
***************************************
.. toctree::
:maxdepth: 2
api-wallet
api-providers
api-contract
api-utils
-----
.. EOF

@ -1,259 +0,0 @@
Cookbook
********
This is a small (but growing) collection of simple recipes to perform common tasks
with the Ethereum blockchain and Ethereum accounts.
Some of these recipes are stubs that will be filled in shortly.
If there is a simple recipe you would like added, please send suggestions to support@ethers.io.
-----
Dump All JSON Wallet Balances (in current directory)
====================================================
::
var fs = require('fs');
var path = require('path');
var ethers = require('ethers');
var provider = ethers.providers.getDefaultProvider();
// Geth
var dirname = path.join(process.env.HOME, '.ethereum', 'keystore');
// Parity (use the name of your chain for chainDirectory, such as "homestead")
//var dirname = path.join(process.env.HOME, '.parity', 'keys', chainDirectory, 'keys');
var filenames = fs.readdirSync(dirname);
filenames.forEach(function(filename) {
fs.readFile(path.join(dirname,filename), function(error, data) {
if (error) {
console.log('Error reading file: ' + error.message);
return;
}
var address = JSON.parse(data.toString()).address;
provider.getBalance(address).then(function(balance) {
console.log(address + ':' + ethers.utils.formatEther(balance));
});
});
});
-----
Empty One Account into Another
==============================
::
var ethers = require('ethers');
var provider = ethers.providers.getDefaultProvider();
var newAddress = '';
var privateKey = '';
var wallet = new ethers.Wallet(privateKey, provider);
Promise.all([
wallet.getBalance(),
provider.getGasPrice(),
provider.getCode(newAddress)
]).then(function(results) {
var balance = results[0];
var gasPrice = results[1];
var code = results[2];
if (code !== '0x') {
throw new Error('this tool should not send to a contract');
}
// The exact cost (in gas) to send to an Externally Owned Account (EOA)
var gasLimit = 21000;
// The balance less exactly the txfee in wei
var value = balance.sub(gasPrice.mul(gasLimit))
wallet.send(newAddress, value, {gasLimit: gasLimit}).then(function(transaction) {
console.log(transaction);
});
});
-----
Transactions Confirm UI (with a Custom Signer)
==============================================
::
function CustomSigner(privateKey) {
this.provider = ethers.getDefaultProvider();
var wallet = new ethers.Wallet(privateKey);
this.address = wallet.address;
this.sign = function(transaction) {
return new Promise(function(resolve, reject) {
var allow = confirm('Sign Transaction? To: ' + transaction.to +
", Amount: " + ethers.formatEther(transaction.value));
var etherString = ethers.formatEther(transaction.value);
var modal = document.createElement('pre');
document.body.appendChild(modal);
modal.className = "modal";
modal.textContent += 'Sign Transaction?\n';
modal.textContent += 'To: ' + transaction.address + '\n';
modal.textContent += 'Amount: ' + etherString + '\n';
var confirmButton = document.createElement('div');
modal.appendChild(confirmButton);
confirmButton.textContent = ""confirm";
confirmButton.onclick = function() {
resolve(wallet.sign(transaction));
}
var rejectButton = document.createElement('div');
modal.appendChild(rejectButton);
rejectButton.textContent = ""confirm";
rejectButton.onclick = function() {
modal.remove();
reject(new Error('cancelled transaction'));
}
}
}
-----
Break Apart r, s and v from a Message Signature
================================================
::
var ethers = require('ethers');
var privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
var message = "Hello World";
var wallet = new ethers.Wallet(privateKey);
var signature = wallet.signMessage(message);
// Split apart the signature into an r, s and v that can be used by
// ecrecover in Solidity. The v parameter will be normalized to the
// canonical value of 27 or 28.
var sig = ethers.utils.splitSignature(signature);
console.log(sig);
// {
// r: '0xe0ed34fbbe927a58267ce2e8067a611c69869e20e731bc99187a8bc97058664c',
// s: '0x16de07f7660f06ce0985d1d8e063726783033fda59b307897f26a21392d62b3a',
// v: 28
// }
-----
Coalesce Jaxx Wallets
=====================
The Jaxx Wallet (for iOS, Android, desktop, et cetera) uses HD wallets on Ethereum the
same way as Bitcoin, which results in each transaction being received by a separate
address. As a result, funds get spread across many accounts, making several operations
in Ethereum impossible.
This short recipe will coalesce all these accounts into a single one, by sending the funds
from each account into a single one.
This also results in paying multiple transaction fees (1 fee per account to merge).
@TODO: This is incomplete!!
*Source Code*
-------------
::
var ethers = require('ethers');
var provider = ethers.providers.getDefaultProvider();
var mnemonic = "radar blur cabbage chef fix engine embark joy scheme fiction master release";
var hdnode = ethers.HDNode.fromMnemonic(mnemonic);
hdnode = hdnode.derivePath("m/44'/60'/0'/0");
@TODO:
-----
Access Funds in a Mnemonic Phrase Wallet
========================================
@TODO: This is incomplete
*Source Code*
-------------
::
var ethers = require('ethers');
var walletPath = {
"standard": "m/44'/60'/0'/0/0",
// @TODO: Include some non-standard wallet paths
};
var mnemonic = "radar blur cabbage chef fix engine embark joy scheme fiction master release";
var hdnode = ethers.HDNode.fromMnemonic(mnemonic);
var node = hdnode.derivePath(walletPath.standard);
var wallet = new ethers.Wallet(node.privateKey);
console.log(wallet.address);
// 0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9
@TODO:
-----
Custom Provider
===============
This is a much more advanced topic, and most people should not need to work this
low level. But it is provided for those rare instances where you need some custom
connection logic.
A provider must only implement the method **perform(method, params)**. All data passed
into a provider is sanitized by the Provider subclass, and all results are normalized
before returning them to the user.
For this example, we will build a DebugProvider, which will simple proxy all commands
through to INFURA, but dump all data going back and forth.
::
var inherits = require('inherits');
var ethers = require('ethers');
function DebugProvider(testnet) {
Provider.call(this, testnet);
this.subprovider = new ethers.providers.InfuraProvider(testnet);
}
inherits(DebugProvider, ethers.providers.Provider);
// This should return a Promise (and may throw erros)
// method is the method name (e.g. getBalance) and params is an
// object with normalized values passed in, depending on the method
DebugProvier.prototype.perform = function(method, params) {
this.subprovider.perform(method, params).then(function(result) {
console.log('DEBUG', method, params, '=>', result);
});
}
-----
.. EOF

@ -1,39 +0,0 @@
Getting Started
***************
The ethers.js library is a compact and complete JavaScript library for Ethereum.
-----
Installing in Node.js
=====================
From your project directory::
/Users/ricmoo/my-project> npm install --save ethers
And from the relevant application files::
var ethers = require('ethers');
-----
Including in Web Applications
=============================
For security purposes, it is usually best to place a copy of `this script`_ on
the application's server, but for a quick prototype using the Ethers CDN (content
distribution network) should suffice::
<!-- This exposes the library as a global variable: ethers -->
<script src="https://cdn.ethers.io/scripts/ethers-v3.min.js"
charset="utf-8"
type="text/javascript">
</script>
-----
.. _npm is installed: https://nodejs.org/en/
.. _this script: https://cdn.ethers.io/scripts/ethers-v3.0.min.js

@ -1,27 +0,0 @@
.. ethers.js documentation master file, created by
sphinx-quickstart on Tue Nov 29 10:25:33 2016.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
What is ethers.js
*****************
This library (which was made for and used by ethers.io) is designed to make it
easier to write client-side JavaScript based wallets, keeping the private key on
the owner's machine at all times.
.. toctree::
:maxdepth: 3
:caption: Developer Documentation
getting-started
api
api-advanced
cookbook
notes
testing
-----
.. EOF

@ -1,195 +0,0 @@
Notes
*****
A few quick notes about some of the less obvious aspects of interacting with
Ethereum in JavaScript.
-----
.. _ieee754:
Why can't I just use numbers?
=============================
The first problem many encounter when dealing with Ethereum is the concept of numbers. Most
common currencies are broken down with very little granulairty. For example, there are only
100 cents in a single dollar. However, there are 10\ :sup:`18` **wei** in a single
**ether**.
JavaScript uses `IEEE 754 double-precision binary floating point`_ numbers to represent
numeric values. As a result, there are *holes* in the integer set after
9,007,199,254,740,991; which is problematic for *Ethereum* because that is only
around 0.009 ether (in wei).
To demonstrate how this may be an issue in your code, consider::
> (Number.MAX_SAFE_INTEGER + 4 - 5) == (Number.MAX_SAFE_INTEGER - 1)
false
To remedy this, all numbers (which can be large) are stored and manipulated
as :ref:`Big Numbers <bignumber>`.
The functions :ref:`parseEther( etherString ) <parseEther>` and :ref:`formatEther( wei ) <formatEther>` can be used to convert between
string representations, which are displayed to or entered by the user and Big Number representations
which can have mathematical operations handled safely.
-----
.. _promise:
Promises
========
A `Promise in JavaScript`_ is an object which simplifies many aspects of dealing with
asynchronous functions.
It allows a pending result to be treated in many ways as if it has already been resolved.
The most useful operations you will need are:
:sup:`Promise` . all ( promises )
Returns a new promise that resolves once all the *promises* have resolved.
:sup:`prototype` . then ( onResolve, onReject )
Returns another Promise, which once the Promise was resolved, the *onResolve*
function will be executed and if an error occurs, *onReject* will be called.
If *onResolve* returns a Promise, it will be inserted into the chain of the returned
promise. If *onResolve* throws an Error, the returned Promise will reject.
**Examples**
------------
**Cleaning out an account**
::
var ethers = require('ethers');
var targetAddress = "0x02F024e0882B310c6734703AB9066EdD3a10C6e0";
var privateKey = "0x0123456789012345678901234567890123456789012345678901234567890123";
var wallet = new ethers.Wallet(privateKey);
// Promises we are interested in
var provider = ethers.providers.getDefaultProvider('ropsten');
var balancePromise = provider.getBalance(wallet.address);
var gasPricePromise = provider.getGasPrice();
var transactionCountPromise = provider.getTransactionCount(wallet.address);
var allPromises = Promise.all([
gasPricePromise,
balancePromise,
transactionCountPromise
]);
var sendPromise = allPromises.then(function(results) {
// This function is ONLY called once ALL promises are fulfilled
var gasPrice = results[0];
var balance = results[1];
var transactionCount = results[2];
// Sending a transaction to an externally owned account (EOA) is 21000 gas)
var txFeeInWei = gasPrice.mul(21000);
// This will send the maximum amount (our balance minus the fee)
var value = balance.sub(txFeeInWei);
var transaction = {
to: targetAddress,
gasPrice: gasPrice,
gasLimit: 21000,
nonce: transactionCount,
// The amount to send
value: value,
// Prevent replay attacks across networks
chainId: provider.chainId,
};
var signedTransaction = wallet.sign(transaction);
// By returning a Promise, the sendPromise will resolve once the
// transaction is sent
return provider.sendTransaction(signedTransaction);
});
var minedPromise = sendPromise.then(function(transaction) {
// This will be called once the transaction is sent
// This promise will be resolve once the transaction has been mined.
return provider.waitForTransaction(transaction);
});
minedPromise.then(function(transaction) {
console.log("The transaction was mined: Block " + transaction.blockNumber);
});
// Promises can be re-used for their value; it will not make the external
// call again, and will provide the exact same result every time.
balancePromise.then(function(balance) {
// This *may* return before teh above allPromises, since it only
// required one external call. Keep in mind asynchronous calls can
// be called out of order.
console.log(balance);
});
-----
.. _checksum-address:
Checksum Address
================
A `checksum address`_ uses mixed case hexidecimal strings to encode the checksum
information in the capitalization of the alphabetic characters, while remaining
backwards compatible with non-checksum addresses.
Example::
// Valid; checksum (mixed case)
0xCd2a3d9f938e13Cd947eC05ABC7fe734df8DD826
// Valid; NO checksum (no mixed case)
0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826
0xCD2A3D9F938E13CD947EC05ABC7FE734DF8DD826
// INVALID; (mixed case, but case differs from first example)
0xDc2a3d9f938e13cd947ec05abc7fe734df8dd826
^^
To convert between ICAP and checksum addresses, see :ref:`getAddress() <api-getAddress>`.
.. _checksum address: https://github.com/ethereum/EIPs/issues/55
-----
.. _icap-address:
ICAP Address
============
The original method of adding a checksum to an Ethereum address was by using the
a format compatible with `IBAN`_ addresses, using the country code **XE**. However,
only addresses which have 0 as the first byte (i.e. the address begins with 0x00)
are truely compatible with IBAN, so ICAP extends the definition to allow for 31
alphanumeric characters (instead of the standard 30).
An ICAP address has the following format::
XE [2 digit checksum] [up to 31 alphanumeric characters]
To convert between ICAP and checksum addresses, see :ref:`getAddress() <api-getAddress>`.
-----
.. _IBAN: https://en.wikipedia.org/wiki/International_Bank_Account_Number
.. _IEEE 754 double-precision binary floating point: https://en.wikipedia.org/wiki/Double-precision_floating-point_format
.. _BN.js: https://github.com/indutny/bn.js/
.. _Promise in JavaScript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
.. EOF

@ -1,19 +0,0 @@
Testing
*******
Ethers uses a large suite of test cases to help ensure the library is as
complete, backwards compatible and correct as possible and pass
regression as new features are added.
Many of the test cases are created procedurally.
**@TODO:**
Explain more here on how to run and add testcases.
**@TODO:**
Post links to the testcases on IPFS (the generated test cases can takes hours to
generate and are too large to check into GitHub)
-----
.. EOF

@ -1,565 +0,0 @@
.. |nbsp| unicode:: U+00A0 .. non-breaking space
Low-Level API
**************
These are advanced, low-level API features that should, for most people not be
necessary to worry about.
They are lightly documented here, and in the future will have more documentation,
but the emphasis at this point is documenting the more :ref:`common methods <api>`.
-----
ABI Coder
=========
Creating Instances
------------------
new :sup:`ethers . utils` **. AbiCoder** ( [ coerceFunc ] )
Create a new ABI Coder object, which calls *coerceFunc* for each parsed value
during decoding. The *coerceFunc* should have the signature: ``function(type, value)``.
Static Properties
-----------------
:sup:`ethers . utils` **. defaultAbiCoder**
A default instance of the coder which can be used, which has a *coerceFunc*
which will call ``toNumber()`` on BigNumbers whose **type** is less than
53 bits and is safe for JavaScript Number instances.
Prototype
---------
:sup:`prototype` . encode ( types , values ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Returns a :ref:`hex string <hexstring>` of the *values* encoded as the *types*.
Throws if a value is invalid for the type.
:sup:`prototype` . decode ( types , data ) |nbsp| :sup:`=>` |nbsp| :sup:`Result`
Returns an Object by parsing *data* assuming *types*, with each parameter
accessible as a positional parameters. Throws if *data* is invalid
for the *types*.
-----
.. _api-hdnode:
HDNode
======
A *Hierarchical Deterministic Wallet* represents a large tree of private keys
which can reliably be reproduced from an initial seed. Each node in the tree
is represented by an HDNode which can be descended into.
A *mnemonic phrase* represents a simple way to generate the initial seed.
See the `BIP 32 Specification`_ to learn more about HD Wallets and hardened vs
non-hardened nodes.
See the `BIP 39 Specification`_ to learn more about Mnemonic Phrases.
Creating Instances
------------------
:sup:`ethers . utils . HDNode` **. fromMnemonic** ( mnemonic ) |nbsp| :sup:`=>` |nbsp| :sup:`HDNode`
Create an HDNode from a *mnemonic* phrase.
:sup:`ethers . utils . HDNode` **. fromSeed** ( seed ) |nbsp| :sup:`=>` |nbsp| :sup:`HDNode`
Create an HDNode from a seed.
:sup:`ethers . utils . HDNode` **. fromExtendedKey** ( extendedKey ) |nbsp| :sup:`=>` |nbsp| :sup:`HDNode`
Create an HDNode from an extended private key (xpriv) or extended public key (xpub).
Prototype
---------
:sup:`prototype` **. privateKey**
The :ref:`hex string <hexstring>` private key for this node.
:sup:`prototype` **. publicKey**
The (compressed) public key for this node.
:sup:`prototype` **. chainCode**
The chain code for this node.
:sup:`prototype` **. index**
The index (from the parent) of this node (0 for the master node).
:sup:`prototype` **. depth**
The depth within the hierarchy of this node.
:sup:`prototype` **. fingerprint**
The fingerprint of this node. This can be used to identify a node, but wallets
should handle collisions.
:sup:`prototype` **. parentFingerprint**
The fingerprint of this node's parent (or 0x00000000 for the master node).
:sup:`prototype` **. extendedKey**
The extended private key (xpriv) of the node, or the extended public key (xpub)
if the node has been neutered.
Deriving Child and Neutered Nodes
---------------------------------
:sup:`prototype` **. derivePath** ( path ) |nbsp| :sup:`=>` |nbsp| :sup:`HDNode`
Derive the path from this node. Path is slash (**/**) delimited path components.
The first component may be "m" for master (which enforces the starting node is
in fact a master node) and each subsequent path component should be a positive
integer (up to 31 bits), which can optionally include an apostrophe (**'**) to
indicate hardened derivation for that path components. See below for some examples.
:sup:`prototype` **. neuter** ( ) |nbsp| :sup:`=>` |nbsp| :sup:`HDNode`
Returns a new instance of the node without a private key. This can be used to
derive an extended public key. See the BIP32 standard for more details.
Static Methods
--------------
:sup:`ethers . utils . HDNode` **. mnemonicToEntropy** ( mnemonic ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Convert a *mnemonic* to its binary entropy. (throws an error if the checksum
is invalid)
:sup:`ethers . utils . HDNode` **. entropyToMnemonic** ( entropy ) |nbsp| :sup:`=>` |nbsp| :sup:`string`
Convert the binary *entropy* to the mnemonic phrase.
:sup:`ethers . utils . HDNode` **. mnemonicToSeed** ( mnemonic ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Compute the BIP39 seed from *mnemonic*.
:sup:`ethers . utils . HDNode` **. isValidMnemonic** ( string ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean`
Returns true if and only if the string is a valid mnemonic (including
the checksum)
.. code-block:: javascript
:caption: *HDNode derivation*
let HDNode = require('ethers').utils.HDNode;
let mnemonic = "radar blur cabbage chef fix engine embark joy scheme fiction master release";
let masterNode = HDNode.fromMnemonic(mnemonic);
let standardEthereum = masterNode.derivePath("m/44'/60'/0'/0/0");
// Get the extended private key
let xpriv = node.extendedKey;
// Get the extended public key
let xpub = node.neuter().extnededKey;
-----
.. _api-interface:
Interface
=========
The Interface Object is a meta-class that accepts a Solidity (or compatible)
Application Binary Interface (ABI) and populates functions to deal with encoding
and decoding the parameters to pass in and results returned.
Creating an Instance
--------------------
new :sup:`ethers . utils` . Interface ( abi )
Returns a new instance and populates the properties with the ABI constructor,
methods and events. The *abi* may be either a JSON string or the parsed JSON
Object.
Prototype
---------
:sup:`prototype` . abi
A **copy** of the ABI is returned, modifying this object will not alter the ABI.
:sup:`prototype` . deployFunction
A DeployDesciption for the constructor defined in the ABI, or the default constructor
if omitted.
:sup:`prototype` . events
An object of all the events available in the ABI, by name and signature, which map
to a EventDescription.
:sup:`prototype` . functions
An object of all the functions available in the ABI, by name and signature, which map
to a FunctionDescription.
Parsing Objects
---------------
:sup:`prototype` . parseTransaction ( transaction ) |nbsp| :sup:`=>` |nbsp| :sup:`TransactionDescription`
Parse *transaction* and return a description of the call it represents.
:sup:`prototype` . parseLog ( log ) |nbsp| :sup:`=>` |nbsp| :sup:`LogDescription`
Parse *log* and return a description of the event logs it represents.
Object Test Functions
---------------------
:sup:`prototype` . isInterface ( value ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean`
Returns true if *value* is an Interface.
:sup:`prototype` . isIndexed ( value ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean`
Returns true if *value* is a dynamic Indexed value, which means the actual
value of *value* is the hash of the actual value.
Descriptions
------------
**Deploy Description**
============================== ======================================
name description
============================== ======================================
inputs The description of the constructor input parameters
payable Whether the constructor can accept *Ether*
encode(params) A function which encodes *params*
============================== ======================================
**Event Description**
============================== ======================================
name description
============================== ======================================
name The event name (e.g. "Transfer")
signature The event signature (e.g. "Transfer(address indexed,address indexed,uint256)")
inputs The event input parameters
anonymous Whether the event is an anonymous event
topic The topic for this event signature
encodeTopics(params) A function which computes filter topics for given *params*
decode(data, topics) A function to parse the log result *data* and *topics*
============================== ======================================
**Function Description**
============================== ======================================
name description
============================== ======================================
name The method name (e.g. "transfer")
type The method type (i.e. "call" or "transaction")
signature The method signature (e.g. "transfer(address to, uint256 amount)")
sighash The signature hash of the signature (4 bytes)
inputs The description of the method input parameters
outputs The description of the method output parameters
payable Whether the method can accept *Ether*
gas The maximum gas this method will consume (null if unknown)
encode(params) A function which encodes *params*
decode(data) A function which decodes the result *data*
============================== ======================================
**Log Description**
============================== ======================================
name description
============================== ======================================
name The event name (e.g. "Transfer")
signature The event signature (e.g. "Transfer(address indexed,address indexed,uint256)")
topics The event topics
decode(data, topics) A function to parse the logs
values The decoded values of the event
============================== ======================================
**Transaction Description**
============================== ======================================
name description
============================== ======================================
name The method name (e.g. "transfer")
args The arguments passed to the method
signature The method signature (e.g. "transfer(address to, uint256 amount)")
sighash The signature hash of the signature (4 bytes)
decode(data) A function to parse the result data
value The value (in wei) of the transaction
============================== ======================================
-----
Provider (Sub-Classing)
=======================
See the :ref:`Provider API <api-provider>` for more common usage. This documentation
is designed for developers that are sub-classing BaseProvider.
Static Methods
--------------
:sup:`BaseProvider` . inherits ( childProvider ) |nbsp| :sup:`=>` |nbsp| :sup:`void`
Set up *childProvider* as an provider, inheriting the parent prototype and
set up a prototype.inherits on the *childProvider*.
Prototype
---------
:sup:`prototype` . perform ( method , params ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<any>`
The only method needed to override in a subclass. All values are sanitized
and defaults populated in params and the result is sanitized before returning.
Returns a :ref:`Promise <promise>`, see the example below for overview of
*method* and *params*.
.. code-block:: javascript
:caption: *BaseProvider Sub-Class Stub*
const ethers = require('ethers');
// The new provider Object
function DemoProvider(something) {
let network = getNetworkSomehow()
// The super must be called with either a Network or a Promise
// that resolves to a Network
ethers.providers.BaseProvider.call(this, network);
ethers.utils.defineReadOnly(this, 'somethingElse', somethingElse);
}
// Inherit the Provider
ethers.providers.BaseProvider.inherits(DemoProvider);
// Override perform
DemoProvider.prototype.perform = function(method, params) {
switch (method) {
case 'getBlockNumber':
// Params:
// { }
case 'getGasPrice':
// Params:
// { }
case 'getBalance':
// Params:
// {
// address: address,
// blockTag: blockTag
// }
case 'getTransactionCount':
// Params:
// {
// address: address,
// blockTag: blockTag
// }
case 'getCode':
// Params:
// {
// address: address,
// blockTag: blockTag
// }
case 'getStorageAt':
// Params:
// {
// address: address,
// position: hexString,
// blockTag: blockTag
// }
case 'sendTransaction':
// Params:
// {
// signedTransaction: hexString
// }
case 'getBlock':
// Params:
// Exactly one of the following will be specified, the other will be absent
// {
// blockHash: blockHash,
// blockTag: blockTag
// }
case 'getTransaction':
// Params:
// {
// transactionHash: hexString
// }
case 'getTransactionReceipt':
// Params:
// {
// transactionHash: hexString
// }
case 'call':
// Params:
// {
// transaction: See Transaction Requests (on Providers API)
// }
case 'estimateGas':
// Params:
// {
// transaction: See Transaction Requests (on Providers API)
// }
case 'getLogs':
// Params:
// {
// address: address,
// fromBlock: blockTag,
// toBlock: blockTag,
// topics: array (possibly nested) of topics
// }
default:
break;
}
return Promise.reject(new Error('not implemented - ' + method));
};
-----
Recursive-Length Prefixed Encoding (RLP)
========================================
This encoding method is used internally for several aspects of Ethereum, such as
encoding transactions and determining contract addresses. For most developers this
should not be necessary to use.
RLP can encode nested arrays, with data as :ref:`hex strings <hexstring>` and Uint8Array (or other non-Array
:ref:`arrayish <arrayish>` objects). A decoded object will always have data represented as :ref:`hex strings <hexstring>` and
Arrays.
See: https://github.com/ethereum/wiki/wiki/RLP
Static Methods
--------------
:sup:`ethers . utils . RLP` . encode( object ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Encodes an object as an RLP :ref:`hex string <hexstring>`. (throws an Error if the object contains
invalid items)
:sup:`ethers . utils . RLP` . decode( hexStringOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`any`
Decode *hexStringOrArrayish* into the encoded object. (throws an Error if
invalid RLP-coded data)
.. code-block:: javascript
:caption: *RLP coder*
let object = [ ["0x42"], "0x1234", [ [], [] ] ];
let encoded = ethers.utils.RLP.encode(object);
console.log(encoded);
// 0xc8c142821234c2c0c0
let decoded = ethers.utils.RLP.decode(encoded);
console.log(decoded);
// [ [ '0x42' ], '0x1234', [ [], [] ] ]
-----
Signing Key
===========
The SigningKey interface provides an abstraction around the
*secp256k1 elliptic curve cryptography* library, which signs digests,
computes public keys from private keys and performs *ecrecover* which
computes a public key from a digest and a signature.
Creating Instances
------------------
new :sup:`ethers . utils` . SigningKey ( privateKey )
Create a new SigningKey and compute the corresponding public key and address.
A private key may be a any :ref:`hex string <hexstring>` or an
:ref:`Arrayish <arrayish>` representing 32 bytes.
Prototype
---------
:sup:`prototype` . address
The Ethereum checksum address for this key pair.
:sup:`prototype` . privateKey
The private key for the key pair.
:sup:`prototype` . publicKey
The uncompressed public key for the key pair.
Cryptographic Operations
------------------------
:sup:`prototype` . signDigest ( messageDigest ) |nbsp| :sup:`=>` |nbsp| :sup:`Signature`
The :ref:`expanded-format Signature <signature>` for the digests, signed
by this key pair.
:sup:`prototype` . computeSharedSecret ( publicOrPrivateKey ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Compute the ECDH shared secret from this keys private key and the
*publicOrPrivateKey*. In is generally considered good practice to
further hash this value before using it as a key.
.. code-block:: javascript
:caption: *Signing Key*
const ethers = require('ethers');
let privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
let signingKey = new ethers.utils.SigningKey(privateKey);
console.log('Address: ' + signingKey.address);
// "Address: 0x14791697260E4c9A71f18484C9f997B308e59325"
let message = "Hello World";
let messageBytes = ethers.utils.toUtf8Bytes(message);
let messageDigest = ethers.utils.keccak256(messageBytes);
console.log("Digest: " + messageDigest);
// "Digest: 0x592fa743889fc7f92ac2a37bb1f5ba1daf2a5c84741ca0e0061d243a2e6707ba"
let signature = signingKey.signDigest(messageDigest);
console.log(signature);
// {
// recoveryParam: 0,
// r: "0x79f56f3422dc67f57b2aeeb0b20295a99ec90420b203177f83d419c98beda7fe",
// s: "0x1a9d05433883bdc7e6d882740f4ea7921ef458a61b2cfe6197c2bb1bc47236fd"
// }
let recovered = ethers.utils.recoverAddress(messageDigest, signature);
console.log("Recovered: " + recovered);
// "Recovered: 0x14791697260E4c9A71f18484C9f997B308e59325"
let publicKey = signingKey.publicKey;
console.log('Public Key: ' + publicKey);
// "Public Key: 0x026655feed4d214c261e0a6b554395596f1f1476a77d999560e5a8df9b8a1a3515"
let compressedPublicKey = ethers.utlis.computePublicKey(publicKey, true);
let uncompressedPublicKey = ethers.utils.computePublicKey(publicKey, false);
console.log(compressedPublicKey);
// "0x026655feed4d214c261e0a6b554395596f1f1476a77d999560e5a8df9b8a1a3515"
console.log(uncompressedPublicKey);
// "0x046655feed4d214c261e0a6b554395596f1f1476a77d999560e5a8df9b8a1a35" +
// "15217e88dd05e938efdd71b2cce322bf01da96cd42087b236e8f5043157a9c068e"
let address = ethers.utils.computeAddress(publicKey);
console.log('Address: ' + address);
// "Address: 0x14791697260E4c9A71f18484C9f997B308e59325"
-----
.. _BIP 32 Specification: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
.. _BIP 39 Specification: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
.. EOF

@ -1,760 +0,0 @@
.. |nbsp| unicode:: U+00A0 .. non-breaking space
.. _api-contract:
Contracts
*********
A Contract is an abstraction of an executable program on the Ethereum Blockchain. A
Contract has code (called byte code) as well as allocated long-term memory (called
storage). Every deployed Contract has an address, which is used to connect to it
so that it may be sent messages to call its methods.
A Contract can emit **Events**, which can be efficiently observed by applications to
be notified when a contract has performed specific operation. Events cannot be read
by a Contract.
There are two types of methods that can be called on a Contract:
A **Constant** method may not add, remove or change any data in the storage, nor
log any events, and may only call **Constant** methods on other contracts. These
methods are free (**no** *Ether* is required) to call. The result from them may also
be returned to the caller.
A **Non-Constant** method requires a fee (in *Ether*) to be paid, but may perform any
state-changing operation desired, log events, send ether and call **Non-Constant**
methods on other Contracts. These methods **cannot** return their result to the caller.
These methods must be triggered by a transaction, sent by an Externally Owned Account (EOA)
either directly or indirectly (i.e. called from another contract), and are required
to be mined before the effects are present. Therefore, the duration required for these
operations can vary widely, and depend on the transaction gas price, network congestion and
miner priority heuristics.
The Contract API provides simple way to connect to a Contract and call its methods,
as functions on a JavaScript object, handling all the binary protocol conversion,
internal name mangling and topic construction. This allows a Contract object to be
used like any standard JavaScript object, without having to worry about the
low-level details of the Ethereum Virtual Machine or Blockchain.
The Contract object is a meta-class, which is a class that defines a Class at
run-time. The Contract definition (called an **Application Binary Interface**, or ABI)
can be provided and the available methods and events will be dynamically added to
the object.
Throughout this document, we will refer to the following Contract.
.. code-block:: javascript
:caption: *SimpleStorage Contract*
pragma solidity ^0.4.24;
contract SimpleStorage {
event ValueChanged(address indexed author, string oldValue, string newValue);
string _value;
constructor(string value) public {
emit ValueChanged(msg.sender, _value, value);
_value = value;
}
function getValue() view public returns (string) {
return _value;
}
function setValue(string value) public {
emit ValueChanged(msg.sender, _value, value);
_value = value;
}
}
-----
.. _contract-deployment:
Deploying a Contract
====================
To deploy a contract to the Ethereum network, a **ContractFactory** can be created
which manages the Contract bytecode and **Application Binary Interface** (ABI),
usually generated from the *Solidity* compiler.
Creating a Contract Factory
---------------------------
new :sup:`ethers` . ContractFactory ( abi , bytecode [ , signer ] )
Creates a factory for deployment of the Contract with *bytecode*, and the
constructor defined in the *abi*. The *signer* will be used to send
any deployment transaction.
:sup:`ethers` . ContractFactory . fromSolidity ( compilerOutput [ , signer ] )
Creates a ContractFactory from the *compilerOutput* of the *Solidity*
compiler or from the *Truffle* JSON.
(i.e. ``output.contracts['SimpleStorage.sol'].SimpleStorage``)
:sup:`prototype` . connect ( signer ) |nbsp| :sup:`=>` |nbsp| :sup:`ContractFactory`
Create a **new instance** of the ContractFactory, connected to the new *signer*.
Prototype
---------
:sup:`prototype` . bytecode
The Contract executable byte code..
:sup:`prototype` . interface
The Contract Application Binary Interface (ABI).
:sup:`prototype` . signer
The :ref:`Signer <signer>` that will be used to send transactions to the network.
If this is null, ``deploy()`` cannot be called.
Connecting
----------
:sup:`prototype` . attach ( address ) |nbsp| :sup:`=>` |nbsp| :sup:`Contract`
Connect to an existing instance of this Contract at *address* using the
Contract Interface and Signer.
Deployment
----------
:sup:`prototype` . deploy ( ... ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<Contract>`
Creates a transaction to deploy the transaction and
sends it to the network using the contract :ref:`Signer <signer>`, returning a
:ref:`Promise <promise>` that resolves to a Contract. The transaction is available
as contract.deployTransaction.
Keep in mind that the Contract may not be mined immediately. The
``contract.deployed()`` function will return a :ref:`Promise <promise>`
which will resolve once the contract is deployed, or reject if there
was an error during deployment.
:sup:`prototype` . getDeployTransaction ( ... ) |nbsp| :sup:`=>` |nbsp| :sup:`UnsignedTransaction`
Returns the transaction required to deploy the Contract with the provided
constructor arguments. This is often useful for signing offline transactions or
analysis tools.
.. code-block:: javascript
:caption: *Deploy a Contract*
const ethers = require('ethers');
// The Contract interface
let abi = [
"event ValueChanged(address indexed author, string oldValue, string newValue)",
"constructor(string value)",
"function getValue() view returns (string value)",
"function setValue(string value)"
];
// The bytecode from Solidity, compiling the above source
let bytecode = "0x608060405234801561001057600080fd5b506040516105bd3803806105bd8339" +
"8101604081815282518183526000805460026000196101006001841615020190" +
"91160492840183905293019233927fe826f71647b8486f2bae59832124c70792" +
"fba044036720a54ec8dacdd5df4fcb9285919081906020820190606083019086" +
"9080156100cd5780601f106100a2576101008083540402835291602001916100" +
"cd565b820191906000526020600020905b815481529060010190602001808311" +
"6100b057829003601f168201915b505083810382528451815284516020918201" +
"9186019080838360005b838110156101015781810151838201526020016100e9" +
"565b50505050905090810190601f16801561012e578082038051600183602003" +
"6101000a031916815260200191505b5094505050505060405180910390a28051" +
"610150906000906020840190610157565b50506101f2565b8280546001816001" +
"16156101000203166002900490600052602060002090601f0160209004810192" +
"82601f1061019857805160ff19168380011785556101c5565b82800160010185" +
"5582156101c5579182015b828111156101c55782518255916020019190600101" +
"906101aa565b506101d19291506101d5565b5090565b6101ef91905b80821115" +
"6101d157600081556001016101db565b90565b6103bc806102016000396000f3" +
"0060806040526004361061004b5763ffffffff7c010000000000000000000000" +
"0000000000000000000000000000000000600035041663209652558114610050" +
"57806393a09352146100da575b600080fd5b34801561005c57600080fd5b5061" +
"0065610135565b60408051602080825283518183015283519192839290830191" +
"85019080838360005b8381101561009f57818101518382015260200161008756" +
"5b50505050905090810190601f1680156100cc57808203805160018360200361" +
"01000a031916815260200191505b509250505060405180910390f35b34801561" +
"00e657600080fd5b506040805160206004803580820135601f81018490048402" +
"8501840190955284845261013394369492936024939284019190819084018382" +
"80828437509497506101cc9650505050505050565b005b600080546040805160" +
"20601f6002600019610100600188161502019095169490940493840181900481" +
"0282018101909252828152606093909290918301828280156101c15780601f10" +
"610196576101008083540402835291602001916101c1565b8201919060005260" +
"20600020905b8154815290600101906020018083116101a457829003601f1682" +
"01915b505050505090505b90565b604080518181526000805460026000196101" +
"00600184161502019091160492820183905233927fe826f71647b8486f2bae59" +
"832124c70792fba044036720a54ec8dacdd5df4fcb9285918190602082019060" +
"60830190869080156102715780601f1061024657610100808354040283529160" +
"200191610271565b820191906000526020600020905b81548152906001019060" +
"200180831161025457829003601f168201915b50508381038252845181528451" +
"60209182019186019080838360005b838110156102a557818101518382015260" +
"200161028d565b50505050905090810190601f1680156102d257808203805160" +
"01836020036101000a031916815260200191505b509450505050506040518091" +
"0390a280516102f49060009060208401906102f8565b5050565b828054600181" +
"600116156101000203166002900490600052602060002090601f016020900481" +
"019282601f1061033957805160ff1916838001178555610366565b8280016001" +
"0185558215610366579182015b82811115610366578251825591602001919060" +
"01019061034b565b50610372929150610376565b5090565b6101c991905b8082" +
"1115610372576000815560010161037c5600a165627a7a723058202225a35c50" +
"7b31ac6df494f4be31057c7202b5084c592bdb9b29f232407abeac0029";
// Connect to the network
let provider = ethers.getDefaultProvider('ropsten');
// Load the wallet to deploy the contract with
let privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
let wallet = new ethers.Wallet(privateKey, provider);
// Deployment is asynchronous, so we use an async IIFE
(async function() {
// Create an instance of a Contract Factory
let factory = new ethers.ContractFactory(abi, bytecode, wallet);
// Notice we pass in "Hello World" as the parameter to the constructor
let contract = await factory.deploy("Hello World");
// The address the Contract WILL have once mined
// See: https://ropsten.etherscan.io/address/0x2bd9aaa2953f988153c8629926d22a6a5f69b14e
console.log(contract.address);
// "0x2bD9aAa2953F988153c8629926D22A6a5F69b14E"
// The transaction that was sent to the network to deploy the Contract
// See: https://ropsten.etherscan.io/tx/0x159b76843662a15bd67e482dcfbee55e8e44efad26c5a614245e12a00d4b1a51
console.log(contract.deployTransaction.hash);
// "0x159b76843662a15bd67e482dcfbee55e8e44efad26c5a614245e12a00d4b1a51"
// The contract is NOT deployed yet; we must wait until it is mined
await contract.deployed()
// Done! The contract is deployed.
})();
-----
Connecting to Existing Contracts
=================================
Once a Contract has been deployed, it can be connected to using
the **Contract** object.
Connecting to a Contract
------------------------
new :sup:`ethers` . Contract ( addressOrName , abi , providerOrSigner )
Connects to the contract at *addressOrName* defined by *abi*, connected as *providerOrSigner*.
For supported formats for *abi*, see :ref:`Contract ABI <contract-abi>`.
For access capabilities and restrictions, see :ref:`Providers vs Signers <providers-vs-signers>`
.. code-block:: javascript
:caption: *Connecting to an existing Contract*
const ethers = require('ethers');
// The Contract interface
let abi = [
"event ValueChanged(address indexed author, string oldValue, string newValue)",
"constructor(string value)",
"function getValue() view returns (string value)",
"function setValue(string value)"
];
// Connect to the network
let provider = ethers.getDefaultProvider();
// The address from the above deployment example
let contractAddress = "0x2bD9aAa2953F988153c8629926D22A6a5F69b14E";
// We connect to the Contract using a Provider, so we will only
// have read-only access to the Contract
let contract = new ethers.Contract(contractAddress, abi, provider);
.. code-block:: javascript
:caption: *Calling a read-only Constant Method*
// Get the current value
let currentValue = await contract.getValue();
console.log(currentValue);
// "Hello World"
.. code-block:: javascript
:caption: *Calling a Non-Constant Method*
// A Signer from a private key
let privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
let wallet = new ethers.Wallet(privateKey, provider);
// Create a new instance of the Contract with a Signer, which allows
// update methods
let contractWithSigner = contract.connect(wallet);
// ... OR ...
// let contractWithSigner = new Contract(contractAddress, abi, wallet)
// Set a new Value, which returns the transaction
let tx = await contractWithSigner.setValue("I like turtles.");
// See: https://ropsten.etherscan.io/tx/0xaf0068dcf728afa5accd02172867627da4e6f946dfb8174a7be31f01b11d5364
console.log(tx.hash);
// "0xaf0068dcf728afa5accd02172867627da4e6f946dfb8174a7be31f01b11d5364"
// The operation is NOT complete yet; we must wait until it is mined
await tx.wait();
// Call the Contract's getValue() method again
let newValue = await contract.getValue();
console.log(currentValue);
// "I like turtles."
.. code-block:: javascript
:caption: *Listening to Events*
contract.on("ValueChanged", (author, oldValue, newValue, event) => {
// Called when anyone changes the value
console.log(author);
// "0x14791697260E4c9A71f18484C9f997B308e59325"
console.log(oldValue);
// "Hello World"
console.log(newValue);
// "Ilike turtles."
// See Event Emitter below for all properties on Event
console.log(event.blockNumber);
// 4115004
});
.. code-block:: javascript
:caption: *Filtering an Events*
// A filter that matches my Signer as the author
let filter = contract.filters.ValueChanged(wallet.address);
contract.on(filter, (author, oldValue, newValue, event) => {
// Called ONLY when your account changes the value
});
-----
Prototype
---------
:sup:`prototype` . address
The address (or ENS name) of the contract.
:sup:`prototype` . deployTransaction
If the contract was deployed by a ContractFactory, this is the transaction
used to deploy it, otherwise it is null.
:sup:`prototype` . interface
The :ref:`Interface <api-interface>` meta-class of the parsed
ABI. Generally, this should not need to be accessed directly.
Additional properties will be added to the prototype at run-time, based on
the ABI provided, see :ref:`Contract Meta-Class <contract-metaclass>`.
-----
Waiting for Deployment
----------------------
:sup:`prototype` . deployed ( ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<Contract>`
If the contract is the result of ``deploy()``, returns
a :ref:`Promise <promise>` that resolves to the contract once it
has been mined, or rejects if the contract failed to deploy. If the
contract has been deployed already, this will return a
:ref:`Promise <promise>` that resolves once the on-chain code has
been confirmed.
-----
.. _contract-metaclass:
Meta-Class Properties
=====================
Since a Contract is dynamic and loaded at run-time, many of the properties
that will exist on a Contract are determined at run-time from
the :ref:`Contract ABI <contract-abi>`.
Contract Methods
----------------
All functions populated from the ABI are also included on the contract object
directly, for example ``contract.functions.getValue()`` can also be called
using ``contract.getValue()``.
:sup:`prototype` . functions . *functionName*
An object that maps each ABI function name to a function that will
either call (for constant functions) or sign and send a transaction
(for non-constant functions)
Calling a **Constant** function requires either a :ref:`Provider <provider-connect>` or
a Signer with a :ref:`Provider <provider-connect>`.
Calling a **Non-Constant** function (i.e. sending a transaction) requires a
:ref:`Signer <signer>`.
:sup:`prototype` . estimate . *functionName*
An object that maps each ABI function name to a function that will
estimate the cost the provided parameters.
Contract Event Filters
----------------------
Filters allow for a flexible and efficient way to fetch only a subset of the
events that match specific criteria. The ``filters`` property contains a
function for every Event in the ABI that computes a Filter for a given
set of values. The ``null`` matches any value.
:sup:`prototype` . filters . *eventname*
A function that generates filters that can be listened to, using the
``on(eventName, ...)`` function, filtered by the Event values.
.. code-block:: javascript
:caption: *Filtering Events*
// A filter from me to anyone
let filterFromMe = contract.filters.Transfer(myAddress);
// A filter from anyone to me
let filterToMe = contract.filters.Transfer(null, myAddress);
// A filter from me AND to me
let filterFromMeToMe = contract.filters.Transfer(myAddress, myAddress);
contract.on(filterFromMe, (fromAddress, toAddress, value, event) => {
console.log('I sent', value);
});
contract.on(filterToMe, (fromAddress, toAddress, value, event) => {
console.log('I received', value);
});
contract.on(filterFromMeToMe, (fromAddress, toAddress, value, event) => {
console.log('Myself to me', value);
});
-----
.. _contract-overrides:
Overrides
=========
Every Contract method may take one additional (optional) parameter which specifies the
transaction (or call) overrides.
.. code-block:: javascript
:caption: *Contract Transaction Overrides*
// All overrides are optional
let overrides = {
// The maximum units of gas for the transaction to use
gasLimit: 23000,
// The price (in wei) per unit of gas
gasPrice: utils.parseUnits('9.0', 'gwei'),
// The nonce to use in the transaction
nonce: 123,
// The amount to send with the transaction (i.e. msg.value)
value: utils.parseEther('1.0'),
// The chain ID (or network ID) to use
chainId: 1
};
// Solidity: function someFunction(address addr) public
let tx = contract.someFunction(addr, overrides)
.. code-block:: javascript
:caption: *Contract Call Overrides*
let overrides = {
// The address to execute the call as
from: "0x0123456789012345678901234567890123456789",
// The maximum units of gas for the transaction to use
gasLimit: 23000,
};
// Solidity: function someFunction(address addr) public pure returns (bytes32 result)
let result = contract.someFunction(addr, overrides)
-----
.. _contract-event-emitter:
Event Emitter
=============
Each Contract supports many of the operations available from the `Event Emitter API`_.
To listen for Events, the contract requires either a :ref:`Provider <provider-connect>` or
a Signer with a :ref:`Provider <provider-connect>`.
Event Names
-----------
The available eventNames are:
- **string** -- The name of an event (e.g. "TestEvent" or "TestEvent(string, uint)")
- **filter** -- See :ref:`Contract Filters <contract-filter>`
- **\*** -- All events
Event Object
------------
All event callbacks receive the parameters specified in the ABI as well as one additional
Event Object with
- **blockNumber**, **blockHash**, **transactionHash** -- The Block and Transaction of the Log
- **address** -- The contract address for the Log
- **data** -- The Log data
- **topics** -- An array of the Log topics
- **args** -- An array of the parsed arguments for the event
- **event** -- the name of the event (e.g. "Transfer")
- **eventSignature** -- the full signature of the event (e.g. "Transfer(address,address,uint256)")
- **getBlock()** -- A function that resolves to the Block containing the Log
- **getTransaction()** -- A function that resolves to the Transaction containing the Log
- **getTransactionReceipt()** -- A function that resolves to the Transaction Receipt containing the Log
- **removeListener()** -- A function that removes this callack as a listener
- **decode(data, topics)** -- A function that decodes data and topics into parsed arguments
Configuring Events
------------------
:sup:`prototype` . on ( eventName , callback ) |nbsp| :sup:`=>` |nbsp| :sup:`Contract`
Registers *callback* to be called on every *eventName*. Returns the contract, so calls may be chained.
:sup:`prototype` . addListner ( eventName , callback ) |nbsp| :sup:`=>` |nbsp| :sup:`Contract`
An alias for ``on``.
:sup:`prototype` . once ( eventName , callback ) |nbsp| :sup:`=>` |nbsp| :sup:`Contract`
Register *callback* to be called at most once, for *eventName*. Returns the contract, so calls may be chained.
:sup:`prototype` . emit ( eventName , ... ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean`
Trigger all callbacks for *eventName*, returning true if there was at
least one listener. This should generally not be called directly.
:sup:`prototype` . listenerCount ( [ eventName ] ) |nbsp| :sup:`=>` |nbsp| :sup:`number`
Returns the number of callbacks registered for *eventName*.
:sup:`prototype` . listeners ( eventName ) |nbsp| :sup:`=>` |nbsp| :sup:`Listeners[]`
Returns a list of callbacks for *eventName*.
:sup:`prototype` . removeAllListeners ( eventName ) |nbsp| :sup:`=>` |nbsp| :sup:`Contract`
De-registers all listeners for *eventName*. Returns the contract, so calls may be chained.
:sup:`prototype` . removeListener ( eventName , callback ) |nbsp| :sup:`=>` |nbsp| :sup:`Contract`
De-registers the specific *callback* for *eventName*. Returns the contract, so calls may be chained.
.. code-block:: javascript
:caption: *Events*
contract.on("ValueChanged", (oldValue, newValue, event) => {
console.log(oldValue, newValue);
});
-----
.. _providers-vs-signers:
Providers vs Signers
====================
A Contract object has a notion of an "frame of reference", which will determine
what type of access and whom the Contract is enacted upon as. This is specified
by the **providerOrSigner** parameter when connecting to a Contract.
There are three possible cases for connecting a Contract using the providerOrSigner.
============================================ ========================================
providerOrSigner Operation Privileges
============================================ ========================================
:ref:`Provider <provider-connect>` Read-Only Access
:ref:`Signer <signer>` (without a provider) Write-Only Access (as account owner)
:ref:`Signer <signer>` (with a provider) Read and Write Access (as account owner)
============================================ ========================================
The **providerOrSigner** is immutable, so to change the "frame of reference" to
another account or provider, use the ``connect`` function.
:sup:`prototype` . connect ( providerOrSigner )
Create a **new instance** of the Contract object connected as *providerOrSigner*.
Types
=====
There are many variable types available in *Solidity*, some which convert
to and from JavaScript gracefully, and others that do not. Here are some
note regarding passing and returning values in Contracts.
Bytes
-----
Bytes are available in fixed-length or dynamic-length variants. In both cases, the
values are returned as a hex string and may be passed in as either a hex string or
as an :ref:`arrayish <arrayish>`.
To convert the string into an array, use the :ref:`arrayify() <arrayish>` utility function.
Integers
--------
Integers in *solidity* are a fixed number of bits (aligned to the nearest byte)
and are available in signed and unsigned variants.
For example, a **uint256** is 256 bits (32 bytes) and unsigned. An **int8**
is 8 bits (1 byte) and signed.
When the type is 48 bits (6 bytes) or less, values are returned as a JavaScript
Number, since Javascript Numbers are safe to use up to 53 bits.
Any types with 56 bits (7 bytes) or more will be returned as a BigNumber,
even if the *value* is within the 53 bit safe range.
When passing numeric values in, JavaScript Numbers, hex strings or any BigNumber
is acceptable (however, take care when using JavaScript Numbers and performing
mathematical operations on them).
The **uint** and **int** types are aliases for **uint256** and **int256**,
respectively.
Strings
-------
For short strings, many Contracts use a bytes32 to encode a null-terminated
string representation, rather than a length-prefixed representation, so the
:ref:`formatBytes32String <bytes32string>` and :ref:`parseBytes32String <bytes32string>`
utility functions can be used to handle this conversion.
To convert between the two dynamic types, strings and bytes, the
:ref:`toUtf8Bytes() <utf8-strings>` and :ref:`toUtf8String() <utf8-strings>`
utility functions can be used.
Structs
-------
Structs can be specified as Objects with their named properties, or as an Array,
the same length as the struct.
**Constant** methods which return a single item, return that item directly. If the
method returns multiple values then an object is returned which can be accessed by
either the named properties or by their indices, in which case both point to the
**same instance**.
.. code-block:: javascript
:caption: *Example Return Types*
/**
* Contract Methods
*
* function oneItem() public view returns (uint256 param1);
* function twoItems() public view returns (uint256 param1, uint256 param2);
*
*/
let resultOne = await oneItem();
console.log(resultOne);
// 1337
let resultTwo = await twoItems();
console.log(resultTwo);
// {
// "param1": 1337,
// "param2": 42,
// 0: 1337,
// 1: 42,
// length: 2
// }
assert.ok(resultTwo[0] === resultTwo.param1);
assert.ok(resultTwo[1] === resultTwo.param2);
-----
.. _contract-filter:
Filtering Events
================
On every contract, there is a ``filters`` property, which can be used to
generate an event filter. And event filter can be passed into the ``on(eventName)``
of a contract.
.. code-block:: javascript
:caption: *Find all ERC-20 transfers to myAddress*
// The null field indicates any value matches, this specifies
// "any Transfer from any to myAddress"
let filter = contract.filters.Transfer(null, myAddress);
// Listen for our filtered results
contract.on(filter, (from, to, value) => {
console.log('I received ' + value.toString() + ' tokens from ' + from);
});
-----
.. _contract-abi:
Application Binary Interface (ABI)
==================================
Each Contract has a description of its interface, which describes each function
and event.
The Solidity compiler generates the ABI in a JSON format, which can be used as
a JSON string or parsed as a JavaScript Object. This is generated by the
compiler and can be loaded as a file, or copied into the source code.
The ABI may also be specified using `Human-Readable ABI`_, which is much easier
to use when typing in an ABI by hand, for example, as well as easier to read. This
is simply an array of strings, each of which is the Solidity function or event
signature.
.. code-block:: javascript
:caption: *Human-Readable ABI*
let ABI = [
"event Transfer(address from, address to, uint amount)",
"function transfer(address to, uint amount)",
"function symbol() view returns (string)"
]
-----
.. _Human-Readable ABI: https://blog.ricmoo.com/human-readable-contract-abis-in-ethers-js-141902f4d917
.. _Event Emitter API: https://nodejs.org/api/events.html#events_class_eventemitter
.. EOF

File diff suppressed because it is too large Load Diff

@ -1,701 +0,0 @@
.. |nbsp| unicode:: U+00A0 .. non-breaking space
Utilities
*********
The utility functions provide a large assortment of common utility functions
required to write dapps, process user input and format data.
-----
Addresses
=========
There are :ref:`several formats <checksum-address>` available to represent Ethereum
addresses and various ways they are determined.
.. _utils-getaddress:
:sup:`utils` . getAddress ( address ) |nbsp| :sup:`=>` |nbsp| :sup:`Address`
Normalize any supported address-format to a :ref:`checksum address <checksum-address>`.
:sup:`utils` . getIcapAddress ( address ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Normalize any supported address-format to a :ref:`ICAP address <icap-address>`.
:sup:`utils` . getContractAddress ( transaction ) |nbsp| :sup:`=>` |nbsp| :sup:`Address`
Computes the contract address of a contract deployed by *transaction*. The only
properties used are *from* and *nonce*.
.. code-block:: javascript
:caption: *convert between address formats*
let address = "0xd115bffabbdd893a6f7cea402e7338643ced44a6";
let icapAddress = "XE93OF8SR0OWI6F4FO88KWO4UNNGG1FEBHI";
console.log(utils.getAddress(address));
// "0xD115BFFAbbdd893A6f7ceA402e7338643Ced44a6"
console.log(utils.getAddress(icapAddress));
// "0xD115BFFAbbdd893A6f7ceA402e7338643Ced44a6"
console.log(utils.getAddress(address, true));
// "XE93OF8SR0OWI6F4FO88KWO4UNNGG1FEBHI"
console.log(utils.getAddress(icapAddress, true));
// "XE93OF8SR0OWI6F4FO88KWO4UNNGG1FEBHI"
.. code-block:: javascript
:caption: *determine a contract address*
// Ropsten: 0x5bdfd14fcc917abc2f02a30721d152a6f147f09e8cbaad4e0d5405d646c5c3e1
let transaction = {
from: '0xc6af6e1a78a6752c7f8cd63877eb789a2adb776c',
nonce: 0
};
console.log(utils.getContractAddress(transaction));
// "0x0CcCC7507aEDf9FEaF8C8D731421746e16b4d39D"
-----
.. _arrayish:
Arrayish
========
An arrayish object is used to describe binary data and has the following conditions met:
- has a *length* property
- has a value for each index from 0 up to (but excluding) *length*
- has a valid byte for each value; a byte is an integer in the range [0, 255]
- is **not** a string
**Examples:** ``Buffer``, ``[ 1, 2, 3 ]``, ``Uint8Array``
:sup:`utils` . isArrayish ( object ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean`
Returns true if *object* can be treated as an arrayish object.
:sup:`utils` . arrayify ( hexStringOrBigNumberOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`Uint8Array`
Returns a Uint8Array of a hex string, BigNumber or of an `Arrayish`_ object.
:sup:`utils` . concat ( arrayOfHexStringsAndArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`Uint8Array`
Return a Uint8Array of all *arrayOfHexStringsAndArrayish* concatenated.
:sup:`utils` . padZeros ( typedUint8Array, length ) |nbsp| :sup:`=>` |nbsp| :sup:`Uint8Array`
Return a Uint8Array of *typedUint8Array* with zeros prepended to *length* bytes.
:sup:`utils` . stripZeros ( hexStringOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`Uint8Array`
Returns a Uint8Array with all leading zero **bytes** striped.
-----
.. _bignumber:
Big Numbers
===========
A BigNumber is an immutable object which allow accurate math operations
on values larger than :ref:`JavaScript can accurately handle <ieee754>`
can safely handle. Also see: :ref:`Constants <constants>`
:sup:`prototype` . add ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber`
Return a new BigNumber of this plus *otherValue*.
:sup:`prototype` . sub ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber`
Return a new BigNumber of this minus *otherValue*.
:sup:`prototype` . mul ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber`
Return a new BigNumber of this times *otherValue*.
:sup:`prototype` . div ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber`
Return a new BigNumber of this divided by *otherValue*.
:sup:`prototype` . mod ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber`
Return a new BigNumber of this modulo *otherValue*.
:sup:`prototype` . maskn ( bits ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber`
Return a new BigNumber with the number of *bits* masked.
:sup:`prototype` . eq ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean`
Return true if this is equal to *otherValue*.
:sup:`prototype` . lt ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean`
Return true if this is less than *otherValue*.
:sup:`prototype` . lte ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean`
Return true if this is less or equal to *otherValue*.
:sup:`prototype` . gt ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean`
Return true if this is greater than *otherValue*.
:sup:`prototype` . gte ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean`
Return true if this is greater than or equal to *otherValue*.
:sup:`prototype` . isZero ( ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean`
Return true if this is equal to zero.
:sup:`prototype` . toNumber ( ) |nbsp| :sup:`=>` |nbsp| :sup:`number`
Return a JavaScript number of the value.
An error is thrown if the value is outside the safe range for JavaScript
IEEE 754 64-bit floating point numbers (over 53 bits of mantissa).
:sup:`prototype` . toString () |nbsp| :sup:`=>` |nbsp| :sup:`string`
Return a decimal string representation.
:sup:`prototype` . toHexString ( ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Return a hexstring representation of the value.
Creating Instances
------------------
:sup:`utils` . bigNumberify ( value ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber`
Returns a BigNumber instance of *value*. The *value* may be anything that can
reliably be converted into a BigNumber:
============================ ======================= =================================
Type Examples Notes
============================ ======================= =================================
decimal string ``"42"``, ``"-42"``
hexadecimal string ``"0x2a"``, ``"-0x2a"`` case-insensitive
numbers ``42``, ``-42`` must be witin the `safe range`_
:ref:`Arrayish <arrayish>` ``[ 30, 252 ]`` big-endian encoding
BigNumber any other BigNumber returns the same instance
============================ ======================= =================================
.. code-block:: javascript
:caption: *examples*
let gasPriceWei = utils.bigNumberify("20902747399");
let gasLimit = utils.bigNumberify(3000000);
let maxCostWei = gasPriceWei.mul(gasLimit)
console.log("Max Cost: " + maxCostWei.toString());
// "Max Cost: 62708242197000000"
console.log("Number: " + maxCostWei.toNumber());
// throws an Error, the value is too large for JavaScript to handle safely
-----
.. _bytes32string:
Bytes32 Strings
===============
Often for short strings, it is far more efficient to store them as
a fixed, null-terminated bytes32, instead of a dynamic length-prefixed
bytes.
:sup:`utils` . formatBytes32String ( text ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Returns a :ref:`hex string <hexstring>` representation of *text*, exactly
32 bytes wide. Strings **must** be 31 bytes or shorter, or an exception
is thrown.
**NOTE:** Keep in mind that UTF-8 characters outside the ASCII range can
be multiple bytes long.
:sup:`utils` . parseBytes32String ( hexStringOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`string`
Returns *hexStringOrArrayish* as the original string, as generated by ``formatBytes32String``.
.. code-block:: javascript
:caption: *example*
let text = "Hello World!"
let bytes32 = ethers.utils.formatBytes32String(text)
// "0x48656c6c6f20576f726c64210000000000000000000000000000000000000000"
let originalText = ethers.utils.parseBytes32String(bytes32)
// "Hello World!"
-----
.. _constants:
Constants
=========
:sup:`ethers . constants` . AddressZero
The address ``0x0000000000000000000000000000000000000000``.
:sup:`ethers . constants` . HashZero
The bytes32 ``0x0000000000000000000000000000000000000000000000000000000000000000``.
:sup:`ethers . constants` . MaxUint256
The bytes32 ``0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff``.
:sup:`ethers . constants` . NegativeOne
The :ref:`BigNumber <bignumber>` ``bigNumberify(-1)``.
:sup:`ethers . constants` . Zero
The :ref:`BigNumber <bignumber>` ``bigNumberify(0)``.
:sup:`ethers . constants` . One
The :ref:`BigNumber <bignumber>` ``bigNumberify(1)``.
:sup:`ethers . constants` . Two
The :ref:`BigNumber <bignumber>` ``bigNumberify(2)``.
:sup:`ethers . constants` . WeiPerEther
The :ref:`BigNumber <bignumber>` ``bigNumberify("1000000000000000000")``.
:sup:`ethers . constants` . EtherSymbol
The Greek character Xi, used as the symbol for *ether*.
-----
Cryptographic Functions
=======================
Elliptic Curve
--------------
:sup:`utils` . computeAddress ( publicOrPrivateKey ) |nbsp| :sup:`=>` |nbsp| :sup:`Address`
Computes the Ethereum address given a public key or private key.
:sup:`utils` . computePublicKey ( publicOrPrivateKey [ , compressed :sup:`= false` ] ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Compute the public key for *publicOrPrivateKey*, optionally *compressed*. If
*publicOrPrivateKey* is a public key, it may be either compressed or uncompressed.
:sup:`utils` . recoverAddress ( digest , signature ) |nbsp| :sup:`=>` |nbsp| :sup:`Address`
Returns the Ethereum address by using ecrecover with the *digest* for the
*signature*.
:sup:`utils` . recoverPublicKey ( digest , signature ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Returns the public key by using ecrecover with the *digest* for the *signature*.
:sup:`utils` . verifyMessage ( messageStringOrArrayish , signature ) |nbsp| :sup:`=>` |nbsp| :sup:`Addresss`
Returns the address of the account that signed *messageStringOrArrayish* to
generate *signature*.
.. code-block:: javascript
:caption: *verify a message signature*
let signature = "0xddd0a7290af9526056b4e35a077b9a11b513aa0028ec6c9880948544508f3c63" +
"265e99e47ad31bb2cab9646c504576b3abc6939a1710afc08cbf3034d73214b8" +
"1c";
let signingAddress = Wallet.verifyMessage('hello world', signature);
console.log(signingAddress);
// "0x14791697260E4c9A71f18484C9f997B308e59325"
Hash Functions
--------------
:sup:`utils` . keccak256 ( hexStringOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Compute the keccak256 cryptographic hash of a value, returned as a hex string. (Note:
often Ethereum documentation refers to this, **incorrectly**, as SHA3)
:sup:`utils` . sha256 ( hexStringOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Compute the SHA2-256 cryptographic hash of a value, returned as a hex string.
.. code-block:: javascript
:caption: *hashing binary data*
console.log(utils.keccak256([ 0x42 ]));
// '0x1f675bff07515f5df96737194ea945c36c41e7b4fcef307b7cd4d0e602a69111'
console.log(utils.keccak256("0x42"));
// '0x1f675bff07515f5df96737194ea945c36c41e7b4fcef307b7cd4d0e602a69111'
console.log(utils.sha256([ 0x42 ]));
// '0xdf7e70e5021544f4834bbee64a9e3789febc4be81470df629cad6ddb03320a5c'
console.log(utils.sha256("0x42"));
// '0xdf7e70e5021544f4834bbee64a9e3789febc4be81470df629cad6ddb03320a5c'
Hash Function Helpers
---------------------
:sup:`utils` . hashMessage ( stringOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Compute the prefixed message hash of a stringOrArrayish, by converting the
message to bytes (as necessary) and prefixing with ``\x19Ethereum Signed Message\n``
and the length of the message. See the `eth_sign`_ JSON-RPC method for more information.
:sup:`utils` . id ( utf8String ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Compute the keccak256 cryptographic hash of a UTF-8 string, returned as a hex string.
.. code-block:: javascript
:caption: *hashing utf-8 strings*
// Convert the string to binary data
let message = "Hello World";
let messageBytes = utils.toUtf8Bytes(message);
utils.keccak256(messageBytes);
// '0x592fa743889fc7f92ac2a37bb1f5ba1daf2a5c84741ca0e0061d243a2e6707ba'
// Which is equivalent to using the id function
utils.id("Hello World");
// '0x592fa743889fc7f92ac2a37bb1f5ba1daf2a5c84741ca0e0061d243a2e6707ba'
// Compute the sighash for a Solidity method
console.log(utils.id("addr(bytes32)"));
// '0x3b3b57de213591bb50e06975ea011e4c8c4b3e6de4009450c1a9e55f66e4bfa4'
Key Derivation
--------------
:sup:`utils` . pbkdf2 ( password , salt , iterations , keylen , hashAlgorithm )
Return the pbkdf2 derived key from *password* and *salt* with *iterations* of
*length* using the *hashAlgorithm*. The supported hash algorithms are ``sha256``
and ``sha512``.
Random
------
:sup:`utils` . randomBytes ( length ) |nbsp| :sup:`=>` |nbsp| :sup:`Uint8Array`
Return a Uint8Array of cryptographically secure random bytes
.. code-block:: javascript
:caption: *generate random bytes*
let randomBytes3 = utils.randomBytes(3)
// Uint8Array [ 194, 22, 140 ]
let randomBytes32 = utils.randomBytes(32)
// Uint8Array [ 162, 131, 117, 110, 196, 73, 144, 177, 201, 75, 88,
// 105, 227, 210, 104, 226, 82, 65, 103, 157, 36, 170,
// 214, 92, 190, 141, 239, 54, 96, 39, 240, 95 ]
.. code-block:: javascript
:caption: *generate a random number*
let randomNumber = utils.bigNumberify(utils.randomBytes(32));
// BigNumber { _hex: 0x617542634156966e0bbb6c673bf88015f542c96eb115186fd93881518f05f7ff }
Solidity
--------
Solidity uses a `non-standard packed mode`_ to encode parameters that are passed
into its hashing functions. The parameter types and values can be used to compute
the result of the hash functions as would be performed by Solidity.
:sup:`utils` . solidityKeccak256 ( types, values ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Compute the keccak256 cryptographic hash using the Solidity non-standard (tightly)
packed data for *values* given the *types*.
:sup:`utils` . soliditySha256 ( types, values ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Compute the SHA256 cryptographic hash using the Solidity non-standard (tightly)
packed data for *values* given the *types*.
:sup:`utils` . solidityPack ( types, values ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Compute the Solidity non-standard (tightly) packed data for *values* given the *types*.
.. code-block:: javascript
:caption: *examples*
let result = utils.solidityKeccak256([ 'int8', 'bytes1', 'string' ], [ -1, '0x42', 'hello' ]);
console.log(result);
// '0x52d7e6a62ca667228365be2143375d0a2a92a3bd4325dd571609dfdc7026686e'
result = utils.soliditySha256([ 'int8', 'bytes1', 'string' ], [ -1, '0x42', 'hello' ]);
console.log(result);
// '0x1eaebba7999af2691d823bf0c817e635bbe7e89ec7ed32a11e00ca94e86cbf37'
result = utils.solidityPack([ 'int8', 'bytes1', 'string' ], [ -1, '0x42', 'hello' ]);
console.log(result);
// '0xff4268656c6c6f'
-----
Ether Strings and Wei
=====================
:sup:`utils` . etherSymbol
The ethereum symbol (the Greek letter *Xi* )
.. _parseEther:
:sup:`utils` . parseEther ( etherString ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber`
Parse the *etherString* representation of ether into a BigNumber instance
of the amount of wei.
.. _formatEther:
:sup:`utils` . formatEther ( wei ) |nbsp| :sup:`=>` |nbsp| :sup:`string`
Format an amount of *wei* into a decimal string representing the amount of ether.
The output will always include at least one whole number and at least one decimal
place, otherwise leading and trailing 0's will be trimmed.
.. _parseUnits:
:sup:`utils` . parseUnits ( valueString , decimalsOrUnitName ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber`
Parse the *valueString* representation of units into a BigNumber instance
of the amount of wei. The *decimalsOrUnitsName* may be a number of decimals between
3 and 18 (multiple of 3) or a name, such as `gwei`.
.. _formatUnits:
:sup:`utils` . formatUnits ( wei , decimalsOrUnitName ) |nbsp| :sup:`=>` |nbsp| :sup:`string`
Format an amount of *wei* into a decimal string representing the amount of units.
The output will always include at least one whole number and at least one decimal place,
otherwise leading and trailing 0's will be trimmed. The *decimalsOrUnitsName*
may be a number of decimals between 3 and 18 (multiple of 3) or a name, such as `gwei`.
:sup:`utils` . commify ( numberOrString ) |nbsp| :sup:`=>` |nbsp| :sup:`string`
Returns *numberOrString* with commas placed at every third position within the whole
component. If *numberOrString* contains a decimal point, the output will as well with
at least one digit for both the whole and decimal components. If there no decimal,
then the output will also not contain a decimal.
.. code-block:: javascript
:caption: *examples*
let wei = utils.parseEther('1000.0');
console.log(wei.toString(10));
// "1000000000000000000000"
console.log(utils.formatEther(0));
// "0.0"
let wei = utils.bigNumberify("1000000000000000000000");
console.log(utils.formatEther(wei));
// "1000.0"
console.log(utils.formatEther(wei, {commify: true}));
// "1,000.0"
console.log(utils.formatEther(wei, {pad: true}));
// "1000.000000000000000000" (18 decimal places)
console.log(utils.formatEther(wei, {commify: true, pad: true}));
// "1,000.000000000000000000" (18 decimal places)
-----
.. _hexstring:
Hex Strings
===========
A hex string is **always** prefixed with "0x" and consists of the characters
0 -- 9 and a -- f. It is always returned lower case with even-length, but any hex
string passed into a function may be any case and may be odd-length.
:sup:`utils` . hexlify ( numberOrBigNumberOrHexStringOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Converts any number, :ref:`BigNumber <bignumber>`, hex string or
`Arrayish`_ to a hex string. (otherwise, throws an error)
:sup:`utils` . isHexString ( value ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean`
Returns true if *value* is a valid hexstring.
:sup:`utils` . hexDataLength ( hexString ) |nbsp| :sup:`=>` |nbsp| :sup:`number`
Returns the length (in bytes) of *hexString* if it is a valid data hexstring (even length).
:sup:`utils` . hexDataSlice ( hexString , offset [ , endOffset ] ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Returns a string for the subdata of *hexString* from *offset* **bytes**
(each byte is two nibbled) to *endOffset* **bytes**. If no *endOffset* is
specified, the result is to the end of the *hexString* is used. Each byte is two nibbles.
:sup:`utils` . hexStripZeros ( hexString ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Returns *hexString* with all leading zeros removed, but retaining at least
one nibble, even if zero (e.g. ``0x0``). This may return an odd-length string.
:sup:`utils` . hexZeroPad ( hexString , length ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Returns *hexString* padded (on the left) with zeros to length **bytes** (each
byte is two nibbles).
-----
Namehash
========
:sup:`utils` . namehash ( ensName ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Compute the namehash of *ensName*. Currently only supports the
characters ``[a-z0-9.-]``. The concerns with fully supporting UTF-8
are largely security releated, but `are open for discussion`_.
.. code-block:: javascript
:caption: *examples*
let namehash = utils.namehash('ricmoo.firefly.eth');
// "0x0bcad17ecf260d6506c6b97768bdc2acfb6694445d27ffd3f9c1cfbee4a9bd6d"
-----
.. _signature:
Signatures
==========
There are two common formats for signatures in Ethereum. The **flat-format**, which
is a hexstring with 65 bytes (130 nibbles); or an **expanded-format**, which is an object with
the properties:
- **r** and **s** --- the (r, s) public point of a signature
- **recoveryParam** --- the recovery parameter of a signautre (either ``0`` or ``1``)
- **v** --- the recovery param nomalized for Solidity (either ``27`` or ``28``)
:sup:`utils` . splitSignature ( hexStringOrArrayishOrSignature ) |nbsp| :sup:`=>` |nbsp| :sup:`Signature`
Returns an expanded-format signature object for *hexStringOrArrayishOrSignature*.
Passing in an signature that is already in the expanded-format will ensure
both *recoveryParam* and *v* are populated.
:sup:`utils` . joinSignature ( signature ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Returns the flat-format signature hexstring of *signature*. The final *v*
byte will always be normalized to ``0x1b`` of ``0x1c``.
.. code-block:: javascript
:caption: *To Expanded-Format*
// Flat-format; this is the format provided by JSON-RPC responses
let flat = "0x0ba9770fd8778383f6d56faadc71e17b75f0d6e3ff0a408d5e6c4cee3bd70a16" +
"3574da0ebfb1eaac261698b057b342e52ea53f85287272cea471a4cda41e3466" +
"1b"
let expanded = utils.splitSignature(flat);
console.log(expanded);
// {
// r: "0x0ba9770fd8778383f6d56faadc71e17b75f0d6e3ff0a408d5e6c4cee3bd70a16",
// s: "0x3574da0ebfb1eaac261698b057b342e52ea53f85287272cea471a4cda41e3466",
// recoveryParam: 0,
// v: 27
// }
.. code-block:: javascript
:caption: *To Flat-Format*
// Expanded-format; this is the format Solidity and other tools often require
let expanded = {
r: "0x0ba9770fd8778383f6d56faadc71e17b75f0d6e3ff0a408d5e6c4cee3bd70a16",
s: "0x3574da0ebfb1eaac261698b057b342e52ea53f85287272cea471a4cda41e3466",
recoveryParam: 0,
v: 27
}
let flat = utils.joinSignature(expanded);
console.log(flat)
// "0x0ba9770fd8778383f6d56faadc71e17b75f0d6e3ff0a408d5e6c4cee3bd70a16" +
// "3574da0ebfb1eaac261698b057b342e52ea53f85287272cea471a4cda41e3466" +
// "1b"
-----
.. _transactions:
Transactions
============
:sup:`utils` . serializeTransaction ( transaction [ , signature ] ) |nbsp| :sup:`=>` |nbsp| :sup:`hex`
Serialize *transaction* as a :ref:`hex-string <hexstring>`, optionally including
the *signature*.
If *signature* is provided, it may be either the :ref:`Flat Format <signature>`
or the :ref:`Expanded Format <signature>`, and the serialized transaction will
be a signed transaction.
:sup:`utils` . parseTransaction ( rawTransaction ) |nbsp| :sup:`=>` |nbsp| :sup:`Transaction`
Parse the serialized transaction, returning an object with the properties:
- **to**
- **nonce**
- **gasPrice**
- **gasLimit**
- **data**
- **value**
- **chainId**
If the transactions is signed, addition properties will be present:
- **r**, **s** and **v** --- the signature public point and recoveryParam (adjusted for the chainId)
- **from** --- the address of the account that signed the transaction
- **hash** --- the transaction hash
-----
.. _utf8-strings:
UTF-8 Strings
=============
.. _utf8-to-bytes:
:sup:`utils` . toUtf8Bytes ( string ) |nbsp| :sup:`=>` |nbsp| :sup:`Uint8Array`
Converts a UTF-8 string to a Uint8Array.
.. _utf8-to-string:
:sup:`utils` . toUtf8String ( hexStringOrArrayish , [ ignoreErrors :sup:`= false` ) |nbsp| :sup:`=>` |nbsp| :sup:`string`
Converts a hex-encoded string or array to its UTF-8 representation.
.. code-block:: javascript
:caption: *To UTF-8 Bytes*
let text = "Hello World";
let bytes = utils.toUtf8Bytes(text);
console.log(bytes);
// Uint8Array [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
.. code-block:: javascript
:caption: *To UTF-8 String*
let array = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100];
let stringFromArray = utils.toUtf8String(array)
console.log(stringFromArray);
// "Hello World"
let hexString = "0x48656c6c6f20576f726c64";
let stringFromHexString = utils.toUtf8String(hexString);
console.log(stringFromHexString);
// "Hello World"
-----
Web
===
:sup:`utils` . fetchJson ( urlOrInfo [ , processFunc ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<any>`
Returns a :ref:`Promise <promise>` of the contents of *urlOrInfo*, processed by
*processFunc*.
The *urlOrInfo* may also be specified as an object with the properties:
- **url** --- the JSON-RPC URL (required)
- **user** --- a username to use for Basic Authentication (optional)
- **password** --- a password to use for Basic Authentication (optional)
- **allowInsecure** --- allow Basic Authentication over an insecure HTTP network (default: false)
- **timeout** --- number of milliseconds to abort the request (default: 2 minutes)
- **headers** --- additional headers to send to the server (case insensitive)
:sup:`utils` . poll ( func , [ options ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<any>`
Poll using the function *func*, resolving when it does not return ``undefined``. By
default this method will use the `exponential back-off`_ algorithm.
The *options* is an object with the properties:
- **timeout** --- after this many millisecconds, the promise will reject with a ``timeout`` error (default: no timeout)
- **floor** --- minimum amount of time between polling (default: 0)
- **ceiling** --- minimum amount of time between polling (default: 10s)
- **interval** --- the interval to use for exponential backoff (default: 250ms)
- **onceBlock** --- a function which takes 2 parameters, the string ``block`` and a callback *func*; polling will occur everytime *func* is called; any provider can be passed in for this property
-----
.. _are open for discussion: https://github.com/ethers-io/ethers.js/issues/42
.. _eth_sign: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
.. _exponential back-off: https://en.wikipedia.org/wiki/Exponential_backoff
.. _safe range: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isSafeInteger
.. _non-standard packed mode: http://solidity.readthedocs.io/en/develop/abi-spec.html#non-standard-packed-mode
.. EOF

@ -1,459 +0,0 @@
.. |nbsp| unicode:: U+00A0 .. non-breaking space
.. _api-wallet:
Wallets and Signers
*******************
A **Wallet** manages a private/public key pair which is used to cryptographically sign
transactions and prove ownership on the Ethereum network.
-----
.. _wallet:
Wallet
======
The **Wallet** implements the :ref:`Signer API <signer>` and can be used anywhere a *Signer*
is expected and has all the required properties.
|
Creating Instances
------------------
new :sup:`Wallet` ( privateKey [ , provider ] )
Creates a new instance from *privateKey* and optionally connect a provider
:sup:`Wallet` . createRandom ( [ options ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Wallet`
Creates a new random wallet. Ensure this wallet is stored somewhere safe, if
lost there is **NO way to recover it**.
Options may have the properties:
- **extraEntropy** --- additional entropy to stir into the random source
.. _fromEncryptedJson:
:sup:`Wallet` . fromEncryptedJson ( json, password [ , progressCallback ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Wallet`
Decrypt an encrypted Secret Storage `JSON Wallet`_ (from Geth, parity, Crowdsale
tools, or that was created using *prototype.encrypt* )
:sup:`Wallet` . fromMnemonic ( mnemonic [ , path :sup:`= "m/44'/60'/0'/0/0"` [ , wordlist ] ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Wallet`
Generate a `BIP-039`_ + `BIP-044`_ wallet from *mnemonic* deriving *path* using
the *wordlist*. The default language is English (en).
In the browserified ``dist/ethers.min.js`` only the English wordlist is
available. Each additional wordlist may be included by adding a ``<script>``
for the ``dist/wordlist-*.js``
The current supported wordlists are:
===================== =========================== =======================
Language node.js Browser
===================== =========================== =======================
English (US) ``ethers.wordlists.en`` *included*
Italian ``ethers.wordlists.it`` ``dist/wordlist-it.js``
Japanese ``ethers.wordlists.ja`` ``dist/wordlist-ja.js``
Korean ``ethers.wordlists.ko`` ``dist/wordlist-ko.js``
Chinese (simplified) ``ethers.wordlists.zh_cn`` ``dist/wordlist-zh.js``
Chinese (traditional) ``ethers.wordlists.zh_tw`` ``dist/wordlist-zh.js``
===================== =========================== =======================
.. _wallet-connect:
:sup:`prototype` . connect ( provider ) |nbsp| :sup:`=>` |nbsp| :sup:`Wallet`
Creates a new Wallet instance from an existing instance, connected to a new *provider*.
|
|
.. code-block:: javascript
:caption: *load a private key*
let privateKey = "0x0123456789012345678901234567890123456789012345678901234567890123";
let wallet = new ethers.Wallet(privateKey);
// Connect a wallet to mainnet
let provider = ethers.getDefaultProvider();
let walletWithProvider = new ethers.Wallet(privateKey, provider);
.. code-block:: javascript
:caption: *create a new random account*
let randomWallet = ethers.Wallet.createRandom();
.. code-block:: javascript
:caption: *load a JSON wallet*
let data = {
id: "fb1280c0-d646-4e40-9550-7026b1be504a",
address: "88a5c2d9919e46f883eb62f7b8dd9d0cc45bc290",
Crypto: {
kdfparams: {
dklen: 32,
p: 1,
salt: "bbfa53547e3e3bfcc9786a2cbef8504a5031d82734ecef02153e29daeed658fd",
r: 8,
n: 262144
},
kdf: "scrypt",
ciphertext: "10adcc8bcaf49474c6710460e0dc974331f71ee4c7baa7314b4a23d25fd6c406",
mac: "1cf53b5ae8d75f8c037b453e7c3c61b010225d916768a6b145adf5cf9cb3a703",
cipher: "aes-128-ctr",
cipherparams: {
iv: "1dcdf13e49cea706994ed38804f6d171"
}
},
"version" : 3
};
let json = JSON.stringify(data);
let password = "foo";
ethers.Wallet.fromEncryptedJson(json, password).then(function(wallet) {
console.log("Address: " + wallet.address);
// "Address: 0x88a5C2d9919e46F883EB62F7b8Dd9d0CC45bc290"
});
.. code-block:: javascript
:caption: *load a mnemonic phrase*
let mnemonic = "radar blur cabbage chef fix engine embark joy scheme fiction master release";
let mnemonicWallet = ethers.Wallet.fromMnemonic(mnemonic);
// Load the second account from a mnemonic
let path = "m/44'/60'/1'/0/0";
let secondMnemonicWallet = ethers.Wallet.fromMnemonic(mnemonic, path);
// Load using a non-english locale wordlist (the path "null" will use the default)
let secondMnemonicWallet = ethers.Wallet.fromMnemonic(mnemonic, null, ethers.wordlists.ko);
-----
Prototype
---------
:sup:`prototype` . address
The public address of a wallet
:sup:`prototype` . privateKey
The private key of a wallet; keep this secret
:sup:`prototype` . provider
A connected :ref:`Provider <provider>` which allows the wallet to
connect to the Ethereum network to query its state and send transactions,
or null if no provider is connected.
To change the provider, use the :ref:`connect <wallet-connect>` method, which will return
a **new instance** of the Wallet connected to the provider.
:sup:`prototype` . mnemonic
The mnemonic phrase for this wallet, or null if the mnemonic is unknown.
:sup:`prototype` . path
The mnemonic path for this wallet, or null if the mnemonic is unknown.
-----
Signing
-------
:sup:`prototype` . sign ( transaction ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<string>`
Signs *transaction* and returns a :ref:`Promise <promise>` that resolves to
the signed transaction as a :ref:`hex string <hexstring>`.
In general, the `sendTransaction`_ method is preferred to ``sign``, as it can automatically
populate values asynchronously.
The properties for transaction are all optional and include:
- **to**
- **gasLimit**
- **gasPrice**
- **nonce**
- **data**
- **value**
- **chainId**
:sup:`prototype` . signMessage ( message ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<string>`
Signs *message* and returns a :ref:`Promise <promise>` that resolves to
the :ref:`flat-format <signature>` signature.
If *message* is a string, it is converted to UTF-8 bytes, otherwise it is
preserved as a binary representation of the :ref:`Arrayish <arrayish>` data.
.. code-block:: javascript
:caption: *signing transactions*
let privateKey = "0x3141592653589793238462643383279502884197169399375105820974944592"
let wallet = new ethers.Wallet(privateKey)
console.log(wallet.address)
// "0x7357589f8e367c2C31F51242fB77B350A11830F3"
// All properties are optional
let transaction = {
nonce: 0,
gasLimit: 21000,
gasPrice: utils.bigNumberify("20000000000"),
to: "0x88a5C2d9919e46F883EB62F7b8Dd9d0CC45bc290",
// ... or supports ENS names
// to: "ricmoo.firefly.eth",
value: utils.parseEther("1.0"),
data: "0x",
// This ensures the transaction cannot be replayed on different networks
chainId: ethers.utils.getNetwork('homestead').chainId
}
let signPromise = wallet.sign(transaction)
signPromise.then((signedTransaction) => {
console.log(signedTransaction);
// "0xf86c808504a817c8008252089488a5c2d9919e46f883eb62f7b8dd9d0cc45bc2
// 90880de0b6b3a76400008025a05e766fa4bbb395108dc250ec66c2f88355d240
// acdc47ab5dfaad46bcf63f2a34a05b2cb6290fd8ff801d07f6767df63c1c3da7
// a7b83b53cd6cea3d3075ef9597d5"
// This can now be sent to the Ethereum network
let provider = ethers.getDefaultProvider()
provider.sendTransaction(signedTransaction).then((tx) => {
console.log(tx);
// {
// // These will match the above values (excluded properties are zero)
// "nonce", "gasLimit", "gasPrice", "to", "value", "data", "chainId"
//
// // These will now be present
// "from", "hash", "r", "s", "v"
// }
// Hash:
});
})
.. code-block:: javascript
:caption: *signing text messages*
let privateKey = "0x3141592653589793238462643383279502884197169399375105820974944592"
let wallet = new ethers.Wallet(privateKey);
// Sign a text message
let signPromise = wallet.signMessage("Hello World!")
signPromise.then((signature) => {
// Flat-format
console.log(signature);
// "0xea09d6e94e52b48489bd66754c9c02a772f029d4a2f136bba9917ab3042a0474
// 301198d8c2afb71351753436b7e5a420745fed77b6c3089bbcca64113575ec3c
// 1c"
// Expanded-format
console.log(ethers.utils.splitSignature(signature));
// {
// r: "0xea09d6e94e52b48489bd66754c9c02a772f029d4a2f136bba9917ab3042a0474",
// s: "0x301198d8c2afb71351753436b7e5a420745fed77b6c3089bbcca64113575ec3c",
// v: 28,
// recoveryParam: 1
// }
});
.. code-block:: javascript
:caption: *signing binary messages*
let privateKey = "0x3141592653589793238462643383279502884197169399375105820974944592"
let wallet = new ethers.Wallet(privateKey);
// The 66 character hex string MUST be converted to a 32-byte array first!
let hash = "0x3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0";
let binaryData = ethers.utils.arrayify(hash);
let signPromise = wallet.signMessage(binaryData)
signPromise.then((signature) => {
console.log(signature);
// "0x5e9b7a7bd77ac21372939d386342ae58081a33bf53479152c87c1e787c27d06b
// 118d3eccff0ace49891e192049e16b5210047068384772ba1fdb33bbcba58039
// 1c"
});
-----
Blockchain Operations
---------------------
These operations require the wallet have a provider attached to it.
:sup:`prototype` . getBalance ( [ blockTag :sup:`= "latest"` ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<BigNumber>`
Returns a :ref:`Promise <promise>` that resolves to the balance of the wallet
(as a :ref:`BigNumber <bignumber>`, in **wei**) at the :ref:`blockTag <blocktag>`.
:sup:`prototype` . getTransactionCount ( [ blockTag :sup:`= "latest"` ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<number>`
Returns a :ref:`Promise <promise>` that resovles to the number of transactions
this account has ever sent (also called the *nonce*) at the :ref:`blockTag <blocktag>`.
:sup:`prototype` . estimateGas ( transaction ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<BigNumber>`
Returns a :ref:`Promise <promise>` with the estimated cost for *transaction* (as a
:ref:`BigNumber <bignumber>`, in **gas**)
.. _sendTransaction:
:sup:`prototype` . sendTransaction ( transaction ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<TransactionResponse>`
Sends the *transaction* (see :ref:`Transaction Requests <transaction-request>`) to
the network and returns a :ref:`Promise <promise>` that resolves to a
:ref:`Transaction Response <transaction-response>`. Any properties that are not
provided will be populated from the network.
.. code-block:: javascript
:caption: *query the network*
// We require a provider to query the network
let provider = ethers.getDefaultProvider();
let privateKey = "0x3141592653589793238462643383279502884197169399375105820974944592"
let wallet = new ethers.Wallet(privateKey, provider);
let balancePromise = wallet.getBalance();
balancePromise.then((balance) => {
console.log(balance);
});
let transactionCountPromise = wallet.getTransactionCount();
transactionCountPromise.then((transactionCount) => {
console.log(transactionCount);
});
.. code-block:: javascript
:caption: *transfer ether*
// We require a provider to send transactions
let provider = ethers.getDefaultProvider();
let privateKey = "0x3141592653589793238462643383279502884197169399375105820974944592"
let wallet = new ethers.Wallet(privateKey, provider);
let amount = ethers.utils.parseEther('1.0');
let tx = {
to: "0x88a5c2d9919e46f883eb62f7b8dd9d0cc45bc290",
// ... or supports ENS names
// to: "ricmoo.firefly.eth",
// We must pass in the amount as wei (1 ether = 1e18 wei), so we
// use this convenience function to convert ether to wei.
value: ethers.utils.parseEther('1.0')
};
let sendPromise = wallet.sendTransaction(tx);
sendPromise.then((tx) => {
console.log(tx);
// {
// // All transaction fields will be present
// "nonce", "gasLimit", "pasPrice", "to", "value", "data",
// "from", "hash", "r", "s", "v"
// }
});
-----
Encrypted JSON Wallets
----------------------
Many systems store private keys as encrypted JSON wallets, in various formats. There are several
formats and algorithms that are used, all of which are supported to be read.
Only the secure scrypt variation can be generated.
See :ref:`Wallet.fromEncryptedJson <fromEncryptedJson>` for creating a
Wallet instance from a JSON wallet.
:sup:`prototype` . encrypt ( password [ , options [ , progressCallback ] ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<string>`
Encrypts the wallet as an encrypted JSON wallet, with the *password*.
All options are optional. The valid options are:
- **salt** --- the salt to use for scrypt
- **iv** --- the initialization vecotr to use for aes-ctr-128
- **uuid** --- the UUID to use for the wallet
- **scrypt** --- the scrypt parameters to use (N, r and p)
- **entropy** --- the mnemonic entropy of this wallet; generally you should **not** specify this
- **mnemonic** --- the mnemonic phrase of this wallet; generally you should **not** specify this
- **path** --- the mnemonic path of this wallet; generally you should **not** specify this
If the *progressCallback* is specified, it will be called periodically during
encryption with a value between 0 and 1, inclusive indicating the progress.
.. code-block:: javascript
:caption: *encrypt a wallet as an encrypted JSON wallet*
let password = "password123";
function callback(progress) {
console.log("Encrypting: " + parseInt(progress * 100) + "% complete");
}
let encryptPromise = wallet.encrypt(password, callback);
encryptPromise.then(function(json) {
console.log(json);
});
-----
.. _signer:
Signer API
==========
The Signer API is an abstract class which makes it easy to extend and add new signers,
that can be used by this library and extension libraries. The :ref:`Wallet <wallet>`
extends the Signer API, as do the :ref:`JsonRpcSigner <signer-jsonrpc>` and the
`Ledger Hardware Wallet Signer`_.
To implement a Signer, inherit the abstract class *ethers.types.Signer* and implement
the following properties:
:sup:`object` . provider
A :ref:`Provider <api-provider>` that is connected to the network. This is optional, however,
without a *provider*, **only** *write-only* operations should be expected to work.
:sup:`object` . getAddress ( ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<Address>`
Returns a :ref:`Promise <promise>` that resolves to the account address.
:sup:`object` . signMessage ( message ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<hex>`
Returns a :ref:`Promise <promise>` that resolves to the :ref:`Flat-Format Signature <signature>`
for the *message*.
If *message* is a string, it is converted to UTF-8 bytes, otherwise it is
preserved as a binary representation of the :ref:`Arrayish <arrayish>` data.
:sup:`object` . sendTransaction ( transaction ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise<TransactionResponse>`
Sends the *transaction* (see :ref:`Transaction Requests <transaction-request>`) to
the network and returns a :ref:`Promise <promise>` that resolves to a
:ref:`Transaction Response <transaction-response>`. Any properties that are not
provided will be populated from the network.
-----
.. _BIP-039: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
.. _BIP-044: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
.. _Ledger Hardware Wallet Signer: https://github.com/ethers-io/ethers-ledger
.. _JSON Wallet: https://medium.com/@julien.maffre/what-is-an-ethereum-keystore-file-86c8c5917b97
.. EOF

@ -1,16 +0,0 @@
.. _api:
Application Programming Interface (API)
***************************************
.. toctree::
:maxdepth: 2
api-wallet
api-providers
api-contract
api-utils
-----
.. EOF

@ -1,221 +0,0 @@
Accounts
********
Some quick examples of using Accounts.
-----
Dump All JSON Wallet Balances (in current directory)
====================================================
.. code-block:: javascript
:caption: *Load JSON Wallet Balances*
const fs = require('fs');
const path = require('path');
const ethers = require('ethers');
let provider = ethers.getDefaultProvider();
// Geth
let dirname = path.join(process.env.HOME, '.ethereum', 'keystore');
// Parity (use the name of your chain for chainDirectory, such as "homestead")
//var dirname = path.join(process.env.HOME, '.parity', 'keys', chainDirectory, 'keys');
let filenames = fs.readdirSync(dirname);
filenames.forEach(async function(filename) {
// Get the Wallet JSON
let data = await fs.readFile(path.join(dirname,filename));
// Get the Wallet address
let address = ethers.utils.getJsonWalletAddress(data.toString());
// Look up the balance
let balance = await provider.getBalance(address);
console.log(address + ':' + ethers.utils.formatEther(balance));
});
-----
Sweep an Account into Another
=============================
This will sweep **all** the funds from one account's *privateKey* and
place it in another account, *newAddress*.
.. code-block:: javascript
:caption: *Sweep an Account*
const ethers = require('ethers');
async function sweep(privateKey, newAddress) {
let provider = ethers.getDefaultProvider();
let wallet = new ethers.Wallet(privateKey, provider);
// Make sure we are sweeping to an EOA, not a contract. The gas required
// to send to a contract cannot be certain, so we may leave dust behind
// or not set a high enough gas limit, in which case the transaction will
// fail.
let code = await provider.getCode(newAddress);
if (code !== '0x') { throw new Error('Cannot sweep to a contract'); }
// Get the current balance
let balance = await wallet.getBalance();
// Normally we would let the Wallet populate this for us, but we
// need to compute EXACTLY how much value to send
let gasPrice = await provider.getGasPrice();
// The exact cost (in gas) to send to an Externally Owned Account (EOA)
let gasLimit = 21000;
// The balance less exactly the txfee in wei
let value = balance.sub(gasPrice.mul(gasLimit))
let tx = await wallet.sendTransaction({
gasLimit: gasLimit,
gasPrice: gasPrice,
to: newAddress,
value: value
});
console.log('Sent in Transaction: ' + tx.hash);
});
-----
Coalesce Jaxx Wallets
=====================
The Jaxx Wallet (for iOS, Android, desktop, et cetera) uses HD wallets on Ethereum the
same way as Bitcoin, which results in each transaction being received by a separate
address. As a result, funds get spread across many accounts, making several operations
in Ethereum impossible.
This short recipe will coalesce all these accounts into a single one, by sending the funds
from each account into a single one.
This also results in paying multiple transaction fees (1 fee per account to merge).
@TODO: This is incomplete!!
.. code-block:: javascript
:caption: *TODO*
const ethers = require('ethers');
let provider = ethers.getDefaultProvider();
let mnemonic = "radar blur cabbage chef fix engine embark joy scheme fiction master release";
let hdnode = ethers.utils.HDNode.fromMnemonic(mnemonic);
let hdnode = hdnode.derivePath("m/44'/60'/0'/0");
// @TODO
-----
Access Funds in a Mnemonic Phrase Wallet
========================================
@TODO: This is incomplete
.. code-block:: javascript
:caption: *TODO*
const ethers = require('ethers');
let walletPath = {
"standard": "m/44'/60'/0'/0/0",
// @TODO: Include some non-standard wallet paths
};
let mnemonic = "radar blur cabbage chef fix engine embark joy scheme fiction master release";
let hdnode = ethers.HDNode.fromMnemonic(mnemonic);
let node = hdnode.derivePath(walletPath.standard);
let wallet = new ethers.Wallet(node.privateKey);
console.log(wallet.address);
// 0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9
// @TODO:
-----
Random Mnemonic
===============
Often you may simply want a random mnemonic that is valid. It is important to
note that **not** all random sets of words are valid; there is a checksum
included in the binary encoding of the entropy, so it is important to use
a method that correctly encodes this checksum.
.. code-block:: javascript
:caption: *Random Mnemonic*
const ethers = require('ethers');
// All createRandom Wallets are generated from random mnemonics
let wallet = ethers.Wallet.createRandom();
let randomMnemonic = wallet.mnemonic;
.. code-block:: javascript
:caption: *More Complex Random Mnemonic*
const utils = require('ethers/utils');
// Chose the length of your mnemonic:
// - 16 bytes => 12 words (* this example)
// - 20 bytes => 15 words
// - 24 bytes => 18 words
// - 28 bytes => 21 words
// - 32 bytes => 24 words
let bytes = ethers.utils.random(16);
// Select the language:
// - en, es, fr, ja, ko, it, zh_ch, zh_tw
let language = ethers.wordlists.en;
let randomMnemonic = ethers.utils.HDNode.entropyToMnemonic(bytes, language)
-----
Get Transaction History
=======================
Unfortunately, transaction history is not something that is easy to get. It
is not indexed by the blockchain, not by a standard node, "out-of-the-box".
At the time of this recipe, the indices to store the entire history are
around 800GB. For Parity you may enable tracing and disable pruning, in
which case you can use some of the vendor specific JSON-RPC debug methods.
For many cases, you can probably rely on Etherscan, which dedicates large
amounts of resources to tracking and storing this information.
.. code-block:: javascript
:caption: *Transaction History*
let etherscanProvider = new ethers.providers.EtherscanProvider();
etherscanProvider.getHistory(address).then((history) => {
history.forEach((tx) => {
console.log(tx);
})
});
-----
@TODO: Example of signing and verifying a hash in ethers and in Solidity.
-----
.. EOF

@ -1,108 +0,0 @@
Contracts
*********
Some quick examples for techniques with Contracts.
-----
Return a Value from a State-Changing Method
===========================================
Since a state-changing (non-constant) function can take a non-trivial
amount of time to mine, the response is a transaction, and cannot
return values directly.
Using events, we can simulate a return value from a non-constant function.
.. code-block:: javascript
:caption: *Solidity*
contract Example {
event Return(uint256);
uint256 _accum = 0;
function increment() returns (uint256 sum) {
_accum++;
Returns(_accum);
}
}
.. code-block:: javascript
:caption: *JavaScript*
const assert = require('assert')
const {
Contract,
Wallet,
getDefaultProvider
} = require('ethers')
const provider = getDefaultProvider('ropsten')
const wallet = new Wallet(privateKey, provider)
const abi = [
"event Return(uint256)",
"function increment() returns (uint256 sum)"
]
const contractAddress = "0x..."
const contract = new Contract(contractAddress, abi)
async function increment() {
// Call the contract, getting back the transaction
let tx = await contract.increment()
// Wait for the transaction to have 2 confirmations.
// See the note below on "Economic Value" for considerations
// regarding the number of suggested confirmations
let receipt = await tx.wait(2)
// The receipt will have an "events" Array, which will have
// the emitted event from the Contract. The "Return(uint256)"
// call is the last event.
let sumEvent = receipt.events.pop()
// Not necessary; these are just for the purpose of this
// example
assert.equal(sumEvent.event, 'Return')
assert.equal(sumEvent.eventSignature, 'Return(uint256)')
// The sum is the first (and in this case only) parameter
// in the "Return(uint256 sum)" event
let sum = sumEvent.args[0]
return sum
}
increment.then((value) => {
console.log(value);
});
-----
Economic Incentives and Economic Value
======================================
A very important aspect of Smart Contracts is consideration of the
Economic Value being protected; even a completely logically correct
Smart Contract can fall victim to misaligned economic incentives.
Imagine a city with an average parking ticket cost of $60, but the
parking enforcement is not effective, allowing a person to park anytime
and anywhere with only an average of 3 tickets per year. If
the average cost to pay for parking is $10, and you park 100 times per year,
the $180 in fines compared to the $1,000 in paying for parking is actually
incentivizing illegal parking and disincentivizing paying legitimate parking.
This is a fairly involved topic, which we will write an article for
and then link to from here, along with a related topic, "Miner
Front-Running".
-----
.. eof

@ -1,122 +0,0 @@
Providers
*********
The Ethereum eco-system provides many methods of interacting with the
blockchain. In ethers.js we expose a Provider API that covers the
breadth of operations, however often it is useful to inter-operate with
other existing APIs and libraries.
-----
MetaMask
========
The MetaMask plug-in enables Ethereum for the Chrome browser, making it
easy for people new ecosystem to get started, exposing the Ethereum
network as a standard Web3 Provider.
.. code-block:: javascript
:caption: *Connecting to MetaMask*
// MetaMask injects a Web3 Provider as "web3.currentProvider", so
// we can wrap it up in the ethers.js Web3Provider, which wraps a
// Web3 Provider and exposes the ethers.js Provider API.
const provider = new ethers.providers.Web3Provider(web3.currentProvider);
// There is only ever up to one account in MetaMask exposed
const signer = provider.getSigner();
-----
TestRPC / Ganache
=================
The Ganache (formerly TestRPC) is a mock-blockchain which helps create
temporary instances of an Ethereum node for testing.
**NOTE:**
Ganache is not entirely standards-compliant and may
not always behave properly. If you are getting deeper
into Ethereum development, we recommend installing
Geth or Parity and using a development chain
.. code-block:: javascript
:caption: *Connecting to a Ganache Node*
// Once a Ganache node is running, it behaves very similar to a
// JSON-RPC API node.
const url = "http://localhost:8545";
// Or if you are running the UI version, use this instead:
// const url = "http://localhost:7545"
const provider = new ethers.providers.JsonRpcProvider(url);
// Getting the accounts
const signer0 = provider.getSigner(0);
const signer1 = provider.getSigner(1);
.. code-block:: javascript
:caption: *Using an In-Process Ganache Instance*
// If you would like to run an in-process instance of Ganache, you can
// use a method similar to the MetaMask solution; we wrap the Web3 Provider
// API with an ethers.js Web3Provider, which exposes the ethers.js API
// from a Web3 Provider
const ganache = Ganache.provider(ganacheOptions);
const provider = new ethers.providers.Web3Provider(ganache);
// Getting the accounts
const signer0 = provider.getSigner(0);
const signer1 = provider.getSigner(1);
-----
Custom Provider
===============
This is a much more advanced topic, and most people should not need to work this
low level. But it is provided for those rare instances where you need some custom
connection logic.
A provider must only implement the method **perform(method, params)**. All data passed
into a provider is sanitized by the BaseProvider subclass, and all results are normalized
before returning them to the user.
For this example, we will build a DebugProvider, which will simple proxy all commands
through another Provider, but dump all data going back and forth.
.. code-block:: javascript
:caption: *Sub-Class Provider for Debugging*
const ethers = require('ethers');
class DebugProvider extends ethers.providers.BaseProvider {
readonly provider: ethers.providers.Provider;
constructor(provider) {
super(provider.getNetork());
this.provider = provider;
}
// This should return a Promise (and may throw erros)
// method is the method name (e.g. getBalance) and params is an
// object with normalized values passed in, depending on the method
perform(method, params): Promise<any> {
this.provider.perform(method, params).then((result) => {
console.log('DEBUG', method, params, '=>', result);
}, (error) => {
console.log('DEBUG:ERROR', method, params, '=>', error);
throw error;
});
}
}
-----
.. EOF

@ -1,93 +0,0 @@
React Native
************
The React Native environment has a lot of little quirks, so this
documentation is aimed at helping smooth those over.
Please feel free to create issues on GitHub for recommendations and
additions to this document.
-----
Shims
=====
There are several pieces of functionality missing from the current version
of React-Native. Here is a list of functionality the ``ethers/dist/shims`` will
provide if unavailable:
- ``ArrayBuffer.isView``
- ``atob`` and ``btoa``
- ``nextTick``
- ``Promise``
- ``String.prototype.normalize``
.. code-block:: javascript
:caption: *Importing into React-Native*
// Import the required shims
import 'ethers/dist/shims.js';
// Import the ethers library
import { ethers } from 'ethers';
**Note**
This file **must** be minified, since the React-Native ``require``
seems to hijack the variable name ``require``, even when encapsulated
inside a closure. The minification process replaces the ``require``
with a mangled name, so that there is no collision. This is hacky
and in the future a better method would be preferred. Suggestions?
**Note**
As we find additional features not generally available, they will
be added to this shim file. It is targetted toward platforms where
build-size is not critical, so functionality is favored over keeping
the size small.
-----
Wordlists
=========
React-Native will pull in the browser version of ethers, which does not have
all the additional word lists, by default. Each desired wordlist must be
separately imported.
.. code-block:: javascript
:caption: *Importing languages into React-Native*
import {
es, // Spanish
fr, // French
it, // Italian
ja, // Japanese
ko, // Korean
zh_ch, // Chinese (simplified)
zh_tw // Chinese (tranditional)
} from 'ethers/wordlists';
-----
Other Notes
===========
**console.log**
The use of ``console.log`` in React Native `can substantially impact performance`_.
For this reason, you may wish to reduce the log level to not show info and warnings.
.. code-block:: javascript
:caption: *Change Log Level*
// The default is "info"; other options
// "debug", "info", "warn", "error", "off"
ethers.errors.setLogLevel("error");
-----
TODO: Include instructions on installing crypto performance
- scrypt (it is VERY slow in React Native; too slow to be functional)
.. _can substantially impact performance: https://docs.expo.io/versions/latest/react-native/performance/#using-consolelog-statements
.. EOF

@ -1,209 +0,0 @@
Signing Messages
****************
Signing messages can be used for various method of authentication and off-chain
operations, which can be put on-chain if necessary.
-----
Signing a String Message
========================
By allowing a user to sign a string, which can be verified on-chain, interesting
forms of authentication on-chain can be achieved. This is a quick example of how
an arbitrary string can be signed by a private key, and verified on-chain. The
Contract can be called by another Contract, for example, before unlocking
functionality by the caller.
.. code-block:: javascript
:caption: *Solidity Contract*
contract Verifier {
// Returns the address that signed a given string message
function verifyString(string message, uint8 v, bytes32 r,
bytes32 s) public pure returns (address signer) {
// The message header; we will fill in the length next
string memory header = "\x19Ethereum Signed Message:\n000000";
uint256 lengthOffset;
uint256 length;
assembly {
// The first word of a string is its length
length := mload(message)
// The beginning of the base-10 message length in the prefix
lengthOffset := add(header, 57)
}
// Maximum length we support
require(length <= 999999);
// The length of the message's length in base-10
uint256 lengthLength = 0;
// The divisor to get the next left-most message length digit
uint256 divisor = 100000;
// Move one digit of the message length to the right at a time
while (divisor != 0) {
// The place value at the divisor
uint256 digit = length / divisor;
if (digit == 0) {
// Skip leading zeros
if (lengthLength == 0) {
divisor /= 10;
continue;
}
}
// Found a non-zero digit or non-leading zero digit
lengthLength++;
// Remove this digit from the message length's current value
length -= digit * divisor;
// Shift our base-10 divisor over
divisor /= 10;
// Convert the digit to its ASCII representation (man ascii)
digit += 0x30;
// Move to the next character and write the digit
lengthOffset++;
assembly {
mstore8(lengthOffset, digit)
}
}
// The null string requires exactly 1 zero (unskip 1 leading 0)
if (lengthLength == 0) {
lengthLength = 1 + 0x19 + 1;
} else {
lengthLength += 1 + 0x19;
}
// Truncate the tailing zeros from the header
assembly {
mstore(header, lengthLength)
}
// Perform the elliptic curve recover operation
bytes32 check = keccak256(header, message);
return ecrecover(check, v, r, s);
}
}
.. code-block:: javascript
:caption: *JavaScript*
let abi = [
"function verifyString(string, uint8, bytes32, bytes32) public pure returns (address)"
];
let provider = ethers.getDefaultProvider('ropsten');
// Create a wallet to sign the message with
let privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
let wallet = new ethers.Wallet(privateKey);
console.log(wallet.address);
// "0x14791697260E4c9A71f18484C9f997B308e59325"
let contractAddress = '0x80F85dA065115F576F1fbe5E14285dA51ea39260';
let contract = new Contract(contractAddress, abi, provider);
let message = "Hello World";
// Sign the string message
let flatSig = await wallet.signMessage(message);
// For Solidity, we need the expanded-format of a signature
let sig = ethers.utils.splitSignature(flatSig);
// Call the verifyString function
let recovered = await contract.verifyString(message, sig.v, sig.r, sig.s);
console.log(recovered);
// "0x14791697260E4c9A71f18484C9f997B308e59325"
-----
Signing a Digest Hash
=====================
Signing a digest can be far more space efficient than signing an arbitrary
string (as you probably notice when comparing the length of the Solidity
source code), however, with this method, many Wallet UI would not be able to
fully inform the user what they are about to sign, so this method should only
be used in quite specific cases, such as in custom Wallet applications.
.. code-block:: javascript
:caption: *Solidity Contract*
contract Verifier {
function verifyHash(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public pure
returns (address signer) {
bytes32 messageDigest = keccak256("\x19Ethereum Signed Message:\n32", hash);
return ecrecover(messageDigest, v, r, s);
}
}
.. code-block:: javascript
:caption: *JavaScript*
let abi = [
"function verifyHash(bytes32, uint8, bytes32, bytes32) public pure returns (address)"
];
let provider = ethers.getDefaultProvider('ropsten');
// Create a wallet to sign the hash with
let privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123';
let wallet = new ethers.Wallet(privateKey);
console.log(wallet.address);
// "0x14791697260E4c9A71f18484C9f997B308e59325"
let contractAddress = '0x80F85dA065115F576F1fbe5E14285dA51ea39260';
let contract = new ethers.Contract(contractAddress, abi, provider);
// The hash we wish to sign and verify
let messageHash = ethers.utils.id("Hello World");
// Note: messageHash is a string, that is 66-bytes long, to sign the
// binary value, we must convert it to the 32 byte Array that
// the string represents
//
// i.e.
// // 66-byte string
// "0x592fa743889fc7f92ac2a37bb1f5ba1daf2a5c84741ca0e0061d243a2e6707ba"
//
// ... vs ...
//
// // 32 entry Uint8Array
// [ 89, 47, 167, 67, 136, 159, 199, 249, 42, 194, 163,
// 123, 177, 245, 186, 29, 175, 42, 92, 132, 116, 28,
// 160, 224, 6, 29, 36, 58, 46, 103, 7, 186]
let messageHashBytes = ethers.utils.arrayify(messageHash)
// Sign the binary data
let flatSig = await wallet.signMessage(messageHashBytes);
// For Solidity, we need the expanded-format of a signature
let sig = ethers.utils.splitSignature(flatSig);
// Call the verifyHash function
let recovered = await contract.verifyHash(messageHash, sig.v, sig.r, sig.s);
console.log(recovered);
// "0x14791697260E4c9A71f18484C9f997B308e59325"
-----
.. EOF

@ -1,77 +0,0 @@
Testing
*******
Some quick examples for techniques for testing.
-----
Contract Events
===============
.. code-block:: javascript
:caption: *Testing ERC-20 Transfer Event*
describe('Events', async function() {
it('triggers a Transfer event', function() {
let contract = new Contract(contractAddress, abi, accounts[0]);
let transferEvent = new Promise((resolve, reject) => {
contract.on('Transfer', (from, to, amount, event) => {
event.removeListener();
resolve({
from: from,
to: to,
amount: amount
});
});
setTimeout(() => {
reject(new Error('timeout'));
}, 60000)
});
let tx = await contract.transfer(accounts[1], 12345);
let event = await transferEvent;
assert.equal(event.from, account[0].address);
assert.equal(event.to, account[1].address);
assert.equal(event.amount.toNumber(), 12345);
});
});
-----
Using Multiple Accounts
=======================
.. code-block:: javascript
:caption: *Testing Multiple Accounts*
describe('Events', async function() {
it('triggers a Transfer event', function() {
// Connect to Geth/Parity node on http://localhost:8545
let provider = new providers.JsonRpcProvider();
// Get the first two accounts from the Geth/Parity node
let signer0 = provider.getSigner(0);
let signer1 = provider.getSigner(1);
// Read-only connection to the contract
let contract = new Contract(contractAddress, abi, provider);
// Read-Write connection to the contract
let contractAsSigner0 = contract.connect(signer0);
let contractAsSigner1 = contract.connect(signer1);
// ...
});
});
-----
.. eof

@ -1,27 +0,0 @@
Cookbook
********
This is a small (but growing) collection of simple recipes to perform common tasks
with the Ethereum blockchain and Ethereum accounts.
Some of these recipes are stubs that will be filled in shortly.
If there is a simple recipe you would like added, please send suggestions to support@ethers.io.
-----
.. toctree::
:maxdepth: 2
cookbook-accounts
cookbook-contracts
cookbook-providers
cookbook-signing
cookbook-testing
cookbook-react
-----
.. EOF

@ -1,56 +0,0 @@
Getting Started
***************
The ethers.js library is a compact and complete JavaScript library for Ethereum.
-----
Installing in Node.js
=====================
Install the ethers.js library from your project directory::
/home/ricmoo/my-project> npm install --save ethers
Importing
---------
.. code-block:: javascript
:caption: *JavaScript (ES3)*
var ethers = require('ethers');
.. code-block:: javascript
:caption: *JavaScript (ES5 or ES6)*
const ethers = require('ethers');
.. code-block:: javascript
:caption: *JavaScript (ES6) / TypeScript*
import { ethers } from 'ethers';
-----
Including in Web Applications
=============================
For security purposes, it is usually best to place a **copy** of `this script`_ on
the application's server, but for a quick prototype using the Ethers CDN (content
distribution network) should suffice.
.. code-block:: html
:caption: *HTML*
<!-- This exposes the library as a global variable: ethers -->
<script src="https://cdn.ethers.io/scripts/ethers-v4.min.js"
charset="utf-8"
type="text/javascript">
</script>
-----
.. _npm is installed: https://nodejs.org/en/
.. _this script: https://cdn.ethers.io/scripts/ethers-v4.min.js

@ -1,66 +0,0 @@
.. ethers.js documentation master file, created by
sphinx-quickstart on Tue Nov 29 10:25:33 2016.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
What is ethers.js
*****************
The ethers.js library aims to be a complete and compact library for interacting
with the Ethereum Blockchain and its ecosystem. It was originally designed for
use with `ethers.io`_ and has since expanded into a much more general-purpose
library.
-----
Features
========
- Keep your private keys in your client, **safe** and sound
- Import and export **JSON wallets** (Geth, Parity and crowdsale)
- Import and export BIP 39 **mnemonic phrases** (12 word backup phrases) and HD Wallets (English, Italian, Japanese, Korean, Simplified Chinese, Traditional Chinese; more coming soon)
- Meta-classes create JavaScript objects from any contract ABI, including **ABIv2** and **Human-Readable** ABI
- Connect to Ethereum nodes over `JSON-RPC`_, `INFURA`_, `Etherscan`_, or `MetaMask`_.
- **ENS names** are first-class citizens; they can be used anywhere an Ethereum addresses can be used
- **Tiny** (~88kb compressed; 284kb uncompressed)
- **Complete** functionality for all your Ethereum needs
- Extensive `documentation`_
- Large collection of **test cases** which are maintained and added to
- Fully **TypeScript** ready, with definition files and full TypeScript source
- **MIT License** (including ALL dependencies); completely open source to do with as you please
----
.. toctree::
:maxdepth: 3
:caption: Developer Documentation
getting-started
api
api-advanced
cookbook
migration
notes
testing
-----
Legacy Documentation
====================
For documentation of older versions, we will keep a list here.
- `version 3.0`_
-----
.. _ethers.io: https://ethers.io
.. _JSON-RPC: https://github.com/ethereum/wiki/wiki/JSON-RPC
.. _INFURA: https://infura.io/
.. _Etherscan: https://etherscan.io/
.. _MetaMask: https://metamask.io/
.. _version 3.0: https://docs.ethers.io/ethers.js/v3.0/html/
.. _documentation: https://docs.ethers.io
.. EOF

@ -1,654 +0,0 @@
.. _migration:
Migration Guides
****************
Migrating from Web3 to ethers v4
================================
Todo: This is coming soon.
-----
Migrating from ethers v3 to ethers v4
=====================================
A lot of the functionality has remained the same, but there has been some
slight refactoring and improved paradigms.
-----
Constants
---------
All constants have moved from the utils to the root ethers object.
.. code-block:: javascript
:caption: *Constants --- ethers v3*
let one = ethers.utils.constants.One;
.. code-block:: javascript
:caption: *Constants --- ethers v4*
let one = ethers.constants.One;
-----
Deploying Contracts
-------------------
Deploying contracts has undergone some significant change. The new API is more
seamless and reduces the amount of low-level understanding that is required,
such as the details of how *init transaction* behave.
More complex and complete objects are also returned through-out the
process, so there are far less calls to utility functions after a deployment
required to populate databases and track status.
.. code-block:: javascript
:caption: *ethers v3*
let tx = Contract.getDeployTransaction(bytecode, abi, arg1, arg2);
// overrides
tx.gasLimit = 1500000;
wallet.sendTransaction(tx).then((tx) => {
let contractAddress = ethers.utils.getContractAddress(tx);
let contract = new ethers.Contract(contractAddress, abi, wallet);
provider.waitForTransaction(tx).then((tx) => {
provider.getTransactionReceipt(tx.hash).then((receipt) => {
if (receipt.status === 0) {
throw new Error('failed to deploy');
}
contract.someFunction();
});
});
});
.. code-block:: javascript
:caption: *Deploy a Contract --- ethers v4*
// Construct a Contract Factory
let factory = new ethers.ContractFactory(abi, bytecode, signer);
// Deploy automatically detects gasLimit and all other parameters
// Overrides can optionally be passed as an extra parameter
// Optional; all unspecified values will queried from the network
let overrides = { };
factory.deploy(arg1, arg2, overrides).then((contract) => {
// The contract is returned immediately; it has not been mined yet
// The contract known its address (before it is even mined)
console.log(contract.address);
// You can access the in-flight transaction that is currently waiting to be mined
console.log(contract.deployTransaction);
// A full transaction with:
// - from
// - nonce
// - hash
// - all other Transaction Response fields
// - wait() => Promise that resolves to the TransactionReceipt
// The "deployed()" function will return a Promise that resolves
// to the contract, once it has been mined. If the contract fails
// to deploy, the Promise will reject.
contract.deployed().then((contract) => {
// The contract is now deployed
contract.someFunction();
}, (error) => {
// The transaction failed to deploy
console.log('Failed to deploy in TX:', error.transactionHash);
});
});
.. code-block:: javascript
:caption: *Deploy a Contract with async/await --- ethers v4*
async function() {
let factory = new ethers.ContractFactory(abi, bytecode, signer);
let contract = await factory.deploy(arg1, arg2);
try {
await contract.deployed();
} catch (error) {
console.log('Failed to deploy in TX:', error.transactionHash);
throw error;
}
contract.someFunction();
}
.. code-block:: javascript
:caption: *Get Deployment Transaction --- ethers v4*
// If you still need the deployment transaction, and don't wish to
// actually deploy, you can much more easily just use the Interface
// object without the need for a provider or signer.
let factory = new ethers.ContractFactory(abi, bytecode);
let tx = factory.getDeployTransaction(arg1, arg2);
-----
Encrypted Wallets
-----------------
.. code-block:: javascript
:caption: *Checking JSON Wallets --- ethers v3*
let isJsonWallet = ethers.Wallet.isEncryptedWallet(json);
.. code-block:: javascript
:caption: *Checking JSON Wallets --- ethers v4*
let address = ethers.utils.getJsonWalletAddress(json);
let isJsonWallet = (address !== null)
.. code-block:: javascript
:caption: *Decrypting JSON Wallets --- ethers v3*
let wallet = await ethers.Wallet.fromEncryptedWallet(json, password);
.. code-block:: javascript
:caption: *Decrypting JSON Wallets --- ethers v4*
let wallet = await ethers.Wallet.fromEncryptedJson(json, password);
-----
Events
------
Events now behave like a modern JavaScript Event Emitter, rather than a 1995
web browser.
The events now play nicer with the arrow operator (i.e. ``() => { ... }``),
since rather than modifying the `this` inside the callbacks, an additional
rich object is passed along.
.. code-block:: javascript
:caption: *Events --- ethers v3*
// Solidity: event SomeEvent(address foo, uint256 bar)
contract.onsomeevent = function(foo, bar) {
console.log(foo, bar);
// The Log was available at this:
// - this.event
// - this.removeListener()
};
.. code-block:: javascript
:caption: *Listening to an Event --- ethers v4*
// Solidity: event SomeEvent(address foo, uint256 bar)
contract.on('SomeEvent', (foo, bar, eventInfo) => {
console.log(foo, bar);
// eventInfo
// - Log (blockNumber, blockHash, txHash, removed, address, data, etc.)
// - args: [ foo, bar ]
// - decode: (data, topics) => [ foo, bar ]
// - event: "SomeEvent"
// - eventSignature: "SomeEvent(address,uint256)"
// - removeListener: () => removes this listener
// - getBlock: () => returns a Promise of the block
// - getTransaction: () => returns a Promise of transaction
// - getTransactionReceipt: () => returns a Promise of the receipt
});
.. code-block:: javascript
:caption: *Indexed Events --- ethers v3*
// Detecting a parameters is an indexed hash, and not a value
contract.someEvent = function(foo) {
if (foo.indexed) {
// The value is just a hash to filter by
}
}
.. code-block:: javascript
:caption: *Indexed Events --- ethers v4*
let Indexed = ethers.types.Indexed;
// Detecting a parameters is an indexed hash, and not a value
contract.someEvent = function(foo) {
if (Indexed.isIndexed(foo)) {
// The value is just a hash to filter by
}
}
.. code-block:: javascript
:caption: *Filtering Events --- ethers v4*
// Solidity: event SomeEvent(address indexed foo, uint256 bar)
let address = '0x8B40a2E27C5E87aa66DfA7F80BF675176F49DCA7';
let filter = contract.filters.SomeEvent(address, null);
console.log(filter);
// {
// address: contract.address,
// topics: [
// 0xdde371250dcd21c331edbb965b9163f4898566e8c60e28868533281edf66ab03,
// 0x0000000000000000000000008b40a2e27c5e87aa66dfa7f80bf675176f49dca7
// ]
// }
contract.on(filter, (foo, bar, eventInfo) => {
console.log(foo === address);
// true
});
If there are multiple events with the same name:
.. code-block:: javascript
:caption: *Event Name Collision --- ethers v4*
// Solidity
// - event SomeEvent(address foo, uint256 bar)
// - event SomeEvent(address foo, address bar)
contract.on('SomeEvent(address, uint256)', (foo, bar, eventInfo) => {
// ...
});
contract.on('SomeEvent(address, address)', (foo, bar, eventInfo) => {
// ...
});
-----
Fetching JSON
-------------
The JSON fetching routine, since it was mostly used for Providers was
on the Provider object in v3. In v4, it has moved to utils, since there
are other common cases where it may be useful.
.. code-block:: javascript
:caption: *Fetching JSON --- ethers v3*
ethers.providers.Provider.fetchJson(url).then((object) => {
// ...
});
.. code-block:: javascript
:caption: *Fetching JSON --- ethers v4*
ethers.utils.fetchJson(url).then((object) => {
// ...
});
-----
Interfaces
----------
This has always been a fairly low-level API, and mostly available for
framework developers and other tools that require quite specific access
to working with an ABI. Most of the changes are to simplify the interaction,
so while there will probably be changes required, if you use this class, the
complexity and size of your code should be reduced.
.. code-block:: javascript
:caption: *Interface --- ethers v3*
let iface = ethers.Interface(address, abi, providerOrSigner);
.. code-block:: javascript
:caption: *Interface --- ethers v4*
let iface = ethers.utils.Interface(address, abi, providerOrSigner);
.. code-block:: javascript
:caption: *Function Description --- ethers v3*
let address = "0x8B40a2E27C5E87aa66DfA7F80BF675176F49DCA7";
let value = 1000;
// Solidity: function someFunc(address foo, uint256 bar) constant returns (address result)
let functionCallable = iface.functionst.someFunc
// functionInfo
// - inputs: { names: [ "foo", "bar" ], types: [ "address", "uint256" ] }
// - outputs: { names: [ "result" ], types: [ "address" ] }
// - payable: false
// - parseResult: (data) => any
// - signature: "someFunc(address,uint256)"
// - sighash: "0xd90a6a67"
let data = functionCallable(address, value);
let result = functionCallable.parseResult(callResultData);
.. code-block:: javascript
:caption: *Function Description --- ethers v4*
let address = "0x8B40a2E27C5E87aa66DfA7F80BF675176F49DCA7";
let value = 1000;
// Solidity: function someFunc(address foo, uint256 bar) constant returns (address result)
let functionInfo = iface.functions.someFunc;
// functionInfo
// - type: "call" (or "transaction" for non-constant functions)
// - name: "someFunc"
// - signature: "someFunc(address,uint256)"
// - sighash: "0xd90a6a67"
// - inputs: [ { name: foo", type: "bar" }, { name: "bar", type: "uint256" } ]
// - outputs: [ { name: "result", type: "address" } ]
// - payable: false
// - encode: (params) => string
// - decode: (data) => any
// Note: This takes in an array; it no longer uses ...args
let data = functionInfo.encode([ address, value ]);
let result = functionInfo.decode(callResultData);
.. code-block:: javascript
:caption: *Event Description --- ethers v3*
// Solidity: event SomeEvent(address foo, uint256 bar)
let eventInfo = iface.events.SomeEvent;
// eventInfo
// - topics: [ ethers.utils.id("SomeEvent(address,uint256)") ]
// - anonymous: false
// - name: "SomeEvent"
// - signature: "SomeEvent(address,uint256)"
// - type: "event"
// - inputs: { names: [ 'foo', 'bar' ], types: [ 'address', 'uint256' ] }
// - parse: (topics, data) => Result
.. code-block:: javascript
:caption: *Event Description --- ethers v4*
// Solidity: event SomeEvent(address foo, uint256 bar)
let eventInfo = iface.events.SomeEvent;
// eventInfo
// - name: "SomeEvent"
// - signature: "SomeEvent(address,bar)"
// - inputs: [ { name: "foo", type: "address" }, { name: "bar", type: "uint256" } ]
// - anonymous: false
// - topic: ethers.utils.id("SomeEvent(address,uint256)")
// - encodeTopics: (Array<any>) => Array<string>
// - decode: (data, topics) => Result
// Create event filter topics
let address = '0x8B40a2E27C5E87aa66DfA7F80BF675176F49DCA7';
eventInfo.encodeTopics(address, null)
// topics: [
// "0xdde371250dcd21c331edbb965b9163f4898566e8c60e28868533281edf66ab03",
// "0x0000000000000000000000008b40a2e27c5e87aa66dfa7f80bf675176f49dca7"
// ]
-----
Networks
--------
.. code-block:: javascript
:caption: *Getting Network Info - ethers v3*
let network = ethers.providers.getNetwork('ropsten')
.. code-block:: javascript
:caption: *Getting Network Info - ethers v4*
let network = ethers.utils.getNetwork('ropsten');
// Networks may now also be found by their network ID
let network = ethers.utils.getNetwork(3);
// And networks can be validated as an object
let network = ethers.utils.getNetwork({ name: "custom", chainId: 1337 });
// Validation fails; this will throw an error, since Rinkeby is not
// chain ID 1 (homestead is)
let network = ethers.utils.getNetwork({ name: "rinkeby", chainId: 1 });
-----
Parsing Transactions
--------------------
The transaction parsing was moved out of the Wallet and into its own class
in the utilities, along with a general serialization API.
.. code-block:: javascript
:caption: *ethers v3*
let tx = ethers.Wallet.parseTransaction(rawTransaction);
.. code-block:: javascript
:caption: *ethers v4*
let tx = ethers.utils.parseTransaction(rawTransaction);
-----
Custom Signer
-------------
.. code-block:: javascript
:caption: *Custome Signer --- ethers v3*
let signer = {
// Required
getAddress: function() { ... },
provider: provider,
// Optional
estimateGas: function(tx) { ... },
sendTransaction: function(tx) { ... },
sign: function(tx) { ... },
};
.. code-block:: javascript
:caption: *Custom Signer --- JavaScript --- ethers v4*
function CustomSigner {
ethers.Signer.call(this);
// Optional
this.provider = provider;
}
inherits(CustomSigner, ethers.Signer);
// Required
CustomSigner.prototype.getAddress = () => { ... };
CustomSigner.prototype.sendTransaction = (tx) => { ... };
CustomSigner.prototype.signMessage = (message) => { ... };
// Optional
CustomSigner.prototype.connect = (provider) => { ... };
.. code-block:: javascript
:caption: *Custom Signer --- TypeScript --- ethers v4*
import {
Signer,
utils
} from 'ethers';
import {
Provider,
TransactionRequest,
TransactionReqponse
} from 'ethers/providers';
class CustomSigner extends Signer {
this.provider = provider;
readony provider: Provider;
constructor(provider) {
super();
// Optional
this.provider = // ...
}
getAddress() {
// Return a promise to the address
};
sendTransaction = (transaction: TransactionRequest): Promise<TransaxctinResponse> {
// This will popualte missing properties, like nonce, gasLimit, etc
return utils.populateTransaction(transaction).then((tx) => {
// Send the transaction and resolve the transaction
});
};
signMessage(message: string | ethers.utils.Arrayish): Promise<string> {
let dataToSign: Uint8Array = utils.hashMessage(message);;
// Sign ths dataToSign and resolve teh flat-format signature
};
// Optional; highly recommended
connect(provider: Provider): CustomSigner {
return new CustomSigner(provider);
}
}
-----
Default Provider
----------------
.. code-block:: javascript
:caption: *Default Provider --- ethers v3*
let provider = ethers.providers.getDefaultProvider();
.. code-block:: javascript
:caption: *Default Provider --- ethers v4*
let provider = ethers.getDefaultProvider();
-----
Big Number
----------
.. code-block:: javascript
:caption: *isBigNumber --- ethers v3*
let checkBigNumber = ethers.utils.isBigNumber(value);
.. code-block:: javascript
:caption: *isBigNumber --- ethers v4*
let checkBigNumber = BigNumber.isBigNumber(value);
-----
JsonRpcProvider
----------------
.. code-block:: javascript
:caption: *Connecting --- ethers v3*
let url = "http://localhost:8545";
let network = "rinkeby";
let provider = new ethers.providers.JsonRpcProvider(url, network);
// Even if the network was wrong, this would mostly seem to work and
// fail once the chain ID was attempted
// The network was a synchronous property on Provider
let network = provider.network;
.. code-block:: javascript
:caption: *Connecting --- ethers v4*
// In v4, the network is automatically determined; you may override
// the network, but it must match, or it will fail early
let url = "http://localhost:8545";
let provider = new ethers.providers.JsonRpcProvider(url);
// The network is now an asynchronous property:
provider.getNetwork().then((network) => {
// ...
});
// One useful and common exception it that, if any async call from
// the provider has ever succeeded, the synchronous network property
// is then valid. The network property is populated before any
// async call is made, so once an async call has finished, the network
// property is available synchronously.
async function() {
await provider.getBlockNumber();
let network = provider.network;
}
.. code-block:: javascript
:caption: *Sending Transactions --- ethers v3*
provider.sendTransaction(rawTransaction).then((hash) => {
// Just a transaction hash
});
.. code-block:: javascript
:caption: *Sending Transactions --- ethers v4*
provider.sendTransaction(rawTransaction).then((transaction) => {
// A full Transaction Response is returned
// - from
// - to
// - gasLimit, gasPrice
// - nonce
// - r, s, v
// - wait() => Promise that resolves the Transaction Receipt once mined
// and rejects with an error is the stats is 0; the error
// will have a transactionHash property as well as a
// transaction property.
let hash = transaction.hash;
});
-----
Verifying Messages
------------------
The message verification was moved from a static class on the Wallet to the
utilities, along with a few other functions of the elliptic curve cryptographic
exposed.
.. code-block:: javascript
:caption: *ethers v3*
let signingAddress = ethers.Wallet.verifyMessage(message, signature);
.. code-block:: javascript
:caption: *ethers v4*
let signingAddress = ethers.utils.verifyMessage(message, signature);
-----
Waiting for Transactions
------------------------
In v3, the ``transaction.wait()`` returned a Promise which would resolve to the
**TransactionResponse** once it is mined.
In v4, the ``transaction.wait()`` returned a Promise which would resolve to the
**TransactionReceipt** once it is mined.
-----
.. eof

@ -1,314 +0,0 @@
Notes
*****
A few quick notes about some of the less obvious aspects of interacting with
Ethereum in JavaScript.
-----
.. _ieee754:
Why can't I just use numbers?
=============================
The first problem many encounter when dealing with Ethereum is the concept of numbers. Most
common currencies are broken down with very little granularity. For example, there are only
100 cents in a single dollar. However, there are 10\ :sup:`18` **wei** in a single
**ether**.
JavaScript uses `IEEE 754 double-precision binary floating point`_ numbers to represent
numeric values. As a result, there are *holes* in the integer set after
9,007,199,254,740,991; which is problematic for *Ethereum* because that is only
around 0.009 ether (in wei).
To demonstrate how this may be an issue in your code, consider::
> (Number.MAX_SAFE_INTEGER + 4 - 5) == (Number.MAX_SAFE_INTEGER - 1)
false
To remedy this, all numbers (which can be large) are stored and manipulated
as :ref:`Big Numbers <bignumber>`.
The functions :ref:`parseEther( etherString ) <parseEther>` and :ref:`formatEther( wei ) <formatEther>` can be used to convert between
string representations, which are displayed to or entered by the user and Big Number representations
which can have mathematical operations handled safely.
-----
.. _promise:
Promises
========
A `Promise in JavaScript`_ is an object which simplifies many aspects of dealing with
asynchronous functions.
It allows a pending result to be treated in many ways as if it has already been resolved.
The most useful operations you will need are:
:sup:`Promise` . all ( promises )
Returns a new promise that resolves once all the *promises* have resolved.
:sup:`prototype` . then ( onResolve, onReject )
Returns another Promise, which once the Promise was resolved, the *onResolve*
function will be executed and if an error occurs, *onReject* will be called.
If *onResolve* returns a Promise, it will be inserted into the chain of the returned
promise. If *onResolve* throws an Error, the returned Promise will reject.
.. code-block:: javascript
:caption: *Cleaning out an account*
var ethers = require('ethers');
var targetAddress = "0x02F024e0882B310c6734703AB9066EdD3a10C6e0";
var privateKey = "0x0123456789012345678901234567890123456789012345678901234567890123";
var wallet = new ethers.Wallet(privateKey);
// Promises we are interested in
var provider = ethers.getDefaultProvider('ropsten');
var balancePromise = provider.getBalance(wallet.address);
var gasPricePromise = provider.getGasPrice();
var transactionCountPromise = provider.getTransactionCount(wallet.address);
var allPromises = Promise.all([
gasPricePromise,
balancePromise,
transactionCountPromise
]);
var sendPromise = allPromises.then(function(results) {
// This function is ONLY called once ALL promises are fulfilled
var gasPrice = results[0];
var balance = results[1];
var transactionCount = results[2];
// Sending a transaction to an externally owned account (EOA) is 21000 gas)
var txFeeInWei = gasPrice.mul(21000);
// This will send the maximum amount (our balance minus the fee)
var value = balance.sub(txFeeInWei);
var transaction = {
to: targetAddress,
gasPrice: gasPrice,
gasLimit: 21000,
nonce: transactionCount,
// The amount to send
value: value,
// Prevent replay attacks across networks
chainId: provider.chainId,
};
var signedTransaction = wallet.sign(transaction);
// By returning a Promise, the sendPromise will resolve once the
// transaction is sent
return provider.sendTransaction(signedTransaction);
});
var minedPromise = sendPromise.then(function(transaction) {
// This will be called once the transaction is sent
// This promise will be resolve once the transaction has been mined.
return provider.waitForTransaction(transaction);
});
minedPromise.then(function(transaction) {
console.log("The transaction was mined: Block " + transaction.blockNumber);
});
// Promises can be re-used for their value; it will not make the external
// call again, and will provide the exact same result every time.
balancePromise.then(function(balance) {
// This *may* return before the above allPromises, since it only
// required one external call. Keep in mind asynchronous calls can
// be called out of order.
console.log(balance);
});
-----
.. _checksum-address:
Checksum Address
================
A `checksum address`_ uses mixed case hexadecimal strings to encode the checksum
information in the capitalization of the alphabetic characters, while remaining
backwards compatible with non-checksum addresses.
Example::
// Valid; checksum (mixed case)
0xCd2a3d9f938e13Cd947eC05ABC7fe734df8DD826
// Valid; NO checksum (no mixed case)
0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826
0xCD2A3D9F938E13CD947EC05ABC7FE734DF8DD826
// INVALID; (mixed case, but case differs from first example)
0xDc2a3d9f938e13cd947ec05abc7fe734df8dd826
^^
To convert to a checksum addresses, see :ref:`getAddress() <utils-getaddress>`.
.. _checksum address: https://eips.ethereum.org/EIPS/eip-55
-----
.. _icap-address:
ICAP Address
============
The original method of adding a checksum to an Ethereum address was by using the
a format compatible with `IBAN`_ addresses, using the country code **XE**. However,
only addresses which have 0 as the first byte (i.e. the address begins with 0x00)
are truly compatible with IBAN, so ICAP extends the definition to allow for 31
alphanumeric characters (instead of the standard 30).
An ICAP address has the following format::
XE [2 digit checksum] [up to 31 alphanumeric characters]
To convert to an ICAP addresses, see :ref:`getIcapAddress() <utils-getaddress>`.
-----
Supported Platforms
===================
The ethers.js library aims to be as inclusive as possible. People often ask, "why
don't you use feature X or syntax Y", to which the response is usually that it
begins to heavily restricts the potential user-base.
The current target for ethers.js is to support an environment which is close to ES3,
with the addition of Object.defineProperty, which is a bit more advanced than an old
ES3 environment, but which adds considerable safety and security to the library.
The phantomjs test harness (``npm run test-phantomjs``) has a handful of shims included
in the tests/test.html, but serves as a good benchmark for what minimum features as
supported.
Currently the Test Suite runs against:
- node 6
- node 8
- node 10
- phantomjs
Another supported aspect is the use of paths in ``require``. A small part of the
library may be included, for example, ``keccak256``, by using::
var keccak256 = require('ethers/utils/keccak256').keccak256;
Which means renaming files is a breaking change, and may only be done between
major version releases. This is useful for people using older, pre-ES6
tree-shaking, to keep their package sizes small.
Now that the library also supports TypeScript, another question that often comes
up is (for example) "why are you doing runtime checks that a value is a number,
the TypeScript compiler checks that for you". It is important to keep in mind that
TypeScript, while a useful tool, is not the tool that everyone uses, and so for
anyone using JavaScript sans TypeScript, the library should guarantee safety and
correctness for them too and fail early and fail loud if anything is out of the
ordinary.
-----
Contributing
============
I fully welcome anyone to contribute to the project, and appreciate all the
help I can get. That said, if you have ideas for a PR, please discuss them
as an issue on GitHub first.
A few notes on contributing.
- Please read the above section on Supported Platforms.
- An important feature of ethers.js is that it is small, which means uncommon features or large features need a great deal of discussion.
- Since ethers.js is designed to be extensible, there are often ways to add optional packages; for example, look at the BIP39 mnemonic wordlists, which are not bundled into the browser version, but are designed to be seamlessly loaded into the browser if their functionality is required.
- Dependencies; part A) in line with the above, "keep things small", adding a dependency is a big deal, as they often bring many other packages with them. A great deal of effort has been used to tune the build process and dependency list to keep things tight
- Dependencies; part B) adding additional third party libraries, adds a huge attack vector fun malicious code or unexpected consequences, so adding a dependency is certainly something that needs to be very convincingly argued.
- Dependencies; part C) part B applies to dev dependencies too. A devDependency can inject or otherwise do strange things and increases the attack vector for bugs and malicious code
- Changing filenames or breaking backwards compatibility is a no-go for minor version changes
- Major version changes do not happen often. We place @TODO in the source code for things that will be updated at the next version change.
- Please use the GitHub issue system to make requests, or discuss changes you would like to make.
- Testing is a must. It should generally take you longer to write test cases than it does the actual code.
- All test cases must pass on all platforms supported on Travis CI.
-----
Security
========
A lot of people store a lot of value in Ethereum and the code that runs it. As
such, security is important.
The GitHub and NPM Package
--------------------------
The keys used to sign code on GitHub are well protected, but anyones computer
can be compromised.
All services involved have two-factor authentication set up, but please keep in
mind that bleeding-edge technology should probably not be used in production
environments.
Keep in mind, however, that at the end of the day, if NPM were hacked, anything
in the system could be replaced.
By using a version that is perhaps a few weeks old, providing there are no
advisories otherwise, there has been adequate time for any compromise to have
been broadcast.
Also, one of the test cases verifies the deterministic build on `Travis CI`_. **Never**
install a version which has failed the Continuous Integration tests on Travis CI.
Long story short, be careful.
In the event of any significant issue, it will be posted on the README.md file,
have an issue posted, with ALL CAPS in the title and will be broadcast on the
@ethersproject twitter.
Memory Hard Brute-Force Encrpyting
----------------------------------
A topic that often comes up is the poor performance of decrypting Wallet.
While it may not be immediately obvious, this is intentional for security
purposes.
If it takes the legitimate user, who knows the password 5 seconds or so to
unlock their account, that means that an attacker must spend 5 seconds per
password attempt, so to guess a million passwords, requires 5 million
seconds. Client software can streamline the process by using Secure Enclaves
or other secure local places to store the decrypted wallet to improve the
customer experience past the first decryption.
Responsible Disclosure
----------------------
If you find a critical bug or security issue with ethers.js, please contact
support@ethers.io so that we can address it before you make it public.
You will receive credit for the discovery after it is fixed and announced. :)
-----
.. _IBAN: https://en.wikipedia.org/wiki/International_Bank_Account_Number
.. _IEEE 754 double-precision binary floating point: https://en.wikipedia.org/wiki/Double-precision_floating-point_format
.. _BN.js: https://github.com/indutny/bn.js/
.. _Promise in JavaScript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
.. _Travis CI: https://travis-ci.org/ethers-io/ethers.js
.. EOF

@ -1,19 +0,0 @@
Testing
*******
Ethers uses a large suite of test cases to help ensure the library is as
complete, backwards compatible and correct as possible and pass
regression as new features are added.
Many of the test cases are created procedurally.
**@TODO:**
Explain more here on how to run and add testcases.
**@TODO:**
Post links to the testcases on IPFS (the generated test cases can takes hours to
generate and are too large to check into GitHub)
-----
.. EOF