bitcore-wallet-service
Version:
A service for Mutisig HD Bitcoin Wallets
296 lines • 10.5 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SolChain = void 0;
const crypto_wallet_core_1 = require("crypto-wallet-core");
const lodash_1 = __importDefault(require("lodash"));
const defaults_1 = require("../../common/defaults");
const errordefinitions_1 = require("../../errors/errordefinitions");
const logger_1 = __importDefault(require("../../logger"));
class SolChain {
constructor() {
this.chain = 'SOL';
}
convertBitcoreBalance(bitcoreBalance, locked) {
const { unconfirmed, confirmed, balance } = bitcoreBalance;
const convertedBalance = {
totalAmount: balance,
totalConfirmedAmount: confirmed,
lockedAmount: locked,
lockedConfirmedAmount: locked,
availableAmount: balance - locked,
availableConfirmedAmount: confirmed - locked,
byAddress: []
};
return convertedBalance;
}
getWalletBalance(server, wallet, opts, cb) {
const bc = server._getBlockchainExplorer(wallet.chain || wallet.coin, wallet.network);
if (opts.tokenAddress) {
wallet.tokenAddress = opts.tokenAddress;
}
bc.getBalance(wallet, (err, balance) => {
if (err) {
return cb(err);
}
server.getPendingTxs(opts, (err, txps) => {
if (err)
return cb(err);
const { fees, amounts } = txps.reduce((acc, txp) => {
if (!opts.tokenAddress) {
acc.fees += txp.fee || 0;
}
if (!(txp.tokenAddress && !opts.tokenAddress)) {
acc.amounts += txp.amount;
}
return acc;
}, { fees: 0, amounts: 0 });
const lockedSum = (amounts + fees) || 0;
const convertedBalance = this.convertBitcoreBalance(balance, lockedSum);
server.storage.fetchAddresses(server.walletId, (err, addresses) => {
if (err)
return cb(err);
if (addresses.length > 0) {
const byAddress = [
{
address: addresses[0].address,
path: addresses[0].path,
amount: convertedBalance.totalAmount
}
];
convertedBalance.byAddress = byAddress;
}
return cb(null, convertedBalance);
});
});
});
}
getFee(server, wallet, opts) {
return new Promise(resolve => {
const numSignatures = opts.signatures || 1;
return resolve({ fee: 5000 * numSignatures });
});
}
getBitcoreTx(txp, opts = { signed: true }) {
const { data, outputs, payProUrl, tokenAddress, isTokenSwap, multiTx } = txp;
if (multiTx) {
throw errordefinitions_1.Errors.MULTI_TX_UNSUPPORTED;
}
const isSPL = tokenAddress && !payProUrl && !isTokenSwap;
const chain = isSPL ? `${this.chain}SPL` : this.chain;
const recipients = outputs.map(output => {
return {
amount: output.amount,
address: output.toAddress,
data: output.data
};
});
if (data) {
recipients[0].data = data;
}
const unsignedTxs = [];
for (let index = 0; index < recipients.length; index++) {
let params = {
...recipients[index],
recipients: [recipients[index]]
};
unsignedTxs.push(crypto_wallet_core_1.Transactions.create({ ...txp, chain, ...params }));
}
const tx = {
uncheckedSerialize: () => unsignedTxs,
txid: () => txp.txid,
toObject: () => {
let ret = lodash_1.default.clone(txp);
ret.outputs[0].satoshis = ret.outputs[0].amount;
return ret;
},
getFee: () => {
return txp.fee;
},
getChangeOutput: () => null
};
if (opts.signed) {
const sigs = txp.getCurrentSignatures();
for (const x of sigs) {
this.addSignaturesToBitcoreTx(tx, txp.inputs, txp.inputPaths, x.signatures, x.xpub);
}
}
return tx;
}
addSignaturesToBitcoreTx(tx, inputs, inputPaths, signatures, xpub) {
if (signatures.length === 0) {
throw new Error('Signatures Required');
}
const unsignedTxs = tx.uncheckedSerialize();
const signedTxs = [];
for (let index = 0; index < signatures.length; index++) {
const signed = crypto_wallet_core_1.Transactions.applySignature({
chain: this.chain,
tx: unsignedTxs[index],
signature: signatures[index]
});
signedTxs.push(signed);
tx.id = crypto_wallet_core_1.Transactions.getHash({ tx: signed, chain: this.chain });
}
tx.uncheckedSerialize = () => signedTxs;
}
getTransactionCount(server, wallet, from) {
return new Promise((resolve, reject) => {
server._getTransactionCount(wallet, from, (err, count) => {
if (err)
return reject(err);
return resolve(count);
});
});
}
getWalletSendMaxInfo(server, wallet, opts, cb) {
server.getBalance({}, (err, balance) => {
if (err)
return cb(err);
const { availableAmount } = balance;
const sigs = opts.signatures || 1;
let fee = sigs * 5000;
return cb(null, {
utxosBelowFee: 0,
amountBelowFee: 0,
amount: availableAmount - fee,
feePerKb: opts.feePerKb,
fee
});
});
}
checkValidTxAmount(output) {
try {
if (output.amount == null ||
output.amount < 0 ||
isNaN(output.amount) ||
crypto_wallet_core_1.Web3.utils.toBN(BigInt(output.amount).toString()).toString() !== BigInt(output.amount).toString()) {
logger_1.default.warn('output.amount is not a valid value: ' + output.amount);
return false;
}
return true;
}
catch (err) {
logger_1.default.warn(`Invalid output amount (${output.amount}) in checkValidTxAmount: $o`, err);
return false;
}
}
checkTx(txp) {
try {
const tx = this.getBitcoreTx(txp);
}
catch (ex) {
logger_1.default.debug('Error building Bitcore transaction: %o', ex);
return ex;
}
return null;
}
selectTxInputs(server, txp, wallet, _opts, cb) {
server.getBalance({ wallet }, (err, balance) => {
if (err)
return cb(err);
const { totalAmount, availableAmount } = balance;
const minRentException = defaults_1.Defaults.MIN_SOL_BALANCE;
if (totalAmount - minRentException < txp.getTotalAmount()) {
return cb(errordefinitions_1.Errors.INSUFFICIENT_FUNDS);
}
else if (availableAmount < txp.getTotalAmount()) {
return cb(errordefinitions_1.Errors.LOCKED_FUNDS);
}
else {
return cb(this.checkTx(txp));
}
});
}
validateAddress(wallet, inaddr, opts) {
const chain = this.chain.toLowerCase();
const isValidTo = crypto_wallet_core_1.Validation.validateAddress(chain, wallet.network, inaddr);
if (!isValidTo) {
throw errordefinitions_1.Errors.INVALID_ADDRESS;
}
const isValidFrom = crypto_wallet_core_1.Validation.validateAddress(chain, wallet.network, opts.from);
if (!isValidFrom) {
throw errordefinitions_1.Errors.INVALID_ADDRESS;
}
return;
}
addressFromStorageTransform(network, address) {
if (network != 'livenet') {
const x = address.address.indexOf(':' + network);
if (x >= 0) {
address.address = address.address.substr(0, x);
}
}
}
addressToStorageTransform(network, address) {
if (network != 'livenet')
address.address += ':' + network;
}
getMinimumRent(server, wallet, cb) {
const bc = server._getBlockchainExplorer(wallet.chain || wallet.coin, wallet.network);
bc.getReserve((err, reserve) => {
if (err) {
return cb(err);
}
return cb(null, reserve);
});
}
refreshTxData(server, txp, _opts, cb) {
if ((txp.blockHeight || txp.blockHash) && txp.isRepublishEnabled()) {
server._getBlockchainHeight(txp.chain, txp.network, (err, height, hash) => {
if (err)
return cb(err);
txp.blockHeight = height;
txp.blockHash = hash;
return cb(null, txp);
});
}
else {
return cb(null, txp);
}
}
getReserve(server, wallet, cb) {
return cb(null, 0);
}
getSizeSafetyMargin() {
return 0;
}
getInputSizeSafetyMargin() {
return 0;
}
notifyConfirmations() {
return false;
}
supportsMultisig() {
return false;
}
isUTXOChain() {
return false;
}
isSingleAddress() {
return true;
}
getDustAmountValue() {
return 0;
}
getChangeAddress() { }
checkDust(_output, _opts) { }
checkScriptOutput(output) { }
onCoin(coin) {
return null;
}
convertFeePerKb(p, feePerKb) {
return [p, feePerKb];
}
checkTxUTXOs(server, txp, opts, cb) {
return cb();
}
checkUtxos(opts) { }
onTx(tx) {
return null;
}
}
exports.SolChain = SolChain;
//# sourceMappingURL=index.js.map