UNPKG

@okxweb3/coin-bitcoin

Version:

@ok/coin-bitcoin is a Bitcoin SDK for building Web3 wallets and applications. It supports BTC, BSV, DOGE, LTC, and TBTC, enabling private key management, transaction signing, address generation, and inscriptions like BRC-20, Runes, CAT, and Atomicals.

691 lines 26.2 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; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.convert2UtxoTx = exports.number2Hex = exports.TBtcWallet = exports.BtcWallet = exports.BITCOIN_MESSAGE_BIP0322_SIMPLE = exports.BITCOIN_MESSAGE_ECDSA = void 0; const coin_base_1 = require("@okxweb3/coin-base"); const crypto_lib_1 = require("@okxweb3/crypto-lib"); const coin_base_2 = require("@okxweb3/coin-base"); const bitcoin = __importStar(require("../index")); const index_1 = require("../index"); exports.BITCOIN_MESSAGE_ECDSA = 0; exports.BITCOIN_MESSAGE_BIP0322_SIMPLE = 1; class BtcWallet extends coin_base_1.BaseWallet { network() { return bitcoin.networks.bitcoin; } async getDerivedPath(param) { if (!param.segwitType) { return `m/44'/0'/0'/0/${param.index}`; } if (param.segwitType == coin_base_1.segwitType.SEGWIT_NESTED) { return `m/84'/0'/0'/0/${param.index}`; } else if (param.segwitType == coin_base_1.segwitType.SEGWIT_NESTED_49) { return `m/49'/0'/0'/0/${param.index}`; } else if (param.segwitType == coin_base_1.segwitType.SEGWIT_NATIVE) { return `m/84'/0'/0'/0/${param.index}`; } else if (param.segwitType == coin_base_1.segwitType.SEGWIT_TAPROOT) { return `m/86'/0'/0'/0/${param.index}`; } else { return Promise.reject(coin_base_1.DerivePathError); } } async validPrivateKey(param) { let isValid; try { const { version } = bitcoin.wif.decode(param.privateKey); isValid = version === this.network().wif; } catch (e) { isValid = false; } const data = { isValid: isValid, privateKey: param.privateKey, }; return Promise.resolve(data); } async getNewAddress(param) { try { let network = this.network(); let privateKey = param.privateKey; const addressType = param.addressType || 'Legacy'; const publicKey = bitcoin.wif2Public(privateKey, network); let address; if (addressType === 'Legacy') { const result = bitcoin.payments.p2pkh({ pubkey: publicKey, network, }); address = result.address; } else if (addressType === 'segwit_native') { const result = bitcoin.payments.p2wpkh({ pubkey: publicKey, network, }); address = result.address; } else if (addressType === 'segwit_nested') { const result = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2wpkh({ pubkey: publicKey, network, }), }); address = result.address; } else if (addressType === 'segwit_taproot') { const result = bitcoin.payments.p2tr({ internalPubkey: publicKey.slice(1), network, }); address = result.address; } let data = { address: address || '', publicKey: coin_base_2.base.toHex(addressType === 'segwit_taproot' ? publicKey.slice(1) : publicKey), compressedPublicKey: coin_base_2.base.toHex(publicKey), }; return Promise.resolve(data); } catch (e) { return Promise.reject(coin_base_1.NewAddressError); } } async validAddress(param) { let isValid = false; let network = this.network(); try { let outputScript = bitcoin.address.toOutputScript(param.address, network); if (outputScript) { isValid = true; } } catch (e) { } if (param.addressType) { isValid = param.addressType === bitcoin.getAddressType(param.address, network); } let data = { isValid: isValid, address: param.address, }; return Promise.resolve(data); } async signTransaction(param) { const type = param.data.type || 0; if (type === bitcoin.BtcXrcTypes.INSCRIBE) { try { return Promise.resolve(bitcoin.inscribe(this.network(), param.data)); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.PSBT) { try { return Promise.resolve(bitcoin.psbtSign(param.data.psbt, param.privateKey, this.network())); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.PSBT_DECODE) { try { return Promise.resolve(bitcoin.psbtDecode(param.data.psbt, this.network())); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.PSBT_MPC_UNSIGNED_LIST) { try { return Promise.resolve(bitcoin.generateMPCUnsignedListingPSBT(param.data.psbt, param.data.publicKey, this.network())); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.PSBT_MPC_SIGNED_LIST) { try { return Promise.resolve(bitcoin.generateMPCSignedListingPSBT(param.data.psbt, param.data.publicKey, param.data.signature, this.network())); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.PSBT_MPC_UNSIGNED_BUY) { try { return Promise.resolve(bitcoin.generateMPCUnsignedBuyingPSBT(param.data.psbt, param.data.publicKey, this.network(), param.data.batchSize)); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.PSBT_MPC_SIGNED_BUY) { try { return Promise.resolve(bitcoin.generateMPCSignedBuyingTx(param.data.psbt, param.data.publicKey, param.data.signatureList, this.network(), param.data.batchSize)); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.PSBT_MPC_UNSIGNED) { try { return Promise.resolve(bitcoin.generateMPCUnsignedPSBT(param.data.psbt, param.data.publicKey, this.network())); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.PSBT_MPC_SIGNED) { try { return Promise.resolve(bitcoin.generateMPCSignedPSBT(param.data.psbt, param.data.publicKey, param.data.signatureList, this.network())); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.PSBT_KEY_SCRIPT_PATH) { try { return Promise.resolve(bitcoin.signPsbtWithKeyPathAndScriptPath(param.data.psbt, param.privateKey, this.network(), { autoFinalized: param.data.autoFinalized, toSignInputs: param.data.toSignInputs, })); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.PSBT_KEY_SCRIPT_PATH_BATCH) { try { return Promise.resolve(bitcoin.signPsbtWithKeyPathAndScriptPathBatch(param.data.psbtHexs, param.privateKey, this.network(), param.data.options)); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.SRC20) { try { return Promise.resolve(bitcoin.srcInscribe(this.network(), param.data)); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.RUNE) { try { let wallet = new index_1.RuneWallet(); if (this.network() === index_1.networks.testnet) { wallet = new index_1.RuneTestWallet(); } return Promise.resolve(wallet.signTransaction(param)); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.RUNEMAIN) { try { let wallet = new index_1.RuneMainWallet(); if (this.network() === index_1.networks.testnet) { wallet = new index_1.RuneMainTestWallet(); } return Promise.resolve(wallet.signTransaction(param)); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.ARC20) { try { let wallet = new index_1.AtomicalWallet(); if (this.network() === index_1.networks.testnet) { wallet = new index_1.AtomicalTestWallet(); } return Promise.resolve(wallet.signTransaction(param)); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.CAT20) { let wallet = new index_1.CatWallet(); try { return Promise.resolve(wallet.signTransaction(param)); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else if (type === bitcoin.BtcXrcTypes.PSBT_RUNEMAIN) { try { let wallet = new index_1.RuneMainWallet(); if (this.network() === index_1.networks.testnet) { wallet = new index_1.RuneMainTestWallet(); } return Promise.resolve(wallet.buildPsbt(param)); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else { let txHex = null; try { const privateKey = param.privateKey; const utxoTx = convert2UtxoTx(param.data); txHex = bitcoin.signBtc(utxoTx, privateKey, this.network()); return Promise.resolve(txHex); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } } getRandomPrivateKey() { try { let network = this.network(); while (true) { const privateKey = coin_base_2.base.randomBytes(32); if ((0, coin_base_1.secp256k1SignTest)(privateKey)) { const wif = bitcoin.private2Wif(privateKey, network); return Promise.resolve(wif); } } } catch (e) { return Promise.reject(coin_base_1.GenPrivateKeyError); } } getDerivedPrivateKey(param) { let network = this.network(); return crypto_lib_1.bip39 .mnemonicToSeedV2(param.mnemonic) .then((masterSeed) => { let childKey = crypto_lib_1.bip32.fromSeedV2(masterSeed, param.hdPath); if (!childKey.privateKey) { return Promise.reject(coin_base_1.GenPrivateKeyError); } const wif = bitcoin.private2Wif(Buffer.from(childKey.privateKey), network); return Promise.resolve(wif); }) .catch((e) => { return Promise.reject(coin_base_1.GenPrivateKeyError); }); } getAddressByPublicKey(param) { try { const network = this.network(); const publicKey = coin_base_2.base.fromHex(param.publicKey); if (!param.addressType) { const addresses = []; addresses.push({ addressType: 'Legacy', address: bitcoin.payments.p2pkh({ pubkey: publicKey, network, }).address, }); addresses.push({ addressType: 'segwit_nested', address: bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2wpkh({ pubkey: publicKey, network, }), }).address, }); addresses.push({ addressType: 'segwit_native', address: bitcoin.payments.p2wpkh({ pubkey: publicKey, network, }).address, }); return Promise.resolve(addresses); } else if (param.addressType === 'Legacy') { return Promise.resolve(bitcoin.payments.p2pkh({ pubkey: publicKey, network }) .address); } else if (param.addressType === 'segwit_nested') { return Promise.resolve(bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2wpkh({ pubkey: publicKey, network, }), }).address); } else if (param.addressType === 'segwit_native') { return Promise.resolve(bitcoin.payments.p2wpkh({ pubkey: publicKey, network }) .address); } else if (param.addressType === 'segwit_taproot') { return Promise.resolve(bitcoin.payments.p2tr({ internalPubkey: publicKey.slice(1), network, }).address); } } catch (e) { } return Promise.reject(coin_base_1.NewAddressError); } getMPCRawTransaction(param) { try { const utxoTx = convert2UtxoTx(param.data); const hash = []; const unsignedTx = bitcoin.signBtc(utxoTx, '', this.network(), hash); const data = { raw: unsignedTx, hash: hash, }; return Promise.resolve(data); } catch (e) { return Promise.reject(coin_base_1.GetMpcRawTransactionError); } } getMPCTransaction(param) { try { const hex = bitcoin.getMPCTransaction(param.raw, param.sigs, false); return Promise.resolve(hex); } catch (e) { return Promise.reject(coin_base_1.GetMpcTransactionError); } } async getMPCRawMessage(param) { try { const msgHash = await this.signMessage0(param); return Promise.resolve({ hash: msgHash }); } catch (e) { return Promise.reject(coin_base_1.GetMpcRawTransactionError); } } async getMPCSignedMessage(param) { try { return Promise.resolve(bitcoin.message.getMPCSignedMessage(param.hash, param.sigs, param.publicKey)); } catch (e) { return Promise.reject(coin_base_1.GetMpcTransactionError); } } getHardWareRawTransaction(param) { try { const type = param.data.type || 0; const utxoTx = convert2UtxoTx(param.data); if (type === 2) { const change = bitcoin.signBtc(utxoTx, '', this.network(), undefined, true, true); const dustSize = utxoTx.dustSize || 546; if (parseInt(change) >= dustSize) { const changeUtxo = { address: utxoTx.address, amount: parseInt(change), bip32Derivation: utxoTx.bip32Derivation, }; utxoTx.outputs.push(changeUtxo); } const hex = bitcoin.buildPsbt(utxoTx, this.network()); return Promise.resolve(hex); } else { const hex = bitcoin.signBtc(utxoTx, '', this.network(), undefined, true); return Promise.resolve(hex); } } catch (e) { return Promise.reject(coin_base_1.GetHardwareRawTransactionError); } } async calcTxHash(param) { try { return Promise.resolve(bitcoin.Transaction.fromHex(param.data).getId()); } catch (e) { return Promise.reject(coin_base_1.CalcTxHashError); } } async signMessage(param) { if (!param.privateKey) { return Promise.reject(`${coin_base_1.InvalidPrivateKeyError}: cannot be empty`); } const { isValid } = await this.validPrivateKey({ privateKey: param.privateKey, }); if (!isValid) { return Promise.reject(`${coin_base_1.InvalidPrivateKeyError}: not valid private key`); } return this.signMessage0(param); } signMessage0(param) { try { const typedMessage = param.data; let signature; if (typedMessage.type === exports.BITCOIN_MESSAGE_ECDSA) { signature = bitcoin.message.sign(param.privateKey, typedMessage.message, this.network()); } else { signature = bitcoin.bip0322.signSimple(typedMessage.message, typedMessage.address, param.privateKey, this.network()); } return Promise.resolve(signature); } catch (e) { return Promise.reject(coin_base_1.SignMsgError); } } async signCommonMsg(params) { let addr = await this.getNewAddress({ privateKey: params.privateKey, addressType: params.addressType, }); let publicKey = addr.compressedPublicKey ? addr.compressedPublicKey : addr.publicKey; if (publicKey.startsWith('0x')) { publicKey = publicKey.substring(2); } let privateKey = (0, index_1.privateKeyFromWIF)(params.privateKey, this.network()); return super.signCommonMsg({ privateKey: params.privateKey, privateKeyHex: privateKey, publicKey: publicKey, addressType: params.addressType, message: params.message, signType: coin_base_1.SignType.Secp256k1, }); } async verifyMessage(param) { try { const typedMessage = param.data; if (typedMessage.type === exports.BITCOIN_MESSAGE_ECDSA) { const ret = bitcoin.message.verify(typedMessage.publicKey, typedMessage.message, param.signature); return Promise.resolve(ret); } else { const ret = bitcoin.bip0322.verifySimple(typedMessage.message, typedMessage.address, param.signature, typedMessage.publicKey, this.network()); return Promise.resolve(ret); } } catch (e) { return Promise.reject(coin_base_1.SignMsgError); } } static async extractPsbtTransaction(txHex) { try { return Promise.resolve(bitcoin.extractPsbtTransaction(txHex)); } catch (e) { return Promise.reject(coin_base_1.SignMsgError); } } async validSignedTransaction(param) { try { if (param.data) { param.data.forEach((o) => (o.value = o.amount)); } const tx = bitcoin.ValidSignedTransaction(param.tx, param.data, this.network()); return Promise.resolve((0, coin_base_1.jsonStringifyUniform)(tx)); } catch (e) { return Promise.reject(coin_base_1.validSignedTransactionError); } } async estimateFee(param) { try { const type = param.data.type || 0; if (type === bitcoin.BtcXrcTypes.INSCRIBE) { return Promise.reject(coin_base_1.EstimateFeeError); } else if (type === bitcoin.BtcXrcTypes.PSBT) { return Promise.reject(coin_base_1.EstimateFeeError); } else if (type === bitcoin.BtcXrcTypes.RUNE) { try { let wallet = new index_1.RuneWallet(); if (this.network() === index_1.networks.testnet) { wallet = new index_1.RuneTestWallet(); } return Promise.resolve(wallet.estimateFee(param)); } catch (e) { return Promise.reject(coin_base_1.EstimateFeeError); } } else if (type === bitcoin.BtcXrcTypes.RUNEMAIN) { try { let wallet = new index_1.RuneMainWallet(); if (this.network() === index_1.networks.testnet) { wallet = new index_1.RuneMainTestWallet(); } return Promise.resolve(wallet.estimateFee(param)); } catch (e) { return Promise.reject(coin_base_1.EstimateFeeError); } } else if (type === bitcoin.BtcXrcTypes.ARC20) { try { let wallet = new index_1.AtomicalWallet(); if (this.network() === index_1.networks.testnet) { wallet = new index_1.AtomicalTestWallet(); } return Promise.resolve(wallet.estimateFee(param)); } catch (e) { return Promise.reject(coin_base_1.EstimateFeeError); } } else if (type === bitcoin.BtcXrcTypes.CAT20) { try { let wallet = new index_1.CatWallet(); return Promise.resolve(wallet.estimateFee(param)); } catch (e) { return Promise.reject(coin_base_1.EstimateFeeError); } } else { const utxoTx = convert2UtxoTx(param.data); const fee = bitcoin.estimateBtcFee(utxoTx, this.network()); return Promise.resolve(fee); } } catch (e) { return Promise.reject(coin_base_1.EstimateFeeError); } } static async oneKeyBuildBtcTx(txData) { try { return Promise.resolve(bitcoin.oneKeyBuildBtcTx(txData)); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } async buildPsbt(param) { const type = param.data.type || 0; if (type === bitcoin.BtcXrcTypes.RUNEMAIN) { try { let wallet = new index_1.RuneMainWallet(); if (this.network() === index_1.networks.testnet) { wallet = new index_1.RuneMainTestWallet(); } return Promise.resolve(wallet.buildPsbt(param)); } catch (e) { return Promise.reject(coin_base_1.SignTxError); } } else { let txHex = null; return Promise.resolve(txHex); } } } exports.BtcWallet = BtcWallet; class TBtcWallet extends BtcWallet { network() { return bitcoin.networks.testnet; } } exports.TBtcWallet = TBtcWallet; function number2Hex(n, length) { let s = n.toString(16); const d = length - s.length; if (d > 0) { for (let i = 0; i < d; i++) { s = '0' + s; } } return s; } exports.number2Hex = number2Hex; function convert2UtxoTx(utxoTx) { const tx = (0, coin_base_1.cloneObject)(utxoTx); tx.inputs.forEach((it) => { it.amount = (0, coin_base_1.convert2Number)(it.amount); }); tx.outputs.forEach((it) => { it.amount = (0, coin_base_1.convert2Number)(it.amount); }); if (tx.omni) { tx.omni.amount = (0, coin_base_1.convert2Number)(tx.omni.amount); } if (utxoTx.dustSize) { tx.dustSize = (0, coin_base_1.convert2Number)(utxoTx.dustSize); } return tx; } exports.convert2UtxoTx = convert2UtxoTx; //# sourceMappingURL=BtcWallet.js.map