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¶
The Wallet implements the Signer API and can be used anywhere a Signer is expected and has all the required properties.
Creating Instances¶
- new Wallet ( privateKey [ , provider ] )
- Creates a new instance from privateKey and optionally connect a provider
- Wallet . createRandom ( [ options ] ) => 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
- Wallet . fromEncryptedJson ( json, password [ , progressCallback ] ) => Wallet
- Decrypt an encrypted Secret Storage JSON Wallet (from Geth, parity, Crowdsale tools, or that was created using prototype.encrypt )
- Wallet . fromMnemonic ( mnemonic [ , path = “m/44’/60’/0’/0/0” [ , wordlist ] ] ) => 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 thedist/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
- prototype . connect ( provider ) => Wallet
- Creates a new Wallet instance from an existing instance, connected to a new provider.
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);
let randomWallet = ethers.Wallet.createRandom();
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"
});
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¶
- prototype . address
- The public address of a wallet
- prototype . privateKey
- The private key of a wallet; keep this secret
- prototype . provider
A connected 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 connect method, which will return a new instance of the Wallet connected to the provider.
- prototype . mnemonic
- The mnemonic phrase for this wallet, or null if the mnemonic is unknown.
- prototype . path
- The mnemonic path for this wallet, or null if the mnemonic is unknown.
Signing¶
- prototype . sign ( transaction ) => Promise<string>
Signs transaction and returns a Promise that resolves to the signed transaction as a hex string.
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
- prototype . signMessage ( message ) => Promise<string>
Signs message and returns a Promise that resolves to the flat-format signature.
If message is a string, it is converted to UTF-8 bytes, otherwise it is preserved as a binary representation of the Arrayish data.
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:
});
})
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
// }
});
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.
- prototype . getBalance ( [ blockTag = “latest” ] ) => Promise<BigNumber>
- Returns a Promise that resolves to the balance of the wallet (as a BigNumber, in wei) at the blockTag.
- prototype . getTransactionCount ( [ blockTag = “latest” ] ) => Promise<number>
- Returns a Promise that resovles to the number of transactions this account has ever sent (also called the nonce) at the blockTag.
- prototype . estimateGas ( transaction ) => Promise<BigNumber>
- Returns a Promise with the estimated cost for transaction (as a BigNumber, in gas)
- prototype . sendTransaction ( transaction ) => Promise<TransactionResponse>
- Sends the transaction (see Transaction Requests) to the network and returns a Promise that resolves to a Transaction Response. Any properties that are not provided will be populated from 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);
});
// 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 Wallet.fromEncryptedJson for creating a Wallet instance from a JSON wallet.
- prototype . encrypt ( password [ , options [ , progressCallback ] ] ) => 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.
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 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 Wallet extends the Signer API, as do the JsonRpcSigner and the Ledger Hardware Wallet Signer.
To implement a Signer, inherit the abstract class ethers.types.Signer and implement the following properties:
- object . provider
- A Provider that is connected to the network. This is optional, however, without a provider, only write-only operations should be expected to work.
- object . getAddress ( ) => Promise<Address>
- Returns a Promise that resolves to the account address.
- object . signMessage ( message ) => Promise<hex>
Returns a Promise that resolves to the Flat-Format 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 Arrayish data.
- object . sendTransaction ( transaction ) => Promise<TransactionResponse>
- Sends the transaction (see Transaction Requests) to the network and returns a Promise that resolves to a Transaction Response. Any properties that are not provided will be populated from the network.