{"version":3,"sources":["../../src/internal/transaction.ts"],"sourcesContent":["// Copyright © Endless\n// Copyright © Aptos Foundation\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * This file contains the underlying implementations for exposed API surface in\n * the {@link api/transaction}. By moving the methods out into a separate file,\n * other namespaces and processes can access these methods without depending on the entire\n * transaction namespace and without having a dependency cycle error.\n */\n\nimport { EndlessConfig } from \"../api/endlessConfig\";\nimport { EndlessApiError, getEndlessFullNode, getEndlessIndexer, paginateWithCursor } from \"../client\";\nimport {\n  TransactionResponseType,\n  type AnyNumber,\n  type GasEstimation,\n  type HexInput,\n  PageableU64,\n  PaginationArgsOfIndexer,\n  type PaginationArgs,\n  type TransactionResponse,\n  WaitForTransactionOptions,\n  CommittedTransactionResponse,\n  Block,\n} from \"../types\";\nimport { DEFAULT_TXN_TIMEOUT_SEC } from \"../utils/const\";\nimport { sleep } from \"../utils/helpers\";\nimport { memoizeAsync } from \"../utils/memoize\";\n\nexport async function getTransactions(args: {\n  endlessConfig: EndlessConfig;\n  options?: PaginationArgs;\n}): Promise<TransactionResponse[]> {\n  const { endlessConfig, options } = args;\n  return paginateWithCursor<{}, TransactionResponse[]>({\n    endlessConfig,\n    originMethod: \"getTransactions\",\n    path: \"transactions\",\n    params: { start: options?.offset, limit: options?.limit },\n  });\n}\n\nexport async function getGasPriceEstimation(args: { endlessConfig: EndlessConfig }) {\n  const { endlessConfig } = args;\n\n  return memoizeAsync(\n    async () => {\n      const { data } = await getEndlessFullNode<{}, GasEstimation>({\n        endlessConfig,\n        originMethod: \"getGasPriceEstimation\",\n        path: \"estimate_gas_price\",\n      });\n      return data;\n    },\n    `gas-price-${endlessConfig.network}`,\n    1000 * 60 * 5, // 5 minutes\n  )();\n}\n\nexport async function getTransactionByVersion(args: {\n  endlessConfig: EndlessConfig;\n  ledgerVersion: AnyNumber;\n}): Promise<TransactionResponse> {\n  const { endlessConfig, ledgerVersion } = args;\n  const { data } = await getEndlessFullNode<{}, TransactionResponse>({\n    endlessConfig,\n    originMethod: \"getTransactionByVersion\",\n    path: `transactions/by_version/${ledgerVersion}`,\n  });\n  return data;\n}\n\nexport async function getTransactionByHash(args: {\n  endlessConfig: EndlessConfig;\n  transactionHash: HexInput;\n}): Promise<TransactionResponse> {\n  const { endlessConfig, transactionHash } = args;\n  const { data } = await getEndlessFullNode<{}, TransactionResponse>({\n    endlessConfig,\n    path: `transactions/by_hash/${transactionHash}`,\n    originMethod: \"getTransactionByHash\",\n  });\n  return data;\n}\n\nexport async function isTransactionPending(args: {\n  endlessConfig: EndlessConfig;\n  transactionHash: HexInput;\n}): Promise<boolean> {\n  const { endlessConfig, transactionHash } = args;\n  try {\n    const transaction = await getTransactionByHash({ endlessConfig, transactionHash });\n    return transaction.type === TransactionResponseType.Pending;\n  } catch (e: any) {\n    if (e?.status === 404) {\n      return true;\n    }\n    throw e;\n  }\n}\n\nexport async function longWaitForTransaction(args: {\n  endlessConfig: EndlessConfig;\n  transactionHash: HexInput;\n}): Promise<TransactionResponse> {\n  const { endlessConfig, transactionHash } = args;\n  const { data } = await getEndlessFullNode<{}, TransactionResponse>({\n    endlessConfig,\n    path: `transactions/wait_by_hash/${transactionHash}`,\n    originMethod: \"longWaitForTransaction\",\n  });\n  return data;\n}\n\nexport async function waitForTransaction(args: {\n  endlessConfig: EndlessConfig;\n  transactionHash: HexInput;\n  options?: WaitForTransactionOptions;\n}): Promise<CommittedTransactionResponse> {\n  const { endlessConfig, transactionHash, options } = args;\n  const timeoutSecs = options?.timeoutSecs ?? DEFAULT_TXN_TIMEOUT_SEC;\n  const checkSuccess = options?.checkSuccess ?? true;\n\n  let isPending = true;\n  let timeElapsed = 0;\n  let lastTxn: TransactionResponse | undefined;\n  let lastError: EndlessApiError | undefined;\n  let backoffIntervalMs = 200;\n  const backoffMultiplier = 1.5;\n\n  function handleAPIError(e: any) {\n    // In short, this means we will retry if it was an EndlessApiError and the code was 404 or 5xx.\n    const isEndlessApiError = e instanceof EndlessApiError;\n    if (!isEndlessApiError) {\n      throw e; // This would be unexpected\n    }\n    lastError = e;\n    const isRequestError = e.status !== 404 && e.status >= 400 && e.status < 500;\n    if (isRequestError) {\n      throw e;\n    }\n  }\n\n  // check to see if the txn is already on the blockchain\n  try {\n    lastTxn = await getTransactionByHash({ endlessConfig, transactionHash });\n    isPending = lastTxn.type === TransactionResponseType.Pending;\n  } catch (e) {\n    handleAPIError(e);\n  }\n\n  // If the transaction is pending, we do a long wait once to avoid polling\n  if (isPending) {\n    const startTime = Date.now();\n    try {\n      lastTxn = await longWaitForTransaction({ endlessConfig, transactionHash });\n      isPending = lastTxn.type === TransactionResponseType.Pending;\n    } catch (e) {\n      handleAPIError(e);\n    }\n    timeElapsed = (Date.now() - startTime) / 1000;\n  }\n\n  // Now we do polling to see if the transaction is still pending\n  while (isPending) {\n    if (timeElapsed >= timeoutSecs) {\n      break;\n    }\n    try {\n      // eslint-disable-next-line no-await-in-loop\n      lastTxn = await getTransactionByHash({ endlessConfig, transactionHash });\n\n      isPending = lastTxn.type === TransactionResponseType.Pending;\n\n      if (!isPending) {\n        break;\n      }\n    } catch (e) {\n      handleAPIError(e);\n    }\n    // eslint-disable-next-line no-await-in-loop\n    await sleep(backoffIntervalMs);\n    timeElapsed += backoffIntervalMs / 1000; // Convert to seconds\n    backoffIntervalMs *= backoffMultiplier;\n  }\n\n  // There is a chance that lastTxn is still undefined. Let's throw the last error otherwise a WaitForTransactionError\n  if (lastTxn === undefined) {\n    if (lastError) {\n      throw lastError;\n    } else {\n      throw new WaitForTransactionError(\n        `Fetching transaction ${transactionHash} failed and timed out after ${timeoutSecs} seconds`,\n        lastTxn,\n      );\n    }\n  }\n\n  if (lastTxn.type === TransactionResponseType.Pending) {\n    throw new WaitForTransactionError(\n      `Transaction ${transactionHash} timed out in pending state after ${timeoutSecs} seconds`,\n      lastTxn,\n    );\n  }\n  if (!checkSuccess) {\n    return lastTxn;\n  }\n  if (!lastTxn.success) {\n    throw new FailedTransactionError(\n      `Transaction ${transactionHash} failed with an error: ${lastTxn.vm_status}`,\n      lastTxn,\n    );\n  }\n\n  return lastTxn;\n}\n\n/**\n * This error is used by `waitForTransaction` when waiting for a\n * transaction to time out or when the transaction response is undefined\n */\nexport class WaitForTransactionError extends Error {\n  public readonly lastSubmittedTransaction: TransactionResponse | undefined;\n\n  constructor(message: string, lastSubmittedTransaction: TransactionResponse | undefined) {\n    super(message);\n    this.lastSubmittedTransaction = lastSubmittedTransaction;\n  }\n}\n\n/**\n * This error is used by `waitForTransaction` if `checkSuccess` is true.\n * See that function for more information.\n */\nexport class FailedTransactionError extends Error {\n  public readonly transaction: TransactionResponse;\n\n  constructor(message: string, transaction: TransactionResponse) {\n    super(message);\n    this.transaction = transaction;\n  }\n}\n\nexport async function getBlockByVersion(args: {\n  endlessConfig: EndlessConfig;\n  ledgerVersion: AnyNumber;\n  options?: { withTransactions?: boolean };\n}): Promise<Block> {\n  const { endlessConfig, ledgerVersion, options } = args;\n  const { data: block } = await getEndlessFullNode<{}, Block>({\n    endlessConfig,\n    originMethod: \"getBlockByVersion\",\n    path: `blocks/by_version/${ledgerVersion}`,\n    params: { with_transactions: options?.withTransactions },\n  });\n\n  return fillBlockTransactions({ block, ...args });\n}\n\nexport async function getBlockByHeight(args: {\n  endlessConfig: EndlessConfig;\n  blockHeight: AnyNumber;\n  options?: { withTransactions?: boolean };\n}): Promise<Block> {\n  const { endlessConfig, blockHeight, options } = args;\n  const { data: block } = await getEndlessFullNode<{}, Block>({\n    endlessConfig,\n    originMethod: \"getBlockByHeight\",\n    path: `blocks/by_height/${blockHeight}`,\n    params: { with_transactions: options?.withTransactions },\n  });\n  return fillBlockTransactions({ block, ...args });\n}\n\n/**\n * Fills in the block with transactions if not enough were returned\n * @param args\n */\nasync function fillBlockTransactions(args: {\n  endlessConfig: EndlessConfig;\n  block: Block;\n  options?: { withTransactions?: boolean };\n}) {\n  const { endlessConfig, block, options } = args;\n  if (options?.withTransactions) {\n    // Transactions should be filled, but this ensures it\n    block.transactions = block.transactions ?? [];\n\n    const lastTxn = block.transactions[block.transactions.length - 1];\n    const firstVersion = BigInt(block.first_version);\n    const lastVersion = BigInt(block.last_version);\n\n    // Convert the transaction to the type\n    const curVersion: string | undefined = (lastTxn as any)?.version;\n    let latestVersion;\n\n    // This time, if we don't have any transactions, we will try once with the start of the block\n    if (curVersion === undefined) {\n      latestVersion = firstVersion - 1n;\n    } else {\n      latestVersion = BigInt(curVersion);\n    }\n\n    // If we have all the transactions in the block, we can skip out, otherwise we need to fill the transactions\n    if (latestVersion === lastVersion) {\n      return block;\n    }\n\n    // For now, we will grab all the transactions in groups of 100, but we can make this more efficient by trying larger\n    // amounts\n    const fetchFutures = [];\n    const pageSize = 100n;\n    for (let i = latestVersion + 1n; i < lastVersion; i += BigInt(100)) {\n      fetchFutures.push(\n        getTransactions({\n          endlessConfig,\n          options: {\n            offset: i,\n            limit: Math.min(Number(pageSize), Number(lastVersion - i + 1n)),\n          },\n        }),\n      );\n    }\n\n    // Combine all the futures\n    const responses = await Promise.all(fetchFutures);\n    for (const txns of responses) {\n      block.transactions.push(...txns);\n    }\n  }\n\n  return block;\n}\n\nexport async function getDailyTransactions(args: {\n  endlessConfig: EndlessConfig;\n  options?: { days?: AnyNumber; tz?: number };\n}): Promise<string[]> {\n  const { endlessConfig, options } = args;\n  const { data } = await getEndlessIndexer<{}, string[]>({\n    endlessConfig,\n    originMethod: \"getDailyTransactions\",\n    path: \"status/daily_txns\",\n    params: {\n      days: options?.days,\n      tz: options?.tz,\n    },\n  });\n  return data;\n}\n\nexport async function getUserTransactions(args: {\n  endlessConfig: EndlessConfig;\n  options?: PaginationArgsOfIndexer;\n}): Promise<PageableU64> {\n  const { endlessConfig, options } = args;\n  const { data } = await getEndlessIndexer<{}, PageableU64>({\n    endlessConfig,\n    originMethod: \"getUserTransactions\",\n    path: \"transactions/user\",\n    params: {\n      page: options?.page,\n      pageSize: options?.pageSize,\n    },\n  });\n  return data;\n}\n"],"mappings":"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","names":["getTransactions","args","endlessConfig","options","paginateWithCursor","getGasPriceEstimation","memoizeAsync","data","getEndlessFullNode","getTransactionByVersion","ledgerVersion","getTransactionByHash","transactionHash","isTransactionPending","e","longWaitForTransaction","waitForTransaction","timeoutSecs","checkSuccess","isPending","timeElapsed","lastTxn","lastError","backoffIntervalMs","backoffMultiplier","handleAPIError","EndlessApiError","startTime","sleep","WaitForTransactionError","FailedTransactionError","message","lastSubmittedTransaction","transaction","getBlockByVersion","block","fillBlockTransactions","getBlockByHeight","blockHeight","firstVersion","lastVersion","curVersion","latestVersion","fetchFutures","pageSize","i","responses","txns","getDailyTransactions","getEndlessIndexer","getUserTransactions"]}