js-cosmos-wallet
Version:
js version of cosmos wallet signer
171 lines (165 loc) • 6.66 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.jsCosmosWallet = {})));
}(this, (function (exports) { 'use strict';
// Import here Polyfills if needed. Recommended core-js (npm i -D core-js)
// import "core-js/fn/array.find"
// ...
var bip39 = require("bip39");
var bip32 = require("bip32");
var bech32 = require("bech32");
var secp256k1 = require("secp256k1");
var sha256 = require("crypto-js/sha256");
var ripemd160 = require("crypto-js/ripemd160");
var CryptoJS = require("crypto-js");
var hdPathAtom = "m/44'/118'/0'/0/0"; // key controlling ATOM allocation
var standardRandomBytesFunc = function (x) { return CryptoJS.lib.WordArray.random(x).toString(); };
function generateWalletFromSeed(mnemonic) {
var masterKey = deriveMasterKey(mnemonic);
var _a = deriveKeypair(masterKey), privateKey = _a.privateKey, publicKey = _a.publicKey;
var cosmosAddress = createCosmosAddress(publicKey);
return {
privateKey: privateKey.toString("hex"),
publicKey: publicKey.toString("hex"),
cosmosAddress: cosmosAddress
};
}
function generateSeed(randomBytesFunc) {
if (randomBytesFunc === void 0) { randomBytesFunc = standardRandomBytesFunc; }
var randomBytes = Buffer.from(randomBytesFunc(32), "hex");
if (randomBytes.length !== 32)
throw Error("Entropy has incorrect length");
var mnemonic = bip39.entropyToMnemonic(randomBytes.toString("hex"));
return mnemonic;
}
function generateWallet(randomBytesFunc) {
if (randomBytesFunc === void 0) { randomBytesFunc = standardRandomBytesFunc; }
var mnemonic = generateSeed(randomBytesFunc);
return generateWalletFromSeed(mnemonic);
}
// NOTE: this only works with a compressed public key (33 bytes)
function createCosmosAddress(publicKey) {
var message = CryptoJS.enc.Hex.parse(publicKey.toString("hex"));
var hash = ripemd160(sha256(message)).toString();
var address = Buffer.from(hash, "hex");
var cosmosAddress = bech32ify(address, "cosmos");
return cosmosAddress;
}
function deriveMasterKey(mnemonic) {
// throws if mnemonic is invalid
bip39.validateMnemonic(mnemonic);
var seed = bip39.mnemonicToSeed(mnemonic);
var masterKey = bip32.fromSeed(seed);
return masterKey;
}
function deriveKeypair(masterKey) {
var cosmosHD = masterKey.derivePath(hdPathAtom);
var privateKey = cosmosHD.privateKey;
var publicKey = secp256k1.publicKeyCreate(privateKey, true);
return {
privateKey: privateKey,
publicKey: publicKey
};
}
function bech32ify(address, prefix) {
var words = bech32.toWords(address);
return bech32.encode(prefix, words);
}
// Transactions often have amino decoded objects in them {type, value}.
// We need to strip this clutter as we need to sign only the values.
function prepareSignBytes(jsonTx) {
if (Array.isArray(jsonTx)) {
return jsonTx.map(prepareSignBytes);
}
// string or number
if (typeof jsonTx !== "object") {
return jsonTx;
}
var sorted = {};
Object.keys(jsonTx)
.sort()
.forEach(function (key) {
if (jsonTx[key] === undefined || jsonTx[key] === null)
return;
sorted[key] = prepareSignBytes(jsonTx[key]);
});
return sorted;
}
/*
The SDK expects a certain message format to serialize and then sign.
type StdSignMsg struct {
ChainID string `json:"chain_id"`
AccountNumber uint64 `json:"account_number"`
Sequence uint64 `json:"sequence"`
Fee auth.StdFee `json:"fee"`
Msgs []sdk.Msg `json:"msgs"`
Memo string `json:"memo"`
}
*/
function createSignMessage(jsonTx, _a) {
var sequence = _a.sequence, account_number = _a.account_number, chain_id = _a.chain_id;
// sign bytes need amount to be an array
var fee = {
amount: jsonTx.fee.amount || [],
gas: jsonTx.fee.gas
};
return JSON.stringify(prepareSignBytes({
fee: fee,
memo: jsonTx.memo,
msgs: jsonTx.msg,
sequence: sequence,
account_number: account_number,
chain_id: chain_id
}));
}
// produces the signature for a message (returns Buffer)
function signWithPrivateKey(signMessage, privateKey) {
var signHash = Buffer.from(sha256(signMessage).toString(), "hex");
var signature = secp256k1.sign(signHash, Buffer.from(privateKey, "hex")).signature;
return signature;
}
function createSignature(signature, publicKey) {
return {
signature: signature.toString("base64"),
pub_key: {
type: "tendermint/PubKeySecp256k1",
value: publicKey.toString("base64")
}
};
}
// main function to sign a jsonTx using the local keystore wallet
// returns the complete signature object to add to the tx
function sign(jsonTx, wallet, requestMetaData) {
var signMessage = createSignMessage(jsonTx, requestMetaData);
var signatureBuffer = signWithPrivateKey(signMessage, wallet.privateKey);
var pubKeyBuffer = Buffer.from(wallet.publicKey, "hex");
return createSignature(signatureBuffer, pubKeyBuffer);
}
// adds the signature object to the tx
function createSignedTx(tx, signature) {
return Object.assign({}, tx, {
signatures: [signature]
});
}
// the broadcast body consists of the signed tx and a return type
function createBroadcastBody(signedTx) {
return JSON.stringify({
tx: signedTx,
return: "block"
});
}
exports.generateWalletFromSeed = generateWalletFromSeed;
exports.generateSeed = generateSeed;
exports.generateWallet = generateWallet;
exports.createCosmosAddress = createCosmosAddress;
exports.prepareSignBytes = prepareSignBytes;
exports.createSignMessage = createSignMessage;
exports.signWithPrivateKey = signWithPrivateKey;
exports.createSignature = createSignature;
exports.sign = sign;
exports.createSignedTx = createSignedTx;
exports.createBroadcastBody = createBroadcastBody;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=js-cosmos-wallet.umd.js.map