bitcore-wallet-service
Version:
A service for Mutisig HD Bitcoin Wallets
381 lines • 13.7 kB
JavaScript
;
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 () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Utils = void 0;
const CWC = __importStar(require("crypto-wallet-core"));
const lodash_1 = __importDefault(require("lodash"));
const config_1 = __importDefault(require("../../config"));
const logger_1 = require("../logger");
const constants_1 = require("./constants");
const $ = require('preconditions').singleton();
const bitcore = require('bitcore-lib');
const crypto = bitcore.crypto;
const secp256k1 = require('secp256k1');
const Bitcore = require('bitcore-lib');
const Bitcore_ = {
btc: Bitcore,
bch: require('bitcore-lib-cash'),
doge: require('bitcore-lib-doge'),
ltc: require('bitcore-lib-ltc')
};
exports.Utils = {
isObject(obj) {
return obj && typeof obj === 'object' && !Array.isArray(obj);
},
isNumber(val) {
return val != null && !isNaN(val);
},
isNumberish(val) {
return exports.Utils.isNumber(val) || typeof val === 'bigint';
},
getMissingFields(obj, args) {
args = args || [];
if (!Array.isArray(args))
args = [args];
if (!exports.Utils.isObject(obj))
return args;
const missing = args.filter(arg => !obj.hasOwnProperty(arg));
return missing;
},
strip(number) {
return parseFloat(number.toPrecision(12));
},
hashMessage(text, noReverse) {
$.checkArgument(text);
const buf = Buffer.from(text);
let ret = crypto.Hash.sha256sha256(buf);
if (!noReverse) {
ret = new bitcore.encoding.BufferReader(ret).readReverse();
}
return ret;
},
verifyMessage(message, signature, publicKey) {
$.checkArgument(message);
const flattenedMessage = Array.isArray(message) ? message.join(',') : message;
const hash = exports.Utils.hashMessage(flattenedMessage, true);
const sig = exports.Utils._tryImportSignature(signature);
if (!sig) {
return false;
}
const publicKeyBuffer = exports.Utils._tryImportPublicKey(publicKey);
if (!publicKeyBuffer) {
return false;
}
return exports.Utils._tryVerifyMessage(hash, sig, publicKeyBuffer);
},
_tryImportPublicKey(publicKey) {
let publicKeyBuffer = publicKey;
try {
if (!Buffer.isBuffer(publicKey)) {
publicKeyBuffer = Buffer.from(publicKey, 'hex');
}
return publicKeyBuffer;
}
catch (e) {
logger_1.logger.error('_tryImportPublicKey encountered an error: %o', e);
return false;
}
},
_tryImportSignature(signature) {
try {
let signatureBuffer = signature;
if (!Buffer.isBuffer(signature)) {
signatureBuffer = Buffer.from(signature, 'hex');
}
return secp256k1.signatureImport(signatureBuffer);
}
catch (e) {
logger_1.logger.error('_tryImportSignature encountered an error: %o', e);
return false;
}
},
_tryVerifyMessage(hash, sig, publicKeyBuffer) {
try {
return secp256k1.ecdsaVerify(sig, hash, publicKeyBuffer);
}
catch (e) {
logger_1.logger.error('_tryVerifyMessage encountered an error: %o', e);
return false;
}
},
formatAmount(satoshis, unit, opts) {
const UNITS = Object.entries(CWC.Constants.UNITS).reduce((units, [currency, currencyConfig]) => {
units[currency] = {
toSatoshis: currencyConfig.toSatoshis,
maxDecimals: currencyConfig.short.maxDecimals,
minDecimals: currencyConfig.short.minDecimals
};
return units;
}, {});
$.shouldBeNumber(satoshis);
function addSeparators(nStr, thousands, decimal, minDecimals) {
nStr = nStr.replace('.', decimal);
const x = nStr.split(decimal);
let x0 = x[0];
let x1 = x[1];
x1 = lodash_1.default.dropRightWhile(x1, (n, i) => {
return n == '0' && i >= minDecimals;
}).join('');
const x2 = x.length > 1 ? decimal + x1 : '';
x0 = x0.replace(/\B(?=(\d{3})+(?!\d))/g, thousands);
return x0 + x2;
}
opts = opts || {};
if (!UNITS[unit] && !opts.decimals && !opts.toSatoshis) {
return Number(satoshis).toLocaleString();
}
const u = Object.assign({}, UNITS[unit], opts);
var decimals = opts.decimals ? opts.decimals : u;
var toSatoshis = opts.toSatoshis ? opts.toSatoshis : u.toSatoshis;
const amount = (satoshis / toSatoshis).toFixed(decimals.maxDecimals);
return addSeparators(amount, opts.thousandsSeparator || ',', opts.decimalSeparator || '.', decimals.minDecimals);
},
formatAmountInBtc(amount) {
return (exports.Utils.formatAmount(amount, 'btc', {
minDecimals: 8,
maxDecimals: 8
}) + 'btc');
},
formatUtxos(utxos) {
if (!utxos?.length)
return 'none';
return utxos.map(i => {
const amount = exports.Utils.formatAmountInBtc(i.satoshis);
const confirmations = i.confirmations ? i.confirmations + 'c' : 'u';
return amount + '/' + confirmations;
}).join(', ');
},
formatRatio(ratio) {
return (ratio * 100).toFixed(4) + '%';
},
formatSize(size) {
return (size / 1000).toFixed(4) + 'kB';
},
parseVersion(version) {
const v = {};
if (!version)
return null;
let x = version.split('-');
if (x.length != 2) {
v.agent = version;
return v;
}
v.agent = ['bwc', 'bws'].includes(x[0]) ? 'bwc' : x[0];
x = x[1].split('.');
v.major = x[0] ? parseInt(x[0]) : null;
v.minor = x[1] ? parseInt(x[1]) : null;
v.patch = x[2] ? parseInt(x[2]) : null;
return v;
},
parseAppVersion(agent) {
const v = {};
if (!agent)
return null;
agent = agent.toLowerCase();
let w;
w = agent.indexOf('copay');
if (w >= 0) {
v.app = 'copay';
}
else {
w = agent.indexOf('bitpay');
if (w >= 0) {
v.app = 'bitpay';
}
else {
v.app = 'other';
return v;
}
}
const version = agent.substr(w + v.app.length);
const x = version.split('.');
v.major = x[0] ? parseInt(x[0].replace(/\D/g, '')) : null;
v.minor = x[1] ? parseInt(x[1]) : null;
v.patch = x[2] ? parseInt(x[2]) : null;
return v;
},
getIpFromReq(req) {
if (req.headers) {
if (req.headers['x-forwarded-for'])
return req.headers['x-forwarded-for'].split(',')[0];
if (req.headers['x-real-ip'])
return req.headers['x-real-ip'].split(',')[0];
}
if (req.ip)
return req.ip;
if (req.connection && req.connection.remoteAddress)
return req.connection.remoteAddress;
return '';
},
checkValueInCollection(value, collection) {
if (typeof value !== 'string')
return false;
return Object.values(collection).includes(value);
},
getAddressCoin(address) {
try {
new Bitcore_['btc'].Address(address);
return 'btc';
}
catch (e) {
try {
new Bitcore_['bch'].Address(address);
return 'bch';
}
catch (e) {
try {
new Bitcore_['doge'].Address(address);
return 'doge';
}
catch (e) {
try {
new Bitcore_['ltc'].Address(address);
return 'ltc';
}
catch (e) {
return;
}
}
}
}
},
translateAddress(address, coin) {
const origCoin = exports.Utils.getAddressCoin(address);
const origAddress = new Bitcore_[origCoin].Address(address);
const origObj = origAddress.toObject();
const result = Bitcore_[coin].Address.fromObject(origObj);
return coin == 'bch' ? result.toLegacyAddress() : result.toString();
},
compareNetworks(network1, network2, chain) {
network1 = network1 ? exports.Utils.getNetworkName(chain, network1.toLowerCase()) : null;
network2 = network2 ? exports.Utils.getNetworkName(chain, network2.toLowerCase()) : null;
if (network1 == network2)
return true;
if (config_1.default.allowRegtest && ['testnet', 'regtest'].includes(exports.Utils.getNetworkType(network1)) && ['testnet', 'regtest'].includes(exports.Utils.getNetworkType(network2)))
return true;
return false;
},
getNetworkName(chain, network) {
const aliases = constants_1.Constants.NETWORK_ALIASES[chain];
if (aliases && aliases[network]) {
return aliases[network];
}
return network;
},
getGenericName(network) {
if (network === 'mainnet')
return 'livenet';
const isTestnet = !!Object.keys(constants_1.Constants.NETWORK_ALIASES).find(key => constants_1.Constants.NETWORK_ALIASES[key].testnet === network);
if (isTestnet)
return 'testnet';
return network;
},
getNetworkType(network) {
if (['mainnet', 'livenet'].includes(network)) {
return 'mainnet';
}
if (network === 'regtest') {
return 'regtest';
}
return 'testnet';
},
castToBool(input) {
input = input?.toString();
if (input?.toLowerCase() === 'true' || input == '1') {
return true;
}
return false;
},
sortAsc(arr, ...keys) {
function transformVals(val1, val2) {
if (val1 === undefined) {
val1 = '\uFFFF';
}
else if (val1 === null || val1 === false || val1.toString() === 'NaN') {
val1 = '0';
}
else if (val1 === true) {
val1 = '1';
}
if (val2 === undefined) {
val2 = '\uFFFF';
}
else if (val2 === null || val2 === false || val2.toString() === 'NaN') {
val2 = '0';
}
else if (val2 === true) {
val2 = '1';
}
return [Buffer.from(val1.toString()), Buffer.from(val2.toString())];
}
;
if (!keys.length) {
return arr.sort((a, b) => { const [_a, _b] = transformVals(a, b); return _a.compare(_b); });
}
else if (keys.length === 1 && !Array.isArray(keys[0])) {
return arr.sort((a, b) => { const [_a, _b] = transformVals(a[keys[0]], b[keys[0]]); return _a.compare(_b); });
}
return arr.sort((a, b) => {
let aVal = '';
let bVal = '';
for (let k of keys) {
const [aTemp, bTemp] = transformVals(Array.isArray(k) ? k.reduce((val, key) => val[key], a) : a[k], Array.isArray(k) ? k.reduce((val, key) => val[key], b) : b[k]);
aVal += aTemp.toString();
bVal += bTemp.toString();
}
return Buffer.from(aVal).compare(Buffer.from(bVal));
});
},
sortDesc(arr, ...keys) {
return exports.Utils.sortAsc(arr, ...keys).reverse();
},
fromPairs(input) {
return input.reduce((map, [k, v]) => {
map[k] = v;
return map;
}, {});
},
difference(arr1, arr2) {
if (!Array.isArray(arr1))
return [];
if (!Array.isArray(arr2))
arr2 = null;
return arr1.filter(x => !arr2?.includes(x));
}
};
//# sourceMappingURL=utils.js.map