UNPKG

@bandprotocol/bandchain.js

Version:

Library for interacting with BandChain in browser and Node.js environments

311 lines (310 loc) 12.7 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Address = exports.PublicKey = exports.PrivateKey = exports.Ledger = void 0; const bip39 = __importStar(require("bip39")); const bip32_1 = require("bip32"); const bech32_1 = require("bech32"); const secp256k1_1 = __importStar(require("secp256k1")); const crypto_1 = __importDefault(require("crypto")); const ecpair_1 = __importDefault(require("ecpair")); const ecc = __importStar(require("@bitcoinerlab/secp256k1")); const ledger_cosmos_js_1 = __importDefault(require("ledger-cosmos-js")); const helpers_1 = require("./helpers"); const error_1 = require("./error"); const keys_pb_1 = require("../codegen/cosmos/crypto/secp256k1/keys_pb"); const ECPair = (0, ecpair_1.default)(ecc); const bip32 = (0, bip32_1.BIP32Factory)(ecc); const BECH32_PUBKEY_ACC_PREFIX = 'bandpub'; const BECH32_PUBKEY_VAL_PREFIX = 'bandvaloperpub'; const BECH32_PUBKEY_CONS_PREFIX = 'bandvalconspub'; const BECH32_ADDR_ACC_PREFIX = 'band'; const BECH32_ADDR_VAL_PREFIX = 'bandvaloper'; const BECH32_ADDR_CONS_PREFIX = 'bandvalcons'; const DEFAULT_DERIVATION_PATH = "m/44'/494'/0'/0/0"; const DEFAULT_DERIVATION_PATH_LEDGER = "m/44'/118'/0'/0/0"; var ConnectType; (function (ConnectType) { ConnectType[ConnectType["Node"] = 0] = "Node"; ConnectType[ConnectType["Web"] = 1] = "Web"; })(ConnectType || (ConnectType = {})); class Ledger { constructor() { this.hidPath = DEFAULT_DERIVATION_PATH_LEDGER; this.disconnect = () => new Promise((resolve) => resolve()); } static connectLedgerWeb(hidPath = DEFAULT_DERIVATION_PATH_LEDGER) { return __awaiter(this, void 0, void 0, function* () { return Ledger.connect(hidPath, ConnectType.Web); }); } static connectLedgerNode(hidPath = DEFAULT_DERIVATION_PATH_LEDGER) { return __awaiter(this, void 0, void 0, function* () { return Ledger.connect(hidPath, ConnectType.Node); }); } static connect(hidPath, connectType) { return __awaiter(this, void 0, void 0, function* () { if (!(0, helpers_1.isBip44)(hidPath)) throw Error('Not BIP 44'); let ledger = new Ledger(); ledger.hidPath = hidPath; yield ledger._connect(connectType); return ledger; }); } _connect(connectType) { return __awaiter(this, void 0, void 0, function* () { if (this.cosmosApp) return; let transport; switch (connectType) { case ConnectType.Node: const { default: TransportNodeHid, } = require('@ledgerhq/hw-transport-node-hid'); transport = yield TransportNodeHid.create(3); break; case ConnectType.Web: if (navigator.usb) { const { default: TransportWebUSB, } = require('@ledgerhq/hw-transport-webusb'); transport = yield TransportWebUSB.create(3); } else { const { default: TransportWebHid, } = require('@ledgerhq/hw-transport-webhid'); transport = yield TransportWebHid.create(3); } break; } const ledgerCosmosApp = new ledger_cosmos_js_1.default(transport); this.cosmosApp = ledgerCosmosApp; this.disconnect = () => transport.close(); yield this.isCosmosAppOpen(); }); } checkLedgerError(response, errorOnUndefined) { if (!response) { if (errorOnUndefined) throw new Error(errorOnUndefined); return; } switch (response.error_message) { case `No errors`: return; default: throw new Error(response.error_message); } } isCosmosAppOpen() { return __awaiter(this, void 0, void 0, function* () { const response = yield (0, helpers_1.promiseTimeout)(this.cosmosApp.appInfo(), 5000); this.checkLedgerError(response, `Can't connect with CosmosApp`); const { appName } = response; if (appName.toLowerCase() !== 'cosmos') throw new Error(`Please close ${appName} and open the Cosmos app.`); return true; }); } appInfo() { return __awaiter(this, void 0, void 0, function* () { const response = yield (0, helpers_1.promiseTimeout)(this.cosmosApp.appInfo(), 5000); this.checkLedgerError(response, `Can't connect with CosmosApp`); return response; }); } sign(transaction) { return __awaiter(this, void 0, void 0, function* () { const response = yield this.cosmosApp.sign((0, helpers_1.bip44ToArray)(this.hidPath), transaction.getSignMessage().toString()); this.checkLedgerError(response); return Buffer.from((0, secp256k1_1.signatureImport)(response.signature)); }); } getPubKeyAndBech32Address() { return __awaiter(this, void 0, void 0, function* () { const response = yield (0, helpers_1.promiseTimeout)(this.cosmosApp.getAddressAndPubKey((0, helpers_1.bip44ToArray)(this.hidPath), 'band'), 5000); this.checkLedgerError(response, `Can't connect with CosmosApp`); return { bech32_address: response.bech32_address, pubKey: PublicKey.fromHex(response.compressed_pk.toString('hex')), }; }); } } exports.Ledger = Ledger; class PrivateKey { constructor(signingKey) { this.signingKey = signingKey; } static generate(path = DEFAULT_DERIVATION_PATH) { const phrase = bip39.generateMnemonic(256); return [phrase, this.fromMnemonic(phrase, path)]; } static fromMnemonic(words, path = DEFAULT_DERIVATION_PATH) { const seed = bip39.mnemonicToSeedSync(words); const node = bip32.fromSeed(seed); const child = node.derivePath(path); if (!child.privateKey) throw new error_1.CreateError('Cannot create private key'); const ecpair = ECPair.fromPrivateKey(child.privateKey, { compressed: false, }); if (!ecpair.privateKey) throw new error_1.CreateError('Cannot create private key'); return new PrivateKey(ecpair.privateKey); } static fromHex(priv) { return new PrivateKey(Buffer.from(priv, 'hex')); } toHex() { return this.signingKey.toString('hex'); } toPubkey() { const pubKeyByte = secp256k1_1.default.publicKeyCreate(this.signingKey); return PublicKey.fromHex(Buffer.from(pubKeyByte).toString('hex')); } sign(msg) { const hash = crypto_1.default.createHash('sha256').update(msg).digest('hex'); const buf = Buffer.from(hash, 'hex'); const { signature } = secp256k1_1.default.ecdsaSign(buf, this.signingKey); return Buffer.from(signature); } } exports.PrivateKey = PrivateKey; class PublicKey { constructor(verifyKey) { this.verifyKey = verifyKey; } static fromBech32(bech, _prefix) { const { prefix, words } = bech32_1.bech32.decode(bech); if (prefix != _prefix) throw new error_1.ValueError('Invalid bech32 prefix'); if (words.length === 0) throw new error_1.DecodeError('Cannot decode bech32'); return new PublicKey(Buffer.from(bech32_1.bech32.fromWords(words).slice(5))); } static fromHex(pub) { return new PublicKey(Buffer.from(pub, 'hex')); } static fromAccBech32(bech) { return this.fromBech32(bech, BECH32_PUBKEY_ACC_PREFIX); } static fromValBech32(bech) { return this.fromBech32(bech, BECH32_PUBKEY_VAL_PREFIX); } static fromConsBech32(bech) { return this.fromBech32(bech, BECH32_PUBKEY_CONS_PREFIX); } toBech32(prefix) { const hex = Buffer.concat([ Buffer.from('eb5ae98721', 'hex'), this.verifyKey, ]); const words = bech32_1.bech32.toWords(Buffer.from(hex)); if (words.length === 0) throw new error_1.UnsuccessfulCallError('Unsuccessful bech32.toWords call'); return bech32_1.bech32.encode(prefix, words); } toPubkeyProto() { const publicKeyProto = new keys_pb_1.PubKey(); publicKeyProto.setKey(this.verifyKey); return publicKeyProto; } toAccBech32() { return this.toBech32(BECH32_PUBKEY_ACC_PREFIX); } toValBech32() { return this.toBech32(BECH32_PUBKEY_VAL_PREFIX); } toConsBech32() { return this.toBech32(BECH32_PUBKEY_CONS_PREFIX); } toHex() { return this.verifyKey.toString('hex'); } toAddress() { const hash = crypto_1.default.createHash('sha256').update(this.verifyKey).digest(); return Address.fromHex(crypto_1.default.createHash('ripemd160').update(hash).digest('hex')); } verify(msg, sig) { const hash = crypto_1.default.createHash('sha256').update(msg).digest('hex'); const buf = Buffer.from(hash, 'hex'); return secp256k1_1.default.ecdsaVerify(sig, buf, this.verifyKey); } } exports.PublicKey = PublicKey; class Address { constructor(addr) { this.addr = addr; } static fromBech32(bech, _prefix) { const { prefix, words } = bech32_1.bech32.decode(bech); if (prefix != _prefix) throw new error_1.ValueError('Invalid bech32 prefix'); if (words.length === 0) throw new error_1.DecodeError('Cannot decode bech32'); return new Address(Buffer.from(bech32_1.bech32.fromWords(words))); } static fromHex(hex) { return new Address(Buffer.from(hex, 'hex')); } static fromAccBech32(bech) { return this.fromBech32(bech, BECH32_ADDR_ACC_PREFIX); } static fromValBech32(bech) { return this.fromBech32(bech, BECH32_ADDR_VAL_PREFIX); } static fromConsBech32(bech) { return this.fromBech32(bech, BECH32_ADDR_CONS_PREFIX); } toBech32(prefix) { const words = bech32_1.bech32.toWords(this.addr); if (words.length === 0) throw new error_1.UnsuccessfulCallError('Unsuccessful bech32.toWords call'); return bech32_1.bech32.encode(prefix, words); } toAccBech32() { return this.toBech32(BECH32_ADDR_ACC_PREFIX); } toValBech32() { return this.toBech32(BECH32_ADDR_VAL_PREFIX); } toConsBech32() { return this.toBech32(BECH32_ADDR_CONS_PREFIX); } toHex() { return this.addr.toString('hex'); } } exports.Address = Address;