{"version":3,"file":"required-tokens.cjs","sourceRoot":"","sources":["../../src/utils/required-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { toHex } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport { add0x, type Hex } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n  getNativeToken,\n  getTokenBalance,\n  getTokenFiatRate,\n  getTokenInfo,\n} from './token';\nimport type {\n  FiatRates,\n  TransactionPayControllerMessenger,\n  TransactionPayRequiredToken,\n} from '../types';\n\nconst FOUR_BYTE_TOKEN_TRANSFER = '0xa9059cbb';\n\n/**\n * Parse required tokens from a transaction.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns An array of required tokens.\n */\nexport function parseRequiredTokens(\n  transaction: TransactionMeta,\n  messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken[] {\n  return [\n    getTokenTransferToken(transaction, messenger),\n    getGasFeeToken(transaction, messenger),\n  ].filter(Boolean) as TransactionPayRequiredToken[];\n}\n\n/**\n * Parse a required token from a token transfer.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns The required token or undefined if the transaction is not a token transfer.\n */\nfunction getTokenTransferToken(\n  transaction: TransactionMeta,\n  messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n  const { data, to } = getTokenTransferData(transaction) ?? {};\n\n  if (!to || !data) {\n    return undefined;\n  }\n\n  let transferAmount: Hex | undefined;\n\n  try {\n    const result = new Interface(abiERC20).decodeFunctionData('transfer', data);\n    transferAmount = toHex(result._value);\n  } catch {\n    // Intentionally empty\n  }\n\n  if (transferAmount === undefined) {\n    return undefined;\n  }\n\n  return buildRequiredToken(transaction, to, transferAmount, messenger);\n}\n\n/**\n * Get the gas fee token required for a transaction.\n *\n * @param transaction - Transaction metadata.\n * @param messenger - Controller messenger.\n * @returns The gas fee token or undefined if it could not be determined.\n */\nfunction getGasFeeToken(\n  transaction: TransactionMeta,\n  messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n  const { chainId, txParams } = transaction;\n  const { gas, maxFeePerGas } = txParams;\n  const nativeTokenAddress = getNativeToken(chainId);\n\n  const maxGasCostRawHex = add0x(\n    new BigNumber(gas ?? '0x0')\n      .multipliedBy(new BigNumber(maxFeePerGas ?? '0x0'))\n      .toString(16),\n  );\n\n  const token = buildRequiredToken(\n    transaction,\n    nativeTokenAddress,\n    maxGasCostRawHex,\n    messenger,\n  );\n\n  if (!token) {\n    return undefined;\n  }\n\n  const amountUsdValue = new BigNumber(token.amountUsd);\n\n  const hasBalance = new BigNumber(token.balanceRaw).isGreaterThanOrEqualTo(\n    token.amountRaw,\n  );\n\n  if (hasBalance || amountUsdValue.isGreaterThanOrEqualTo(1)) {\n    return {\n      ...token,\n      allowUnderMinimum: true,\n      skipIfBalance: true,\n    };\n  }\n\n  const fiatRates = getTokenFiatRate(\n    messenger,\n    nativeTokenAddress,\n    chainId,\n  ) as FiatRates;\n\n  const oneDollarRawHex = add0x(\n    new BigNumber(1).dividedBy(fiatRates.usdRate).shiftedBy(18).toString(16),\n  );\n\n  const oneDollarToken = buildRequiredToken(\n    transaction,\n    nativeTokenAddress,\n    oneDollarRawHex,\n    messenger,\n  );\n\n  /* istanbul ignore next */\n  if (!oneDollarToken) {\n    return undefined;\n  }\n\n  return {\n    ...oneDollarToken,\n    allowUnderMinimum: true,\n    skipIfBalance: true,\n  };\n}\n\n/**\n * Get the full token properties for a specific token and amount.\n *\n * @param transaction - Transaction metadata.\n * @param tokenAddress - Token address.\n * @param amountRawHex - Raw token amount in hexadecimal format.\n * @param messenger - Controller messenger.\n * @returns The full token properties or undefined if the token data could not be retrieved.\n */\nfunction buildRequiredToken(\n  transaction: TransactionMeta,\n  tokenAddress: Hex,\n  amountRawHex: Hex,\n  messenger: TransactionPayControllerMessenger,\n): TransactionPayRequiredToken | undefined {\n  const { chainId, txParams } = transaction;\n  const from = txParams.from as Hex;\n\n  const { decimals: tokenDecimals, symbol } =\n    getTokenInfo(messenger, tokenAddress, chainId) ?? {};\n\n  const fiatRates = getTokenFiatRate(messenger, tokenAddress, chainId);\n  const tokenBalance = getTokenBalance(messenger, from, chainId, tokenAddress);\n\n  if (tokenDecimals === undefined || !symbol || fiatRates === undefined) {\n    return undefined;\n  }\n\n  const {\n    amountHuman: balanceHuman,\n    amountRaw: balanceRaw,\n    amountFiat: balanceFiat,\n    amountUsd: balanceUsd,\n  } = calculateAmounts(tokenBalance, tokenDecimals, fiatRates);\n\n  const { amountHuman, amountRaw, amountFiat, amountUsd } = calculateAmounts(\n    amountRawHex,\n    tokenDecimals,\n    fiatRates,\n  );\n\n  return {\n    address: tokenAddress,\n    allowUnderMinimum: false,\n    amountFiat,\n    amountHuman,\n    amountRaw,\n    amountUsd,\n    balanceFiat,\n    balanceHuman,\n    balanceRaw,\n    balanceUsd,\n    chainId,\n    decimals: tokenDecimals,\n    skipIfBalance: false,\n    symbol,\n  };\n}\n\n/**\n * Calculates the various amount representations for a token value.\n *\n * @param amountRawInput - Raw amount.\n * @param decimals - Number of decimals for the token.\n * @param fiatRates - Fiat rates for the token.\n * @returns Object containing amount in fiat, human-readable, raw, and USD formats.\n */\nfunction calculateAmounts(\n  amountRawInput: BigNumber.Value,\n  decimals: number,\n  fiatRates: FiatRates,\n) {\n  const amountRawValue = new BigNumber(amountRawInput);\n  const amountHumanValue = amountRawValue.shiftedBy(-decimals);\n\n  const amountFiat = amountHumanValue\n    .multipliedBy(fiatRates.fiatRate)\n    .toString(10);\n\n  const amountUsd = amountHumanValue\n    .multipliedBy(fiatRates.usdRate)\n    .toString(10);\n\n  const amountRaw = amountRawValue.toFixed(0);\n  const amountHuman = amountHumanValue.toString(10);\n\n  return {\n    amountFiat,\n    amountHuman,\n    amountRaw,\n    amountUsd,\n  };\n}\n\n/**\n * Find token transfer data in a transaction.\n *\n * @param transactionMeta - Transaction metadata.\n * @returns - Token transfer data or undefined if not found.\n */\nfunction getTokenTransferData(transactionMeta: TransactionMeta):\n  | {\n      data: Hex;\n      to: Hex;\n      index?: number;\n    }\n  | undefined {\n  const { nestedTransactions, txParams } = transactionMeta;\n  const { data: singleData } = txParams;\n  const singleTo = txParams?.to as Hex | undefined;\n\n  if (singleData?.startsWith(FOUR_BYTE_TOKEN_TRANSFER) && singleTo) {\n    return { data: singleData as Hex, to: singleTo, index: undefined };\n  }\n\n  const nestedCallIndex = nestedTransactions?.findIndex((call) =>\n    call.data?.startsWith(FOUR_BYTE_TOKEN_TRANSFER),\n  );\n\n  const nestedCall =\n    nestedCallIndex !== undefined\n      ? nestedTransactions?.[nestedCallIndex]\n      : undefined;\n\n  if (nestedCall?.data && nestedCall.to) {\n    return {\n      data: nestedCall.data,\n      to: nestedCall.to,\n      index: nestedCallIndex,\n    };\n  }\n\n  return undefined;\n}\n"]}