import { __assign, __awaiter, __generator } from "tslib";
import assert from "assert";
import { CHAIN_IDs } from "../constants";
import { BigNumber, chainIsOPStack, fixedPointAdjustment, isEvmProvider, toBNWei } from "../utils";
import { getPublicClient } from "./util";
import * as arbitrum from "./adapters/arbitrum";
import * as ethereum from "./adapters/ethereum";
import * as polygon from "./adapters/polygon";
import * as lineaViem from "./adapters/linea-viem";
import * as solana from "./adapters/solana";
var GAS_PRICE_ESTIMATE_DEFAULTS = {
    legacyFallback: true,
};
// Chains that use the Viem gas price oracle.
var VIEM_CHAINS = [CHAIN_IDs.LINEA];
/**
 * Provide an estimate for the current gas price for a particular chain.
 * @param provider A valid ethers provider.
 * @param {GasPriceEstimateOptions} opts optional parameters.
 * @returns An  object of type GasPriceEstimate.
 */
export function getGasPriceEstimate(provider, opts) {
    var _a, _b, _c, _d;
    if (opts === void 0) { opts = {}; }
    return __awaiter(this, void 0, void 0, function () {
        var baseFeeMultiplier, priorityFeeMultiplier, optsWithDefaults_1, chainId, _e, optsWithDefaults, useViem;
        return __generator(this, function (_f) {
            switch (_f.label) {
                case 0:
                    baseFeeMultiplier = (_a = opts.baseFeeMultiplier) !== null && _a !== void 0 ? _a : toBNWei("1");
                    priorityFeeMultiplier = (_b = opts.priorityFeeMultiplier) !== null && _b !== void 0 ? _b : toBNWei("1");
                    // Exit here if we need to estimate on Solana.
                    if (!isEvmProvider(provider)) {
                        optsWithDefaults_1 = __assign(__assign(__assign(__assign({}, GAS_PRICE_ESTIMATE_DEFAULTS), { baseFeeMultiplier: baseFeeMultiplier, priorityFeeMultiplier: priorityFeeMultiplier }), opts), { chainId: (_c = opts.chainId) !== null && _c !== void 0 ? _c : CHAIN_IDs.SOLANA });
                        return [2 /*return*/, solana.messageFee(provider, optsWithDefaults_1)];
                    }
                    if (!((_d = opts.chainId) !== null && _d !== void 0)) return [3 /*break*/, 1];
                    _e = _d;
                    return [3 /*break*/, 3];
                case 1: return [4 /*yield*/, provider.getNetwork()];
                case 2:
                    _e = (_f.sent()).chainId;
                    _f.label = 3;
                case 3:
                    chainId = _e;
                    optsWithDefaults = __assign(__assign(__assign(__assign({}, GAS_PRICE_ESTIMATE_DEFAULTS), { baseFeeMultiplier: baseFeeMultiplier, priorityFeeMultiplier: priorityFeeMultiplier }), opts), { chainId: chainId });
                    useViem = VIEM_CHAINS.includes(chainId);
                    return [2 /*return*/, useViem
                            ? _getViemGasPriceEstimate(chainId, optsWithDefaults)
                            : _getEthersGasPriceEstimate(provider, optsWithDefaults)];
            }
        });
    });
}
/**
 * Provide an estimate for the current gas price for a particular chain.
 * @param chainId The chain ID to query for gas prices.
 * @param provider A valid ethers provider.
 * @param legacyFallback In the case of an unrecognised chain, fall back to type 0 gas estimation.
 * @returns An object of type GasPriceEstimate.
 */
