Wallets and Signers

A Wallet manages a private/public key pair which is used to cryptographically sign transactions and prove ownership on the blockchain 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 created using prototype.encrypt )
Wallet . fromMnemonic ( mnemonic [ , path = “m/44’/118’/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).

The current supported wordlists are:

Language node.js
English (US) wordlists.en
Italian wordlists.it
Japanese wordlists.ja
Korean wordlists.ko
Chinese (simplified) wordlists.zh_cn
Chinese (traditional) wordlists.zh_tw
prototype . connect ( provider )   => Wallet
Creates a new Wallet instance from an existing instance, connected to a new provider.
load a private key
let privateKey = "0x0123456789012345678901234567890123456789012345678901234567890123";
let wallet = new mxw.Wallet(privateKey);

// Connect a wallet to mainnet
let provider = mxw.getDefaultProvider();
let walletWithProvider = new mxw.Wallet(privateKey, provider);
create a new random account
let randomWallet = mxw.Wallet.createRandom();
create a new random account with chinese mnemonic
let randomWallet = mxw.Wallet.createRandom({
    locale: mxw.wordlists.zh
});
console.log("Mnemonic:", randomWallet.mnemonic);
load an encrypted JSON wallet
let data = {
    address: "mxw15f3aw83y2hgzzs6hk6utputr2xchwe5x745l9s",
    id: "c5bb2456-071a-4b0d-b5a9-2075ee36a11e",
    version: 3,
    Crypto: {
        cipher: "aes-128-ctr",
        cipherparams: {
            iv: "88220a02a82b254a6c23247615932c60"
        },
        ciphertext: "5de598a84adda99ed92dc09a7f83736c68a06129f05bc0081f9cef7041866709",
        kdf: "scrypt",
        kdfparams: {
            salt: "a05e912bfe756f0ee2dfb0cf7a38d4b84930a1de31396a59d7b9cdb42dc74342",
            n: 131072,
            dklen: 32,
            p: 1,
            r: 8
        },
        mac: "b41dcf04bfa45b88c7aa4cc8e1edc47c218aa84a5e289ac7e7981982c98dbe82"
    },
    "x-mxw": {
        client: "mxw-sdk",
        filename: "UTC--2019-06-07T15-02-23.0Z--mxw15f3aw83y2hgzzs6hk6utputr2xchwe5x745l9s",
        mnemonicCounter: "9ac2433e799915cdaa109cb66dc4ca00",
        mnemonicCiphertext: "5da742bee220e6c92419a7369a3d5f44",
        path: "m/44'/118'/0'/0/0",
        locale: "en",
        version: "0.1"
    }
};

let json = JSON.stringify(data);
let password = "any strong password";

mxw.Wallet.fromEncryptedJson(json, password).then((wallet) => {
    console.log("Wallet: " + JSON.stringify(wallet, null, 4));
    // Wallet Address should be "mxw15f3aw83y2hgzzs6hk6utputr2xchwe5x745l9s"
});
load a mnemonic phrase
let mnemonic = "cradle embody shrimp analyst leave ribbon foot liquid supply dynamic swallow bacon";
let mnemonicWallet = mxw.Wallet.fromMnemonic(mnemonic);
console.log("WamnemonicWalletllet: " + JSON.stringify(mnemonicWallet, null, 4));
// Wallet Address should be "mxw15f3aw83y2hgzzs6hk6utputr2xchwe5x745l9s"

// Load the second account from a mnemonic
let path = "m/44'/118'/1'/0/0";
let secondMnemonicWallet = mxw.Wallet.fromMnemonic(mnemonic, path);
console.log("secondMnemonicWallet: " + JSON.stringify(secondMnemonicWallet, null, 4));
// Wallet Address should be "mxw12h2a2ky8cyldm5qhm6xluu0ggapeztzcypww4c"

// Load using a non-english locale wordlist (the path "null" will use the default)
let zhMnemonic = "手 农 勾 讲 嫂 蒋 借 棚 遗 没 紫 雾";
let zhMnemonicWallet = mxw.Wallet.fromMnemonic(zhMnemonic, null, mxw.wordlists.zh);
console.log("zhMnemonicWallet: " + JSON.stringify(zhMnemonicWallet, null, 4));
// Wallet Address should be "mxw10elph2l8r92dy9kjmugammjkejq2jnlu06gs3y"

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 blockchain 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:
type?: string,
value?: {
    msg?: [{ type: string, value: any }],
    fee?: {
        amount?: [{ denom: string, amount: BigNumberish }],
        gas: BigNumberish
    },
    memo?: string
}
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.

signing transactions
let privateKey = "0x9d74e1f662488cc6a0c46d7d87acff5d1f1f53bab476647deecf3c90f24d5468";
let provider = mxw.getDefaultProvider();
let wallet = new mxw.Wallet(privateKey, provider);

console.log(wallet.address);
// "mxw15f3aw83y2hgzzs6hk6utputr2xchwe5x745l9s"

let amount = mxw.utils.parseMxw("1.0");

// All properties are optional, except fee
let transaction = {
    type: "auth/StdTx",
    value: {
        msg: [
            {
                type: "cosmos-sdk/MsgSend",
                value: {
                    amount: [
                        {
                            amount: amount,
                            denom: "siu",
                        },
                    ],
                    from_address: wallet.address,
                    to_address: "mxw12h2a2ky8cyldm5qhm6xluu0ggapeztzcypww4c",
                }
            }
        ],
        memo: "Hello Blockchain"
    },
    fee: provider.getTransactionFee("bank", "bank-send", null, amount)
};

return wallet.sign(transaction).then((signedTransaction) => {

    console.log(signedTransaction);
    // Should be base64 encoded string

    return provider.sendTransaction(signedTransaction).then((tx) => {

        console.log(tx);
        // Should be transaction response with transaction hash value

        // Query transaction receipt by transaction hash
        return provider.waitForTransaction(tx.hash).then((receipt) => {

            console.log(receipt);
            // Should check the transaction status = 1 means successfully added into block
        });
    });
});
signing text messages
let privateKey = "0x9d74e1f662488cc6a0c46d7d87acff5d1f1f53bab476647deecf3c90f24d5468";
let wallet = new mxw.Wallet(privateKey);

// Sign a text message
return wallet.signMessage("Hello Blockchain!").then((signature) => {

    // Flat-format
    console.log(signature);
    // BPfvQe3WfYaBRBBHG03pnkqPMQ7Yr53FpiNJztraiRhfu3FFz0orTgM1Abv3
    // fNrBMATZl6q3JcFhmbp94hrURQ==

    // Expanded-format
    console.log(mxw.utils.splitSignature(signature));
    // {
    //     r: "0x04f7ef41edd67d86814410471b4de99e4a8f310ed8af9dc5a62349cedada8918",
    //     s: "0x5fbb7145cf4a2b4e033501bbf77cdac13004d997aab725c16199ba7de21ad445",
    //     v: 27,
    //     recoveryParam: 0
    // }
});
signing binary messages
let privateKey = "0x9d74e1f662488cc6a0c46d7d87acff5d1f1f53bab476647deecf3c90f24d5468";
let wallet = new mxw.Wallet(privateKey);

// The 66 character hex string MUST be converted to a 32-byte array first!
let hash = "0x48656c6c6f20426c6f636b636861696e21";
let binaryData = mxw.utils.arrayify(hash);

return wallet.signMessage(binaryData).then((signature) => {

    console.log(signature);
    // "0x5e9b7a7bd77ac21372939d386342ae58081a33bf53479152c87c1e787c27d06b
    //    118d3eccff0ace49891e192049e16b5210047068384772ba1fdb33bbcba58039
    //    1c"

    let address = mxw.utils.verifyMessage(binaryData, signature);
    console.log(address);
    // Should be equal to signer wallet address mxw15f3aw83y2hgzzs6hk6utputr2xchwe5x745l9s
});

Name Service

prototype . createAlias ( name, appFee )   => Promise<TransactionReceipt>

Sign alias creation transaction and send it to network and returns a Promise that resolves to a Transaction Response. Alias application approval is required by authority.

Note: The alias should not contains any spaces, special characters or any sensitive words. The application fee should be set according to the configured value.


Cryptographic Functions

prototype . computeSharedSecret ( otherPublicKey )   => string
Compute the shared secret by using other wallet’s public key and returns as a hex string. In general, the shared secret should not directly uses as encryption key. Instead of derive it using pbkdf2.

Blockchain Operations

These operations require the wallet have a provider attached to it.

prototype . getBalance ( )   => Promise<BigNumber>
Returns a Promise that resolves to the balance (as a BigNumber, in cin) of the wallet. Be aware of the number of decimals for cin is 18. The balance can be convert to a human readable format by formatMxw, versa parseMxw.
prototype . transfer ( addressOrName, value )   => Promise<TransactionReceipt>

Sends the transfer transaction to the network and returns a Promise that resolves to a Transaction Receipt.

The addressOrName can be set to recipient alias or wallet address. The value is the number of cin (as a BigNumber) that transfers to recipient. Be aware of the number of decimals for cin is 18.

prototype . getTransactionCount ( )   => Promise<BigNumber>
Returns a Promise that resovles to the number of transactions this account has ever sent (as a BigNumber).
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.
query the network
// We require a provider to query the network
let provider = mxw.getDefaultProvider();

let privateKey = "0x9d74e1f662488cc6a0c46d7d87acff5d1f1f53bab476647deecf3c90f24d5468";
let wallet = new mxw.Wallet(privateKey, provider);

wallet.getBalance().then((balance) => {
    console.log(balance);
});

wallet.getTransactionCount().then((nonce) => {
    console.log(nonce);
});
transfer mxw
// We require a provider to send transactions
let provider = mxw.getDefaultProvider();

let privateKey = "0x9d74e1f662488cc6a0c46d7d87acff5d1f1f53bab476647deecf3c90f24d5468";
let wallet = new mxw.Wallet(privateKey, provider);

let to = "mxw12h2a2ky8cyldm5qhm6xluu0ggapeztzcypww4c";
// ... or supports Alias names
// to: "jeansoon",

let amount = mxw.utils.parseMxw("1.0");
// We must pass in the amount as siu (1 mxw = 1e18 siu), so we
// use this convenience function to convert mxw to siu.

return wallet.transfer(to, amount).then((receipt) => {
    console.log(receipt);
    // Should check the transaction status = 1 means successfully added into block
});

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.

encrypt a wallet as an encrypted JSON wallet
let password = "any strong password";

function callback(progress) {
    console.log("Encrypting: " + parseInt(progress * 100) + "% complete");
}

return wallet.encrypt(password, callback).then((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.

To implement a Signer, inherit the abstract class mxw.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 . sign ( transaction )   => Promise<hex>
Returns a Promise that resolves to the signed transaction that ready to send to the network.
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.