Cookbook

Some quick snippets of code and ideas to work from.

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 Balances of All Geth Wallets (in the current director)

Geth
~/.ethereum/keystore
Parity
~/.parity/keys/some directory/keys

SourceCode:

var fs = require('fs');

var ethers = require('ethers');
var provider = ethers.providers.defaultProvider();

var filenames = fs.readDirSync('.');

filenames.forEach(function(filename) {
    fs.readFile(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.formatEther(balance));
        });
    });
});

Empty One Account into Another

Include example links to etherscan showing the transactions

Source Code:

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)

Source Code:

var ethers = require('ethers');

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'));
            }
    }
}

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 hdnode = ethers.HDNode.fromMnemonic();
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 = "";

var hdnode = ethers.HDNode.fromMnemonic(mnemonic);
var node = hdnode.derivePath(walletPath.standard);

var wallet = new Wallet(node.privateKey);
console.log(wallet.address);

@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.

Source Code:

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);
    });
}