function _getEthersGasPriceEstimate(provider, opts) {
    var _a;
    var chainId = opts.chainId, legacyFallback = opts.legacyFallback;
    // There shouldn't be any chains in here that we have a Viem adapter for because we'll always use Viem in that case.
    assert(!VIEM_CHAINS.includes(chainId), "Chain ID ".concat(chainId, " will use Viem gas price estimation"));
    var gasPriceFeeds = (_a = {},
        _a[CHAIN_IDs.ALEPH_ZERO] = arbitrum.eip1559,
        _a[CHAIN_IDs.ARBITRUM] = arbitrum.eip1559,
        _a[CHAIN_IDs.BSC] = ethereum.legacy,
        _a[CHAIN_IDs.MAINNET] = ethereum.eip1559,
        _a[CHAIN_IDs.POLYGON] = polygon.gasStation,
        _a[CHAIN_IDs.SCROLL] = ethereum.legacy,
        _a[CHAIN_IDs.ZK_SYNC] = ethereum.legacy,
        // Testnet Chains
        _a[CHAIN_IDs.ARBITRUM_SEPOLIA] = arbitrum.eip1559,
        _a[CHAIN_IDs.POLYGON_AMOY] = polygon.gasStation,
        _a[CHAIN_IDs.SEPOLIA] = ethereum.eip1559,
        _a[CHAIN_IDs.TATARA] = ethereum.eip1559,
        _a);
    var gasPriceFeed = gasPriceFeeds[chainId];
    assert(gasPriceFeed || legacyFallback, "No suitable gas price oracle for Chain ID ".concat(chainId));
    gasPriceFeed !== null && gasPriceFeed !== void 0 ? gasPriceFeed : (gasPriceFeed = chainIsOPStack(chainId) ? ethereum.eip1559 : ethereum.legacy);
    return gasPriceFeed(provider, opts);
}
/**
 * Provide an estimate for the current gas price for a particular chain.
 * @param providerOrChainId A valid ethers provider or a chain ID.
 * @param transport An optional Viem Transport object for custom gas price retrieval.
 * @param unsignedTx Only used in Linea provider to estimate priority gas fee.
 * @returns An object of type GasPriceEstimate.
 */
export function _getViemGasPriceEstimate(providerOrChainId, opts) {
    return __awaiter(this, void 0, void 0, function () {
        var baseFeeMultiplier, transport, chainId, _a, viemProvider, gasPriceFeeds, maxFeePerGas, maxPriorityFeePerGas, gasPrice;
        var _b, _c, _d;
        return __generator(this, function (_e) {
            switch (_e.label) {
                case 0:
                    baseFeeMultiplier = opts.baseFeeMultiplier, transport = opts.transport;
                    if (!(typeof providerOrChainId === "number")) return [3 /*break*/, 1];
                    _a = providerOrChainId;
                    return [3 /*break*/, 3];
                case 1: return [4 /*yield*/, providerOrChainId.getNetwork()];
                case 2:
                    _a = (_e.sent()).chainId;
                    _e.label = 3;
                case 3:
                    chainId = _a;
                    viemProvider = getPublicClient(chainId, transport);
                    gasPriceFeeds = (_b = {},
                        _b[CHAIN_IDs.LINEA] = lineaViem.eip1559,
                        _b);
                    if (!gasPriceFeeds[chainId]) return [3 /*break*/, 5];
                    return [4 /*yield*/, gasPriceFeeds[chainId](viemProvider, opts)];
                case 4:
                    (_c = _e.sent(), maxFeePerGas = _c.maxFeePerGas, maxPriorityFeePerGas = _c.maxPriorityFeePerGas);
                    return [3 /*break*/, 7];
                case 5:
                    gasPrice = void 0;
                    return [4 /*yield*/, viemProvider.estimateFeesPerGas()];
                case 6:
                    (_d = _e.sent(), maxFeePerGas = _d.maxFeePerGas, maxPriorityFeePerGas = _d.maxPriorityFeePerGas, gasPrice = _d.gasPrice);
                    maxFeePerGas !== null && maxFeePerGas !== void 0 ? maxFeePerGas : (maxFeePerGas = (gasPrice * BigInt(baseFeeMultiplier.toString())) / BigInt(fixedPointAdjustment.toString()));
                    maxPriorityFeePerGas !== null && maxPriorityFeePerGas !== void 0 ? maxPriorityFeePerGas : (maxPriorityFeePerGas = BigInt(0));
                    _e.label = 7;
                case 7: return [2 /*return*/, {
                        maxFeePerGas: BigNumber.from(maxFeePerGas.toString()),
                        maxPriorityFeePerGas: BigNumber.from(maxPriorityFeePerGas.toString()),
                    }];
            }
        });
    });
}
//# sourceMappingURL=oracle.js.map