@ducatus/ducatus-wallet-client-rev
Version:
Client for @ducatus/ducatus-wallet-service-rev
330 lines • 14.1 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
var ducatus_crypto_wallet_core_rev_1 = require("@ducatus/ducatus-crypto-wallet-core-rev");
var _ = __importStar(require("lodash"));
var constants_1 = require("./constants");
var defaults_1 = require("./defaults");
var $ = require('preconditions').singleton();
var sjcl = require('sjcl');
var Stringify = require('json-stable-stringify');
var Bitcore = ducatus_crypto_wallet_core_rev_1.BitcoreLib;
var Bitcore_ = {
btc: Bitcore,
bch: ducatus_crypto_wallet_core_rev_1.BitcoreLibCash,
eth: Bitcore,
xrp: Bitcore,
duc: ducatus_crypto_wallet_core_rev_1.DucatuscoreLib,
ducx: Bitcore
};
var PrivateKey = Bitcore.PrivateKey;
var PublicKey = Bitcore.PublicKey;
var crypto = Bitcore.crypto;
var SJCL = {};
var Utils = (function () {
function Utils() {
}
Utils.getChain = function (coin) {
var normalizedChain = coin.toUpperCase();
if (constants_1.Constants.ERC20.includes(coin)) {
normalizedChain = 'ETH';
}
if (constants_1.Constants.DRC20.includes(coin)) {
normalizedChain = 'DUCX';
}
return normalizedChain;
};
Utils.encryptMessage = function (message, encryptingKey) {
var key = sjcl.codec.base64.toBits(encryptingKey);
return sjcl.encrypt(key, message, _.defaults({
ks: 128,
iter: 1
}, SJCL));
};
Utils.decryptMessage = function (cyphertextJson, encryptingKey) {
if (!cyphertextJson)
return;
if (!encryptingKey)
throw new Error('No key');
var key = sjcl.codec.base64.toBits(encryptingKey);
return sjcl.decrypt(key, cyphertextJson);
};
Utils.decryptMessageNoThrow = function (cyphertextJson, encryptingKey) {
if (!encryptingKey)
return '<ECANNOTDECRYPT>';
if (!cyphertextJson)
return '';
var r = this.isJsonString(cyphertextJson);
if (!r || !r.iv || !r.ct) {
return cyphertextJson;
}
try {
return this.decryptMessage(cyphertextJson, encryptingKey);
}
catch (e) {
return '<ECANNOTDECRYPT>';
}
};
Utils.isJsonString = function (str) {
var r;
try {
r = JSON.parse(str);
}
catch (e) {
return false;
}
return r;
};
Utils.hashMessage = function (text) {
$.checkArgument(text);
var buf = Buffer.from(text);
var ret = crypto.Hash.sha256sha256(buf);
ret = new Bitcore.encoding.BufferReader(ret).readReverse();
return ret;
};
Utils.signMessage = function (message, privKey) {
$.checkArgument(message);
var priv = new PrivateKey(privKey);
var flattenedMessage = _.isArray(message) ? _.join(message) : message;
var hash = this.hashMessage(flattenedMessage);
return crypto.ECDSA.sign(hash, priv, 'little').toString();
};
Utils.verifyMessage = function (message, signature, pubKey) {
$.checkArgument(message);
$.checkArgument(pubKey);
if (!signature)
return false;
var pub = new PublicKey(pubKey);
var flattenedMessage = _.isArray(message) ? _.join(message) : message;
var hash = this.hashMessage(flattenedMessage);
try {
var sig = new crypto.Signature.fromString(signature);
return crypto.ECDSA.verify(hash, sig, pub, 'little');
}
catch (e) {
return false;
}
};
Utils.privateKeyToAESKey = function (privKey) {
$.checkArgument(privKey && _.isString(privKey));
$.checkArgument(Bitcore.PrivateKey.isValid(privKey), 'The private key received is invalid');
var pk = Bitcore.PrivateKey.fromString(privKey);
return Bitcore.crypto.Hash.sha256(pk.toBuffer())
.slice(0, 16)
.toString('base64');
};
Utils.getCopayerHash = function (name, xPubKey, requestPubKey) {
return [name, xPubKey, requestPubKey].join('|');
};
Utils.getProposalHash = function (proposalHeader) {
if (arguments.length > 1) {
return this.getOldHash.apply(this, arguments);
}
return Stringify(proposalHeader);
};
Utils.getOldHash = function (toAddress, amount, message, payProUrl) {
return [toAddress, amount, message || '', payProUrl || ''].join('|');
};
Utils.parseDerivationPath = function (path) {
var pathIndex = /m\/([0-9]*)\/([0-9]*)/;
var _a = path.match(pathIndex), _input = _a[0], changeIndex = _a[1], addressIndex = _a[2];
var isChange = Number.parseInt(changeIndex) > 0;
return { _input: _input, addressIndex: addressIndex, isChange: isChange };
};
Utils.deriveAddress = function (scriptType, publicKeyRing, path, m, network, coin) {
$.checkArgument(_.includes(_.values(constants_1.Constants.SCRIPT_TYPES), scriptType));
coin = coin || 'btc';
var chain = this.getChain(coin).toLowerCase();
var bitcore = Bitcore_[chain];
var publicKeys = _.map(publicKeyRing, function (item) {
var xpub = new bitcore.HDPublicKey(item.xPubKey);
return xpub.deriveChild(path).publicKey;
});
var bitcoreAddress;
switch (scriptType) {
case constants_1.Constants.SCRIPT_TYPES.P2WSH:
var nestedWitness = false;
bitcoreAddress = bitcore.Address.createMultisig(publicKeys, m, network, nestedWitness, 'witnessscripthash');
break;
case constants_1.Constants.SCRIPT_TYPES.P2SH:
bitcoreAddress = bitcore.Address.createMultisig(publicKeys, m, network);
break;
case constants_1.Constants.SCRIPT_TYPES.P2WPKH:
bitcoreAddress = bitcore.Address.fromPublicKey(publicKeys[0], network, 'witnesspubkeyhash');
break;
case constants_1.Constants.SCRIPT_TYPES.P2PKH:
$.checkState(_.isArray(publicKeys) && publicKeys.length == 1);
if (constants_1.Constants.UTXO_COINS.includes(coin)) {
bitcoreAddress = bitcore.Address.fromPublicKey(publicKeys[0], network);
}
else {
var _a = this.parseDerivationPath(path), addressIndex = _a.addressIndex, isChange = _a.isChange;
var xPubKey = publicKeyRing[0].xPubKey;
bitcoreAddress = ducatus_crypto_wallet_core_rev_1.Deriver.deriveAddress(chain.toUpperCase(), network, xPubKey, addressIndex, isChange);
}
break;
}
return {
address: bitcoreAddress.toString(true),
path: path,
publicKeys: _.invokeMap(publicKeys, 'toString')
};
};
Utils.xPubToCopayerId = function (coin, xpub) {
var chain = this.getChain(coin).toLowerCase();
var str = chain == 'btc' ? xpub : chain + xpub;
var hash = sjcl.hash.sha256.hash(str);
return sjcl.codec.hex.fromBits(hash);
};
Utils.signRequestPubKey = function (requestPubKey, xPrivKey) {
var priv = new Bitcore.HDPrivateKey(xPrivKey).deriveChild(constants_1.Constants.PATHS.REQUEST_KEY_AUTH).privateKey;
return this.signMessage(requestPubKey, priv);
};
Utils.verifyRequestPubKey = function (requestPubKey, signature, xPubKey) {
var pub = new Bitcore.HDPublicKey(xPubKey).deriveChild(constants_1.Constants.PATHS.REQUEST_KEY_AUTH).publicKey;
return this.verifyMessage(requestPubKey, signature, pub.toString());
};
Utils.formatAmount = function (satoshis, unit, opts) {
$.shouldBeNumber(satoshis);
$.checkArgument(_.includes(_.keys(constants_1.Constants.UNITS), unit));
var clipDecimals = function (number, decimals) {
var x = number.toString().split('.');
var d = (x[1] || '0').substring(0, decimals);
return parseFloat(x[0] + '.' + d);
};
var addSeparators = function (nStr, thousands, decimal, minDecimals) {
nStr = nStr.replace('.', decimal);
var x = nStr.split(decimal);
var x0 = x[0];
var x1 = x[1];
x1 = _.dropRightWhile(x1, function (n, i) {
return n == '0' && i >= minDecimals;
}).join('');
var x2 = x.length > 1 ? decimal + x1 : '';
x0 = x0.replace(/\B(?=(\d{3})+(?!\d))/g, thousands);
return x0 + x2;
};
opts = opts || {};
var u = constants_1.Constants.UNITS[unit];
var precision = opts.fullPrecision ? 'full' : 'short';
var amount = clipDecimals(satoshis / u.toSatoshis, u[precision].maxDecimals).toFixed(u[precision].maxDecimals);
return addSeparators(amount, opts.thousandsSeparator || ',', opts.decimalSeparator || '.', u[precision].minDecimals);
};
Utils.buildTx = function (txp) {
var coin = txp.coin || 'btc';
if (constants_1.Constants.UTXO_COINS.includes(coin)) {
var bitcore = Bitcore_[coin];
var t = new bitcore.Transaction();
if (txp.version >= 4) {
t.setVersion(2);
}
else {
t.setVersion(1);
}
$.checkState(_.includes(_.values(constants_1.Constants.SCRIPT_TYPES), txp.addressType));
switch (txp.addressType) {
case constants_1.Constants.SCRIPT_TYPES.P2WSH:
case constants_1.Constants.SCRIPT_TYPES.P2SH:
_.each(txp.inputs, function (i) {
t.from(i, i.publicKeys, txp.requiredSignatures);
});
break;
case constants_1.Constants.SCRIPT_TYPES.P2WPKH:
case constants_1.Constants.SCRIPT_TYPES.P2PKH:
t.from(txp.inputs);
break;
}
if (txp.toAddress && txp.amount && !txp.outputs) {
t.to(txp.toAddress, txp.amount);
}
else if (txp.outputs) {
_.each(txp.outputs, function (o) {
$.checkState(o.script || o.toAddress, 'Output should have either toAddress or script specified');
if (o.script) {
t.addOutput(new bitcore.Transaction.Output({
script: o.script,
satoshis: o.amount
}));
}
else {
t.to(o.toAddress, o.amount);
}
});
}
t.fee(txp.fee);
t.change(txp.changeAddress.address);
if (t.outputs.length > 1) {
var outputOrder = _.reject(txp.outputOrder, function (order) {
return order >= t.outputs.length;
});
$.checkState(t.outputs.length == outputOrder.length);
t.sortOutputs(function (outputs) {
return _.map(outputOrder, function (i) {
return outputs[i];
});
});
}
var totalInputs = _.reduce(txp.inputs, function (memo, i) {
return +i.satoshis + memo;
}, 0);
var totalOutputs = _.reduce(t.outputs, function (memo, o) {
return +o.satoshis + memo;
}, 0);
$.checkState(totalInputs - totalOutputs >= 0);
$.checkState(totalInputs - totalOutputs <= defaults_1.Defaults.MAX_TX_FEE);
return t;
}
else {
var data = txp.data, destinationTag = txp.destinationTag, outputs = txp.outputs, payProUrl = txp.payProUrl, tokenAddress = txp.tokenAddress, tokenId = txp.tokenId;
var recipients = outputs.map(function (output) {
return {
amount: output.amount,
address: output.toAddress,
data: output.data,
gasLimit: output.gasLimit
};
});
if (data) {
recipients[0].data = data;
}
var unsignedTxs_1 = [];
var isERC20 = tokenAddress && !payProUrl;
var isERC721 = isERC20 && tokenId;
var chain = isERC721
? 'ERC721'
: isERC20
? this.getChain(coin) === 'DUCX'
? 'DRC20'
: 'ERC20'
: this.getChain(coin);
if (txp.wDucxAddress) {
chain = 'TOB';
}
for (var index = 0; index < recipients.length; index++) {
var rawTx = ducatus_crypto_wallet_core_rev_1.Transactions.create(__assign(__assign(__assign({}, txp), recipients[index]), { tag: destinationTag ? Number(destinationTag) : undefined, chain: chain, nonce: Number(txp.nonce) + Number(index), recipients: [recipients[index]] }));
unsignedTxs_1.push(rawTx);
}
return { uncheckedSerialize: function () { return unsignedTxs_1; } };
}
};
return Utils;
}());
exports.Utils = Utils;
//# sourceMappingURL=utils.js.map