{"size": 4191, "ext": "js", "max_stars_repo_path": "trades/accept_trade.js", "max_stars_repo_name": "niteshbalusu11/paid-services", "max_stars_repo_stars_event_min_datetime": null, "max_stars_repo_stars_event_max_datetime": null, "max_issues_repo_path": "trades/accept_trade.js", "max_issues_repo_name": "niteshbalusu11/paid-services", "max_issues_repo_issues_event_min_datetime": null, "max_issues_repo_issues_event_max_datetime": null, "max_forks_repo_path": "trades/accept_trade.js", "max_forks_repo_name": "niteshbalusu11/paid-services", "max_forks_repo_forks_event_min_datetime": null, "max_forks_repo_forks_event_max_datetime": null}
{"max_stars_count": null, "max_issues_count": null, "max_forks_count": null, "avg_line_length": 28.7054794521, "max_line_length": 78, "alphanum_fraction": 0.5781436411}
const {acceptsChannelOpen} = require('ln-sync');
const asyncAuto = require('async/auto');
const asyncEach = require('async/each');
const {cancelHodlInvoice} = require('ln-service');
const {getChainFeeRate} = require('ln-service');
const {getInvoice} = require('ln-service');
const {openChannel} = require('ln-service');
const {returnResult} = require('asyncjs-util');
const {settleHodlInvoice} = require('ln-service');

const {isArray} = Array;
const slowConf = 144;

/** Accept an open ended trade

  {
    cancel: [<Alternative Invoice Id Hex String>]
    [channel]: <Channel Capacity Tokens Number>
    from: <Trade With Node Identity Public Key Hex String>
    id: <Trade Id Hex String>
    lnd: <Authenticated LND API Object>
    secret: <Invoice to Settle Preimage Hex String>
  }

  @returns via cbk or Promise
  {
    [opening_channel]: {
      fee_tokens_per_vbyte: <Chain Fee Rate Number>
      transaction_id: <Channel Funding Transaction Id Hex String>
      transaction_vout: <Channel Funding Transaction Output Index Number>
    }
  }
*/
module.exports = ({cancel, channel, from, id, lnd, secret}, cbk) => {
  return new Promise((resolve, reject) => {
    return asyncAuto({
      // Check arguments
      validate: cbk => {
        if (!isArray(cancel)) {
          return cbk([400, 'ExpectedArrayOfIdsToCancelToAcceptTrade']);
        }

        if (!from) {
          return cbk([400, 'ExpectedWithPeerPublicKeyToAcceptTrade']);
        }

        if (!id) {
          return cbk([400, 'ExpectedAnchorTradeIdToAcceptTrade']);
        }

        if (!lnd) {
          return cbk([400, 'ExpectedAuthenticatedLndToAcceptTrade']);
        }

        if (!secret) {
          return cbk([400, 'ExpectedSettlementPreimageToAcceptTrade']);
        }

        return cbk();
      },

      // Fetch the anchor invoice to make sure it's still open
      getAnchor: ['validate', ({}, cbk) => getInvoice({id, lnd}, cbk)],

      // Get the chain fee rate for channel opening trades
      getFeeRate: ['validate', ({}, cbk) => {
        // Exit early when not trading a channel open
        if (!channel) {
          return cbk();
        }

        return getChainFeeRate({lnd, confirmation_target: slowConf}, cbk);
      }],

      // Cancel alternative invoices so that only one resolves as settled
      cancel: ['getAnchor', ({getAnchor}, cbk) => {
        if (!!getAnchor.is_canceled) {
          return cbk([404, 'OpenTradeNotFound']);
        }

        return asyncEach([].concat(cancel).concat(id), (alternative, cbk) => {
          return cancelHodlInvoice({lnd, id: alternative}, cbk);
        },
        cbk);
      }],

      // Check opening for channel trades
      acceptsOpen: ['cancel', ({}, cbk) => {
        // Exit early when not opening a channel
        if (!channel) {
          return cbk();
        }

        return acceptsChannelOpen({
          lnd,
          capacity: channel,
          partner_public_key: from,
        },
        cbk);
      }],

      // Settle the held invoice with the preimage
      settle: ['acceptsOpen', 'cancel', 'getFeeRate', ({}, cbk) => {
        return settleHodlInvoice({lnd, secret}, cbk);
      }],

      // Open the channel
      openChannel: ['getFeeRate', 'settle', ({getFeeRate}, cbk) => {
        // Exit early when this is not a channel trade
        if (!channel) {
          return cbk();
        }

        return openChannel({
          lnd,
          chain_fee_rate: getFeeRate.tokens_per_vbyte,
          local_tokens: channel,
          partner_public_key: from,
        },
        cbk);
      }],

      // Trade is settled
      settled: [
        'getFeeRate',
        'openChannel',
        ({getFeeRate, openChannel}, cbk) =>
      {
        // Exit early when there is no trade result
        if (!openChannel) {
          return cbk(null, {});
        }

        return cbk(null, {
          opening_channel: {
            fee_tokens_per_vbyte: getFeeRate.tokens_per_vbyte,
            transaction_id: openChannel.transaction_id,
            transaction_vout: openChannel.transaction_vout,
          },
        });
      }],
    },
    returnResult({reject, resolve, of: 'settled'}, cbk));
  });
};
