{"version":3,"sources":["../src/utils/feeRateHelpers.ts"],"sourcesContent":["import { BigNumber } from \"./BigNumber\"\nimport { concat, last, reduce } from \"./arrayHelpers\"\nimport { checkNever, OneOrMore } from \"./typeHelpers\"\nimport {\n  TransferProphet,\n  TransferProphet_Fee_Fixed,\n  TransferProphet_Fee_Rate,\n  TransferProphetAggregated,\n} from \"./types/TransferProphet\"\n\nexport interface TransferProphetAppliedResult {\n  fees: (\n    | (TransferProphet_Fee_Rate & { amount: BigNumber })\n    | TransferProphet_Fee_Fixed\n  )[]\n  netAmount: BigNumber\n}\n\nexport const applyTransferProphets = (\n  transferProphets: OneOrMore<TransferProphet>,\n  amount: BigNumber,\n): OneOrMore<TransferProphetAppliedResult> => {\n  return reduce(\n    (acc, transferProphet) =>\n      concat(acc, [applyTransferProphet(transferProphet, last(acc).netAmount)]),\n    [{ fees: [], netAmount: amount }],\n    transferProphets,\n  )\n}\n\nexport const applyTransferProphet = (\n  transferProphet: TransferProphet,\n  amount: BigNumber,\n): TransferProphetAppliedResult => {\n  const fees: TransferProphetAppliedResult[\"fees\"] = []\n\n  let totalFeeAmount = BigNumber.ZERO\n  for (const f of transferProphet.fees) {\n    let feeAmount = BigNumber.ZERO\n\n    if (f.type === \"rate\") {\n      if (f.token !== transferProphet.bridgeToken) {\n        throw new Error(\n          `[XLinkSDK#applyTransferProphet] transferProphet.bridgeToken (${transferProphet.bridgeToken}) does not match rateFee.token (${f.token}), which is not expected`,\n        )\n      }\n      feeAmount = BigNumber.max([\n        f.minimumAmount,\n        BigNumber.mul(f.rate, amount),\n      ])\n      fees.push({ ...f, amount: feeAmount })\n    } else if (f.type === \"fixed\") {\n      if (f.token === transferProphet.bridgeToken) {\n        feeAmount = f.amount\n      }\n      fees.push(f)\n    } else {\n      checkNever(f)\n    }\n\n    totalFeeAmount = BigNumber.add(totalFeeAmount, feeAmount)\n  }\n\n  const netAmount = BigNumber.max([\n    BigNumber.ZERO,\n    BigNumber.minus(amount, totalFeeAmount),\n  ])\n\n  return { fees, netAmount }\n}\n\n/**\n * @example\n * composeTransferProphets(\n *   [\n *     // tokenA : chain1 -> chain2\n *     transferProphetOf(tokenAChain1, tokenAChain2),\n *     // tokenB : chain2 -> chain3\n *     transferProphetOf(tokenBChain2, tokenBChain3),\n *     // tokenC : chain3 -> chain4\n *     transferProphetOf(tokenCChain3, tokenCChain4),\n *   ],\n *   [\n *     // tokenA -> tokenB : chain2\n *     exchangeRateOf(tokenAChain2, tokenBChain2),\n *     // tokenB -> tokenC : chain3\n *     exchangeRateOf(tokenBChain3, tokenCChain3),\n *   ],\n * )\n */\nexport const composeTransferProphets = (\n  transferProphets: readonly TransferProphet[],\n  exchangeRates: readonly BigNumber[],\n): TransferProphetAggregated<TransferProphet[]> => {\n  const cumulativeExchangeRates = calcCumulativeExchangeRates(exchangeRates)\n\n  return reduce(\n    (res, transferProphet, idx) => ({\n      ...composeTransferProphet2(\n        res,\n        transferProphet,\n        cumulativeExchangeRates[idx],\n      ),\n      transferProphets: [...res.transferProphets, transferProphet],\n    }),\n    composeTransferProphet2(\n      transferProphets[0],\n      transferProphets[1],\n      cumulativeExchangeRates[0],\n    ) as TransferProphetAggregated<TransferProphet[]>,\n    transferProphets.slice(2),\n  )\n}\n/**\n * @example\n * calcCumulativeExchangeRates([\n *   exchangeRateOf(tokenA, tokenB),\n *   exchangeRateOf(tokenB, tokenC),\n *   exchangeRateOf(tokenC, tokenD),\n *   // ...\n * ])\n *\n * // =>\n *\n * [\n *   exchangeRateOf(tokenA, tokenB),\n *   exchangeRateOf(tokenA, tokenC),\n *   exchangeRateOf(tokenA, tokenD),\n *   // ...\n * ]\n */\nconst calcCumulativeExchangeRates = (\n  exchangeRates: readonly BigNumber[],\n): readonly BigNumber[] => {\n  return BigNumber.cumulativeMul(BigNumber.ONE, exchangeRates).slice(1)\n}\n\nexport const composeTransferProphet2 = (\n  transferProphet1: TransferProphet,\n  transferProphet2: TransferProphet,\n  exchangeRate: BigNumber,\n): TransferProphetAggregated<[TransferProphet, TransferProphet]> => {\n  if (exchangeRate == null) {\n    throw new Error(\n      \"[XLinkSDK#composeTransferProphet2] exchangeRate is required\",\n    )\n  }\n\n  const bridgeTokenMinFeeAmount = BigNumber.sum([\n    ...transferProphet1.fees.flatMap(f =>\n      f.type === \"rate\" && f.token === transferProphet1.bridgeToken\n        ? [f.minimumAmount]\n        : [],\n    ),\n    ...transferProphet2.fees.flatMap(f =>\n      f.type === \"rate\" && f.token === transferProphet2.bridgeToken\n        ? [\n            /**\n             * convert to the denomination of the first step token\n             */\n            BigNumber.div(f.minimumAmount, exchangeRate),\n          ]\n        : [],\n    ),\n  ])\n\n  /**\n   * flatFeeRate = 1 - (amount1 * (1-feeRate1) * (1-feeRate2) * (1-feeRateN...) / amount1)\n   * flatFeeRate = 1 - (1-feeRate1) * (1-feeRate2) * (1-feeRateN...)\n   */\n  const step1FlatFeeRate = BigNumber.minus(\n    BigNumber.ONE,\n    last(\n      BigNumber.cumulativeMul(\n        BigNumber.ONE,\n        transferProphet1.fees.flatMap(f =>\n          f.type === \"rate\" && f.token === transferProphet1.bridgeToken\n            ? [BigNumber.minus(1, f.rate)]\n            : [],\n        ),\n      ),\n    ),\n  )\n  /**\n   * step2Amount = step1Amount * (1-feeRate1) * (1-feeRate2) * (1-feeRateN)... * exchangeRate\n   * step2Amount = step1Amount * (1-flatFeeRate) * exchangeRate\n   */\n  const step1ToStep2Rate = BigNumber.mul(\n    BigNumber.minus(1, step1FlatFeeRate),\n    exchangeRate,\n  )\n\n  let minBridgeAmount: BigNumber | null = null\n  if (\n    BigNumber.isZero(bridgeTokenMinFeeAmount) /* min fee amount not set */ &&\n    transferProphet1.minBridgeAmount == null &&\n    transferProphet2.minBridgeAmount == null\n  ) {\n    minBridgeAmount = null\n  } else {\n    minBridgeAmount = BigNumber.max([\n      bridgeTokenMinFeeAmount,\n      transferProphet1.minBridgeAmount ?? 0,\n      transferProphet2.minBridgeAmount == null\n        ? 0\n        : BigNumber.div(transferProphet2.minBridgeAmount, step1ToStep2Rate),\n    ])\n  }\n\n  let maxBridgeAmount: BigNumber | null = null\n  if (\n    transferProphet1.maxBridgeAmount == null &&\n    transferProphet2.maxBridgeAmount == null\n  ) {\n    maxBridgeAmount = null\n  } else if (\n    transferProphet1.maxBridgeAmount != null &&\n    transferProphet2.maxBridgeAmount != null\n  ) {\n    maxBridgeAmount = BigNumber.min([\n      transferProphet1.maxBridgeAmount,\n      BigNumber.div(transferProphet2.maxBridgeAmount, step1ToStep2Rate),\n    ])\n  } else {\n    maxBridgeAmount =\n      transferProphet1.maxBridgeAmount ?? transferProphet2.maxBridgeAmount\n  }\n\n  return {\n    isPaused: transferProphet1.isPaused || transferProphet2.isPaused,\n    bridgeToken: transferProphet1.bridgeToken,\n    minBridgeAmount,\n    maxBridgeAmount,\n    fees: [\n      ...transferProphet1.fees,\n      ...transferProphet2.fees.map(fee => {\n        if (fee.type === \"fixed\") {\n          if (fee.token !== transferProphet2.bridgeToken) return fee\n          return {\n            type: \"fixed\",\n            token: transferProphet1.bridgeToken,\n            amount: BigNumber.div(fee.amount, step1ToStep2Rate),\n          } satisfies TransferProphet_Fee_Fixed\n        }\n\n        if (fee.type === \"rate\") {\n          if (fee.token !== transferProphet2.bridgeToken) return fee\n          return {\n            type: \"rate\",\n            token: transferProphet1.bridgeToken,\n            /**\n             * feeAmount = step2Amount * fee.rate\n             * feeAmount = (step1Amount * (1 - step1FlatFeeRate) * exchangeRate) * fee.rate\n             * step1Amount * newFeeRate = (step1Amount * (1 - step1FlatFeeRate) * exchangeRate) * fee.rate\n             * newFeeRate = (1 - step1FlatFeeRate) * exchangeRate * fee.rate\n             * newFeeRate = step1ToStep2Rate * fee.rate\n             */\n            rate: BigNumber.mul(step1ToStep2Rate, fee.rate),\n            minimumAmount: BigNumber.div(fee.minimumAmount, step1ToStep2Rate),\n          } satisfies TransferProphet_Fee_Rate\n        }\n\n        checkNever(fee)\n        return fee\n      }),\n    ],\n    transferProphets: [transferProphet1, transferProphet2],\n  }\n}\n\nexport const composeRates2 = (\n  rate1: BigNumber,\n  rate2: BigNumber,\n): BigNumber => {\n  /**\n   * n = bridge amount\n   * rate = ((n * r1) +\n   *         (n * (1 - r1)) * r2)\n   *        / n\n   *      |\n   *      V\n   *      = (n * r1 / n) +\n   *        (n * (1 - r1) * r2 / n)\n   *      |\n   *      V\n   *      = r1 + (1 - r1) * r2\n   */\n  // prettier-ignore\n  return BigNumber.sum([\n    rate1,\n    BigNumber.mul(\n      BigNumber.minus(1, rate1),\n      rate2,\n    ),\n  ])\n}\n"],"mappings":"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","names":[]}