"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CCTPV2_FINALITY_THRESHOLD_FAST = exports.CCTPV2_FINALITY_THRESHOLD_STANDARD = void 0;
exports.cctpAddressToBytes32 = cctpAddressToBytes32;
exports.cctpBytes32ToAddress = cctpBytes32ToAddress;
exports.getCctpDomainForChainId = getCctpDomainForChainId;
exports.getCctpDestinationChainFromDomain = getCctpDestinationChainFromDomain;
exports.isDepositForBurnEvent = isDepositForBurnEvent;
exports.fetchCctpV2Attestations = fetchCctpV2Attestations;
exports.getPendingAttestationStatus = getPendingAttestationStatus;
exports.hasCCTPMessageBeenProcessedEvm = hasCCTPMessageBeenProcessedEvm;
exports.getV2FastBurnAllowance = getV2FastBurnAllowance;
exports.getV2MinTransferFees = getV2MinTransferFees;
exports.fetchAttestationsForTxn = fetchAttestationsForTxn;
exports.getMessageSentVersion = getMessageSentVersion;
exports.getDepositForBurnVersion = getDepositForBurnVersion;
const tslib_1 = require("tslib");
const constants_1 = require("@across-protocol/constants");
const FetchUtils_1 = require("./FetchUtils");
const ethers_1 = require("ethers");
const TypeGuards_1 = require("./TypeGuards");
const NetworkUtils_1 = require("./NetworkUtils");
const assert_1 = tslib_1.__importDefault(require("assert"));
const BigNumberUtils_1 = require("./BigNumberUtils");
exports.CCTPV2_FINALITY_THRESHOLD_STANDARD = 2000;
exports.CCTPV2_FINALITY_THRESHOLD_FAST = 1000;
const CCTP_MESSAGE_SENT_TOPIC_HASH = ethers_1.ethers.utils.id("MessageSent(bytes)");
const CCTP_DEPOSIT_FOR_BURN_TOPIC_HASH_V1 = ethers_1.ethers.utils.id("DepositForBurn(uint64,address,uint256,address,bytes32,uint32,bytes32,bytes32)");
const CCTP_DEPOSIT_FOR_BURN_TOPIC_HASH_V2 = ethers_1.ethers.utils.id("DepositForBurn(address,uint256,address,bytes32,uint32,bytes32,bytes32,uint256,uint32,bytes)");
function cctpAddressToBytes32(address) {
    return ethers_1.ethers.utils.hexZeroPad(address, 32);
}
function cctpBytes32ToAddress(bytes32) {
    return ethers_1.ethers.utils.getAddress(ethers_1.ethers.utils.hexDataSlice(bytes32, 12));
}
function getCctpDomainForChainId(chainId) {
    const cctpDomain = constants_1.PUBLIC_NETWORKS[chainId]?.cctpDomain;
    if (!(0, TypeGuards_1.isDefined)(cctpDomain) || cctpDomain === constants_1.CCTP_NO_DOMAIN) {
        throw new Error(`No CCTP domain found for chainId: ${chainId}`);
    }
    return cctpDomain;
}
function getCctpDestinationChainFromDomain(domain, productionNetworks) {
    if (domain === constants_1.CCTP_NO_DOMAIN) {
        throw new Error("Cannot input CCTP_NO_DOMAIN to getCctpDestinationChainFromDomain");
    }
    const networks = productionNetworks ? constants_1.PRODUCTION_NETWORKS : constants_1.TEST_NETWORKS;
    const otherNetworks = productionNetworks ? constants_1.TEST_NETWORKS : constants_1.PRODUCTION_NETWORKS;
    const chainId = Object.keys(networks).find((key) => networks[Number(key)].cctpDomain.toString() === domain.toString());
    if (!(0, TypeGuards_1.isDefined)(chainId)) {
        const chainId = Object.keys(otherNetworks).find((key) => otherNetworks[Number(key)].cctpDomain.toString() === domain.toString());
        if (!(0, TypeGuards_1.isDefined)(chainId)) {
            throw new Error(`No chainId found for domain: ${domain}`);
        }
        return parseInt(chainId);
    }
    return parseInt(chainId);
}
function isDepositForBurnEvent(event) {
    return "amount" in event && "mintRecipient" in event && "burnToken" in event;
}
async function fetchCctpV2Attestations(depositForBurnTxnHashes, sourceChainId) {
    const sourceDomainId = getCctpDomainForChainId(sourceChainId);
    const isMainnet = (0, NetworkUtils_1.chainIsProd)(sourceChainId);
    const attestationResponses = {};
    const chunkSize = process.env.CCTP_API_REQUEST_CHUNK_SIZE ? parseInt(process.env.CCTP_API_REQUEST_CHUNK_SIZE) : 8;
    for (let i = 0; i < depositForBurnTxnHashes.length; i += chunkSize) {
        const chunk = depositForBurnTxnHashes.slice(i, i + chunkSize);
        await Promise.all(chunk.map(async (txHash) => {
            const attestations = await fetchAttestationsForTxn(sourceDomainId, txHash, isMainnet);
            attestationResponses[txHash] = attestations;
        }));
        if (i + chunkSize < depositForBurnTxnHashes.length) {
            await new Promise((resolve) => setTimeout(resolve, 1000));
        }
    }
    return attestationResponses;
}
function getPendingAttestationStatus(attestation) {
    if (!(0, TypeGuards_1.isDefined)(attestation.attestation)) {
        return "pending";
    }
    else {
        return attestation.status === "pending_confirmations" || attestation.attestation === "PENDING"
            ? "pending"
            : "ready";
    }
}
async function hasCCTPMessageBeenProcessedEvm(nonceHash, contract) {
    const resultingCall = await contract.callStatic.usedNonces(nonceHash);
    return (resultingCall ?? BigNumberUtils_1.bnZero).toNumber() === 1;
}
async function getV2FastBurnAllowance(isMainnet) {
    const data = await (0, FetchUtils_1.fetchWithTimeout)(`https://iris-api${isMainnet ? "" : "-sandbox"}.circle.com/v2/fastBurn/USDC/allowance`);
    return data.allowance.toString();
}
async function getV2MinTransferFees(sourceChainId, destinationChainId) {
    const isMainnet = (0, NetworkUtils_1.chainIsProd)(destinationChainId);
    const sourceDomain = getCctpDomainForChainId(sourceChainId);
    const destinationDomain = getCctpDomainForChainId(destinationChainId);
    const endpoint = `https://iris-api${isMainnet ? "" : "-sandbox"}.circle.com/v2/burn/USDC/fees/${sourceDomain}/${destinationDomain}`;
    const data = await (0, FetchUtils_1.fetchWithTimeout)(endpoint);
    const standardFee = data.find((fee) => fee.finalityThreshold === exports.CCTPV2_FINALITY_THRESHOLD_STANDARD);
    (0, assert_1.default)((0, TypeGuards_1.isDefined)(standardFee?.minimumFee), `CCTPUtils#getTransferFees: Standard fee not found in API response: ${endpoint}`);
    const fastFee = data.find((fee) => fee.finalityThreshold === exports.CCTPV2_FINALITY_THRESHOLD_FAST);
    (0, assert_1.default)((0, TypeGuards_1.isDefined)(fastFee?.minimumFee), `CCTPUtils#getTransferFees: Fast fee not found in API response: ${endpoint}`);
    return {
        standard: ethers_1.BigNumber.from(standardFee.minimumFee),
        fast: ethers_1.BigNumber.from(fastFee.minimumFee),
    };
}
async function fetchAttestationsForTxn(sourceDomainId, transactionHash, isMainnet) {
    return await (0, FetchUtils_1.fetchWithTimeout)(`https://iris-api${isMainnet ? "" : "-sandbox"}.circle.com/v2/messages/${sourceDomainId}?transactionHash=${transactionHash}`);
}
function getMessageSentVersion(log) {
    if (log.topics[0] !== CCTP_MESSAGE_SENT_TOPIC_HASH) {
        return -1;
    }
    const messageBytes = ethers_1.ethers.utils.defaultAbiCoder.decode(["bytes"], log.data)[0];
    const version = parseInt(messageBytes.slice(2, 10), 16);
    return version;
}
function getDepositForBurnVersion(log) {
    const topic = log.topics[0];
    switch (topic) {
        case CCTP_DEPOSIT_FOR_BURN_TOPIC_HASH_V1:
            return 0;
        case CCTP_DEPOSIT_FOR_BURN_TOPIC_HASH_V2:
            return 1;
        default:
            return -1;
    }
}
//# sourceMappingURL=CCTPUtils.js.map