UNPKG

@renproject/ren

Version:

Official Ren JavaScript SDK for bridging crypto assets cross-chain.

122 lines 6.04 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { ErrorWithCode, isContractChain, isDepositChain, RenJSError, } from "@renproject/utils"; import BigNumber from "bignumber.js"; export const BIP_DENOMINATOR = 10000; // Some assets may have their gas price defined in a different unit. const assetGasDivisors = { LUNA: 5, }; export const estimateTransactionFee = (renVM, asset, fromChain, toChain) => __awaiter(void 0, void 0, void 0, function* () { // Determine if the transaction is a lock-and-mint, burn-and-release or // burn-and-mint. const [blockState, isLockAssetOnFromChain, isLockAssetOnToChain, isMintAssetOnFromChain, isMintAssetOnToChain, decimalsOnFromChain, decimalsOnToChain, isDepositAssetOnFromChain, isDepositAssetOnToChain,] = yield Promise.all([ renVM.queryBlockState(asset, 5), fromChain.isLockAsset(asset), toChain.isLockAsset(asset), isContractChain(fromChain) && fromChain.isMintAsset(asset), isContractChain(toChain) && toChain.isMintAsset(asset), fromChain.assetDecimals(asset), toChain.assetDecimals(asset), isDepositChain(fromChain) && fromChain.isDepositAsset(asset), isDepositChain(toChain) && toChain.isDepositAsset(asset), ]); if (!isLockAssetOnFromChain && !isMintAssetOnFromChain) { throw ErrorWithCode.updateError(new Error(`Asset not supported by chain ${fromChain.chain}.`), RenJSError.PARAMETER_ERROR); } if (!isLockAssetOnToChain && !isMintAssetOnToChain) { throw ErrorWithCode.updateError(new Error(`Asset not supported by chain ${toChain.chain}.`), RenJSError.PARAMETER_ERROR); } const isLockAndMint = isLockAssetOnFromChain; const isBurnAndRelease = isLockAssetOnToChain; // const isBurnAndMint = isMintAssetOnFromChain && isMintAssetOnToChain; if (!blockState[asset]) { throw ErrorWithCode.updateError(new Error(`No fee details found for ${asset}`), RenJSError.UNKNOWN_ERROR); } const { gasLimit, gasCap, minimumAmount: minimumBeforeFees, dustAmount, } = blockState[asset]; // For burning, use the fees for the origin chain. For other txs, use // the fees for the target chain. const feesChain = isBurnAndRelease ? fromChain.chain : toChain.chain; const mintAndBurnFees = blockState[asset].fees.chains.filter((chainFees) => chainFees.chain === feesChain)[0]; // No other way of getting proper decimals for burn-and-mints. const nativeDecimals = Math.max(decimalsOnFromChain, decimalsOnToChain); const requiresTransfer = (isLockAndMint && isDepositAssetOnFromChain) || (isBurnAndRelease && isDepositAssetOnToChain); const fixedFee = requiresTransfer ? gasLimit .times(gasCap) .shiftedBy(-assetGasDivisors[asset] || 0) .plus(isBurnAndRelease ? dustAmount.plus(1) : 0) : new BigNumber(0); const mintFee = mintAndBurnFees && mintAndBurnFees.mintFee ? mintAndBurnFees.mintFee.toNumber() : 15; const burnFee = mintAndBurnFees && mintAndBurnFees.burnFee ? mintAndBurnFees.burnFee.toNumber() : 15; const burnAndMintFee = mintAndBurnFees && mintAndBurnFees.burnAndMintFee ? mintAndBurnFees.burnAndMintFee.toNumber() : 15; const variableFee = isLockAndMint ? mintFee : isBurnAndRelease ? burnFee : burnAndMintFee; const minimumAmount = minimumBeforeFees .plus(fixedFee) .plus(minimumBeforeFees .plus(fixedFee) .times(variableFee) .dividedBy(BIP_DENOMINATOR) .decimalPlaces(0, BigNumber.ROUND_DOWN)); const estimateOutput = (input) => { const amount = BigNumber.isBigNumber(input) || typeof input === "string" || typeof input === "number" ? input : input.amount; const convertUnit = typeof input === "object" && !BigNumber.isBigNumber(input) ? input.convertUnit || false : false; const amountBN = new BigNumber(amount).shiftedBy(convertUnit ? nativeDecimals : 0); if (amountBN.isLessThan(minimumAmount)) { return new BigNumber(0); } if (isLockAndMint) { return BigNumber.max(amountBN .minus(fixedFee) .times(BIP_DENOMINATOR - variableFee) .dividedBy(BIP_DENOMINATOR) .decimalPlaces(0, BigNumber.ROUND_DOWN), 0).shiftedBy(convertUnit ? -nativeDecimals : 0); } else if (isBurnAndRelease) { return BigNumber.max(amountBN .times(BIP_DENOMINATOR - variableFee) .dividedBy(BIP_DENOMINATOR) .minus(fixedFee) .decimalPlaces(0, BigNumber.ROUND_DOWN), 0).shiftedBy(convertUnit ? -nativeDecimals : 0); } else { // Burn-and-mint transaction. If a fixed-fee is ever added for all // transactions, it will need to be added here. return BigNumber.max(amountBN .times(BIP_DENOMINATOR - variableFee) .dividedBy(BIP_DENOMINATOR) .decimalPlaces(0, BigNumber.ROUND_DOWN), 0).shiftedBy(convertUnit ? -nativeDecimals : 0); } }; return { fixedFee, variableFee, minimumAmount, estimateOutput, }; }); //# sourceMappingURL=fees.js.map