"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EVMSpokePoolClient = void 0;
var tslib_1 = require("tslib");
var evm_1 = require("../../arch/evm");
var utils_1 = require("../../utils");
var EventUtils_1 = require("../../utils/EventUtils");
var BaseAbstractClient_1 = require("../BaseAbstractClient");
var SpokePoolClient_1 = require("./SpokePoolClient");
var types_1 = require("./types");
var EVMSpokePoolClient = (function (_super) {
    tslib_1.__extends(EVMSpokePoolClient, _super);
    function EVMSpokePoolClient(logger, spokePool, hubPoolClient, chainId, deploymentBlock, eventSearchConfig) {
        if (eventSearchConfig === void 0) { eventSearchConfig = { from: 0, maxLookBack: 0 }; }
        var _this = _super.call(this, logger, hubPoolClient, chainId, deploymentBlock, eventSearchConfig) || this;
        _this.spokePool = spokePool;
        _this.type = types_1.EVM_SPOKE_POOL_CLIENT_TYPE;
        _this.spokePoolAddress = utils_1.EvmAddress.from(spokePool.address);
        return _this;
    }
    EVMSpokePoolClient.prototype.relayFillStatus = function (relayData, atHeight) {
        return (0, evm_1.relayFillStatus)(this.spokePool, relayData, atHeight, this.chainId);
    };
    EVMSpokePoolClient.prototype.fillStatusArray = function (relayData, atHeight) {
        return (0, evm_1.fillStatusArray)(this.spokePool, relayData, atHeight);
    };
    EVMSpokePoolClient.prototype.getMaxFillDeadlineInRange = function (startBlock, endBlock) {
        return (0, evm_1.getMaxFillDeadlineInRange)(this.spokePool, startBlock, endBlock);
    };
    EVMSpokePoolClient.prototype._availableEventsOnSpoke = function (eventNames) {
        var _this = this;
        if (eventNames === void 0) { eventNames = SpokePoolClient_1.knownEventNames; }
        return Object.fromEntries(this.spokePool.interface.fragments
            .filter(function (_a) {
            var name = _a.name, type = _a.type;
            return type === "event" && eventNames.includes(name);
        })
            .map(function (_a) {
            var name = _a.name;
            return [name, _this.spokePool.filters[name]()];
        }));
    };
    EVMSpokePoolClient.prototype._queryableEventNames = function () {
        return Object.keys(this._availableEventsOnSpoke(SpokePoolClient_1.knownEventNames));
    };
    EVMSpokePoolClient.prototype._update = function (eventsToQuery) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var searchConfig, reason, eventSearchConfigs, spokePool, timerStart, multicallFunctions, _a, multicallOutput, events, currentTime, errMsg, eventsWithBlockNumber;
            var _this = this;
            return tslib_1.__generator(this, function (_b) {
                switch (_b.label) {
                    case 0: return [4, this.updateSearchConfig(this.spokePool.provider)];
                    case 1:
                        searchConfig = _b.sent();
                        if ((0, BaseAbstractClient_1.isUpdateFailureReason)(searchConfig)) {
                            reason = searchConfig;
                            return [2, { success: false, reason: reason }];
                        }
                        eventSearchConfigs = eventsToQuery.map(function (eventName) {
                            if (!_this._queryableEventNames().includes(eventName)) {
                                throw new Error("SpokePoolClient: Cannot query unrecognised SpokePool event name: ".concat(eventName));
                            }
                            var _searchConfig = tslib_1.__assign({}, searchConfig);
                            if (eventName === "EnabledDepositRoute" && !_this.isUpdated) {
                                _searchConfig.from = _this.deploymentBlock;
                            }
                            return {
                                filter: _this._availableEventsOnSpoke()[eventName],
                                searchConfig: _searchConfig,
                            };
                        });
                        spokePool = this.spokePool;
                        this.log("debug", "Updating SpokePool client for chain ".concat(this.chainId), {
                            eventsToQuery: eventsToQuery,
                            searchConfig: searchConfig,
                            spokePool: spokePool.address,
                        });
                        timerStart = Date.now();
                        multicallFunctions = ["getCurrentTime"];
                        return [4, Promise.all(tslib_1.__spreadArray([
                                spokePool.callStatic.multicall(multicallFunctions.map(function (f) { return spokePool.interface.encodeFunctionData(f); }), { blockTag: searchConfig.to })
                            ], eventSearchConfigs.map(function (config) { return (0, EventUtils_1.paginatedEventQuery)(_this.spokePool, config.filter, config.searchConfig); }), true))];
                    case 2:
                        _a = _b.sent(), multicallOutput = _a[0], events = _a.slice(1);
                        this.log("debug", "Time to query new events from RPC for ".concat(this.chainId, ": ").concat(Date.now() - timerStart, " ms"));
                        currentTime = multicallFunctions.map(function (fn, idx) { return spokePool.interface.decodeFunctionResult(fn, multicallOutput[idx])[0]; })[0];
                        if (!utils_1.BigNumber.isBigNumber(currentTime) || currentTime.lt(this.currentTime)) {
                            errMsg = utils_1.BigNumber.isBigNumber(currentTime)
                                ? "currentTime: ".concat(currentTime, " < ").concat((0, utils_1.toBN)(this.currentTime))
                                : "currentTime is not a BigNumber: ".concat(JSON.stringify(currentTime));
                            throw new Error("EVMSpokePoolClient::update: ".concat(errMsg));
                        }
                        events.forEach(function (events) { return (0, EventUtils_1.sortEventsAscendingInPlace)(events.map(EventUtils_1.logToSortableEvent)); });
                        eventsWithBlockNumber = events.map(function (eventList) {
                            return eventList.map(function (event) { return (0, EventUtils_1.spreadEventWithBlockNumber)(event); });
                        });
                        return [2, {
                                success: true,
                                currentTime: currentTime.toNumber(),
                                searchEndBlock: searchConfig.to,
                                events: eventsWithBlockNumber,
                            }];
                }
            });
        });
    };
    EVMSpokePoolClient.prototype.getTimeAt = function (blockNumber) {
        return (0, evm_1.getTimeAt)(this.spokePool, blockNumber);
    };
    EVMSpokePoolClient.prototype.findDeposit = function (depositId) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var deposit, upperBound, from, chain, reason, to, tStart, maxLookBack, query, tStop, event, _a;
            var _b;
            return tslib_1.__generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        deposit = this.getDeposit(depositId);
                        if (deposit) {
                            return [2, { found: true, deposit: deposit }];
                        }
                        upperBound = this.latestHeightSearched || undefined;
                        return [4, (0, evm_1.findDepositBlock)(this.spokePool, depositId, this.deploymentBlock, upperBound)];
                    case 1:
                        from = _c.sent();
                        chain = (0, utils_1.getNetworkName)(this.chainId);
                        if (!from) {
                            reason = "Unable to find ".concat(chain, " depositId ").concat(depositId) +
                                " within blocks [".concat(this.deploymentBlock, ", ").concat(upperBound !== null && upperBound !== void 0 ? upperBound : "latest", "].");
                            return [2, { found: false, code: utils_1.InvalidFill.DepositIdNotFound, reason: reason }];
                        }
                        to = from;
                        tStart = Date.now();
                        maxLookBack = this.eventSearchConfig.maxLookBack;
                        return [4, Promise.all([
                                (0, EventUtils_1.paginatedEventQuery)(this.spokePool, this.spokePool.filters.V3FundsDeposited(null, null, null, null, null, depositId), { from: from, to: to, maxLookBack: maxLookBack }),
                                (0, EventUtils_1.paginatedEventQuery)(this.spokePool, this.spokePool.filters.FundsDeposited(null, null, null, null, null, depositId), { from: from, to: to, maxLookBack: maxLookBack }),
                            ])];
                    case 2:
                        query = (_c.sent()).flat();
                        tStop = Date.now();
                        event = query.find(function (_a) {
                            var args = _a.args;
                            return args["depositId"].eq(depositId);
                        });
                        if (event === undefined) {
                            return [2, {
                                    found: false,
                                    code: utils_1.InvalidFill.DepositIdNotFound,
                                    reason: "".concat(chain, " depositId ").concat(depositId, " not found at block ").concat(from, "."),
                                }];
                        }
                        _a = [tslib_1.__assign({}, (0, EventUtils_1.spreadEventWithBlockNumber)(event))];
                        _b = { inputToken: (0, utils_1.toAddressType)(event.args.inputToken, event.args.originChainId), outputToken: (0, utils_1.toAddressType)(event.args.outputToken, event.args.destinationChainId), depositor: (0, utils_1.toAddressType)(event.args.depositor, this.chainId), recipient: (0, utils_1.toAddressType)(event.args.recipient, event.args.destinationChainId), exclusiveRelayer: (0, utils_1.toAddressType)(event.args.exclusiveRelayer, event.args.destinationChainId), originChainId: this.chainId };
                        return [4, this.getBlockNumber(Number(event.args["quoteTimestamp"]))];
                    case 3:
                        deposit = tslib_1.__assign.apply(void 0, _a.concat([(_b.quoteBlockNumber = _c.sent(), _b.fromLiteChain = true, _b.toLiteChain = true, _b)]));
                        if (deposit.outputToken.isZeroAddress()) {
                            deposit.outputToken = this.getDestinationTokenForDeposit(deposit);
                        }
                        deposit.fromLiteChain = this.isOriginLiteChain(deposit);
                        deposit.toLiteChain = this.isDestinationLiteChain(deposit);
                        this.logger.debug({
                            at: "SpokePoolClient#findDeposit",
                            message: "Located deposit outside of SpokePoolClient's search range",
                            deposit: deposit,
                            elapsedMs: tStop - tStart,
                        });
                        return [2, { found: true, deposit: deposit }];
                }
            });
        });
    };
    EVMSpokePoolClient.prototype.getTimestampForBlock = function (blockNumber) {
        return (0, evm_1.getTimestampForBlock)(this.spokePool.provider, blockNumber);
    };
    return EVMSpokePoolClient;
}(SpokePoolClient_1.SpokePoolClient));
exports.EVMSpokePoolClient = EVMSpokePoolClient;
//# sourceMappingURL=EVMSpokePoolClient.js.map