UNPKG

@sky-mavis/smart-order-router

Version:
134 lines 13.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Simulator = exports.SimulationStatus = void 0; const katana_core_1 = require("@sky-mavis/katana-core"); const sdk_core_1 = require("@uniswap/sdk-core"); const ethers_1 = require("ethers/lib/ethers"); const routers_1 = require("../routers"); const Erc20__factory_1 = require("../types/other/factories/Erc20__factory"); const Permit2__factory_1 = require("../types/other/factories/Permit2__factory"); const util_1 = require("../util"); var SimulationStatus; (function (SimulationStatus) { SimulationStatus[SimulationStatus["NotSupported"] = 0] = "NotSupported"; SimulationStatus[SimulationStatus["Failed"] = 1] = "Failed"; SimulationStatus[SimulationStatus["Succeeded"] = 2] = "Succeeded"; SimulationStatus[SimulationStatus["InsufficientBalance"] = 3] = "InsufficientBalance"; SimulationStatus[SimulationStatus["NotApproved"] = 4] = "NotApproved"; })(SimulationStatus = exports.SimulationStatus || (exports.SimulationStatus = {})); /** * Provider for dry running transactions. * * @export * @class Simulator */ class Simulator { /** * Returns a new SwapRoute with simulated gas estimates * @returns SwapRoute */ constructor(provider, portionProvider, chainId) { this.chainId = chainId; this.provider = provider; this.portionProvider = portionProvider; } async simulate(fromAddress, swapOptions, swapRoute, amount, quote, providerConfig) { const neededBalance = swapRoute.trade.tradeType == sdk_core_1.TradeType.EXACT_INPUT ? amount : quote; if ((neededBalance.currency.isNative && this.chainId == katana_core_1.ChainId.mainnet) || (await this.userHasSufficientBalance(fromAddress, swapRoute.trade.tradeType, amount, quote))) { util_1.log.info('User has sufficient balance to simulate. Simulating transaction.'); try { return this.simulateTransaction(fromAddress, swapOptions, swapRoute, providerConfig); } catch (e) { util_1.log.error({ e }, 'Error simulating transaction'); return Object.assign(Object.assign({}, swapRoute), { simulationStatus: SimulationStatus.Failed }); } } else { util_1.log.error('User does not have sufficient balance to simulate.'); return Object.assign(Object.assign({}, swapRoute), { simulationStatus: SimulationStatus.InsufficientBalance }); } } async userHasSufficientBalance(fromAddress, tradeType, amount, quote) { try { const neededBalance = tradeType == sdk_core_1.TradeType.EXACT_INPUT ? amount : quote; let balance; if (neededBalance.currency.isNative) { balance = await this.provider.getBalance(fromAddress); } else { const tokenContract = Erc20__factory_1.Erc20__factory.connect(neededBalance.currency.address, this.provider); balance = await tokenContract.balanceOf(fromAddress); } const hasBalance = balance.gte(ethers_1.BigNumber.from(neededBalance.quotient.toString())); util_1.log.info({ fromAddress, balance: balance.toString(), neededBalance: neededBalance.quotient.toString(), neededAddress: neededBalance.wrapped.currency.address, hasBalance, }, 'Result of balance check for simulation'); return hasBalance; } catch (e) { util_1.log.error(e, 'Error while checking user balance'); return false; } } async checkTokenApproved(fromAddress, inputAmount, swapOptions, provider) { var _a, _b; // Check token has approved Permit2 more than expected amount. const tokenContract = Erc20__factory_1.Erc20__factory.connect(inputAmount.currency.wrapped.address, provider); if (swapOptions.type == routers_1.SwapType.UNIVERSAL_ROUTER) { const permit2Allowance = await tokenContract.allowance(fromAddress, (_a = katana_core_1.PERMIT2_ADDRESS[this.chainId]) !== null && _a !== void 0 ? _a : ''); // If a permit has been provided we don't need to check if UR has already been allowed. if (swapOptions.inputTokenPermit) { util_1.log.info({ permitAllowance: permit2Allowance.toString(), inputAmount: inputAmount.quotient.toString(), }, 'Permit was provided for simulation on UR, checking that Permit2 has been approved.'); return permit2Allowance.gte(ethers_1.BigNumber.from(inputAmount.quotient.toString())); } // Check UR has been approved from Permit2. const permit2Contract = Permit2__factory_1.Permit2__factory.connect((_b = katana_core_1.PERMIT2_ADDRESS[this.chainId]) !== null && _b !== void 0 ? _b : '', provider); const { amount: universalRouterAllowance, expiration: tokenExpiration } = await permit2Contract.allowance(fromAddress, inputAmount.currency.wrapped.address, (0, katana_core_1.SWAP_ROUTER_02_ADDRESSES)(this.chainId)); const nowTimestampS = Math.round(Date.now() / 1000); const inputAmountBN = ethers_1.BigNumber.from(inputAmount.quotient.toString()); const permit2Approved = permit2Allowance.gte(inputAmountBN); const universalRouterApproved = universalRouterAllowance.gte(inputAmountBN); const expirationValid = tokenExpiration > nowTimestampS; util_1.log.info({ permitAllowance: permit2Allowance.toString(), tokenAllowance: universalRouterAllowance.toString(), tokenExpirationS: tokenExpiration, nowTimestampS, inputAmount: inputAmount.quotient.toString(), permit2Approved, universalRouterApproved, expirationValid, }, `Simulating on UR, Permit2 approved: ${permit2Approved}, UR approved: ${universalRouterApproved}, Expiraton valid: ${expirationValid}.`); return permit2Approved && universalRouterApproved && expirationValid; } else if (swapOptions.type == routers_1.SwapType.SWAP_ROUTER_02) { if (swapOptions.inputTokenPermit) { util_1.log.info({ inputAmount: inputAmount.quotient.toString(), }, 'Simulating on SwapRouter02 info - Permit was provided for simulation. Not checking allowances.'); return true; } const allowance = await tokenContract.allowance(fromAddress, (0, katana_core_1.SWAP_ROUTER_02_ADDRESSES)(this.chainId)); const hasAllowance = allowance.gte(ethers_1.BigNumber.from(inputAmount.quotient.toString())); util_1.log.info({ hasAllowance, allowance: allowance.toString(), inputAmount: inputAmount.quotient.toString(), }, `Simulating on SwapRouter02 - Has allowance: ${hasAllowance}`); // Return true if token allowance is greater than input amount return hasAllowance; } throw new Error(`Unsupported swap type ${swapOptions}`); } } exports.Simulator = Simulator; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2ltdWxhdGlvbi1wcm92aWRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wcm92aWRlcnMvc2ltdWxhdGlvbi1wcm92aWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFDQSx3REFBNEY7QUFDNUYsZ0RBQThDO0FBQzlDLDhDQUE4QztBQUU5Qyx3Q0FBc0Y7QUFDdEYsNEVBQXlFO0FBQ3pFLGdGQUE2RTtBQUM3RSxrQ0FBOEM7QUFhOUMsSUFBWSxnQkFNWDtBQU5ELFdBQVksZ0JBQWdCO0lBQzFCLHVFQUFnQixDQUFBO0lBQ2hCLDJEQUFVLENBQUE7SUFDVixpRUFBYSxDQUFBO0lBQ2IscUZBQXVCLENBQUE7SUFDdkIscUVBQWUsQ0FBQTtBQUNqQixDQUFDLEVBTlcsZ0JBQWdCLEdBQWhCLHdCQUFnQixLQUFoQix3QkFBZ0IsUUFNM0I7QUFFRDs7Ozs7R0FLRztBQUNILE1BQXNCLFNBQVM7SUFJN0I7OztPQUdHO0lBQ0gsWUFDRSxRQUF5QixFQUN6QixlQUFpQyxFQUN2QixPQUFnQjtRQUFoQixZQUFPLEdBQVAsT0FBTyxDQUFTO1FBRTFCLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxlQUFlLEdBQUcsZUFBZSxDQUFDO0lBQ3pDLENBQUM7SUFFTSxLQUFLLENBQUMsUUFBUSxDQUNuQixXQUFtQixFQUNuQixXQUF3QixFQUN4QixTQUFvQixFQUNwQixNQUFzQixFQUN0QixLQUFxQixFQUNyQixjQUF1QztRQUV2QyxNQUFNLGFBQWEsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLFNBQVMsSUFBSSxvQkFBUyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7UUFDMUYsSUFDRSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxPQUFPLElBQUkscUJBQU8sQ0FBQyxPQUFPLENBQUM7WUFDcEUs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