"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BundleDataClient = void 0;
var tslib_1 = require("tslib");
var assert_1 = tslib_1.__importDefault(require("assert"));
var lodash_1 = tslib_1.__importDefault(require("lodash"));
var interfaces_1 = require("../../interfaces");
var evm_1 = require("../../arch/evm");
var svm_1 = require("../../arch/svm");
var utils_1 = require("../../utils");
var utils_2 = require("./utils");
var SpokePoolClient_1 = require("../SpokePoolClient");
var SpokePoolClientManager_1 = require("../SpokePoolClient/SpokePoolClientManager");
function updateExpiredDepositsV3(dict, deposit) {
    var _a, _b;
    var _c, _d;
    if (!deposit.depositor.isValidOn(deposit.originChainId)) {
        return;
    }
    var originChainId = deposit.originChainId, inputToken = deposit.inputToken;
    (_a = dict[originChainId]) !== null && _a !== void 0 ? _a : (dict[originChainId] = {});
    (_b = (_c = dict[originChainId])[_d = inputToken.toBytes32()]) !== null && _b !== void 0 ? _b : (_c[_d] = []);
    dict[originChainId][inputToken.toBytes32()].push(deposit);
}
function updateBundleDepositsV3(dict, deposit) {
    var _a, _b;
    var _c, _d;
    var originChainId = deposit.originChainId, inputToken = deposit.inputToken;
    (_a = dict[originChainId]) !== null && _a !== void 0 ? _a : (dict[originChainId] = {});
    (_b = (_c = dict[originChainId])[_d = inputToken.toBytes32()]) !== null && _b !== void 0 ? _b : (_c[_d] = []);
    dict[originChainId][inputToken.toBytes32()].push(deposit);
}
function updateBundleFillsV3(dict, fill, lpFeePct, repaymentChainId, repaymentToken, repaymentAddress) {
    var _a, _b, _c;
    var _d, _e;
    if (!fill.relayer.isValidOn(repaymentChainId)) {
        return;
    }
    (_a = dict[repaymentChainId]) !== null && _a !== void 0 ? _a : (dict[repaymentChainId] = {});
    (_b = (_d = dict[repaymentChainId])[_e = repaymentToken.toBytes32()]) !== null && _b !== void 0 ? _b : (_d[_e] = {
        fills: [],
        totalRefundAmount: utils_1.bnZero,
        realizedLpFees: utils_1.bnZero,
        refunds: {},
    });
    var bundleFill = tslib_1.__assign(tslib_1.__assign({}, fill), { lpFeePct: lpFeePct, relayer: repaymentAddress });
    (0, utils_1.assign)(dict, [repaymentChainId, repaymentToken.toBytes32(), "fills"], [bundleFill]);
    var refundObj = dict[repaymentChainId][repaymentToken.toBytes32()];
    var realizedLpFee = bundleFill.inputAmount.mul(bundleFill.lpFeePct).div(utils_1.fixedPointAdjustment);
    refundObj.realizedLpFees = refundObj.realizedLpFees ? refundObj.realizedLpFees.add(realizedLpFee) : realizedLpFee;
    if (!(0, utils_1.isSlowFill)(bundleFill)) {
        var refundAmount = bundleFill.inputAmount.mul(utils_1.fixedPointAdjustment.sub(lpFeePct)).div(utils_1.fixedPointAdjustment);
        refundObj.totalRefundAmount = refundObj.totalRefundAmount
            ? refundObj.totalRefundAmount.add(refundAmount)
            : refundAmount;
        (_c = refundObj.refunds) !== null && _c !== void 0 ? _c : (refundObj.refunds = {});
        if (refundObj.refunds[bundleFill.relayer.toBytes32()]) {
            refundObj.refunds[bundleFill.relayer.toBytes32()] =
                refundObj.refunds[bundleFill.relayer.toBytes32()].add(refundAmount);
        }
        else {
            refundObj.refunds[bundleFill.relayer.toBytes32()] = refundAmount;
        }
    }
}
function updateBundleExcessSlowFills(dict, deposit) {
    var _a, _b;
    var _c, _d;
    var destinationChainId = deposit.destinationChainId, outputToken = deposit.outputToken;
    (_a = dict[destinationChainId]) !== null && _a !== void 0 ? _a : (dict[destinationChainId] = {});
    (_b = (_c = dict[destinationChainId])[_d = outputToken.toBytes32()]) !== null && _b !== void 0 ? _b : (_c[_d] = []);
    dict[destinationChainId][outputToken.toBytes32()].push(deposit);
}
function updateBundleSlowFills(dict, deposit) {
    var _a, _b;
    var _c, _d;
    if (!deposit.recipient.isValidOn(deposit.destinationChainId)) {
        return;
    }
    var destinationChainId = deposit.destinationChainId, outputToken = deposit.outputToken;
    (_a = dict[destinationChainId]) !== null && _a !== void 0 ? _a : (dict[destinationChainId] = {});
    (_b = (_c = dict[destinationChainId])[_d = outputToken.toBytes32()]) !== null && _b !== void 0 ? _b : (_c[_d] = []);
    dict[destinationChainId][outputToken.toBytes32()].push(deposit);
}
var BundleDataClient = (function () {
    function BundleDataClient(logger, clients, spokePoolClients, chainIdListForBundleEvaluationBlockNumbers, blockRangeEndBlockBuffer) {
        if (blockRangeEndBlockBuffer === void 0) { blockRangeEndBlockBuffer = {}; }
        this.logger = logger;
        this.clients = clients;
        this.chainIdListForBundleEvaluationBlockNumbers = chainIdListForBundleEvaluationBlockNumbers;
        this.blockRangeEndBlockBuffer = blockRangeEndBlockBuffer;
        this.loadDataCache = {};
        this.arweaveDataCache = {};
        this.bundleTimestampCache = {};
        this.spokePoolClientManager = new SpokePoolClientManager_1.SpokePoolManager(logger, spokePoolClients);
    }
    BundleDataClient.prototype.clearCache = function () {
        this.loadDataCache = {};
    };
    BundleDataClient.prototype.loadDataFromCache = function (key) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var _a, _b;
            return tslib_1.__generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        _b = (_a = lodash_1.default).cloneDeep;
                        return [4, this.loadDataCache[key]];
                    case 1: return [2, _b.apply(_a, [_c.sent()])];
                }
            });
        });
    };
    BundleDataClient.prototype.getBundleTimestampsFromCache = function (key) {
        if (this.bundleTimestampCache[key]) {
            return lodash_1.default.cloneDeep(this.bundleTimestampCache[key]);
        }
        return undefined;
    };
    BundleDataClient.prototype.setBundleTimestampsInCache = function (key, timestamps) {
        this.bundleTimestampCache[key] = timestamps;
    };
    BundleDataClient.getArweaveClientKey = function (blockRangesForChains) {
        return blockRangesForChains[0][1].toString();
    };
    BundleDataClient.prototype.getArweaveBundleDataClientKey = function (blockRangesForChains) {
        return "bundles-".concat(BundleDataClient.getArweaveClientKey(blockRangesForChains));
    };
    BundleDataClient.prototype.loadPersistedDataFromArweave = function (blockRangesForChains) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var start, persistedData, convertTypedStringRecordIntoNumericRecord, convertSortableEventFieldsIntoRequiredFields, convertEmbeddedSortableEventFieldsIntoRequiredFields, data, bundleData;
            var _a;
            return tslib_1.__generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        if (!(0, utils_1.isDefined)((_a = this.clients) === null || _a === void 0 ? void 0 : _a.arweaveClient)) {
                            return [2, undefined];
                        }
                        start = performance.now();
                        return [4, this.clients.arweaveClient.getByTopic(this.getArweaveBundleDataClientKey(blockRangesForChains), utils_2.BundleDataSS)];
                    case 1:
                        persistedData = _b.sent();
                        if (!(0, utils_1.isDefined)(persistedData) || persistedData.length < 1) {
                            return [2, undefined];
                        }
                        convertTypedStringRecordIntoNumericRecord = function (data) {
                            return Object.keys(data).reduce(function (acc, chainId) {
                                acc[Number(chainId)] = data[chainId];
                                return acc;
                            }, {});
                        };
                        convertSortableEventFieldsIntoRequiredFields = function (data) {
                            return data.map(function (item) {
                                if ((item.txnIndex !== undefined && item.transactionIndex !== undefined) ||
                                    (item.txnIndex === undefined && item.transactionIndex === undefined)) {
                                    throw new Error("Either txnIndex or transactionIndex must be defined, but not both.");
                                }
                                if ((item.txnRef !== undefined && item.transactionHash !== undefined) ||
                                    (item.txnRef === undefined && item.transactionHash === undefined)) {
                                    throw new Error("Either txnRef or transactionHash must be defined, but not both.");
                                }
                                var txnIndex = item.txnIndex, transactionIndex = item.transactionIndex, txnRef = item.txnRef, transactionHash = item.transactionHash, rest = tslib_1.__rest(item, ["txnIndex", "transactionIndex", "txnRef", "transactionHash"]);
                                return tslib_1.__assign(tslib_1.__assign({}, rest), { txnIndex: txnIndex !== null && txnIndex !== void 0 ? txnIndex : transactionIndex, txnRef: txnRef !== null && txnRef !== void 0 ? txnRef : transactionHash });
                            });
                        };
                        convertEmbeddedSortableEventFieldsIntoRequiredFields = function (data) {
                            return Object.fromEntries(Object.entries(data).map(function (_a) {
                                var chainId = _a[0], tokenData = _a[1];
                                return [
                                    chainId,
                                    Object.fromEntries(Object.entries(tokenData).map(function (_a) {
                                        var token = _a[0], data = _a[1];
                                        return [
                                            token,
                                            convertSortableEventFieldsIntoRequiredFields(data),
                                        ];
                                    })),
                                ];
                            }));
                        };
                        data = persistedData[0].data;
                        bundleData = {
                            bundleFillsV3: convertTypedStringRecordIntoNumericRecord(Object.fromEntries(Object.entries(data.bundleFillsV3).map(function (_a) {
                                var chainId = _a[0], tokenData = _a[1];
                                return [
                                    chainId,
                                    Object.fromEntries(Object.entries(tokenData).map(function (_a) {
                                        var token = _a[0], data = _a[1];
                                        return [
                                            token,
                                            {
                                                refunds: Object.fromEntries(Object.entries(data.refunds).map(function (_a) {
                                                    var refundAddress = _a[0], refund = _a[1];
                                                    return [(0, utils_1.toBytes32)(refundAddress), refund];
                                                })),
                                                totalRefundAmount: data.totalRefundAmount,
                                                realizedLpFees: data.realizedLpFees,
                                                fills: convertSortableEventFieldsIntoRequiredFields(data.fills),
                                            },
                                        ];
                                    })),
                                ];
                            }))),
                            expiredDepositsToRefundV3: convertTypedStringRecordIntoNumericRecord(convertEmbeddedSortableEventFieldsIntoRequiredFields(data.expiredDepositsToRefundV3)),
                            bundleDepositsV3: convertTypedStringRecordIntoNumericRecord(convertEmbeddedSortableEventFieldsIntoRequiredFields(data.bundleDepositsV3)),
                            unexecutableSlowFills: convertTypedStringRecordIntoNumericRecord(convertEmbeddedSortableEventFieldsIntoRequiredFields(data.unexecutableSlowFills)),
                            bundleSlowFillsV3: convertTypedStringRecordIntoNumericRecord(convertEmbeddedSortableEventFieldsIntoRequiredFields(data.bundleSlowFillsV3)),
                        };
                        this.logger.debug({
                            at: "BundleDataClient#loadPersistedDataFromArweave",
                            message: "Loaded persisted data from Arweave in ".concat(Math.round(performance.now() - start) / 1000, "s."),
                            blockRanges: JSON.stringify(blockRangesForChains),
                            bundleData: (0, utils_2.prettyPrintV3SpokePoolEvents)(bundleData.bundleDepositsV3, bundleData.bundleFillsV3, bundleData.bundleSlowFillsV3, bundleData.expiredDepositsToRefundV3, bundleData.unexecutableSlowFills),
                        });
                        return [2, bundleData];
                }
            });
        });
    };
    BundleDataClient.prototype.loadArweaveData = function (blockRangesForChains) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var arweaveKey, arweaveData, _a, _b;
            return tslib_1.__generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        arweaveKey = this.getArweaveBundleDataClientKey(blockRangesForChains);
                        if (!this.arweaveDataCache[arweaveKey]) {
                            this.arweaveDataCache[arweaveKey] = this.loadPersistedDataFromArweave(blockRangesForChains);
                        }
                        _b = (_a = lodash_1.default).cloneDeep;
                        return [4, this.arweaveDataCache[arweaveKey]];
                    case 1:
                        arweaveData = _b.apply(_a, [_c.sent()]);
                        return [2, arweaveData];
                }
            });
        });
    };
    BundleDataClient.prototype.loadData = function (blockRangesForChains_1, spokePoolClients_1) {
        return tslib_1.__awaiter(this, arguments, void 0, function (blockRangesForChains, spokePoolClients, attemptArweaveLoad) {
            var key, arweaveData, data;
            if (attemptArweaveLoad === void 0) { attemptArweaveLoad = false; }
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        key = JSON.stringify(blockRangesForChains);
                        if (!!this.loadDataCache[key]) return [3, 4];
                        arweaveData = void 0;
                        if (!attemptArweaveLoad) return [3, 2];
                        return [4, this.loadArweaveData(blockRangesForChains)];
                    case 1:
                        arweaveData = _a.sent();
                        return [3, 3];
                    case 2:
                        arweaveData = undefined;
                        _a.label = 3;
                    case 3:
                        data = (0, utils_1.isDefined)(arweaveData)
                            ?
                                Promise.resolve(arweaveData)
                            : this.loadDataFromScratch(blockRangesForChains, spokePoolClients);
                        this.loadDataCache[key] = data;
                        _a.label = 4;
                    case 4: return [2, this.loadDataFromCache(key)];
                }
            });
        });
    };
    BundleDataClient.prototype.loadDataFromScratch = function (blockRangesForChains, spokePoolClients) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var start, key, _a, bundleStartBlockForMainnet, bundleEndBlockForMainnet, chainIds, bundleDepositsV3, bundleFillsV3, bundleInvalidFillsV3, bundleUnrepayableFillsV3, bundleInvalidSlowFillRequests, bundleSlowFillsV3, expiredDepositsToRefundV3, unexecutableSlowFills, _isChainDisabled, _isChainPaused, _canCreateSlowFillLeaf, _depositIsExpired, _getFillStatusForDeposit, allChainIds, _cachedBundleTimestamps, bundleBlockTimestamps, v3RelayHashes, bundleDepositHashes, olderDepositHashes, decodeBundleDepositHash, _loop_1, _i, allChainIds_1, originChainId, validatedBundleV3Fills, validatedBundleSlowFills, validatedBundleUnexecutableSlowFills, fillCounter, allFillChainIds, _loop_2, _b, allFillChainIds_1, originChainId, promises, _c, v3FillLpFees, v3SlowFillLpFees, v3UnexecutableSlowFillLpFees, v3SpokeEventsReadable, invalidFillsWithPartialMatchedDeposits_1, preFillsForNextBundle_1, unknownReasonInvalidFills_1;
            var _this = this;
            return tslib_1.__generator(this, function (_d) {
                switch (_d.label) {
                    case 0:
                        start = performance.now();
                        key = JSON.stringify(blockRangesForChains);
                        if (!this.clients.configStoreClient.isUpdated) {
                            throw new Error("ConfigStoreClient not updated");
                        }
                        else if (!this.clients.hubPoolClient.isUpdated) {
                            throw new Error("HubPoolClient not updated");
                        }
                        _a = blockRangesForChains[0], bundleStartBlockForMainnet = _a[0], bundleEndBlockForMainnet = _a[1];
                        chainIds = this.clients.configStoreClient.getChainIdIndicesForBlock(bundleStartBlockForMainnet);
                        if (blockRangesForChains.length > chainIds.length) {
                            throw new Error("Unexpected block range list length of ".concat(blockRangesForChains.length, ", should be <= ").concat(chainIds.length));
                        }
                        bundleDepositsV3 = {};
                        bundleFillsV3 = {};
                        bundleInvalidFillsV3 = [];
                        bundleUnrepayableFillsV3 = [];
                        bundleInvalidSlowFillRequests = [];
                        bundleSlowFillsV3 = {};
                        expiredDepositsToRefundV3 = {};
                        unexecutableSlowFills = {};
                        _isChainDisabled = function (chainId) {
                            return (0, utils_2.isChainDisabledAtBlock)(chainId, bundleStartBlockForMainnet, _this.clients.configStoreClient);
                        };
                        _isChainPaused = function (chainId) {
                            var blockRangeForChain = (0, utils_1.getBlockRangeForChain)(blockRangesForChains, chainId, chainIds);
                            return (0, utils_2.isChainPaused)(blockRangeForChain);
                        };
                        _canCreateSlowFillLeaf = function (deposit) {
                            return (_this.clients.hubPoolClient.areTokensEquivalent(deposit.inputToken, deposit.originChainId, deposit.outputToken, deposit.destinationChainId, bundleEndBlockForMainnet) &&
                                !deposit.fromLiteChain &&
                                !deposit.toLiteChain);
                        };
                        _depositIsExpired = function (deposit) {
                            return deposit.fillDeadline <= bundleBlockTimestamps[deposit.destinationChainId][1];
                        };
                        _getFillStatusForDeposit = function (deposit, queryBlock) {
                            return spokePoolClients[deposit.destinationChainId].relayFillStatus(deposit, Math.min(queryBlock, spokePoolClients[deposit.destinationChainId].latestHeightSearched));
                        };
                        allChainIds = blockRangesForChains
                            .map(function (_blockRange, index) { return chainIds[index]; })
                            .filter(function (chainId) { return !_isChainDisabled(chainId) && spokePoolClients[chainId] !== undefined; });
                        allChainIds.forEach(function (chainId) {
                            var spokePoolClient = spokePoolClients[chainId];
                            if (!spokePoolClient.isUpdated) {
                                throw new Error("SpokePoolClient for chain ".concat(chainId, " not updated."));
                            }
                        });
                        _cachedBundleTimestamps = this.getBundleTimestampsFromCache(key);
                        bundleBlockTimestamps = {};
                        if (!!_cachedBundleTimestamps) return [3, 2];
                        return [4, this.getBundleBlockTimestamps(chainIds, blockRangesForChains, spokePoolClients)];
                    case 1:
                        bundleBlockTimestamps = _d.sent();
                        this.setBundleTimestampsInCache(key, bundleBlockTimestamps);
                        this.logger.debug({
                            at: "BundleDataClient#loadData",
                            message: "Bundle block timestamps",
                            bundleBlockTimestamps: bundleBlockTimestamps,
                            blockRangesForChains: JSON.stringify(blockRangesForChains),
                        });
                        return [3, 3];
                    case 2:
                        bundleBlockTimestamps = _cachedBundleTimestamps;
                        _d.label = 3;
                    case 3:
                        v3RelayHashes = {};
                        bundleDepositHashes = [];
                        olderDepositHashes = [];
                        decodeBundleDepositHash = function (depositHash) {
                            var _a = depositHash.split("@"), relayDataHash = _a[0], i = _a[1];
                            return { relayDataHash: relayDataHash, index: Number(i) };
                        };
                        _loop_1 = function (originChainId) {
                            var originClient = spokePoolClients[originChainId];
                            var originChainBlockRange = (0, utils_1.getBlockRangeForChain)(blockRangesForChains, originChainId, chainIds);
                            for (var _e = 0, allChainIds_2 = allChainIds; _e < allChainIds_2.length; _e++) {
                                var destinationChainId = allChainIds_2[_e];
                                originClient.getDepositsForDestinationChainWithDuplicates(destinationChainId).forEach(function (deposit) {
                                    var _a, _b;
                                    if (deposit.blockNumber > originChainBlockRange[1] || (0, utils_1.isZeroValueDeposit)(deposit)) {
                                        return;
                                    }
                                    var relayDataHash = (0, utils_1.getRelayEventKey)(deposit);
                                    if (!v3RelayHashes[relayDataHash]) {
                                        v3RelayHashes[relayDataHash] = {
                                            deposits: [deposit],
                                            fill: undefined,
                                            slowFillRequest: undefined,
                                        };
                                    }
                                    else {
                                        var deposits_1 = v3RelayHashes[relayDataHash].deposits;
                                        (0, assert_1.default)((0, utils_1.isDefined)(deposits_1) && deposits_1.length > 0, "Deposit should exist in relay hash dictionary.");
                                        deposits_1.push(deposit);
                                    }
                                    var deposits = v3RelayHashes[relayDataHash].deposits;
                                    (0, assert_1.default)((0, utils_1.isDefined)(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
                                    var newBundleDepositHash = "".concat(relayDataHash, "@").concat(deposits.length - 1);
                                    var decodedBundleDepositHash = decodeBundleDepositHash(newBundleDepositHash);
                                    (0, assert_1.default)(decodedBundleDepositHash.relayDataHash === relayDataHash &&
                                        decodedBundleDepositHash.index === deposits.length - 1, "Not using correct bundle deposit hash key");
                                    if (deposit.blockNumber >= originChainBlockRange[0]) {
                                        if ((_b = (_a = bundleDepositsV3 === null || bundleDepositsV3 === void 0 ? void 0 : bundleDepositsV3[originChainId]) === null || _a === void 0 ? void 0 : _a[deposit.inputToken.toBytes32()]) === null || _b === void 0 ? void 0 : _b.find(function (d) {
                                            return (0, utils_1.duplicateEvent)(deposit, d);
                                        })) {
                                            _this.logger.debug({
                                                at: "BundleDataClient#loadData",
                                                message: "Duplicate deposit detected",
                                                deposit: (0, utils_1.convertRelayDataParamsToBytes32)(deposit),
                                            });
                                            throw new Error("Duplicate deposit detected");
                                        }
                                        if (!_isChainPaused(originChainId)) {
                                            bundleDepositHashes.push(newBundleDepositHash);
                                            updateBundleDepositsV3(bundleDepositsV3, deposit);
                                        }
                                    }
                                    else if (deposit.blockNumber < originChainBlockRange[0]) {
                                        olderDepositHashes.push(newBundleDepositHash);
                                    }
                                });
                            }
                        };
                        for (_i = 0, allChainIds_1 = allChainIds; _i < allChainIds_1.length; _i++) {
                            originChainId = allChainIds_1[_i];
                            _loop_1(originChainId);
                        }
                        this.logger.debug({
                            at: "BundleDataClient#loadData",
                            message: "Processed ".concat(bundleDepositHashes.length + olderDepositHashes.length, " deposits in ").concat(performance.now() - start, "ms."),
                        });
                        start = performance.now();
                        validatedBundleV3Fills = [];
                        validatedBundleSlowFills = [];
                        validatedBundleUnexecutableSlowFills = [];
                        fillCounter = 0;
                        allFillChainIds = allChainIds.filter(function (chainId) { return !_isChainPaused(chainId); });
                        _loop_2 = function (originChainId) {
                            var originClient, _loop_3, _f, allFillChainIds_2, destinationChainId;
                            return tslib_1.__generator(this, function (_g) {
                                switch (_g.label) {
                                    case 0:
                                        originClient = spokePoolClients[originChainId];
                                        _loop_3 = function (destinationChainId) {
                                            var destinationClient, destinationChainBlockRange, originChainBlockRange, fastFillsReplacingSlowFills;
                                            return tslib_1.__generator(this, function (_h) {
                                                switch (_h.label) {
                                                    case 0:
                                                        destinationClient = spokePoolClients[destinationChainId];
                                                        destinationChainBlockRange = (0, utils_1.getBlockRangeForChain)(blockRangesForChains, destinationChainId, chainIds);
                                                        originChainBlockRange = (0, utils_1.getBlockRangeForChain)(blockRangesForChains, originChainId, chainIds);
                                                        fastFillsReplacingSlowFills = [];
                                                        return [4, (0, utils_1.forEachAsync)(destinationClient
                                                                .getFillsForOriginChain(originChainId)
                                                                .filter(function (fill) {
                                                                return fill.blockNumber <= destinationChainBlockRange[1] &&
                                                                    !(0, utils_1.isZeroValueFillOrSlowFillRequest)(fill) &&
                                                                    !(0, utils_1.invalidOutputToken)(fill);
                                                            }), function (fill) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
                                                                var relayDataHash, deposits, provider_1, fillToRefund_1, duplicateDeposits, historicalDeposit, matchedDeposit, provider, fillToRefund;
                                                                return tslib_1.__generator(this, function (_a) {
                                                                    switch (_a.label) {
                                                                        case 0:
                                                                            fillCounter++;
                                                                            relayDataHash = (0, utils_1.getRelayEventKey)(fill);
                                                                            if (!v3RelayHashes[relayDataHash]) return [3, 5];
                                                                            if (!!v3RelayHashes[relayDataHash].fill) return [3, 3];
                                                                            deposits = v3RelayHashes[relayDataHash].deposits;
                                                                            (0, assert_1.default)((0, utils_1.isDefined)(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
                                                                            v3RelayHashes[relayDataHash].fill = fill;
                                                                            if (!(fill.blockNumber >= destinationChainBlockRange[0])) return [3, 2];
                                                                            if ((0, SpokePoolClient_1.isEVMSpokePoolClient)(destinationClient)) {
                                                                                provider_1 = destinationClient.spokePool.provider;
                                                                            }
                                                                            else if ((0, SpokePoolClient_1.isSVMSpokePoolClient)(destinationClient)) {
                                                                                provider_1 = destinationClient.svmEventsClient.getRpc();
                                                                            }
                                                                            return [4, (0, utils_2.verifyFillRepayment)(fill, provider_1, deposits[0], this.clients.hubPoolClient, bundleEndBlockForMainnet)];
                                                                        case 1:
                                                                            fillToRefund_1 = _a.sent();
                                                                            if (!(0, utils_1.isDefined)(fillToRefund_1)) {
                                                                                bundleUnrepayableFillsV3.push(fill);
                                                                            }
                                                                            else {
                                                                                v3RelayHashes[relayDataHash].fill = fillToRefund_1;
                                                                                validatedBundleV3Fills.push(tslib_1.__assign(tslib_1.__assign({}, fillToRefund_1), { quoteTimestamp: deposits[0].quoteTimestamp }));
                                                                                duplicateDeposits = deposits.slice(1);
                                                                                duplicateDeposits.forEach(function (duplicateDeposit) {
                                                                                    if ((0, utils_1.isSlowFill)(fill)) {
                                                                                        updateExpiredDepositsV3(expiredDepositsToRefundV3, duplicateDeposit);
                                                                                    }
                                                                                    else {
                                                                                        validatedBundleV3Fills.push(tslib_1.__assign(tslib_1.__assign({}, fillToRefund_1), { quoteTimestamp: duplicateDeposit.quoteTimestamp }));
                                                                                    }
                                                                                });
                                                                            }
                                                                            if (fill.relayExecutionInfo.fillType === interfaces_1.FillType.ReplacedSlowFill &&
                                                                                _canCreateSlowFillLeaf(deposits[0])) {
                                                                                fastFillsReplacingSlowFills.push(relayDataHash);
                                                                            }
                                                                            _a.label = 2;
                                                                        case 2: return [3, 4];
                                                                        case 3:
                                                                            this.logger.debug({
                                                                                at: "BundleDataClient#loadData",
                                                                                message: "Duplicate fill detected",
                                                                                fill: (0, utils_1.convertFillParamsToBytes32)(fill),
                                                                            });
                                                                            throw new Error("Duplicate fill detected");
                                                                        case 4: return [2];
                                                                        case 5:
                                                                            v3RelayHashes[relayDataHash] = {
                                                                                deposits: undefined,
                                                                                fill: fill,
                                                                                slowFillRequest: undefined,
                                                                            };
                                                                            if (fill.blockNumber < destinationChainBlockRange[0]) {
                                                                                return [2];
                                                                            }
                                                                            return [4, (0, utils_1.queryHistoricalDepositForFill)(originClient, fill)];
                                                                        case 6:
                                                                            historicalDeposit = _a.sent();
                                                                            if (!historicalDeposit.found) {
                                                                                bundleInvalidFillsV3.push(fill);
                                                                                return [2];
                                                                            }
                                                                            matchedDeposit = historicalDeposit.deposit;
                                                                            if (matchedDeposit.blockNumber > originChainBlockRange[1]) {
                                                                                bundleInvalidFillsV3.push(fill);
                                                                                return [2];
                                                                            }
                                                                            v3RelayHashes[relayDataHash].deposits = [matchedDeposit];
                                                                            if ((0, SpokePoolClient_1.isEVMSpokePoolClient)(destinationClient)) {
                                                                                provider = destinationClient.spokePool.provider;
                                                                            }
                                                                            else if ((0, SpokePoolClient_1.isSVMSpokePoolClient)(destinationClient)) {
                                                                                provider = destinationClient.svmEventsClient.getRpc();
                                                                            }
                                                                            return [4, (0, utils_2.verifyFillRepayment)(fill, provider, matchedDeposit, this.clients.hubPoolClient, bundleEndBlockForMainnet)];
                                                                        case 7:
                                                                            fillToRefund = _a.sent();
                                                                            if (!(0, utils_1.isDefined)(fillToRefund)) {
                                                                                bundleUnrepayableFillsV3.push(fill);
                                                                            }
                                                                            else {
                                                                                (0, assert_1.default)((0, utils_1.getRelayEventKey)(matchedDeposit) === relayDataHash, "Relay hashes should match.");
                                                                                validatedBundleV3Fills.push(tslib_1.__assign(tslib_1.__assign({}, fillToRefund), { quoteTimestamp: matchedDeposit.quoteTimestamp }));
                                                                                v3RelayHashes[relayDataHash].fill = fillToRefund;
                                                                            }
                                                                            if (fill.relayExecutionInfo.fillType === interfaces_1.FillType.ReplacedSlowFill &&
                                                                                _canCreateSlowFillLeaf(matchedDeposit)) {
                                                                                fastFillsReplacingSlowFills.push(relayDataHash);
                                                                            }
                                                                            return [2];
                                                                    }
                                                                });
                                                            }); })];
                                                    case 1:
                                                        _h.sent();
                                                        return [4, (0, utils_1.forEachAsync)(destinationClient
                                                                .getSlowFillRequestsForOriginChain(originChainId)
                                                                .filter(function (request) {
                                                                return request.blockNumber <= destinationChainBlockRange[1] &&
                                                                    !(0, utils_1.isZeroValueFillOrSlowFillRequest)(request) &&
                                                                    !(0, utils_1.invalidOutputToken)(request);
                                                            }), function (slowFillRequest) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
                                                                var relayDataHash, _a, deposits, fill, matchedDeposit_1, historicalDeposit, matchedDeposit;
                                                                return tslib_1.__generator(this, function (_b) {
                                                                    switch (_b.label) {
                                                                        case 0:
                                                                            relayDataHash = (0, utils_1.getRelayEventKey)(slowFillRequest);
                                                                            if (v3RelayHashes[relayDataHash]) {
                                                                                if (!v3RelayHashes[relayDataHash].slowFillRequest) {
                                                                                    v3RelayHashes[relayDataHash].slowFillRequest = slowFillRequest;
                                                                                    _a = v3RelayHashes[relayDataHash], deposits = _a.deposits, fill = _a.fill;
                                                                                    if (fill) {
                                                                                        return [2];
                                                                                    }
                                                                                    (0, assert_1.default)((0, utils_1.isDefined)(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
                                                                                    matchedDeposit_1 = deposits[0];
                                                                                    if (slowFillRequest.blockNumber >= destinationChainBlockRange[0] &&
                                                                                        _canCreateSlowFillLeaf(matchedDeposit_1) &&
                                                                                        !_depositIsExpired(matchedDeposit_1)) {
                                                                                        validatedBundleSlowFills.push(matchedDeposit_1);
                                                                                    }
                                                                                }
                                                                                else {
                                                                                    this.logger.debug({
                                                                                        at: "BundleDataClient#loadData",
                                                                                        message: "Duplicate slow fill request detected",
                                                                                        slowFillRequest: slowFillRequest,
                                                                                    });
                                                                                    throw new Error("Duplicate slow fill request detected.");
                                                                                }
                                                                                return [2];
                                                                            }
                                                                            v3RelayHashes[relayDataHash] = {
                                                                                deposits: undefined,
                                                                                fill: undefined,
                                                                                slowFillRequest: slowFillRequest,
                                                                            };
                                                                            if (slowFillRequest.blockNumber < destinationChainBlockRange[0]) {
                                                                                return [2];
                                                                            }
                                                                            return [4, (0, utils_1.queryHistoricalDepositForFill)(originClient, slowFillRequest)];
                                                                        case 1:
                                                                            historicalDeposit = _b.sent();
                                                                            if (!historicalDeposit.found) {
                                                                                bundleInvalidSlowFillRequests.push(slowFillRequest);
                                                                                return [2];
                                                                            }
                                                                            matchedDeposit = historicalDeposit.deposit;
                                                                            if (matchedDeposit.blockNumber > originChainBlockRange[1]) {
                                                                                bundleInvalidSlowFillRequests.push(slowFillRequest);
                                                                                return [2];
                                                                            }
                                                                            (0, assert_1.default)((0, utils_1.getRelayEventKey)(matchedDeposit) === relayDataHash, "Deposit relay hashes should match.");
                                                                            v3RelayHashes[relayDataHash].deposits = [matchedDeposit];
                                                                            if (!_canCreateSlowFillLeaf(matchedDeposit) || _depositIsExpired(matchedDeposit)) {
                                                                                return [2];
                                                                            }
                                                                            validatedBundleSlowFills.push(matchedDeposit);
                                                                            return [2];
                                                                    }
                                                                });
                                                            }); })];
                                                    case 2:
                                                        _h.sent();
                                                        return [4, (0, utils_1.mapAsync)(bundleDepositHashes, function (depositHash) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
                                                                var _a, relayDataHash, index, _b, deposits, fill, slowFillRequest, deposit, provider, fillToRefund, fillStatus, prefill, provider, verifiedFill;
                                                                return tslib_1.__generator(this, function (_c) {
                                                                    switch (_c.label) {
                                                                        case 0:
                                                                            _a = decodeBundleDepositHash(depositHash), relayDataHash = _a.relayDataHash, index = _a.index;
                                                                            _b = v3RelayHashes[relayDataHash], deposits = _b.deposits, fill = _b.fill, slowFillRequest = _b.slowFillRequest;
                                                                            if (!deposits || deposits.length === 0) {
                                                                                throw new Error("Deposits should exist in relay hash dictionary.");
                                                                            }
                                                                            deposit = deposits[index];
                                                                            if (!deposit)
                                                                                throw new Error("Deposit should exist in relay hash dictionary.");
                                                                            if (deposit.originChainId !== originChainId || deposit.destinationChainId !== destinationChainId) {
                                                                                return [2];
                                                                            }
                                                                            if (!fill) return [3, 3];
                                                                            if (!(fill.blockNumber < destinationChainBlockRange[0])) return [3, 2];
                                                                            provider = void 0;
                                                                            if ((0, SpokePoolClient_1.isEVMSpokePoolClient)(destinationClient)) {
                                                                                provider = destinationClient.spokePool.provider;
                                                                            }
                                                                            else if ((0, SpokePoolClient_1.isSVMSpokePoolClient)(destinationClient)) {
                                                                                provider = destinationClient.svmEventsClient.getRpc();
                                                                            }
                                                                            return [4, (0, utils_2.verifyFillRepayment)(fill, provider, deposits[0], this.clients.hubPoolClient, bundleEndBlockForMainnet)];
                                                                        case 1:
                                                                            fillToRefund = _c.sent();
                                                                            if (!(0, utils_1.isDefined)(fillToRefund)) {
                                                                                bundleUnrepayableFillsV3.push(fill);
                                                                            }
                                                                            else if (!(0, utils_1.isSlowFill)(fill)) {
                                                                                v3RelayHashes[relayDataHash].fill = fillToRefund;
                                                                                validatedBundleV3Fills.push(tslib_1.__assign(tslib_1.__assign({}, fillToRefund), { quoteTimestamp: deposit.quoteTimestamp }));
                                                                            }
                                                                            else {
                                                                                updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
                                                                            }
                                                                            _c.label = 2;
                                                                        case 2: return [2];
                                                                        case 3:
                                                                            if (slowFillRequest) {
                                                                                if (_depositIsExpired(deposit)) {
                                                                                    updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
                                                                                }
                                                                                else if (slowFillRequest.blockNumber < destinationChainBlockRange[0] &&
                                                                                    _canCreateSlowFillLeaf(deposit) &&
                                                                                    validatedBundleSlowFills.every(function (d) { return (0, utils_1.getRelayEventKey)(d) !== relayDataHash; })) {
                                                                                    validatedBundleSlowFills.push(deposit);
                                                                                }
                                                                                return [2];
                                                                            }
                                                                            return [4, _getFillStatusForDeposit(deposit, destinationChainBlockRange[1])];
                                                                        case 4:
                                                                            fillStatus = _c.sent();
                                                                            if (!(fillStatus === interfaces_1.FillStatus.Filled)) return [3, 7];
                                                                            return [4, this.findMatchingFillEvent(deposit, destinationClient)];
                                                                        case 5:
                                                                            prefill = _c.sent();
                                                                            (0, assert_1.default)((0, utils_1.isDefined)(prefill), "findFillEvent# Cannot find prefill: ".concat(relayDataHash));
                                                                            (0, assert_1.default)((0, utils_1.getRelayEventKey)(prefill) === relayDataHash, "Relay hashes should match.");
                                                                            provider = void 0;
                                                                            if ((0, SpokePoolClient_1.isEVMSpokePoolClient)(destinationClient)) {
                                                                                provider = destinationClient.spokePool.provider;
                                                                            }
                                                                            else if ((0, SpokePoolClient_1.isSVMSpokePoolClient)(destinationClient)) {
                                                                                provider = destinationClient.svmEventsClient.getRpc();
                                                                            }
                                                                            return [4, (0, utils_2.verifyFillRepayment)(prefill, provider, deposit, this.clients.hubPoolClient, bundleEndBlockForMainnet)];
                                                                        case 6:
                                                                            verifiedFill = _c.sent();
                                                                            if (!(0, utils_1.isDefined)(verifiedFill)) {
                                                                                bundleUnrepayableFillsV3.push(prefill);
                                                                            }
                                                                            else if (!(0, utils_1.isSlowFill)(verifiedFill)) {
                                                                                validatedBundleV3Fills.push(tslib_1.__assign(tslib_1.__assign({}, verifiedFill), { quoteTimestamp: deposit.quoteTimestamp }));
                                                                            }
                                                                            else {
                                                                                updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
                                                                            }
                                                                            return [3, 8];
                                                                        case 7:
                                                                            if (_depositIsExpired(deposit)) {
                                                                                updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
                                                                            }
                                                                            else if (fillStatus === interfaces_1.FillStatus.RequestedSlowFill &&
                                                                                validatedBundleSlowFills.every(function (d) { return (0, utils_1.getRelayEventKey)(d) !== relayDataHash; })) {
                                                                                if (_canCreateSlowFillLeaf(deposit)) {
                                                                                    validatedBundleSlowFills.push(deposit);
                                                                                }
                                                                            }
                                                                            _c.label = 8;
                                                                        case 8: return [2];
                                                                    }
                                                                });
                                                            }); })];
                                                    case 3:
                                                        _h.sent();
                                                        fastFillsReplacingSlowFills.forEach(function (relayDataHash) {
                                                            var _a = v3RelayHashes[relayDataHash], deposits = _a.deposits, slowFillRequest = _a.slowFillRequest, fill = _a.fill;
                                                            (0, assert_1.default)((fill === null || fill === void 0 ? void 0 : fill.relayExecutionInfo.fillType) === interfaces_1.FillType.ReplacedSlowFill, "Fill type should be ReplacedSlowFill.");
                                                            if (!deposits || deposits.length < 1) {
                                                                throw new Error("Deposit should exist in relay hash dictionary.");
                                                            }
                                                            (0, assert_1.default)(_canCreateSlowFillLeaf(deposits[0]), "fastFillsReplacingSlowFills should contain only deposits that can be slow filled");
                                                            var destinationBlockRange = (0, utils_1.getBlockRangeForChain)(blockRangesForChains, destinationChainId, chainIds);
                                                            var originBlockRange = (0, utils_1.getBlockRangeForChain)(blockRangesForChains, originChainId, chainIds);
                                                            var matchedDeposit = deposits[0];
                                                            if (matchedDeposit.blockNumber < originBlockRange[0] &&
                                                                (!slowFillRequest || slowFillRequest.blockNumber < destinationBlockRange[0])) {
                                                                validatedBundleUnexecutableSlowFills.push(deposits[0]);
                                                            }
                                                        });
                                                        return [2];
                                                }
                                            });
                                        };
                                        _f = 0, allFillChainIds_2 = allFillChainIds;
                                        _g.label = 1;
                                    case 1:
                                        if (!(_f < allFillChainIds_2.length)) return [3, 4];
                                        destinationChainId = allFillChainIds_2[_f];
                                        return [5, _loop_3(destinationChainId)];
                                    case 2:
                                        _g.sent();
                                        _g.label = 3;
                                    case 3:
                                        _f++;
                                        return [3, 1];
                                    case 4: return [2];
                                }
                            });
                        };
                        _b = 0, allFillChainIds_1 = allFillChainIds;
                        _d.label = 4;
                    case 4:
                        if (!(_b < allFillChainIds_1.length)) return [3, 7];
                        originChainId = allFillChainIds_1[_b];
                        return [5, _loop_2(originChainId)];
                    case 5:
                        _d.sent();
                        _d.label = 6;
                    case 6:
                        _b++;
                        return [3, 4];
                    case 7:
                        this.logger.debug({
                            at: "BundleDataClient#loadData",
                            message: "Processed ".concat(fillCounter, " fills in ").concat(performance.now() - start, "ms."),
                        });
                        start = performance.now();
                        return [4, (0, utils_1.forEachAsync)(olderDepositHashes, function (depositHash) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
                                var _a, relayDataHash, index, _b, deposits, slowFillRequest, fill, deposit, destinationChainId, destinationBlockRange, fillStatus;
                                return tslib_1.__generator(this, function (_c) {
                                    switch (_c.label) {
                                        case 0:
                                            _a = decodeBundleDepositHash(depositHash), relayDataHash = _a.relayDataHash, index = _a.index;
                                            _b = v3RelayHashes[relayDataHash], deposits = _b.deposits, slowFillRequest = _b.slowFillRequest, fill = _b.fill;
                                            if (!deposits || deposits.length < 1) {
                                                throw new Error("Deposit should exist in relay hash dictionary.");
                                            }
                                            deposit = deposits[index];
                                            destinationChainId = deposit.destinationChainId;
                                            if (_isChainPaused(destinationChainId)) {
                                                return [2];
                                            }
                                            destinationBlockRange = (0, utils_1.getBlockRangeForChain)(blockRangesForChains, destinationChainId, chainIds);
                                            if (!(!fill &&
                                                (0, utils_1.isDefined)(deposit) &&
                                                _depositIsExpired(deposit) &&
                                                deposit.fillDeadline >= bundleBlockTimestamps[destinationChainId][0] &&
                                                spokePoolClients[destinationChainId] !== undefined)) return [3, 2];
                                            return [4, _getFillStatusForDeposit(deposit, destinationBlockRange[1])];
                                        case 1:
                                            fillStatus = _c.sent();
                                            if (fillStatus !== interfaces_1.FillStatus.Filled) {
                                                updateExpiredDepositsV3(expiredDepositsToRefundV3, deposit);
                                            }
                                            if (fillStatus !== interfaces_1.FillStatus.RequestedSlowFill || !_canCreateSlowFillLeaf(deposit)) {
                                                return [2];
                                            }
                                            if (!slowFillRequest || slowFillRequest.blockNumber < destinationBlockRange[0]) {
                                                validatedBundleUnexecutableSlowFills.push(deposit);
                                            }
                                            _c.label = 2;
                                        case 2: return [2];
                                    }
                                });
                            }); })];
                    case 8:
                        _d.sent();
                        start = performance.now();
                        promises = [
                            validatedBundleV3Fills.length > 0
                                ? this.clients.hubPoolClient.batchComputeRealizedLpFeePct(validatedBundleV3Fills.map(function (fill) {
                                    var deposits = v3RelayHashes[(0, utils_1.getRelayEventKey)(fill)].deposits;
                                    (0, assert_1.default)((0, utils_1.isDefined)(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
                                    var matchedDeposit = deposits[0];
                                    (0, assert_1.default)((0, utils_1.isDefined)(matchedDeposit), "Deposit should exist in relay hash dictionary.");
                                    var paymentChainId = (0, utils_2.getRefundInformationFromFill)(tslib_1.__assign(tslib_1.__assign({}, fill), { fromLiteChain: matchedDeposit.fromLiteChain }), _this.clients.hubPoolClient, bundleEndBlockForMainnet).chainToSendRefundTo;
                                    return tslib_1.__assign(tslib_1.__assign({}, fill), { paymentChainId: paymentChainId });
                                }))
                                : [],
                            validatedBundleSlowFills.length > 0
                                ? this.clients.hubPoolClient.batchComputeRealizedLpFeePct(validatedBundleSlowFills.map(function (deposit) {
                                    return tslib_1.__assign(tslib_1.__assign({}, deposit), { paymentChainId: deposit.destinationChainId });
                                }))
                                : [],
                            validatedBundleUnexecutableSlowFills.length > 0
                                ? this.clients.hubPoolClient.batchComputeRealizedLpFeePct(validatedBundleUnexecutableSlowFills.map(function (deposit) {
                                    return tslib_1.__assign(tslib_1.__assign({}, deposit), { paymentChainId: deposit.destinationChainId });
                                }))
                                : [],
                        ];
                        return [4, Promise.all(promises)];
                    case 9:
                        _c = _d.sent(), v3FillLpFees = _c[0], v3SlowFillLpFees = _c[1], v3UnexecutableSlowFillLpFees = _c[2];
                        this.logger.debug({
                            at: "BundleDataClient#loadData",
                            message: "Computed batch async LP fees in ".concat(performance.now() - start, "ms."),
                        });
                        v3FillLpFees.forEach(function (_a, idx) {
                            var realizedLpFeePct = _a.realizedLpFeePct;
                            var fill = validatedBundleV3Fills[idx];
                            var deposits = v3RelayHashes[(0, utils_1.getRelayEventKey)(fill)].deposits;
                            (0, assert_1.default)((0, utils_1.isDefined)(deposits) && deposits.length > 0, "Deposit should exist in relay hash dictionary.");
                            var associatedDeposit = deposits[0];
                            (0, assert_1.default)((0, utils_1.isDefined)(associatedDeposit), "Deposit should exist in relay hash dictionary.");
                            var _b = (0, utils_2.getRefundInformationFromFill)(tslib_1.__assign(tslib_1.__assign({}, fill), { fromLiteChain: associatedDeposit.fromLiteChain }), _this.clients.hubPoolClient, bundleEndBlockForMainnet), chainToSendRefundTo = _b.chainToSendRefundTo, repaymentToken = _b.repaymentToken;
                            updateBundleFillsV3(bundleFillsV3, fill, realizedLpFeePct, chainToSendRefundTo, repaymentToken, fill.relayer);
                        });
                        v3SlowFillLpFees.forEach(function (_a, idx) {
                            var lpFeePct = _a.realizedLpFeePct;
                            var deposit = validatedBundleSlowFills[idx];
                            var relayDataHash = (0, utils_1.getRelayEventKey)(deposit);
                            if (validatedBundleSlowFills.slice(0, idx).some(function (d) { return (0, utils_1.getRelayEventKey)(d) === relayDataHash; })) {
                                return;
                            }
                            (0, assert_1.default)(!_depositIsExpired(deposit), "Cannot create slow fill leaf for expired deposit.");
                            updateBundleSlowFills(bundleSlowFillsV3, tslib_1.__assign(tslib_1.__assign({}, deposit), { lpFeePct: lpFeePct }));
                        });
                        v3UnexecutableSlowFillLpFees.forEach(function (_a, idx) {
                            var lpFeePct = _a.realizedLpFeePct;
                            var deposit = validatedBundleUnexecutableSlowFills[idx];
                            updateBundleExcessSlowFills(unexecutableSlowFills, tslib_1.__assign(tslib_1.__assign({}, deposit), { lpFeePct: lpFeePct }));
                        });
                        v3SpokeEventsReadable = (0, utils_2.prettyPrintV3SpokePoolEvents)(bundleDepositsV3, bundleFillsV3, bundleSlowFillsV3, expiredDepositsToRefundV3, unexecutableSlowFills);
                        if (bundleInvalidFillsV3.length > 0) {
                            invalidFillsWithPartialMatchedDeposits_1 = [];
                            preFillsForNextBundle_1 = [];
                            unknownReasonInvalidFills_1 = [];
                            bundleInvalidFillsV3.forEach(function (fill) {
                                var originClient = spokePoolClients[fill.originChainId];
                                var fullyMatchedDeposit = originClient.getDepositForFill(fill);
                                if (!(0, utils_1.isDefined)(fullyMatchedDeposit)) {
                                    var partiallyMatchedDeposit = originClient.getDeposit(fill.depositId);
                                    if ((0, utils_1.isDefined)(partiallyMatchedDeposit)) {
                                        invalidFillsWithPartialMatchedDeposits_1.push(fill);
                                    }
                                    else {
                                        unknownReasonInvalidFills_1.push(fill);
                                    }
                                }
                                else {
                                    var originBundleBlockRange = (0, utils_1.getBlockRangeForChain)(blockRangesForChains, fill.originChainId, chainIds);
                                    if (fullyMatchedDeposit.blockNumber <= originBundleBlockRange[1]) {
                                        throw new Error("Detected invalid fill that matches fully with a deposit in current or prior bundle");
                                    }
                                    preFillsForNextBundle_1.push(fill);
                                }
                            });
                            this.logger.debug({
                                at: "BundleDataClient#loadData",
                                message: "Finished loading V3 spoke pool data and found some invalid fills in range",
                                blockRangesForChains: blockRangesForChains,
                                invalidFillsWithPartialMatchedDeposits: invalidFillsWithPartialMatchedDeposits_1.map(function (invalidFill) {
                                    return (0, utils_1.convertFillParamsToBytes32)(invalidFill);
                                }),
                                preFillsForNextBundle: preFillsForNextBundle_1.map(function (preFill) { return (0, utils_1.convertFillParamsToBytes32)(preFill); }),
                                unknownReasonInvalidFills: unknownReasonInvalidFills_1.map(function (invalidFill) {
                                    return (0, utils_1.convertFillParamsToBytes32)(invalidFill);
                                }),
                            });
                        }
                        if (bundleUnrepayableFillsV3.length > 0) {
                            this.logger.debug({
                                at: "BundleDataClient#loadData",
                                message: "Finished loading V3 spoke pool data and found some unrepayable fills in range",
                                blockRangesForChains: blockRangesForChains,
                                bundleUnrepayableFillsV3: bundleUnrepayableFillsV3,
                            });
                        }
                        if (bundleInvalidSlowFillRequests.length > 0) {
                            this.logger.debug({
                                at: "BundleDataClient#loadData",
                                message: "Finished loading V3 spoke pool data and found some invalid slow fill requests in range",
                                blockRangesForChains: blockRangesForChains,
                                bundleInvalidSlowFillRequests: bundleInvalidSlowFillRequests,
                            });
                        }
                        this.logger.debug({
                            at: "BundleDataClient#loadDataFromScratch",
                            message: "Computed bundle data in ".concat(Math.round(performance.now() - start) / 1000, "s."),
                            blockRangesForChains: JSON.stringify(blockRangesForChains),
                            v3SpokeEventsReadable: v3SpokeEventsReadable,
                        });
                        return [2, {
                                bundleDepositsV3: bundleDepositsV3,
                                expiredDepositsToRefundV3: expiredDepositsToRefundV3,
                                bundleFillsV3: bundleFillsV3,
                                unexecutableSlowFills: unexecutableSlowFills,
                                bundleSlowFillsV3: bundleSlowFillsV3,
                            }];
                }
            });
        });
    };
    BundleDataClient.prototype.findMatchingFillEvent = function (deposit, spokePoolClient) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (!(0, SpokePoolClient_1.isSVMSpokePoolClient)(spokePoolClient)) return [3, 2];
                        return [4, (0, svm_1.findFillEvent)(deposit, spokePoolClient.chainId, spokePoolClient.svmEventsClient, spokePoolClient.deploymentBlock, spokePoolClient.latestHeightSearched, spokePoolClient.logger)];
                    case 1: return [2, _a.sent()];
                    case 2:
                        if (!(0, SpokePoolClient_1.isEVMSpokePoolClient)(spokePoolClient)) return [3, 4];
                        return [4, (0, evm_1.findFillEvent)(spokePoolClient.spokePool, deposit, spokePoolClient.deploymentBlock, spokePoolClient.latestHeightSearched)];
                    case 3: return [2, _a.sent()];
                    case 4: throw new Error("Unsupported spoke pool client type");
                }
            });
        });
    };
    BundleDataClient.prototype.getBundleBlockTimestamps = function (chainIds, blockRangesForChains, spokePoolClients) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var _a, _b;
            var _this = this;
            return tslib_1.__generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        _b = (_a = Object).fromEntries;
                        return [4, (0, utils_1.mapAsync)(chainIds, function (chainId, index) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
                                var blockRangeForChain, _startBlockForChain, _endBlockForChain, spokePoolClient, startBlockForChain, endBlockForChain, _a, startTime, _endTime, _b, endBlockDelta, endTime;
                                return tslib_1.__generator(this, function (_c) {
                                    switch (_c.label) {
                                        case 0:
                                            blockRangeForChain = blockRangesForChains[index];
                                            if (!(0, utils_1.isDefined)(blockRangeForChain) ||
                                                (0, utils_2.isChainDisabledAtBlock)(chainId, blockRangesForChains[0][0], this.clients.configStoreClient)) {
                                                return [2];
                                            }
                                            _startBlockForChain = blockRangeForChain[0], _endBlockForChain = blockRangeForChain[1];
                                            spokePoolClient = spokePoolClients[chainId];
                                            if (!(0, utils_1.isDefined)(spokePoolClient)) {
                                                return [2];
                                            }
                                            startBlockForChain = Math.min(_startBlockForChain, spokePoolClient.latestHeightSearched);
                                            endBlockForChain = Math.min(_endBlockForChain + 1, spokePoolClient.latestHeightSearched);
                                            return [4, spokePoolClient.getTimestampForBlock(startBlockForChain)];
                                        case 1:
                                            _b = [
                                                _c.sent()
                                            ];
                                            return [4, spokePoolClient.getTimestampForBlock(endBlockForChain)];
                                        case 2:
                                            _a = _b.concat([
                                                _c.sent()
                                            ]), startTime = _a[0], _endTime = _a[1];
                                            endBlockDelta = endBlockForChain > startBlockForChain ? 1 : 0;
                                            endTime = Math.max(0, _endTime - endBlockDelta);
                                            (0, assert_1.default)(endTime >= startTime, "End time for block ".concat(endBlockForChain, " should be greater than start time for block ").concat(startBlockForChain, ": ").concat(endTime, " >= ").concat(startTime, "."));
                                            (0, assert_1.default)(startBlockForChain === 0 || startTime > 0, "Start timestamp must be greater than 0 if the start block is greater than 0.");
                                            return [2, [chainId, [startTime, endTime]]];
                                    }
                                });
                            }); })];
                    case 1: return [2, _b.apply(_a, [(_c.sent()).filter(utils_1.isDefined)])];
                }
            });
        });
    };
    return BundleDataClient;
}());
exports.BundleDataClient = BundleDataClient;
//# sourceMappingURL=BundleDataClient.js.map