UNPKG

@bithomp/xrpl-api

Version:

A Bithomp JavaScript/TypeScript library for interacting with the XRP Ledger

365 lines (364 loc) 14.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getTransactions = getTransactions; exports.findTransactionsExt = findTransactionsExt; exports.findTransactions = findTransactions; const lodash_1 = __importDefault(require("lodash")); const Client = __importStar(require("../client")); const utils_1 = require("../common/utils"); const transaction_1 = require("../models/transaction"); const balance_changes_1 = require("../parse/outcome/balance_changes"); const MAX_LIMIT = 1000; const DEFAULT_LIMIT = 200; const MAX_LIMIT_WITH_FILTER = 20; const MAX_LIMIT_WITH_TAG = 3; const LIMIT_INCREASE_COUNT = 10; async function getTransactions(account, options = { limit: DEFAULT_LIMIT }) { const { hash, marker } = (0, utils_1.parseMarker)(options.marker); options.marker = marker; const connection = Client.findConnection("history", undefined, undefined, hash); if (!connection) { throw new Error("There is no connection"); } const command = { command: "account_tx", account, ledger_index_min: options.ledgerIndexMin, ledger_index_max: options.ledgerIndexMax, ledger_hash: options.ledgerHash, ledger_index: options.ledgerIndex, binary: !!options.binary, forward: !!options.forward, limit: options.limit, marker: options.marker, }; const response = await connection.request(command); if (!response) { return { account, status: "error", error: "invalidResponse", }; } if (response.error) { const { error, error_code, error_message, error_exception, status, validated, warnings } = response; return (0, utils_1.removeUndefined)({ account, error, error_code, error_message, error_exception, status, validated, warnings, }); } const result = response?.result; if (!result) { return (0, utils_1.removeUndefined)({ account, status: "error", error: "invalidResponse", warnings: response.warnings, }); } if (Array.isArray(result.transactions)) { if (options.balanceChanges === true || options.specification === true) { for (const transaction of result.transactions) { if (options.balanceChanges === true) { transaction.balanceChanges = (0, balance_changes_1.parseBalanceChanges)(transaction.meta, Client.getNativeCurrency()); } if (options.specification === true) { const details = (0, transaction_1.getAccountTxDetails)(transaction, options.includeRawTransactions); transaction.specification = details.specification; transaction.outcome = details.outcome; if (details.rawTransaction) { transaction.rawTransaction = details.rawTransaction; } } } } } if (Array.isArray(result.transactions)) { for (const transaction of result.transactions) { const tx = transaction.tx || transaction; if (!tx.hasOwnProperty("ctid")) { const ctid = (0, transaction_1.encodeCTIDforTransaction)(transaction, connection.getNetworkID()); if (ctid) { tx.ctid = ctid; } } } } const newMarker = (0, utils_1.createMarker)(connection.hash, result.marker); if (newMarker) { result.marker = newMarker; } if (response.warnings && response.warnings.length > 0) { result.warnings = response.warnings; } result.bithompHash = connection.hash; return result; } async function findTransactionsExt(account, options = { limit: DEFAULT_LIMIT, timeout: 15000 }) { let transactions = []; let accountTransactionsError = null; const timeStart = new Date(); const loadOptions = { ...options }; const formatted = loadOptions.legacy === true || loadOptions.formatted === true; loadOptions.binary = false; applyLimitOptions(loadOptions); await applyStartTxOptions(loadOptions); let getTransactionsLimit = loadOptions.limit; if (transactions.length === 0 && loadOptions.startTxHash) { getTransactionsLimit += LIMIT_INCREASE_COUNT; } if (loadOptions.sourceTag || loadOptions.destinationTag) { getTransactionsLimit += LIMIT_INCREASE_COUNT; } if (loadOptions.types) { getTransactionsLimit += LIMIT_INCREASE_COUNT; } if (getTransactionsLimit > MAX_LIMIT) { getTransactionsLimit = MAX_LIMIT; } while (transactions.length !== loadOptions.limit) { const currentTime = new Date(); if (loadOptions.timeout && currentTime.getTime() - timeStart.getTime() > loadOptions.timeout) { break; } const accountTransactions = await getTransactions(account, { ...loadOptions, ...{ balanceChanges: false, specification: false, limit: getTransactionsLimit }, }); if (accountTransactions.error) { if (accountTransactions.error_message === "Request timeout.") { continue; } else { accountTransactionsError = accountTransactions; break; } } let newTransactions = accountTransactions.transactions; loadOptions.marker = accountTransactions.marker; newTransactions = newTransactions .filter(lodash_1.default.partial(filterHelperTransactions, account, loadOptions)) .filter(lodash_1.default.partial(filterHelperStartTx, loadOptions)); if (formatted !== true && (loadOptions.balanceChanges === true || loadOptions.specification === true)) { for (const newTransaction of newTransactions) { if (loadOptions.balanceChanges === true) { newTransaction.balanceChanges = (0, balance_changes_1.parseBalanceChanges)(newTransaction.meta, Client.getNativeCurrency()); } if (loadOptions.specification === true) { const details = (0, transaction_1.getAccountTxDetails)(newTransaction, options.includeRawTransactions); newTransaction.specification = details.specification; newTransaction.outcome = details.outcome; if (details.rawTransaction) { newTransaction.rawTransaction = details.rawTransaction; } } } } if (newTransactions.length === 0 && getTransactionsLimit < MAX_LIMIT) { getTransactionsLimit += LIMIT_INCREASE_COUNT; if (getTransactionsLimit > MAX_LIMIT) { getTransactionsLimit = MAX_LIMIT; } } if (newTransactions.length > 0) { const transactionsToTake = loadOptions.limit - transactions.length; if (transactionsToTake !== newTransactions.length) { const isClio = accountTransactions.warnings?.some((w) => w.id === 2001); let markerTransaction = null; if (isClio) { markerTransaction = newTransactions[transactionsToTake - 1]; } else { markerTransaction = newTransactions[transactionsToTake]; } if (markerTransaction) { const bithompHash = loadOptions.marker?.bithompHash || accountTransactions.bithompHash; loadOptions.marker = { ledger: markerTransaction.tx.ledger_index, seq: markerTransaction.meta.TransactionIndex, }; if (bithompHash) { loadOptions.marker.bithompHash = bithompHash; } } } newTransactions = newTransactions.slice(0, transactionsToTake); transactions = transactions.concat(newTransactions); } if (loadOptions.marker === undefined) { break; } } if (accountTransactionsError && transactions.length === 0) { return accountTransactionsError; } if (loadOptions.marker && transactions.length === 0) { return { status: "error", error: "searchTimeout", marker: loadOptions.marker, }; } if (formatted === true) { transactions = transactions.map((transaction) => (0, transaction_1.getAccountTxDetails)(transaction, loadOptions.includeRawTransactions === true)); } return { account, transactions, marker: loadOptions.marker, validated: true, }; } async function findTransactions(account, options = { limit: DEFAULT_LIMIT, timeout: 15000 }) { const result = await findTransactionsExt(account, options); if (result.error) { return result; } return result.transactions || []; } function applyLimitOptions(options) { if (options.sourceTag > 0 || options.destinationTag > 0) { if (options.limit > MAX_LIMIT_WITH_TAG) { options.limit = MAX_LIMIT_WITH_TAG; } } else if (options.types || options.initiated || options.counterparty) { if (options.limit > MAX_LIMIT_WITH_FILTER) { options.limit = MAX_LIMIT_WITH_FILTER; } } } async function applyStartTxOptions(options) { if (options.startTxHash) { const accountTransaction = await Client.getTransaction(options.startTxHash); if (accountTransaction && !accountTransaction.error) { options.startTx = { tx: accountTransaction, meta: accountTransaction.meta, }; if (options.forward === true) { const ledgerIndex = options.startTx.tx.ledger_index; if (options.ledgerIndexMin === undefined || ledgerIndex > options.ledgerIndexMin) { options.ledgerIndexMin = ledgerIndex; } } else { const ledgerIndex = options.startTx.tx.ledger_index; if (options.ledgerIndexMax === undefined || ledgerIndex < options.ledgerIndexMax) { options.ledgerIndexMax = ledgerIndex; } } } } } function filterHelperStartTx(options, transaction) { return (!options.startTx || (options.forward === true ? (0, utils_1.compareTransactions)(transaction, options.startTx) > 0 : (0, utils_1.compareTransactions)(transaction, options.startTx) < 0)); } function filterHelperTransactions(account, options, transaction) { if (transaction.validated === false) { return false; } if (options.excludeFailures === true && transaction.meta.TransactionResult !== "tesSUCCESS") { return false; } if (options.types && !options.types.includes(transaction.tx.TransactionType)) { return false; } if (options.initiated === true && transaction.tx.Account !== account) { return false; } if (options.initiated === false && transaction.tx.Account === account) { return false; } if (options.counterparty && !counterpartyFilter(options, transaction)) { return false; } if (typeof options.sourceTag === "number" && transaction.tx.SourceTag !== options.sourceTag) { return false; } if (typeof options.destinationTag === "number" && transaction.tx.DestinationTag !== options.destinationTag) { return false; } return true; } function counterpartyFilter(options, transaction) { if (transaction.tx.Account === options.counterparty) { return true; } if (transaction.tx.Destination === options.counterparty) { return true; } if (transaction.tx.Delegate === options.counterparty) { return true; } if (transaction.tx.Subject === options.counterparty) { return true; } if (transaction.tx.Amount?.issuer === options.counterparty) { return true; } if (transaction.tx.SendMax?.issuer === options.counterparty) { return true; } if (typeof transaction.tx.TakerGets === "object" && transaction.tx.TakerGets?.issuer === options.counterparty) { return true; } if (typeof transaction.tx.TakerPays === "object" && transaction.tx.TakerPays?.issuer === options.counterparty) { return true; } if (transaction.tx.LimitAmount?.issuer === options.counterparty) { return true; } if (transaction.tx.Issuer === options.counterparty) { return true; } if (transaction.tx.NFTokenMinter === options.counterparty) { return true; } return false; }