"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.QueryBase = void 0;
var tslib_1 = require("tslib");
var l2_provider_1 = require("@eth-optimism/sdk/dist/l2-provider");
var ethers_1 = require("ethers");
var coingecko_1 = require("../../coingecko");
var constants_1 = require("../../constants");
var typechain_1 = require("../../typechain");
var evm_1 = require("../../arch/evm");
var utils_1 = require("../../utils");
var assert_1 = tslib_1.__importDefault(require("assert"));
var relayFeeCalculator_1 = require("../relayFeeCalculator");
var gasPriceOracle_1 = require("../../gasPriceOracle");
var QueryBase = (function () {
    function QueryBase(provider, symbolMapping, spokePoolAddress, simulatedRelayerAddress, logger, coingeckoProApiKey, fixedGasPrice, coingeckoBaseCurrency) {
        if (coingeckoBaseCurrency === void 0) { coingeckoBaseCurrency = "eth"; }
        this.provider = provider;
        this.symbolMapping = symbolMapping;
        this.spokePoolAddress = spokePoolAddress;
        this.simulatedRelayerAddress = simulatedRelayerAddress;
        this.logger = logger;
        this.coingeckoProApiKey = coingeckoProApiKey;
        this.fixedGasPrice = fixedGasPrice;
        this.coingeckoBaseCurrency = coingeckoBaseCurrency;
        this.spokePool = typechain_1.SpokePool__factory.connect(spokePoolAddress, provider);
    }
    QueryBase.prototype.getGasCosts = function (relayData, relayer, options) {
        if (relayer === void 0) { relayer = (0, relayFeeCalculator_1.getDefaultRelayer)(relayData.destinationChainId); }
        if (options === void 0) { options = {}; }
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var _a, gasPrice, gasUnits, baseFeeMultiplier, priorityFeeMultiplier, opStackL1GasCostMultiplier, transport, recipient, outputToken, exclusiveRelayer, tx, _b, nativeGasCost, tokenGasCost, impliedGasPrice, opStackL1GasCost;
            return tslib_1.__generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        _a = options.gasPrice, gasPrice = _a === void 0 ? this.fixedGasPrice : _a, gasUnits = options.gasUnits, baseFeeMultiplier = options.baseFeeMultiplier, priorityFeeMultiplier = options.priorityFeeMultiplier, opStackL1GasCostMultiplier = options.opStackL1GasCostMultiplier, transport = options.transport;
                        recipient = relayData.recipient, outputToken = relayData.outputToken, exclusiveRelayer = relayData.exclusiveRelayer;
                        (0, assert_1.default)(recipient.isEVM(), "getGasCosts: recipient not an EVM address (".concat(recipient, ")"));
                        (0, assert_1.default)(outputToken.isEVM(), "getGasCosts: outputToken not an EVM address (".concat(outputToken, ")"));
                        (0, assert_1.default)(exclusiveRelayer.isEVM(), "getGasCosts: exclusiveRelayer not an EVM address (".concat(exclusiveRelayer, ")"));
                        return [4, this.getUnsignedTxFromDeposit(tslib_1.__assign(tslib_1.__assign({}, relayData), { recipient: recipient, outputToken: outputToken, exclusiveRelayer: exclusiveRelayer }), relayer)];
                    case 1:
                        tx = _c.sent();
                        return [4, this.estimateGas(tx, relayer, this.provider, {
                                gasPrice: gasPrice,
                                gasUnits: gasUnits,
                                baseFeeMultiplier: baseFeeMultiplier,
                                priorityFeeMultiplier: priorityFeeMultiplier,
                                opStackL1GasCostMultiplier: opStackL1GasCostMultiplier,
                                transport: transport,
                            })];
                    case 2:
                        _b = _c.sent(), nativeGasCost = _b.nativeGasCost, tokenGasCost = _b.tokenGasCost, impliedGasPrice = _b.gasPrice, opStackL1GasCost = _b.opStackL1GasCost;
                        return [2, {
                                nativeGasCost: nativeGasCost,
                                tokenGasCost: tokenGasCost,
                                gasPrice: impliedGasPrice,
                                opStackL1GasCost: opStackL1GasCost,
                            }];
                }
            });
        });
    };
    QueryBase.prototype.getUnsignedTxFromDeposit = function (relayData, relayer) {
        if (relayer === void 0) { relayer = (0, relayFeeCalculator_1.getDefaultRelayer)(relayData.destinationChainId); }
        return (0, evm_1.populateV3Relay)(this.spokePool, relayData, relayer);
    };
    QueryBase.prototype.getNativeGasCost = function (relayData, relayer) {
        if (relayer === void 0) { relayer = (0, relayFeeCalculator_1.getDefaultRelayer)(relayData.destinationChainId); }
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var recipient, outputToken, exclusiveRelayer, unsignedTx, voidSigner;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        recipient = relayData.recipient, outputToken = relayData.outputToken, exclusiveRelayer = relayData.exclusiveRelayer;
                        (0, assert_1.default)(recipient.isEVM(), "getNativeGasCost: recipient not an EVM address (".concat(recipient, ")"));
                        (0, assert_1.default)(outputToken.isEVM(), "getNativeGasCost: outputToken not an EVM address (".concat(outputToken, ")"));
                        (0, assert_1.default)(exclusiveRelayer.isEVM(), "getNativeGasCost: exclusiveRelayer not an EVM address (".concat(exclusiveRelayer, ")"));
                        return [4, this.getUnsignedTxFromDeposit(tslib_1.__assign(tslib_1.__assign({}, relayData), { recipient: recipient, outputToken: outputToken, exclusiveRelayer: exclusiveRelayer }), relayer)];
                    case 1:
                        unsignedTx = _a.sent();
                        voidSigner = new ethers_1.VoidSigner(relayer.toEvmAddress(), this.provider);
                        return [2, voidSigner.estimateGas(unsignedTx)];
                }
            });
        });
    };
    QueryBase.prototype.getOpStackL1DataFee = function (unsignedTx, relayer, options) {
        if (relayer === void 0) { relayer = (0, relayFeeCalculator_1.getDefaultRelayer)(unsignedTx.chainId); }
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var _a, opStackL2GasUnits, _b, opStackL1DataFeeMultiplier, chainId, voidSigner, populatedTransaction, l1DataFee;
            return tslib_1.__generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        _a = options || {}, opStackL2GasUnits = _a.opStackL2GasUnits, _b = _a.opStackL1DataFeeMultiplier, opStackL1DataFeeMultiplier = _b === void 0 ? (0, utils_1.toBNWei)("1") : _b;
                        return [4, this.provider.getNetwork()];
                    case 1:
                        chainId = (_c.sent()).chainId;
                        (0, assert_1.default)((0, l2_provider_1.isL2Provider)(this.provider), "Unexpected provider for chain ID ".concat(chainId, "."));
                        voidSigner = new ethers_1.VoidSigner(relayer.toEvmAddress(), this.provider);
                        return [4, voidSigner.populateTransaction(tslib_1.__assign(tslib_1.__assign({}, unsignedTx), { gasLimit: opStackL2GasUnits }))];
                    case 2:
                        populatedTransaction = _c.sent();
                        return [4, this.provider.estimateL1GasCost(populatedTransaction)];
                    case 3:
                        l1DataFee = _c.sent();
                        return [2, l1DataFee.mul(opStackL1DataFeeMultiplier).div(utils_1.fixedPointAdjustment)];
                }
            });
        });
    };
    QueryBase.prototype.estimateGas = function (unsignedTx, senderAddress, provider, options) {
        if (options === void 0) { options = {}; }
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var _a, _gasPrice, gasUnits, _b, baseFeeMultiplier, _c, priorityFeeMultiplier, _d, opStackL1GasCostMultiplier, transport, chainId, voidSigner, queries, _e, nativeGasCost, gasPriceEstimate, gasPrice, tokenGasCost, opStackL1GasCost, l2GasCost;
            return tslib_1.__generator(this, function (_f) {
                switch (_f.label) {
                    case 0:
                        _a = options || {}, _gasPrice = _a.gasPrice, gasUnits = _a.gasUnits, _b = _a.baseFeeMultiplier, baseFeeMultiplier = _b === void 0 ? (0, utils_1.toBNWei)("1") : _b, _c = _a.priorityFeeMultiplier, priorityFeeMultiplier = _c === void 0 ? (0, utils_1.toBNWei)("1") : _c, _d = _a.opStackL1GasCostMultiplier, opStackL1GasCostMultiplier = _d === void 0 ? (0, utils_1.toBNWei)("1") : _d, transport = _a.transport;
                        return [4, provider.getNetwork()];
                    case 1:
                        chainId = (_f.sent()).chainId;
                        voidSigner = new ethers_1.VoidSigner(senderAddress.toEvmAddress(), provider);
                        queries = [
                            gasUnits ? Promise.resolve(utils_1.BigNumber.from(gasUnits)) : voidSigner.estimateGas(unsignedTx),
                            _gasPrice
                                ? Promise.resolve({ maxFeePerGas: _gasPrice })
                                : (0, gasPriceOracle_1.getGasPriceEstimate)(provider, { chainId: chainId, baseFeeMultiplier: baseFeeMultiplier, priorityFeeMultiplier: priorityFeeMultiplier, transport: transport, unsignedTx: unsignedTx }),
                        ];
                        return [4, Promise.all(queries)];
                    case 2:
                        _e = _f.sent(), nativeGasCost = _e[0], gasPriceEstimate = _e[1];
                        gasPrice = gasPriceEstimate.maxFeePerGas;
                        (0, assert_1.default)(nativeGasCost.gt(utils_1.bnZero), "Gas cost should not be 0");
                        if (!(0, utils_1.chainIsOPStack)(chainId)) return [3, 4];
                        return [4, this.getOpStackL1DataFee(unsignedTx, senderAddress, {
                                opStackL2GasUnits: nativeGasCost,
                                opStackL1DataFeeMultiplier: opStackL1GasCostMultiplier,
                            })];
                    case 3:
                        opStackL1GasCost = _f.sent();
                        l2GasCost = nativeGasCost.mul(gasPrice);
                        tokenGasCost = opStackL1GasCost.add(l2GasCost);
                        return [3, 5];
                    case 4:
                        tokenGasCost = nativeGasCost.mul(gasPrice);
                        _f.label = 5;
                    case 5: return [2, {
                            nativeGasCost: nativeGasCost,
                            tokenGasCost: tokenGasCost,
                            gasPrice: utils_1.BigNumber.from(gasPrice.toString()),
                            opStackL1GasCost: opStackL1GasCost,
                        }];
                }
            });
        });
    };
    QueryBase.prototype.getTokenPrice = function (tokenSymbol) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var coingeckoInstance, _a, price;
            return tslib_1.__generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        if (!this.symbolMapping[tokenSymbol])
                            throw new Error("".concat(tokenSymbol, " does not exist in mapping"));
                        coingeckoInstance = coingecko_1.Coingecko.get(this.logger, this.coingeckoProApiKey);
                        return [4, coingeckoInstance.getCurrentPriceByContract(this.symbolMapping[tokenSymbol].addresses[constants_1.CHAIN_IDs.MAINNET], this.coingeckoBaseCurrency)];
                    case 1:
                        _a = _b.sent(), price = _a[1];
                        return [2, price];
                }
            });
        });
    };
    return QueryBase;
}());
exports.QueryBase = QueryBase;
//# sourceMappingURL=baseQuery.js.map