"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fillStatusArray = exports.getTimestampForBlock = exports.populateV3Relay = void 0;
exports.getTimeAt = getTimeAt;
exports.getMaxFillDeadlineInRange = getMaxFillDeadlineInRange;
exports.getDepositIdAtBlock = getDepositIdAtBlock;
exports.findDepositBlock = findDepositBlock;
exports.relayFillStatus = relayFillStatus;
exports.findFillBlock = findFillBlock;
exports.findFillEvent = findFillEvent;
const tslib_1 = require("tslib");
const assert_1 = tslib_1.__importDefault(require("assert"));
const constants_1 = require("../../constants");
const interfaces_1 = require("../../interfaces");
const UpgradeUtils_1 = require("../evm/UpgradeUtils");
const SpokeUtils_1 = require("../evm/SpokeUtils");
const utils_1 = require("../../utils");
var SpokeUtils_2 = require("../evm/SpokeUtils");
Object.defineProperty(exports, "populateV3Relay", { enumerable: true, get: function () { return SpokeUtils_2.populateV3Relay; } });
Object.defineProperty(exports, "getTimestampForBlock", { enumerable: true, get: function () { return SpokeUtils_2.getTimestampForBlock; } });
Object.defineProperty(exports, "fillStatusArray", { enumerable: true, get: function () { return SpokeUtils_2.fillStatusArray; } });
async function getTimeAt(spokePool, blockNumber) {
    const block = await spokePool.provider.getBlock(blockNumber);
    return block.timestamp;
}
const FALLBACK_FILL_DEADLINE_BUFFER = 21600;
async function getMaxFillDeadlineInRange(spokePool, startBlock, endBlock) {
    const [fillDeadlineBuffer, upgrades] = await Promise.all([
        spokePool.fillDeadlineBuffer(),
        (0, UpgradeUtils_1.get1967Upgrades)(spokePool, startBlock, endBlock),
    ]);
    const currentBuffer = Number(fillDeadlineBuffer);
    if (upgrades.length > 0) {
        return Math.max(currentBuffer, FALLBACK_FILL_DEADLINE_BUFFER);
    }
    return currentBuffer;
}
function getDepositIdAtBlock(_contract, _blockTag) {
    throw new Error("getDepositIdAtBlock: not supported on TVM");
}
async function findDepositBlock(spokePool, depositId, lowBlock, highBlock) {
    if ((0, utils_1.isUnsafeDepositId)(depositId)) {
        throw new Error(`Cannot search for depositId ${depositId}`);
    }
    highBlock ??= await spokePool.provider.getBlockNumber();
    (0, assert_1.default)(highBlock > lowBlock, `Block numbers out of range (${lowBlock} >= ${highBlock})`);
    const events = await (0, utils_1.paginatedEventQuery)(spokePool, spokePool.filters.FundsDeposited(null, null, null, null, null, depositId), { from: lowBlock, to: highBlock });
    if (events.length === 0) {
        return undefined;
    }
    return events[0].blockNumber;
}
async function relayFillStatus(spokePool, relayData, blockTag = "latest", destinationChainId) {
    if (blockTag === "latest") {
        return (0, SpokeUtils_1.relayFillStatus)(spokePool, relayData, blockTag, destinationChainId);
    }
    destinationChainId ??= await spokePool.chainId();
    (0, assert_1.default)((0, utils_1.isDefined)(destinationChainId));
    const hash = (0, utils_1.getRelayDataHash)(relayData, destinationChainId);
    const latestStatus = Number(await spokePool.fillStatuses(hash));
    if (latestStatus === interfaces_1.FillStatus.Unfilled) {
        return interfaces_1.FillStatus.Unfilled;
    }
    const fromBlock = 0;
    const toBlock = Number(blockTag);
    const fillEvents = await (0, utils_1.paginatedEventQuery)(spokePool, spokePool.filters.FilledRelay(null, null, null, null, null, relayData.originChainId, relayData.depositId), { from: fromBlock, to: toBlock });
    if (fillEvents.length > 0) {
        return interfaces_1.FillStatus.Filled;
    }
    if (latestStatus >= interfaces_1.FillStatus.RequestedSlowFill) {
        const slowFillEvents = await (0, utils_1.paginatedEventQuery)(spokePool, spokePool.filters.RequestedSlowFill(null, null, null, null, relayData.originChainId, relayData.depositId), { from: fromBlock, to: toBlock });
        if (slowFillEvents.length > 0) {
            return interfaces_1.FillStatus.RequestedSlowFill;
        }
    }
    return interfaces_1.FillStatus.Unfilled;
}
async function findFillBlock(spokePool, relayData, lowBlockNumber, highBlockNumber) {
    const { provider } = spokePool;
    highBlockNumber ??= await provider.getBlockNumber();
    (0, assert_1.default)(highBlockNumber > lowBlockNumber, `Block numbers out of range (${lowBlockNumber} >= ${highBlockNumber})`);
    const events = await (0, utils_1.paginatedEventQuery)(spokePool, spokePool.filters.FilledRelay(null, null, null, null, null, relayData.originChainId, relayData.depositId), { from: lowBlockNumber, to: highBlockNumber });
    if (events.length === 0) {
        return undefined;
    }
    return events[0].blockNumber;
}
async function findFillEvent(spokePool, relayData, lowBlockNumber, highBlockNumber) {
    const { provider } = spokePool;
    highBlockNumber ??= await provider.getBlockNumber();
    const events = await (0, utils_1.paginatedEventQuery)(spokePool, spokePool.filters.FilledRelay(null, null, null, null, null, relayData.originChainId, relayData.depositId), { from: lowBlockNumber, to: highBlockNumber });
    if (events.length === 0) {
        return undefined;
    }
    const event = events[0];
    const destinationChainId = Object.values(constants_1.CHAIN_IDs).includes(relayData.originChainId)
        ? (await spokePool.provider.getNetwork()).chainId
        : Number(await spokePool.chainId());
    return (0, utils_1.unpackFillEvent)((0, utils_1.spreadEventWithBlockNumber)(event), destinationChainId);
}
//# sourceMappingURL=SpokeUtils.js.map