lightning
Version:
Lightning Network client library
116 lines (97 loc) • 3.65 kB
JavaScript
const asyncAuto = require('async/auto');
const {returnResult} = require('asyncjs-util');
const {Transaction} = require('bitcoinjs-lib');
const {isLnd} = require('./../../lnd_requests');
const bufferAsHex = buffer => buffer.toString('hex');
const {fromBuffer} = Transaction;
const hexAsBuffer = hex => Buffer.from(hex, 'hex');
const initialConfirmationCount = 0;
const {isArray} = Array;
const {isBuffer} = Buffer;
const method = 'sendOutputs';
const minFeeRate = 1;
const strategy = type => !type ? undefined : `STRATEGY_${type.toUpperCase()}`;
const type = 'wallet';
const unconfirmedConfCount = 0;
const weightPerKWeight = 1e3;
const weightPerVByte = 4;
/** Send on-chain funds to multiple output scripts
`utxo_selection` methods: 'largest', 'random'
Requires `onchain:write` permission
Requires LND compiled with `walletrpc` build tag
`utxo_selection` is not supported in LND 0.17.5 and below
{
[description]: <Transaction Label String>
[fee_tokens_per_vbyte]: <Chain Fee Tokens Per Virtual Byte Number>
lnd: <Authenticated LND API Object>
send_to: [{
script: <output Script Hex String>
tokens: <Tokens Number>
}]
[utxo_confirmations]: <Minimum Confirmations for UTXO Selection Number>
[utxo_selection]: <Select UTXOs Using Method String>
}
@returns via cbk or Promise
{
confirmation_count: <Total Confirmations Number>
id: <Transaction Id Hex String>
is_confirmed: <Transaction Is Confirmed Bool>
is_outgoing: <Transaction Is Outgoing Bool>
tokens: <Transaction Tokens Number>
transaction: <Raw Transaction Hex String>
}
*/
module.exports = (args, cbk) => {
return new Promise((resolve, reject) => {
return asyncAuto({
// Check arguments
validate: cbk => {
if (!isLnd({method, type, lnd: args.lnd})) {
return cbk([400, 'ExpectedLndToSendToChainOutputScripts']);
}
if (!isArray(args.send_to) || !args.send_to.length) {
return cbk([400, 'ExpectedSendToOutputScriptsAndTokens']);
}
return cbk();
},
send: ['validate', ({}, cbk) => {
const feePerVByte = args.fee_tokens_per_vbyte || minFeeRate;
const feePerKw = feePerVByte * weightPerKWeight / weightPerVByte;
return args.lnd[type][method]({
coin_selection_strategy: strategy(args.utxo_selection),
label: args.description || undefined,
min_confs: args.utxo_confirmations || undefined,
outputs: args.send_to.map(output => ({
pk_script: hexAsBuffer(output.script),
value: output.tokens.toString(),
})),
sat_per_kw: feePerKw,
spend_unconfirmed: args.utxo_confirmations === unconfirmedConfCount,
},
(err, res) => {
if (!!err) {
return cbk([500, 'UnexpectedSendToChainOutputScriptsErr', {err}]);
}
if (!res) {
return cbk([500, 'ExpectedResponseForSendToChainOutputsRequest']);
}
try {
fromBuffer(res.raw_tx).getId();
} catch (err) {
return cbk([500, 'ExpectedRawTransactionInSendToOutputsResponse']);
}
const row = {
confirmation_count: initialConfirmationCount,
id: fromBuffer(res.raw_tx).getId(),
is_confirmed: false,
is_outgoing: true,
tokens: args.send_to.reduce((sum, n) => sum + n.tokens, Number()),
transaction: bufferAsHex(res.raw_tx),
};
return cbk(null, row);
});
}],
},
returnResult({reject, resolve, of: 'send'}, cbk));
});
};