import { __awaiter, __extends, __generator } from "tslib";
import { BaseHTTPAdapter } from "../../priceClient/adapters/baseAdapter";
import { bnZero, fixedPointAdjustment, isDefined, parseUnits } from "../../utils";
import { CHAIN_IDs } from "../../constants";
import { gasPriceError } from "../util";
import { eip1559 } from "./ethereum";
var POLYGON = CHAIN_IDs.POLYGON;
var PolygonGasStation = /** @class */ (function (_super) {
    __extends(PolygonGasStation, _super);
    function PolygonGasStation(_a) {
        var _this = this;
        var _b = _a === void 0 ? {} : _a, _c = _b.chainId, chainId = _c === void 0 ? POLYGON : _c, host = _b.host, _d = _b.timeout, timeout = _d === void 0 ? 1500 : _d, _e = _b.retries, retries = _e === void 0 ? 1 : _e;
        host = (host !== null && host !== void 0 ? host : chainId === POLYGON) ? "gasstation.polygon.technology" : "gasstation-testnet.polygon.technology";
        _this = _super.call(this, "Polygon Gas Station", host, { timeout: timeout, retries: retries }) || this;
        _this.chainId = chainId;
        return _this;
    }
    PolygonGasStation.prototype.getFeeData = function (strategy) {
        if (strategy === void 0) { strategy = "fast"; }
        return __awaiter(this, void 0, void 0, function () {
            var gas, gasPrice, maxPriorityFeePerGas, maxFeePerGas;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.query("v2", {})];
                    case 1:
                        gas = _a.sent();
                        gasPrice = gas === null || gas === void 0 ? void 0 : gas[strategy];
                        if (!this.isPolygon1559GasPrice(gasPrice)) {
                            // @todo: generalise gasPriceError() to accept a reason/cause?
                            gasPriceError("getFeeData()", this.chainId, bnZero);
                        }
                        [gasPrice.maxFee, gasPrice.maxPriorityFee].forEach(function (gasPrice) {
                            if (Number(gasPrice) < 0) {
                                gasPriceError("getFeeData()", _this.chainId, parseUnits(gasPrice.toString(), 9));
                            }
                        });
                        maxPriorityFeePerGas = parseUnits(gasPrice.maxPriorityFee.toString(), 9);
                        maxFeePerGas = parseUnits(gasPrice.maxFee.toString(), 9);
                        return [2 /*return*/, { maxPriorityFeePerGas: maxPriorityFeePerGas, maxFeePerGas: maxFeePerGas }];
                }
            });
        });
    };
    PolygonGasStation.prototype.isPolygon1559GasPrice = function (gasPrice) {
        if (!isDefined(gasPrice)) {
            return false;
        }
        var _gasPrice = gasPrice;
        return [_gasPrice.maxPriorityFee, _gasPrice.maxFee].every(function (field) { return ["number", "string"].includes(typeof field); });
    };
    return PolygonGasStation;
}(BaseHTTPAdapter));
export { PolygonGasStation };
var MockRevertingPolygonGasStation = /** @class */ (function (_super) {
    __extends(MockRevertingPolygonGasStation, _super);
    function MockRevertingPolygonGasStation() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    MockRevertingPolygonGasStation.prototype.getFeeData = function () {
        throw new Error();
    };
    return MockRevertingPolygonGasStation;
}(PolygonGasStation));
export var MockPolygonGasStationBaseFee = function () { return parseUnits("12", 9); };
export var MockPolygonGasStationPriorityFee = function () { return parseUnits("1", 9); };
var MockPolygonGasStation = /** @class */ (function (_super) {
    __extends(MockPolygonGasStation, _super);
    function MockPolygonGasStation() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    MockPolygonGasStation.prototype.getFeeData = function () {
        return Promise.resolve({
            maxPriorityFeePerGas: MockPolygonGasStationPriorityFee(),
            maxFeePerGas: MockPolygonGasStationBaseFee().add(MockPolygonGasStationPriorityFee()),
        });
    };
    return MockPolygonGasStation;
}(PolygonGasStation));
/**
 * @notice Returns the gas price suggested by the Polygon GasStation API or reconstructs it using
 * the eip1559() method as a fallback.
 * @param provider Ethers Provider.
 * @returns EvmGasPriceEstimate
 */
export function gasStation(provider, opts) {
    return __awaiter(this, void 0, void 0, function () {
        var chainId, baseFeeMultiplier, priorityFeeMultiplier, gasStation, maxPriorityFeePerGas, maxFeePerGas, baseFeeMinusPriorityFee, scaledBaseFee, scaledPriorityFee, err_1, minPriorityFee, priorityDelta;
        var _a, _b;
        return __generator(this, function (_c) {
            switch (_c.label) {
                case 0:
                    chainId = opts.chainId, baseFeeMultiplier = opts.baseFeeMultiplier, priorityFeeMultiplier = opts.priorityFeeMultiplier;
                    if (process.env.TEST_POLYGON_GAS_STATION === "true") {
                        gasStation = new MockPolygonGasStation();
                    }
                    else if (process.env.TEST_REVERTING_POLYGON_GAS_STATION === "true") {
                        gasStation = new MockRevertingPolygonGasStation();
                    }
                    else {
                        gasStation = new PolygonGasStation({ chainId: chainId, timeout: 2000, retries: 0 });
                    }
                    _c.label = 1;
                case 1:
                    _c.trys.push([1, 3, , 5]);
                    return [4 /*yield*/, gasStation.getFeeData()];
                case 2:
                    (_a = _c.sent(), maxPriorityFeePerGas = _a.maxPriorityFeePerGas, maxFeePerGas = _a.maxFeePerGas);
                    baseFeeMinusPriorityFee = maxFeePerGas.sub(maxPriorityFeePerGas);
                    scaledBaseFee = baseFeeMinusPriorityFee.mul(baseFeeMultiplier).div(fixedPointAdjustment);
                    scaledPriorityFee = maxPriorityFeePerGas.mul(priorityFeeMultiplier).div(fixedPointAdjustment);
                    maxFeePerGas = scaledBaseFee.add(scaledPriorityFee);
                    maxPriorityFeePerGas = scaledPriorityFee;
                    return [3 /*break*/, 5];
                case 3:
                    err_1 = _c.sent();
                    return [4 /*yield*/, eip1559(provider, opts)];
                case 4:
                    // Fall back to the RPC provider. May be less accurate.
                    (_b = _c.sent(), maxPriorityFeePerGas = _b.maxPriorityFeePerGas, maxFeePerGas = _b.maxFeePerGas);
                    minPriorityFee = parseUnits("30", 9).mul(priorityFeeMultiplier).div(fixedPointAdjustment);
                    if (maxPriorityFeePerGas.lt(minPriorityFee)) {
                        priorityDelta = minPriorityFee.sub(maxPriorityFeePerGas);
                        maxPriorityFeePerGas = minPriorityFee;
                        maxFeePerGas = maxFeePerGas.add(priorityDelta);
                    }
                    return [3 /*break*/, 5];
                case 5: return [2 /*return*/, { maxPriorityFeePerGas: maxPriorityFeePerGas, maxFeePerGas: maxFeePerGas }];
            }
        });
    });
}
//# sourceMappingURL=polygon.js.map