@abcpros/bitcore-wallet-service
Version:
A service for Mutisig HD Bitcoin Wallets
458 lines • 21.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 __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 __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EthChain = void 0;
var crypto_wallet_core_1 = require("@abcpros/crypto-wallet-core");
var crypto_wallet_core_2 = require("@abcpros/crypto-wallet-core");
var lodash_1 = __importDefault(require("lodash"));
var clienterror_1 = require("../../errors/clienterror");
var logger_1 = __importDefault(require("../../logger"));
var abi_erc20_1 = require("./abi-erc20");
var abi_invoice_1 = require("./abi-invoice");
var Common = require('../../common');
var Constants = Common.Constants;
var Defaults = Common.Defaults;
var Errors = require('../../errors/errordefinitions');
function requireUncached(module) {
delete require.cache[require.resolve(module)];
return require(module);
}
var Erc20Decoder = requireUncached('abi-decoder');
Erc20Decoder.addABI(abi_erc20_1.ERC20Abi);
function getErc20Decoder() {
return Erc20Decoder;
}
var InvoiceDecoder = requireUncached('abi-decoder');
InvoiceDecoder.addABI(abi_invoice_1.InvoiceAbi);
function getInvoiceDecoder() {
return InvoiceDecoder;
}
var EthChain = (function () {
function EthChain() {
}
EthChain.prototype.convertBitcoreBalance = function (bitcoreBalance, locked) {
var unconfirmed = bitcoreBalance.unconfirmed, confirmed = bitcoreBalance.confirmed, balance = bitcoreBalance.balance;
var convertedBalance = {
totalAmount: balance,
totalConfirmedAmount: confirmed,
lockedAmount: locked,
lockedConfirmedAmount: locked,
availableAmount: balance - locked,
availableConfirmedAmount: confirmed - locked,
byAddress: []
};
return convertedBalance;
};
EthChain.prototype.getSizeSafetyMargin = function () {
return 0;
};
EthChain.prototype.convertAddressToScriptPayload = function (address) { };
EthChain.prototype.sendToken = function (wallet, mnemonic, tokenId, token, TOKENQTY, etokenAddress) { };
EthChain.prototype.burnToken = function (wallet, mnemonic, tokenId, TOKENQTY, splitTxId) { };
EthChain.prototype.getChronikClient = function () { };
EthChain.prototype.getTokenInfo = function (tokenId) { };
EthChain.prototype.getInputSizeSafetyMargin = function () {
return 0;
};
EthChain.prototype.notifyConfirmations = function () {
return false;
};
EthChain.prototype.supportsMultisig = function () {
return false;
};
EthChain.prototype.getWalletBalance = function (server, wallet, opts, cb) {
var _this = this;
var bc = server._getBlockchainExplorer(wallet.coin, wallet.network);
if (opts.tokenAddress) {
wallet.tokenAddress = opts.tokenAddress;
}
if (opts.multisigContractAddress) {
wallet.multisigContractAddress = opts.multisigContractAddress;
opts.network = wallet.network;
}
bc.getBalance(wallet, function (err, balance) {
if (err) {
return cb(err);
}
server.getPendingTxs(opts, function (err, txps) {
if (err)
return cb(err);
var lockedSum = opts.multisigContractAddress ? 0 : lodash_1.default.sumBy(txps, 'amount') || 0;
var convertedBalance = _this.convertBitcoreBalance(balance, lockedSum);
server.storage.fetchAddresses(server.walletId, function (err, addresses) {
if (err)
return cb(err);
if (addresses.length > 0) {
var byAddress = [
{
address: addresses[0].address,
path: addresses[0].path,
amount: convertedBalance.totalAmount
}
];
convertedBalance.byAddress = byAddress;
}
return cb(null, convertedBalance);
});
});
});
};
EthChain.prototype.getWalletSendMaxInfo = function (server, wallet, opts, cb) {
server.getBalance({}, function (err, balance) {
if (err)
return cb(err);
var totalAmount = balance.totalAmount, availableAmount = balance.availableAmount;
var fee = opts.feePerKb * Defaults.MIN_GAS_LIMIT;
return cb(null, {
utxosBelowFee: 0,
amountBelowFee: 0,
amount: availableAmount - fee,
feePerKb: opts.feePerKb,
fee: fee
});
});
};
EthChain.prototype.getDustAmountValue = function () {
return 0;
};
EthChain.prototype.getTransactionCount = function (server, wallet, from) {
return new Promise(function (resolve, reject) {
server._getTransactionCount(wallet, from, function (err, nonce) {
if (err)
return reject(err);
return resolve(nonce);
});
});
};
EthChain.prototype.getChangeAddress = function () { };
EthChain.prototype.checkDust = function (output, opts) { };
EthChain.prototype.getFee = function (server, wallet, opts) {
var _this = this;
return new Promise(function (resolve) {
server._getFeePerKb(wallet, opts, function (err, inFeePerKb) { return __awaiter(_this, void 0, void 0, function () {
var feePerKb, gasPrice, from, coin, network, inGasLimit, gasLimit, defaultGasLimit, fee, _i, _a, output, to, value, err_1;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
feePerKb = inFeePerKb;
gasPrice = inFeePerKb;
from = opts.from;
coin = wallet.coin, network = wallet.network;
fee = 0;
_i = 0, _a = opts.outputs;
_b.label = 1;
case 1:
if (!(_i < _a.length)) return [3, 9];
output = _a[_i];
if (!!output.gasLimit) return [3, 6];
_b.label = 2;
case 2:
_b.trys.push([2, 4, , 5]);
to = opts.payProUrl
? output.toAddress
: opts.tokenAddress
? opts.tokenAddress
: opts.multisigContractAddress
? opts.multisigContractAddress
: output.toAddress;
value = opts.tokenAddress || opts.multisigContractAddress ? 0 : output.amount;
return [4, server.estimateGas({
coin: coin,
network: network,
from: from,
to: to,
value: value,
data: output.data,
gasPrice: gasPrice
})];
case 3:
inGasLimit = _b.sent();
defaultGasLimit = opts.tokenAddress ? Defaults.DEFAULT_ERC20_GAS_LIMIT : Defaults.DEFAULT_GAS_LIMIT;
output.gasLimit = inGasLimit || defaultGasLimit;
return [3, 5];
case 4:
err_1 = _b.sent();
output.gasLimit = defaultGasLimit;
return [3, 5];
case 5: return [3, 7];
case 6:
inGasLimit = output.gasLimit;
_b.label = 7;
case 7:
if (lodash_1.default.isNumber(opts.fee)) {
gasPrice = feePerKb = Number((opts.fee / (inGasLimit || defaultGasLimit)).toFixed());
}
gasLimit = inGasLimit || defaultGasLimit;
fee += feePerKb * gasLimit;
_b.label = 8;
case 8:
_i++;
return [3, 1];
case 9: return [2, resolve({ feePerKb: feePerKb, gasPrice: gasPrice, gasLimit: gasLimit, fee: fee })];
}
});
}); });
});
};
EthChain.prototype.getBitcoreTx = function (txp, opts) {
var _this = this;
if (opts === void 0) { opts = { signed: true }; }
var data = txp.data, outputs = txp.outputs, payProUrl = txp.payProUrl, tokenAddress = txp.tokenAddress, multisigContractAddress = txp.multisigContractAddress, isTokenSwap = txp.isTokenSwap;
var isERC20 = tokenAddress && !payProUrl && !isTokenSwap;
var isETHMULTISIG = multisigContractAddress;
var chain = isETHMULTISIG ? 'ETHMULTISIG' : isERC20 ? 'ERC20' : 'ETH';
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 = [];
for (var index = 0; index < recipients.length; index++) {
var rawTx = crypto_wallet_core_1.Transactions.create(__assign(__assign(__assign({}, txp), recipients[index]), { chain: chain, nonce: Number(txp.nonce) + Number(index), recipients: [recipients[index]] }));
unsignedTxs.push(rawTx);
}
var tx = {
uncheckedSerialize: function () { return unsignedTxs; },
txid: function () { return txp.txid; },
toObject: function () {
var ret = lodash_1.default.clone(txp);
ret.outputs[0].satoshis = ret.outputs[0].amount;
return ret;
},
getFee: function () {
return txp.fee;
},
getChangeOutput: function () { return null; }
};
if (opts.signed) {
var sigs = txp.getCurrentSignatures();
sigs.forEach(function (x) {
_this.addSignaturesToBitcoreTx(tx, txp.inputs, txp.inputPaths, x.signatures, x.xpub);
});
}
return tx;
};
EthChain.prototype.convertFeePerKb = function (p, feePerKb) {
return [p, feePerKb];
};
EthChain.prototype.checkTx = function (txp) {
try {
var tx = this.getBitcoreTx(txp);
}
catch (ex) {
logger_1.default.debug('Error building Bitcore transaction', ex);
return ex;
}
return null;
};
EthChain.prototype.checkTxUTXOs = function (server, txp, opts, cb) {
return cb();
};
EthChain.prototype.selectTxInputs = function (server, txp, wallet, opts, cb) {
var _this = this;
server.getBalance({ wallet: wallet, tokenAddress: opts.tokenAddress, multisigContractAddress: opts.multisigContractAddress }, function (err, balance) {
if (err)
return cb(err);
var getInvoiceValue = function (txp) {
var totalAmount;
txp.outputs.forEach(function (output) {
var decodedData = getInvoiceDecoder().decodeMethod(output.data);
if (decodedData && decodedData.name === 'pay') {
totalAmount = decodedData.params[0].value;
}
});
return totalAmount;
};
var totalAmount = balance.totalAmount, availableAmount = balance.availableAmount;
var txpTotalAmount = (opts.multisigContractAddress || opts.tokenAddress) && txp.payProUrl
? getInvoiceValue(txp)
: txp.getTotalAmount(opts);
if (totalAmount < txpTotalAmount) {
return cb(Errors.INSUFFICIENT_FUNDS);
}
else if (availableAmount < txpTotalAmount) {
return cb(Errors.LOCKED_FUNDS);
}
else {
if (opts.tokenAddress || opts.multisigContractAddress) {
server.getBalance({}, function (err, ethBalance) {
if (err)
return cb(err);
var totalAmount = ethBalance.totalAmount, availableAmount = ethBalance.availableAmount;
if (totalAmount < txp.fee) {
return cb(new clienterror_1.ClientError(Errors.codes.INSUFFICIENT_ETH_FEE, Errors.INSUFFICIENT_ETH_FEE.message + ". RequiredFee: " + txp.fee, {
requiredFee: txp.fee
}));
}
else if (availableAmount < txp.fee) {
return cb(new clienterror_1.ClientError(Errors.codes.LOCKED_ETH_FEE, Errors.LOCKED_ETH_FEE.message + ". RequiredFee: " + txp.fee, {
requiredFee: txp.fee
}));
}
else {
return cb(_this.checkTx(txp));
}
});
}
else if (availableAmount - txp.fee < txpTotalAmount) {
return cb(new clienterror_1.ClientError(Errors.codes.INSUFFICIENT_FUNDS_FOR_FEE, Errors.INSUFFICIENT_FUNDS_FOR_FEE.message + ". RequiredFee: " + txp.fee, {
requiredFee: txp.fee
}));
}
else {
return cb(_this.checkTx(txp));
}
}
});
};
EthChain.prototype.checkUtxos = function (opts) { };
EthChain.prototype.checkValidTxAmount = function (output) {
if (!lodash_1.default.isNumber(output.amount) || lodash_1.default.isNaN(output.amount) || output.amount < 0) {
return false;
}
return true;
};
EthChain.prototype.isUTXOCoin = function () {
return false;
};
EthChain.prototype.isSingleAddress = function () {
return true;
};
EthChain.prototype.addressFromStorageTransform = function (network, address) {
if (network != 'livenet') {
var x = address.address.indexOf(':' + network);
if (x >= 0) {
address.address = address.address.substr(0, x);
}
}
};
EthChain.prototype.addressToStorageTransform = function (network, address) {
if (network != 'livenet')
address.address += ':' + network;
};
EthChain.prototype.addSignaturesToBitcoreTx = function (tx, inputs, inputPaths, signatures, xpub) {
if (signatures.length === 0) {
throw new Error('Signatures Required');
}
var chain = 'ETH';
var unsignedTxs = tx.uncheckedSerialize();
var signedTxs = [];
for (var index = 0; index < signatures.length; index++) {
var signed = crypto_wallet_core_1.Transactions.applySignature({
chain: chain,
tx: unsignedTxs[index],
signature: signatures[index]
});
signedTxs.push(signed);
tx.id = crypto_wallet_core_1.Transactions.getHash({ tx: signed, chain: chain });
}
tx.uncheckedSerialize = function () { return signedTxs; };
};
EthChain.prototype.validateAddress = function (wallet, inaddr, opts) {
var chain = 'ETH';
var isValidTo = crypto_wallet_core_1.Validation.validateAddress(chain, wallet.network, inaddr);
if (!isValidTo) {
throw Errors.INVALID_ADDRESS;
}
var isValidFrom = crypto_wallet_core_1.Validation.validateAddress(chain, wallet.network, opts.from);
if (!isValidFrom) {
throw Errors.INVALID_ADDRESS;
}
return;
};
EthChain.prototype.onCoin = function (coin) {
return null;
};
EthChain.prototype.onTx = function (tx) {
var tokenAddress;
var multisigContractAddress;
var address;
var amount;
if (tx.abiType && tx.abiType.type === 'ERC20') {
tokenAddress = tx.to;
address = crypto_wallet_core_2.Web3.utils.toChecksumAddress(tx.abiType.params[0].value);
amount = tx.abiType.params[1].value;
}
else if (tx.abiType && tx.abiType.type === 'MULTISIG' && tx.abiType.name === 'submitTransaction') {
multisigContractAddress = tx.to;
address = crypto_wallet_core_2.Web3.utils.toChecksumAddress(tx.abiType.params[0].value);
amount = tx.abiType.params[1].value;
}
else if (tx.abiType && tx.abiType.type === 'MULTISIG' && tx.abiType.name === 'confirmTransaction') {
multisigContractAddress = tx.to;
address = crypto_wallet_core_2.Web3.utils.toChecksumAddress(tx.internal[0].action.to);
amount = tx.internal[0].action.value;
}
else {
address = tx.to;
amount = tx.value;
}
return {
txid: tx.txid,
out: {
address: address,
amount: amount,
tokenAddress: tokenAddress,
multisigContractAddress: multisigContractAddress
}
};
};
return EthChain;
}());
exports.EthChain = EthChain;
//# sourceMappingURL=index.js.map