"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hasCCTPV1MessageBeenProcessed = exports.createReceiveMessageInstruction = exports.createCloseFillPdaInstruction = exports.createRequestSlowFillInstruction = exports.createDepositInstruction = exports.createFillInstruction = exports.SLOT_DURATION_MS = void 0;
exports.getSlot = getSlot;
exports.getTimestampForSlot = getTimestampForSlot;
exports.getFillDeadline = getFillDeadline;
exports.getDepositIdAtBlock = getDepositIdAtBlock;
exports.findDeposit = findDeposit;
exports.relayFillStatus = relayFillStatus;
exports.fillStatusArray = fillStatusArray;
exports.findFillEvent = findFillEvent;
exports.fillRelayInstruction = fillRelayInstruction;
exports.createTokenAccountsInstruction = createTokenAccountsInstruction;
exports.getFillRelayTx = getFillRelayTx;
exports.getIPFillRelayTx = getIPFillRelayTx;
exports.deserializeMessage = deserializeMessage;
exports.getSlowFillRequestTx = getSlowFillRequestTx;
exports.getAssociatedTokenAddress = getAssociatedTokenAddress;
exports.getRelayDataHash = getRelayDataHash;
exports.getFillRelayViaInstructionParamsInstructions = getFillRelayViaInstructionParamsInstructions;
exports.getDepositDelegatePda = getDepositDelegatePda;
exports.getDepositNowDelegatePda = getDepositNowDelegatePda;
exports.getFillRelayDelegatePda = getFillRelayDelegatePda;
exports.getAccountMetasForTokenlessMessage = getAccountMetasForTokenlessMessage;
exports.getCCTPDepositAccounts = getCCTPDepositAccounts;
exports.getCCTPV1ReceiveMessageTx = getCCTPV1ReceiveMessageTx;
exports.finalizeCCTPV1Messages = finalizeCCTPV1Messages;
exports.getMintInfo = getMintInfo;
var tslib_1 = require("tslib");
var contracts_1 = require("@across-protocol/contracts");
var SvmSpoke_1 = require("@across-protocol/contracts/dist/src/svm/clients/SvmSpoke");
var web3_v1_1 = require("@across-protocol/contracts/dist/src/svm/web3-v1");
var system_1 = require("@solana-program/system");
var token_1 = require("@solana-program/token");
var kit_1 = require("@solana/kit");
var assert_1 = tslib_1.__importDefault(require("assert"));
var utils_1 = require("ethers/lib/utils");
var constants_1 = require("../../constants");
var interfaces_1 = require("../../interfaces");
var utils_2 = require("../../utils");
var _1 = require("./");
var provider_1 = require("./provider");
var types_1 = require("./types");
var utils_3 = require("./utils");
exports.SLOT_DURATION_MS = 400;
function getSlot(provider, commitment, logger) {
    return _callGetSlotWithRetry(provider, commitment, logger);
}
function _callGetSlotWithRetry(provider, commitment, logger) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var err_1, code;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    _a.trys.push([0, 2, , 3]);
                    return [4, provider.getSlot({ commitment: commitment }).send()];
                case 1: return [2, _a.sent()];
                case 2:
                    err_1 = _a.sent();
                    if ((0, provider_1.isSolanaError)(err_1)) {
                        code = err_1.context.__code;
                        logger === null || logger === void 0 ? void 0 : logger.debug({
                            at: "_getSlotWithRetry",
                            message: "Caught error from getSlot()",
                            code: code,
                            commitment: commitment,
                        });
                    }
                    throw err_1;
                case 3: return [2];
            }
        });
    });
}
function getTimestampForSlot(provider, slotNumber, maxRetries, logger) {
    if (maxRetries === void 0) { maxRetries = 2; }
    return _callGetTimestampForSlotWithRetry(provider, slotNumber, 0, maxRetries, logger);
}
function _callGetTimestampForSlotWithRetry(provider, slotNumber, retryAttempt, maxRetries, logger) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var slot, _timestamp, err_2, at, code, message, timestamp;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    slot = slotNumber.toString();
                    _a.label = 1;
                case 1:
                    _a.trys.push([1, 3, , 4]);
                    return [4, provider.getBlockTime(slotNumber).send()];
                case 2:
                    _timestamp = _a.sent();
                    return [3, 4];
                case 3:
                    err_2 = _a.sent();
                    if (!(0, provider_1.isSolanaError)(err_2)) {
                        throw err_2;
                    }
                    at = "getTimestampForSlot";
                    code = err_2.context.__code;
                    switch (code) {
                        case provider_1.SVM_SLOT_SKIPPED:
                        case provider_1.SVM_LONG_TERM_STORAGE_SLOT_SKIPPED:
                            return [2, undefined];
                        default: {
                            message = "Caught error from getBlockTime()";
                            logger === null || logger === void 0 ? void 0 : logger.debug({ at: at, message: message, errorCode: code, slot: slot, retryAttempt: retryAttempt, maxRetries: maxRetries });
                            throw new Error("Unhandled SVM getBlockTime() error for slot ".concat(slot, ": ").concat(code), { cause: err_2 });
                        }
                    }
                    return [3, 4];
                case 4:
                    timestamp = Number(_timestamp);
                    (0, assert_1.default)(!(0, utils_2.isDefined)(_timestamp) || BigInt(timestamp) === _timestamp, "Unexpected block timestamp for SVM slot ".concat(slot, ": ").concat(_timestamp));
                    return [2, timestamp];
            }
        });
    });
}
function getFillDeadline(provider, statePda) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var state;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4, (0, SvmSpoke_1.fetchState)(provider, statePda)];
                case 1:
                    state = _a.sent();
                    return [2, state.data.fillDeadlineBuffer];
            }
        });
    });
}
function getDepositIdAtBlock(_contract, _blockTag) {
    throw new Error("getDepositIdAtBlock: not implemented");
}
function findDeposit(eventClient_1, depositId_1, logger_1, slot_1) {
    return tslib_1.__awaiter(this, arguments, void 0, function (eventClient, depositId, logger, slot, secondsLookback) {
        var provider, opts, currentSlot, endSlot, slotsInElapsed, startSlot, depositEvent, txnIndex, logIndex, blockNumber, txnRef, rawData, _a, originChainId, deposit;
        var _b;
        if (secondsLookback === void 0) { secondsLookback = 2 * 24 * 60 * 60; }
        return tslib_1.__generator(this, function (_c) {
            switch (_c.label) {
                case 0:
                    if ((0, utils_2.isUnsafeDepositId)(depositId)) {
                        throw new Error("Cannot binary search for depositId ".concat(depositId));
                    }
                    provider = eventClient.getRpc();
                    opts = undefined;
                    return [4, (0, utils_3.getNearestSlotTime)(provider, opts, logger)];
                case 1:
                    currentSlot = (_c.sent()).slot;
                    endSlot = slot !== undefined ? BigInt(Math.min(Number(slot), Number(currentSlot))) : currentSlot;
                    slotsInElapsed = BigInt(Math.round((secondsLookback * 1000) / exports.SLOT_DURATION_MS));
                    startSlot = endSlot - slotsInElapsed;
                    return [4, eventClient.queryEvents("FundsDeposited", startSlot, endSlot)];
                case 2:
                    depositEvent = (_b = (_c.sent())) === null || _b === void 0 ? void 0 : _b.find(function (event) {
                        return depositId.eq(event.data.depositId);
                    });
                    if (!depositEvent) {
                        return [2, undefined];
                    }
                    txnIndex = 0;
                    logIndex = 0;
                    blockNumber = Number(depositEvent.slot);
                    txnRef = depositEvent.signature.toString();
                    rawData = (0, _1.unwrapEventData)(depositEvent.data, ["depositId", "outputAmount"]);
                    _a = (0, utils_2.unpackDepositEvent)(tslib_1.__assign(tslib_1.__assign({}, rawData), { blockNumber: blockNumber, txnRef: txnRef, txnIndex: txnIndex, logIndex: logIndex }), constants_1.CHAIN_IDs.SOLANA), originChainId = _a.originChainId, deposit = tslib_1.__rest(_a, ["originChainId"]);
                    return [2, tslib_1.__assign({}, deposit)];
            }
        });
    });
}
function relayFillStatus(programId, relayData, destinationChainId, svmEventsClient, logger, atHeight) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var provider, fillStatusPda, toSlot, commitment, _a, fillStatusAccount, _b, currentSlot, timestamp, decodedAccountData;
        return tslib_1.__generator(this, function (_c) {
            switch (_c.label) {
                case 0:
                    (0, assert_1.default)((0, utils_2.chainIsSvm)(destinationChainId), "Destination chain must be an SVM chain");
                    provider = svmEventsClient.getRpc();
                    return [4, (0, _1.getFillStatusPda)(programId, relayData, destinationChainId)];
                case 1:
                    fillStatusPda = _c.sent();
                    toSlot = BigInt(atHeight !== null && atHeight !== void 0 ? atHeight : 0);
                    if (!(atHeight === undefined)) return [3, 3];
                    commitment = "confirmed";
                    return [4, Promise.all([
                            (0, kit_1.fetchEncodedAccount)(provider, fillStatusPda, { commitment: commitment }),
                            (0, utils_3.getNearestSlotTime)(provider, { commitment: commitment }, logger),
                        ])];
                case 2:
                    _a = _c.sent(), fillStatusAccount = _a[0], _b = _a[1], currentSlot = _b.slot, timestamp = _b.timestamp;
                    toSlot = currentSlot;
                    if (fillStatusAccount.exists) {
                        decodedAccountData = (0, SvmSpoke_1.decodeFillStatusAccount)(fillStatusAccount);
                        return [2, decodedAccountData.data.status];
                    }
                    else if (timestamp < relayData.fillDeadline) {
                        return [2, interfaces_1.FillStatus.Unfilled];
                    }
                    _c.label = 3;
                case 3: return [2, resolveFillStatusFromPdaEvents(fillStatusPda, toSlot, svmEventsClient)];
            }
        });
    });
}
function fillStatusArray(programId, relayData, destinationChainId, svmEventsClient, logger, atHeight) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var provider, chunkSize, chunkedRelayData, fillStatusPdas, fillStatuses, _a, missingStatuses, missingChunked, missingResults, opts, toSlot, _b, _i, missingChunked_1, chunk_1, chunkResults;
        var _this = this;
        return tslib_1.__generator(this, function (_c) {
            switch (_c.label) {
                case 0:
                    (0, assert_1.default)((0, utils_2.chainIsSvm)(destinationChainId), "Destination chain must be an SVM chain");
                    provider = svmEventsClient.getRpc();
                    chunkSize = 100;
                    chunkedRelayData = (0, utils_2.chunk)(relayData, chunkSize);
                    return [4, Promise.all(chunkedRelayData.map(function (relayDataChunk) {
                            return Promise.all(relayDataChunk.map(function (relayData) { return (0, _1.getFillStatusPda)(programId, relayData, destinationChainId); }));
                        }))];
                case 1:
                    fillStatusPdas = (_c.sent()).flat();
                    if (atHeight !== undefined && logger) {
                        logger.warn({
                            at: "SvmSpokeUtils#fillStatusArray",
                            message: "Querying specific slots for large arrays is slow. For current status, omit 'atHeight' param to use latest confirmed slot instead.",
                        });
                    }
                    if (!(atHeight === undefined)) return [3, 3];
                    return [4, fetchBatchFillStatusFromPdaAccounts(provider, fillStatusPdas, relayData, logger)];
                case 2:
                    _a = _c.sent();
                    return [3, 4];
                case 3:
                    _a = new Array(relayData.length).fill(undefined);
                    _c.label = 4;
                case 4:
                    fillStatuses = _a;
                    missingStatuses = fillStatuses.reduce(function (acc, status, index) {
                        if (status === undefined) {
                            acc.push(index);
                        }
                        return acc;
                    }, []);
                    missingChunked = (0, utils_2.chunk)(missingStatuses, chunkSize);
                    missingResults = [];
                    opts = undefined;
                    if (!atHeight) return [3, 5];
                    _b = BigInt(atHeight);
                    return [3, 7];
                case 5: return [4, (0, utils_3.getNearestSlotTime)(provider, opts, logger)];
                case 6:
                    _b = (_c.sent()).slot;
                    _c.label = 7;
                case 7:
                    toSlot = _b;
                    _i = 0, missingChunked_1 = missingChunked;
                    _c.label = 8;
                case 8:
                    if (!(_i < missingChunked_1.length)) return [3, 11];
                    chunk_1 = missingChunked_1[_i];
                    return [4, Promise.all(chunk_1.map(function (missingIndex) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
                            var _a;
                            return tslib_1.__generator(this, function (_b) {
                                switch (_b.label) {
                                    case 0:
                                        _a = {
                                            index: missingIndex
                                        };
                                        return [4, resolveFillStatusFromPdaEvents(fillStatusPdas[missingIndex], toSlot, svmEventsClient)];
                                    case 1: return [2, (_a.fillStatus = _b.sent(),
                                            _a)];
                                }
                            });
                        }); }))];
                case 9:
                    chunkResults = _c.sent();
                    missingResults.push.apply(missingResults, chunkResults);
                    _c.label = 10;
                case 10:
                    _i++;
                    return [3, 8];
                case 11:
                    missingResults.forEach(function (_a) {
                        var index = _a.index, fillStatus = _a.fillStatus;
                        fillStatuses[index] = fillStatus;
                    });
                    return [2, fillStatuses];
            }
        });
    });
}
function findFillEvent(relayData, destinationChainId, svmEventsClient, fromSlot, toSlot, logger) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var opts, _a, _b, programId, fillStatusPda, fillEvents, rawEvent, rawFill, fill;
        return tslib_1.__generator(this, function (_c) {
            switch (_c.label) {
                case 0:
                    (0, assert_1.default)((0, utils_2.chainIsSvm)(destinationChainId), "Destination chain must be an SVM chain");
                    opts = undefined;
                    if (!(toSlot !== null && toSlot !== void 0)) return [3, 1];
                    _a = toSlot;
                    return [3, 3];
                case 1:
                    _b = Number;
                    return [4, (0, utils_3.getNearestSlotTime)(svmEventsClient.getRpc(), opts, logger)];
                case 2:
                    _a = (toSlot = _b.apply(void 0, [(_c.sent()).slot]));
                    _c.label = 3;
                case 3:
                    _a;
                    programId = svmEventsClient.getProgramAddress();
                    return [4, (0, _1.getFillStatusPda)(programId, relayData, destinationChainId)];
                case 4:
                    fillStatusPda = _c.sent();
                    return [4, svmEventsClient.queryDerivedAddressEvents(types_1.SVMEventNames.FilledRelay, fillStatusPda, BigInt(fromSlot), BigInt(toSlot), { limit: 10 })];
                case 5:
                    fillEvents = _c.sent();
                    (0, assert_1.default)(fillEvents.length <= 1, "Expected at most one fill event for ".concat(fillStatusPda, ", got ").concat(fillEvents.length));
                    rawEvent = fillEvents[0];
                    if (!(0, utils_2.isDefined)(rawEvent)) {
                        return [2];
                    }
                    rawFill = (0, _1.unwrapEventData)(rawEvent.data, ["depositId", "inputAmount"]);
                    fill = (0, utils_2.unpackFillEvent)(rawFill, destinationChainId);
                    return [2, fill];
            }
        });
    });
}
function fillRelayInstruction(spokePool, relayData, signer, recipientTokenAccount, repaymentAddress, repaymentChainId) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var program, messageHash, _relayDataHash, relayDataHash, relayer, _a, statePda, fillStatusPda, eventAuthority, delegatePda, relayerTokenAccount, svmRelayData;
        return tslib_1.__generator(this, function (_b) {
            switch (_b.label) {
                case 0:
                    program = (0, _1.toAddress)(spokePool);
                    (0, assert_1.default)(repaymentAddress.isValidOn(repaymentChainId), "Invalid repayment address for chain ".concat(repaymentChainId, ": ").concat(repaymentAddress.toNative(), "."));
                    messageHash = (0, utils_2.getMessageHash)(relayData.message);
                    _relayDataHash = getRelayDataHash(tslib_1.__assign(tslib_1.__assign({}, relayData), { messageHash: messageHash }), relayData.destinationChainId);
                    relayDataHash = new Uint8Array(Buffer.from(_relayDataHash.slice(2), "hex"));
                    relayer = utils_2.SvmAddress.from(signer.address);
                    return [4, Promise.all([
                            (0, _1.getStatePda)(program),
                            (0, _1.getFillStatusPda)(program, relayData, relayData.destinationChainId),
                            (0, _1.getEventAuthority)(program),
                            getFillRelayDelegatePda(relayDataHash, BigInt(repaymentChainId), signer.address, program),
                            getAssociatedTokenAddress(relayer, relayData.outputToken),
                        ])];
                case 1:
                    _a = _b.sent(), statePda = _a[0], fillStatusPda = _a[1], eventAuthority = _a[2], delegatePda = _a[3], relayerTokenAccount = _a[4];
                    svmRelayData = (0, _1.toSvmRelayData)(relayData);
                    return [2, contracts_1.SvmSpokeClient.getFillRelayInstruction({
                            signer: signer,
                            state: statePda,
                            delegate: (0, _1.toAddress)(utils_2.SvmAddress.from(delegatePda.toString())),
                            mint: svmRelayData.outputToken,
                            relayerTokenAccount: relayerTokenAccount,
                            recipientTokenAccount: recipientTokenAccount,
                            fillStatus: fillStatusPda,
                            eventAuthority: eventAuthority,
                            program: program,
                            relayHash: relayDataHash,
                            relayData: (0, kit_1.some)(svmRelayData),
                            repaymentChainId: (0, kit_1.some)(BigInt(repaymentChainId)),
                            repaymentAddress: (0, kit_1.some)((0, _1.toAddress)(repaymentAddress)),
                        })];
            }
        });
    });
}
function createTokenAccountsInstruction(mint, relayer) {
    return contracts_1.SvmSpokeClient.getCreateTokenAccountsInstruction({
        signer: relayer,
        mint: (0, _1.toAddress)(mint),
    });
}
function getFillRelayTx(spokePoolAddr, solanaClient, relayData, signer, repaymentChainId, repaymentAddress) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var svmRelayData, program, messageHash, _relayDataHash, relayDataHash, _a, state, delegate, mintInfo, fillStatus, eventAuthority, _b, recipientAta, relayerAta, recipientAtaEncodedAccount, remainingAccounts, acrossPlusMessage_1, fillInput;
        return tslib_1.__generator(this, function (_c) {
            switch (_c.label) {
                case 0:
                    svmRelayData = (0, _1.toSvmRelayData)(relayData);
                    (0, assert_1.default)(repaymentAddress.isValidOn(repaymentChainId), "getFillRelayTx: repayment address ".concat(repaymentAddress, " not valid on chain ").concat(repaymentChainId, ")"));
                    program = (0, _1.toAddress)(spokePoolAddr);
                    messageHash = (0, utils_2.getMessageHash)(relayData.message);
                    _relayDataHash = getRelayDataHash(tslib_1.__assign(tslib_1.__assign({}, relayData), { messageHash: messageHash }), relayData.destinationChainId);
                    relayDataHash = new Uint8Array(Buffer.from(_relayDataHash.slice(2), "hex"));
                    return [4, Promise.all([
                            (0, _1.getStatePda)(program),
                            getFillRelayDelegatePda(relayDataHash, BigInt(repaymentChainId), (0, _1.toAddress)(repaymentAddress), program),
                            getMintInfo(solanaClient, svmRelayData.outputToken),
                            (0, _1.getFillStatusPda)(program, relayData, relayData.destinationChainId),
                            (0, _1.getEventAuthority)(program),
                        ])];
                case 1:
                    _a = _c.sent(), state = _a[0], delegate = _a[1], mintInfo = _a[2], fillStatus = _a[3], eventAuthority = _a[4];
                    return [4, Promise.all([
                            getAssociatedTokenAddress(relayData.recipient, relayData.outputToken, mintInfo.programAddress),
                            getAssociatedTokenAddress(utils_2.SvmAddress.from(signer.address), relayData.outputToken, mintInfo.programAddress),
                        ])];
                case 2:
                    _b = _c.sent(), recipientAta = _b[0], relayerAta = _b[1];
                    return [4, (0, kit_1.fetchEncodedAccount)(solanaClient, recipientAta)];
                case 3:
                    recipientAtaEncodedAccount = _c.sent();
                    remainingAccounts = [];
                    if (relayData.message !== "0x") {
                        acrossPlusMessage_1 = deserializeMessage(relayData.message);
                        remainingAccounts.push((0, _1.getAccountMeta)(acrossPlusMessage_1.handler, true));
                        remainingAccounts.push.apply(remainingAccounts, acrossPlusMessage_1.accounts.map(function (account, idx) {
                            return (0, _1.getAccountMeta)(account, idx < acrossPlusMessage_1.accounts.length - acrossPlusMessage_1.read_only_len);
                        }));
                    }
                    fillInput = {
                        signer: signer,
                        state: state,
                        delegate: delegate,
                        mint: svmRelayData.outputToken,
                        relayerTokenAccount: relayerAta,
                        recipientTokenAccount: recipientAta,
                        fillStatus: fillStatus,
                        tokenProgram: mintInfo.programAddress,
                        associatedTokenProgram: token_1.ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
                        systemProgram: system_1.SYSTEM_PROGRAM_ADDRESS,
                        eventAuthority: eventAuthority,
                        program: program,
                        relayHash: relayDataHash,
                        relayData: svmRelayData,
                        repaymentChainId: BigInt(repaymentChainId),
                        repaymentAddress: (0, _1.toAddress)(repaymentAddress),
                    };
                    return [2, (0, exports.createFillInstruction)(signer, solanaClient, fillInput, svmRelayData, mintInfo.data.decimals, !recipientAtaEncodedAccount.exists, remainingAccounts)];
            }
        });
    });
}
function getIPFillRelayTx(spokePoolAddr, solanaClient, relayData, signer, repaymentChainId, repaymentAddress) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var program, _relayDataHash, relayDataHash, _a, state, delegate, instructionParams, mint, mintInfo, _b, recipientAta, relayerAta, fillStatus, eventAuthority, remainingAccounts, acrossPlusMessage_2, fillInput;
        return tslib_1.__generator(this, function (_c) {
            switch (_c.label) {
                case 0:
                    program = (0, _1.toAddress)(spokePoolAddr);
                    _relayDataHash = getRelayDataHash(tslib_1.__assign(tslib_1.__assign({}, relayData), { messageHash: (0, utils_2.getMessageHash)(relayData.message) }), relayData.destinationChainId);
                    relayDataHash = new Uint8Array(Buffer.from(_relayDataHash.slice(2), "hex"));
                    return [4, Promise.all([
                            (0, _1.getStatePda)(program),
                            getFillRelayDelegatePda(relayDataHash, BigInt(repaymentChainId), (0, _1.toAddress)(repaymentAddress), program),
                            (0, _1.getInstructionParamsPda)(program, signer.address),
                        ])];
                case 1:
                    _a = _c.sent(), state = _a[0], delegate = _a[1], instructionParams = _a[2];
                    mint = (0, _1.toAddress)(relayData.outputToken);
                    return [4, getMintInfo(solanaClient, mint)];
                case 2:
                    mintInfo = _c.sent();
                    return [4, Promise.all([
                            getAssociatedTokenAddress(relayData.recipient, relayData.outputToken, mintInfo.programAddress),
                            getAssociatedTokenAddress(utils_2.SvmAddress.from(signer.address), relayData.outputToken, mintInfo.programAddress),
                            (0, _1.getFillStatusPda)(program, relayData, relayData.destinationChainId),
                            (0, _1.getEventAuthority)(program),
                        ])];
                case 3:
                    _b = _c.sent(), recipientAta = _b[0], relayerAta = _b[1], fillStatus = _b[2], eventAuthority = _b[3];
                    remainingAccounts = [];
                    if (relayData.message !== "0x") {
                        acrossPlusMessage_2 = deserializeMessage(relayData.message);
                        remainingAccounts.push((0, _1.getAccountMeta)(acrossPlusMessage_2.handler, true));
                        remainingAccounts.push.apply(remainingAccounts, acrossPlusMessage_2.accounts.map(function (account, idx) {
                            return (0, _1.getAccountMeta)(account, idx < acrossPlusMessage_2.accounts.length - acrossPlusMessage_2.read_only_len);
                        }));
                    }
                    fillInput = {
                        signer: signer,
                        state: state,
                        delegate: delegate,
                        mint: mint,
                        relayerTokenAccount: relayerAta,
                        recipientTokenAccount: recipientAta,
                        fillStatus: fillStatus,
                        tokenProgram: mintInfo.programAddress,
                        associatedTokenProgram: token_1.ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
                        systemProgram: system_1.SYSTEM_PROGRAM_ADDRESS,
                        eventAuthority: eventAuthority,
                        program: program,
                        instructionParams: instructionParams,
                        relayHash: relayDataHash,
                        relayData: null,
                        repaymentChainId: null,
                        repaymentAddress: null,
                    };
                    return [2, (0, exports.createFillInstruction)(signer, solanaClient, fillInput, { outputAmount: relayData.outputAmount.toBigInt(), recipient: (0, _1.toAddress)(relayData.recipient) }, mintInfo.data.decimals, true, remainingAccounts)];
            }
        });
    });
}
var createFillInstruction = function (signer_1, solanaClient_1, fillInput_1, relayData_1, tokenDecimals_1) {
    var args_1 = [];
    for (var _i = 5; _i < arguments.length; _i++) {
        args_1[_i - 5] = arguments[_i];
    }
    return tslib_1.__awaiter(void 0, tslib_1.__spreadArray([signer_1, solanaClient_1, fillInput_1, relayData_1, tokenDecimals_1], args_1, true), void 0, function (signer, solanaClient, fillInput, relayData, tokenDecimals, createRecipientAta, remainingAccounts) {
        var mintInfo, approveIx, getCreateAssociatedTokenIx, createFillIx, _a;
        var _b;
        if (createRecipientAta === void 0) { createRecipientAta = false; }
        if (remainingAccounts === void 0) { remainingAccounts = []; }
        return tslib_1.__generator(this, function (_c) {
            switch (_c.label) {
                case 0: return [4, getMintInfo(solanaClient, fillInput.mint)];
                case 1:
                    mintInfo = _c.sent();
                    approveIx = (0, token_1.getApproveCheckedInstruction)({
                        source: fillInput.relayerTokenAccount,
                        mint: fillInput.mint,
                        delegate: fillInput.delegate,
                        owner: fillInput.signer,
                        amount: relayData.outputAmount,
                        decimals: tokenDecimals,
                    }, {
                        programAddress: mintInfo.programAddress,
                    });
                    getCreateAssociatedTokenIx = function () {
                        return (0, token_1.getCreateAssociatedTokenInstruction)({
                            payer: signer,
                            owner: relayData.recipient,
                            mint: fillInput.mint,
                            ata: fillInput.recipientTokenAccount,
                            systemProgram: system_1.SYSTEM_PROGRAM_ADDRESS,
                            tokenProgram: fillInput.tokenProgram,
                        });
                    };
                    createFillIx = contracts_1.SvmSpokeClient.getFillRelayInstruction(fillInput);
                    (_b = createFillIx.accounts).push.apply(_b, remainingAccounts);
                    _a = kit_1.pipe;
                    return [4, (0, _1.createDefaultTransaction)(solanaClient, signer)];
                case 2: return [2, _a.apply(void 0, [_c.sent(), function (tx) { return (createRecipientAta ? (0, kit_1.appendTransactionMessageInstruction)(getCreateAssociatedTokenIx(), tx) : tx); },
                        function (tx) { return (0, kit_1.appendTransactionMessageInstruction)(approveIx, tx); },
                        function (tx) { return (0, kit_1.appendTransactionMessageInstruction)(createFillIx, tx); }])];
            }
        });
    });
};
exports.createFillInstruction = createFillInstruction;
function deserializeMessage(_message) {
    var message = new Uint8Array(Buffer.from(_message.startsWith("0x") ? _message.slice(2) : _message, "hex"));
    var acrossPlusMessageDecoder = (0, _1.getAcrossPlusMessageDecoder)();
    var deserialized = acrossPlusMessageDecoder.decode(message);
    var valueAmountMethod2 = extractValueAmount(message);
    (0, assert_1.default)(deserialized.value_amount === valueAmountMethod2, "svm | deserializeMessage: Deserialization mismatch for value_amount");
    return deserialized;
}
var createDepositInstruction = function (signer_1, solanaClient_1, depositInput_1, tokenDecimals_1) {
    var args_1 = [];
    for (var _i = 4; _i < arguments.length; _i++) {
        args_1[_i - 4] = arguments[_i];
    }
    return tslib_1.__awaiter(void 0, tslib_1.__spreadArray([signer_1, solanaClient_1, depositInput_1, tokenDecimals_1], args_1, true), void 0, function (signer, solanaClient, depositInput, tokenDecimals, createVaultAtaIfNeeded) {
        var getCreateAssociatedTokenIdempotentIx, mintInfo, approveIx, depositIx, _a;
        if (createVaultAtaIfNeeded === void 0) { createVaultAtaIfNeeded = true; }
        return tslib_1.__generator(this, function (_b) {
            switch (_b.label) {
                case 0:
                    getCreateAssociatedTokenIdempotentIx = function () {
                        return (0, token_1.getCreateAssociatedTokenIdempotentInstruction)({
                            payer: signer,
                            owner: depositInput.state,
                            mint: depositInput.mint,
                            ata: depositInput.vault,
                            systemProgram: depositInput.systemProgram,
                            tokenProgram: depositInput.tokenProgram,
                        });
                    };
                    return [4, getMintInfo(solanaClient, depositInput.mint)];
                case 1:
                    mintInfo = _b.sent();
                    approveIx = (0, token_1.getApproveCheckedInstruction)({
                        source: depositInput.depositorTokenAccount,
                        mint: depositInput.mint,
                        delegate: depositInput.delegate,
                        owner: depositInput.depositor,
                        amount: depositInput.inputAmount,
                        decimals: tokenDecimals,
                    }, {
                        programAddress: mintInfo.programAddress,
                    });
                    depositIx = contracts_1.SvmSpokeClient.getDepositInstruction(depositInput);
                    _a = kit_1.pipe;
                    return [4, (0, _1.createDefaultTransaction)(solanaClient, signer)];
                case 2: return [2, _a.apply(void 0, [_b.sent(), function (tx) {
                            return createVaultAtaIfNeeded ? (0, kit_1.appendTransactionMessageInstruction)(getCreateAssociatedTokenIdempotentIx(), tx) : tx;
                        },
                        function (tx) { return (0, kit_1.appendTransactionMessageInstruction)(approveIx, tx); },
                        function (tx) { return (0, kit_1.appendTransactionMessageInstruction)(depositIx, tx); }])];
            }
        });
    });
};
exports.createDepositInstruction = createDepositInstruction;
var createRequestSlowFillInstruction = function (signer, solanaClient, requestSlowFillInput) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
    var requestSlowFillIx, _a;
    return tslib_1.__generator(this, function (_b) {
        switch (_b.label) {
            case 0:
                requestSlowFillIx = contracts_1.SvmSpokeClient.getRequestSlowFillInstruction(requestSlowFillInput);
                _a = kit_1.pipe;
                return [4, (0, _1.createDefaultTransaction)(solanaClient, signer)];
            case 1: return [2, _a.apply(void 0, [_b.sent(), function (tx) {
                        return (0, kit_1.appendTransactionMessageInstruction)(requestSlowFillIx, tx);
                    }])];
        }
    });
}); };
exports.createRequestSlowFillInstruction = createRequestSlowFillInstruction;
function getSlowFillRequestTx(spokePoolAddr, solanaClient, relayData, signer) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var program, messageHash, relayDataHash, _a, state, fillStatus, eventAuthority, svmRelayData, requestSlowFillInput;
        return tslib_1.__generator(this, function (_b) {
            switch (_b.label) {
                case 0:
                    program = (0, _1.toAddress)(spokePoolAddr);
                    messageHash = (0, utils_2.getMessageHash)(relayData.message);
                    relayDataHash = getRelayDataHash(tslib_1.__assign(tslib_1.__assign({}, relayData), { messageHash: messageHash }), relayData.destinationChainId);
                    return [4, Promise.all([
                            (0, _1.getStatePda)(program),
                            (0, _1.getFillStatusPda)(program, relayData, relayData.destinationChainId),
                            (0, _1.getEventAuthority)(program),
                        ])];
                case 1:
                    _a = _b.sent(), state = _a[0], fillStatus = _a[1], eventAuthority = _a[2];
                    svmRelayData = (0, _1.toSvmRelayData)(relayData);
                    requestSlowFillInput = {
                        signer: signer,
                        state: state,
                        fillStatus: fillStatus,
                        eventAuthority: eventAuthority,
                        program: program,
                        relayHash: (0, utils_1.arrayify)(relayDataHash),
                        relayData: svmRelayData,
                        systemProgram: system_1.SYSTEM_PROGRAM_ADDRESS,
                    };
                    return [2, (0, exports.createRequestSlowFillInstruction)(signer, solanaClient, requestSlowFillInput)];
            }
        });
    });
}
var createCloseFillPdaInstruction = function (signer, solanaClient, fillStatusPda) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
    var closeFillPdaIx, _a, _b, _c;
    var _d;
    return tslib_1.__generator(this, function (_e) {
        switch (_e.label) {
            case 0:
                _b = (_a = contracts_1.SvmSpokeClient).getCloseFillPdaInstruction;
                _d = {
                    signer: signer
                };
                return [4, (0, _1.getStatePda)(contracts_1.SvmSpokeClient.SVM_SPOKE_PROGRAM_ADDRESS)];
            case 1:
                closeFillPdaIx = _b.apply(_a, [(_d.state = _e.sent(),
                        _d.fillStatus = fillStatusPda,
                        _d)]);
                _c = kit_1.pipe;
                return [4, (0, _1.createDefaultTransaction)(solanaClient, signer)];
            case 2: return [2, _c.apply(void 0, [_e.sent(), function (tx) {
                        return (0, kit_1.appendTransactionMessageInstruction)(closeFillPdaIx, tx);
                    }])];
        }
    });
}); };
exports.createCloseFillPdaInstruction = createCloseFillPdaInstruction;
var createReceiveMessageInstruction = function (signer, solanaClient, input, remainingAccounts) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
    var receiveMessageIx, _a;
    var _b;
    return tslib_1.__generator(this, function (_c) {
        switch (_c.label) {
            case 0:
                receiveMessageIx = contracts_1.MessageTransmitterClient.getReceiveMessageInstruction(input);
                (_b = receiveMessageIx.accounts).push.apply(_b, remainingAccounts);
                _a = kit_1.pipe;
                return [4, (0, _1.createDefaultTransaction)(solanaClient, signer)];
            case 1: return [2, _a.apply(void 0, [_c.sent(), function (tx) {
                        return (0, kit_1.appendTransactionMessageInstruction)(receiveMessageIx, tx);
                    }])];
        }
    });
}); };
exports.createReceiveMessageInstruction = createReceiveMessageInstruction;
function getAssociatedTokenAddress(owner_1, mint_1) {
    return tslib_1.__awaiter(this, arguments, void 0, function (owner, mint, tokenProgramId) {
        var encoder, associatedToken;
        if (tokenProgramId === void 0) { tokenProgramId = token_1.TOKEN_PROGRAM_ADDRESS; }
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    encoder = (0, kit_1.getAddressEncoder)();
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: token_1.ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
                            seeds: [encoder.encode((0, _1.toAddress)(owner)), encoder.encode(tokenProgramId), encoder.encode((0, _1.toAddress)(mint))],
                        })];
                case 1:
                    associatedToken = (_a.sent())[0];
                    return [2, associatedToken];
            }
        });
    });
}
function getRelayDataHash(relayData, destinationChainId) {
    (0, assert_1.default)(relayData.messageHash.startsWith("0x"), "Message hash must be a hex string");
    var uint64Encoder = (0, kit_1.getU64Encoder)();
    var svmRelayData = (0, _1.toSvmRelayData)(relayData);
    var relayDataEncoder = contracts_1.SvmSpokeClient.getRelayDataEncoder();
    var encodedRelayData = relayDataEncoder.encode(svmRelayData);
    var encodedMessage = Buffer.from(relayData.message.slice(2), "hex");
    var encodedMessageHash = Uint8Array.from(Buffer.from(relayData.messageHash.slice(2), "hex"));
    var messageOffset = encodedRelayData.length - 4 - encodedMessage.length;
    var contentToHash = Buffer.concat([
        encodedRelayData.slice(0, messageOffset),
        encodedMessageHash,
        Uint8Array.from(uint64Encoder.encode(BigInt(destinationChainId))),
    ]);
    return (0, utils_2.keccak256)(contentToHash);
}
function resolveFillStatusFromPdaEvents(fillStatusPda, toSlot, svmEventsClient) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var eventsToQuery, relevantEvents, fillStatusEvent;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    eventsToQuery = [types_1.SVMEventNames.FilledRelay, types_1.SVMEventNames.RequestedSlowFill];
                    return [4, Promise.all(eventsToQuery.map(function (eventName) {
                            return svmEventsClient.queryDerivedAddressEvents(eventName, fillStatusPda, undefined, toSlot, { limit: 10 });
                        }))];
                case 1:
                    relevantEvents = (_a.sent()).flat();
                    if (relevantEvents.length === 0) {
                        return [2, interfaces_1.FillStatus.Unfilled];
                    }
                    relevantEvents.sort(function (a, b) { return Number(a.slot - b.slot); });
                    fillStatusEvent = relevantEvents.pop();
                    switch (fillStatusEvent.name) {
                        case types_1.SVMEventNames.FilledRelay:
                            return [2, interfaces_1.FillStatus.Filled];
                        case types_1.SVMEventNames.RequestedSlowFill:
                            return [2, interfaces_1.FillStatus.RequestedSlowFill];
                        default:
                            throw new Error("Unexpected event name: ".concat(fillStatusEvent.name));
                    }
                    return [2];
            }
        });
    });
}
function fetchBatchFillStatusFromPdaAccounts(provider, fillStatusPdas, relayDataArray, logger) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var chunkSize, commitment, _a, pdaAccounts, timestamp, fillStatuses;
        return tslib_1.__generator(this, function (_b) {
            switch (_b.label) {
                case 0:
                    chunkSize = 100;
                    commitment = "confirmed";
                    return [4, Promise.all([
                            Promise.all((0, utils_2.chunk)(fillStatusPdas, chunkSize).map(function (chunk) { return (0, kit_1.fetchEncodedAccounts)(provider, chunk, { commitment: commitment }); })),
                            (0, utils_3.getNearestSlotTime)(provider, { commitment: commitment }, logger),
                        ])];
                case 1:
                    _a = _b.sent(), pdaAccounts = _a[0], timestamp = _a[1].timestamp;
                    fillStatuses = pdaAccounts.flat().map(function (account, index) {
                        if (account.exists) {
                            var decodedAccount = (0, SvmSpoke_1.decodeFillStatusAccount)(account);
                            return decodedAccount.data.status;
                        }
                        if (timestamp < relayDataArray[index].fillDeadline) {
                            return interfaces_1.FillStatus.Unfilled;
                        }
                        return undefined;
                    });
                    return [2, fillStatuses];
            }
        });
    });
}
function getFillRelayViaInstructionParamsInstructions(spokePool_1, relayData_1, repaymentChainId_1, repaymentAddress_1, signer_1) {
    return tslib_1.__awaiter(this, arguments, void 0, function (spokePool, relayData, repaymentChainId, repaymentAddress, signer, maxWriteSize) {
        var instructionParams, relayDataEncoder, svmRelayData, encodedRelayData, initInstructionParamsIx, instructions, i, offset, offsetEnd, fragment, writeInstructionParamsIx;
        if (maxWriteSize === void 0) { maxWriteSize = 450; }
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4, (0, _1.getInstructionParamsPda)(spokePool, signer.address)];
                case 1:
                    instructionParams = _a.sent();
                    relayDataEncoder = contracts_1.SvmSpokeClient.getFillRelayParamsEncoder();
                    svmRelayData = (0, _1.toSvmRelayData)(relayData);
                    encodedRelayData = relayDataEncoder.encode({
                        relayData: svmRelayData,
                        repaymentChainId: repaymentChainId,
                        repaymentAddress: (0, _1.toAddress)(repaymentAddress),
                    });
                    initInstructionParamsIx = contracts_1.SvmSpokeClient.getInitializeInstructionParamsInstruction({
                        signer: signer,
                        instructionParams: instructionParams,
                        totalSize: encodedRelayData.length,
                    });
                    instructions = [initInstructionParamsIx];
                    for (i = 0; i <= encodedRelayData.length / maxWriteSize; ++i) {
                        offset = i * maxWriteSize;
                        offsetEnd = Math.min(offset + maxWriteSize, encodedRelayData.length);
                        fragment = encodedRelayData.slice(offset, offsetEnd);
                        writeInstructionParamsIx = contracts_1.SvmSpokeClient.getWriteInstructionParamsFragmentInstruction({
                            signer: signer,
                            instructionParams: instructionParams,
                            offset: offset,
                            fragment: fragment,
                        });
                        instructions.push(writeInstructionParamsIx);
                    }
                    return [2, instructions];
            }
        });
    });
}
function getDepositDelegatePda(depositData, programId) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var addrEnc, u64, u32, parts, seedHash, pda;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    addrEnc = (0, kit_1.getAddressEncoder)();
                    u64 = (0, kit_1.getU64Encoder)();
                    u32 = (0, kit_1.getU32Encoder)();
                    parts = [
                        Uint8Array.from(addrEnc.encode(depositData.depositor)),
                        Uint8Array.from(addrEnc.encode(depositData.recipient)),
                        Uint8Array.from(addrEnc.encode(depositData.inputToken)),
                        Uint8Array.from(addrEnc.encode(depositData.outputToken)),
                        Uint8Array.from(u64.encode(depositData.inputAmount)),
                        Uint8Array.from(depositData.outputAmount),
                        Uint8Array.from(u64.encode(depositData.destinationChainId)),
                        Uint8Array.from(addrEnc.encode(depositData.exclusiveRelayer)),
                        Uint8Array.from(u32.encode(depositData.quoteTimestamp)),
                        Uint8Array.from(u32.encode(depositData.fillDeadline)),
                        Uint8Array.from(u32.encode(depositData.exclusivityParameter)),
                        Uint8Array.from(u32.encode(BigInt(depositData.message.length))),
                        depositData.message,
                    ];
                    seedHash = Buffer.from((0, utils_2.keccak256)(Buffer.concat(parts)).slice(2), "hex");
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: programId,
                            seeds: [Buffer.from("delegate"), seedHash],
                        })];
                case 1:
                    pda = (_a.sent())[0];
                    return [2, pda];
            }
        });
    });
}
function getDepositNowDelegatePda(depositData, programId) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var addrEnc, u64, u32, parts, seedHash, pda;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    addrEnc = (0, kit_1.getAddressEncoder)();
                    u64 = (0, kit_1.getU64Encoder)();
                    u32 = (0, kit_1.getU32Encoder)();
                    parts = [
                        Uint8Array.from(addrEnc.encode(depositData.depositor)),
                        Uint8Array.from(addrEnc.encode(depositData.recipient)),
                        Uint8Array.from(addrEnc.encode(depositData.inputToken)),
                        Uint8Array.from(addrEnc.encode(depositData.outputToken)),
                        Uint8Array.from(u64.encode(depositData.inputAmount)),
                        Uint8Array.from(depositData.outputAmount),
                        Uint8Array.from(u64.encode(depositData.destinationChainId)),
                        Uint8Array.from(addrEnc.encode(depositData.exclusiveRelayer)),
                        Uint8Array.from(u32.encode(depositData.fillDeadlineOffset)),
                        Uint8Array.from(u32.encode(depositData.exclusivityPeriod)),
                        Uint8Array.from(u32.encode(BigInt(depositData.message.length))),
                        depositData.message,
                    ];
                    seedHash = Buffer.from((0, utils_2.keccak256)(Buffer.concat(parts)).slice(2), "hex");
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: programId,
                            seeds: [Buffer.from("delegate"), seedHash],
                        })];
                case 1:
                    pda = (_a.sent())[0];
                    return [2, pda];
            }
        });
    });
}
function getFillRelayDelegatePda(relayHash, repaymentChainId, repaymentAddress, programId) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var addrEnc, u64, parts, seedHash, pda;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    addrEnc = (0, kit_1.getAddressEncoder)();
                    u64 = (0, kit_1.getU64Encoder)();
                    parts = [
                        relayHash,
                        Uint8Array.from(u64.encode(repaymentChainId)),
                        Uint8Array.from(addrEnc.encode(repaymentAddress)),
                    ];
                    seedHash = Buffer.from((0, utils_2.keccak256)(Buffer.concat(parts)).slice(2), "hex");
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: programId,
                            seeds: [Buffer.from("delegate"), seedHash],
                        })];
                case 1:
                    pda = (_a.sent())[0];
                    return [2, pda];
            }
        });
    });
}
var hasCCTPV1MessageBeenProcessed = function (solanaClient, signer, nonce, sourceDomain, latestBlockhash) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
    var noncePda, isNonceUsedIx, parserFunction;
    return tslib_1.__generator(this, function (_a) {
        switch (_a.label) {
            case 0: return [4, (0, _1.getCCTPNoncePda)(solanaClient, signer, nonce, sourceDomain)];
            case 1:
                noncePda = _a.sent();
                isNonceUsedIx = contracts_1.MessageTransmitterClient.getIsNonceUsedInstruction({
                    nonce: nonce,
                    usedNonces: noncePda,
                });
                parserFunction = function (buf) {
                    if (buf.length != 1) {
                        throw new Error("Invalid buffer length for isNonceUsedIx");
                    }
                    return Boolean(buf[0]);
                };
                return [4, (0, _1.simulateAndDecode)(solanaClient, isNonceUsedIx, signer, parserFunction, latestBlockhash)];
            case 2: return [2, _a.sent()];
        }
    });
}); };
exports.hasCCTPV1MessageBeenProcessed = hasCCTPV1MessageBeenProcessed;
function getAccountMetasForTokenlessMessage(solanaClient, signer, messageBytes) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var messageHex, messageHeader, programAddress, statePda, selfAuthority, eventAuthority, base, rootBundleId, rootBundle, rootBundleId, rootBundle;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    messageHex = messageBytes.slice(2);
                    messageHeader = (0, web3_v1_1.decodeMessageHeader)(Buffer.from(messageHex, "hex"));
                    programAddress = contracts_1.SvmSpokeClient.SVM_SPOKE_PROGRAM_ADDRESS;
                    return [4, (0, _1.getStatePda)(programAddress)];
                case 1:
                    statePda = _a.sent();
                    return [4, (0, _1.getSelfAuthority)()];
                case 2:
                    selfAuthority = _a.sent();
                    return [4, (0, _1.getEventAuthority)(programAddress)];
                case 3:
                    eventAuthority = _a.sent();
                    base = [
                        { address: statePda, role: kit_1.AccountRole.READONLY },
                        { address: selfAuthority, role: kit_1.AccountRole.READONLY },
                        { address: programAddress, role: kit_1.AccountRole.READONLY },
                    ];
                    if (!(0, utils_3.isRelayRootBundleMessageBody)(messageHeader.messageBody)) return [3, 6];
                    return [4, contracts_1.SvmSpokeClient.fetchState(solanaClient, statePda)];
                case 4:
                    rootBundleId = (_a.sent()).data.rootBundleId;
                    return [4, (0, _1.getRootBundlePda)(programAddress, rootBundleId)];
                case 5:
                    rootBundle = _a.sent();
                    return [2, tslib_1.__spreadArray(tslib_1.__spreadArray([], base, true), [
                            { address: signer.address, role: kit_1.AccountRole.WRITABLE },
                            { address: statePda, role: kit_1.AccountRole.WRITABLE },
                            { address: rootBundle, role: kit_1.AccountRole.WRITABLE },
                            { address: system_1.SYSTEM_PROGRAM_ADDRESS, role: kit_1.AccountRole.READONLY },
                            { address: eventAuthority, role: kit_1.AccountRole.READONLY },
                            { address: programAddress, role: kit_1.AccountRole.READONLY },
                        ], false)];
                case 6:
                    if (!(0, utils_3.isEmergencyDeleteRootBundleMessageBody)(messageHeader.messageBody)) return [3, 8];
                    rootBundleId = (0, utils_3.getEmergencyDeleteRootBundleRootBundleId)(messageHeader.messageBody);
                    return [4, (0, _1.getRootBundlePda)(programAddress, rootBundleId)];
                case 7:
                    rootBundle = _a.sent();
                    return [2, tslib_1.__spreadArray(tslib_1.__spreadArray([], base, true), [
                            { address: signer.address, role: kit_1.AccountRole.READONLY },
                            { address: statePda, role: kit_1.AccountRole.READONLY },
                            { address: rootBundle, role: kit_1.AccountRole.WRITABLE },
                            { address: eventAuthority, role: kit_1.AccountRole.READONLY },
                            { address: programAddress, role: kit_1.AccountRole.READONLY },
                        ], false)];
                case 8: return [2, tslib_1.__spreadArray(tslib_1.__spreadArray([], base, true), [
                        { address: statePda, role: kit_1.AccountRole.WRITABLE },
                        { address: eventAuthority, role: kit_1.AccountRole.READONLY },
                        { address: programAddress, role: kit_1.AccountRole.READONLY },
                    ], false)];
            }
        });
    });
}
function getCCTPDepositAccounts(hubChainId, cctpDestinationDomainId, tokenMessengerMinterAddress, messageTransmitterAddress) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var l2Usdc, _a, tokenMessenger, tokenMinter, localToken, cctpEventAuthority, remoteTokenMessenger, tokenMessengerMinterSenderAuthority, messageTransmitter;
        return tslib_1.__generator(this, function (_b) {
            switch (_b.label) {
                case 0:
                    l2Usdc = utils_2.SvmAddress.from(constants_1.TOKEN_SYMBOLS_MAP.USDC.addresses[(0, utils_2.chainIsProd)(hubChainId) ? constants_1.CHAIN_IDs.SOLANA : constants_1.CHAIN_IDs.SOLANA_DEVNET]);
                    return [4, Promise.all([
                            (0, kit_1.getProgramDerivedAddress)({
                                programAddress: tokenMessengerMinterAddress,
                                seeds: ["token_messenger"],
                            }),
                            (0, kit_1.getProgramDerivedAddress)({
                                programAddress: tokenMessengerMinterAddress,
                                seeds: ["token_minter"],
                            }),
                            (0, kit_1.getProgramDerivedAddress)({
                                programAddress: tokenMessengerMinterAddress,
                                seeds: ["local_token", utils_2.bs58.decode(l2Usdc.toBase58())],
                            }),
                            (0, kit_1.getProgramDerivedAddress)({
                                programAddress: tokenMessengerMinterAddress,
                                seeds: ["__event_authority"],
                            }),
                            (0, kit_1.getProgramDerivedAddress)({
                                programAddress: tokenMessengerMinterAddress,
                                seeds: ["remote_token_messenger", String(cctpDestinationDomainId)],
                            }),
                            (0, kit_1.getProgramDerivedAddress)({
                                programAddress: tokenMessengerMinterAddress,
                                seeds: ["sender_authority"],
                            }),
                            (0, kit_1.getProgramDerivedAddress)({
                                programAddress: messageTransmitterAddress,
                                seeds: ["message_transmitter"],
                            }),
                        ])];
                case 1:
                    _a = _b.sent(), tokenMessenger = _a[0][0], tokenMinter = _a[1][0], localToken = _a[2][0], cctpEventAuthority = _a[3][0], remoteTokenMessenger = _a[4][0], tokenMessengerMinterSenderAuthority = _a[5][0], messageTransmitter = _a[6][0];
                    return [2, {
                            tokenMessenger: tokenMessenger,
                            tokenMinter: tokenMinter,
                            localToken: localToken,
                            cctpEventAuthority: cctpEventAuthority,
                            remoteTokenMessenger: remoteTokenMessenger,
                            tokenMessengerMinterSenderAuthority: tokenMessengerMinterSenderAuthority,
                            messageTransmitter: messageTransmitter,
                        }];
            }
        });
    });
}
function getAccountMetasForDepositMessage(message, hubChainId, tokenMessengerMinter, recipientAta) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var l1Usdc, l2Usdc, tokenMessengerPda, tokenMinterPda, localTokenPda, tokenMessengerEventAuthorityPda, custodyTokenAccountPda, tokenPairPda, remoteTokenMessengerPda;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    l1Usdc = utils_2.EvmAddress.from(constants_1.TOKEN_SYMBOLS_MAP.USDC.addresses[hubChainId]);
                    l2Usdc = utils_2.SvmAddress.from(constants_1.TOKEN_SYMBOLS_MAP.USDC.addresses[(0, utils_2.chainIsProd)(hubChainId) ? constants_1.CHAIN_IDs.SOLANA : constants_1.CHAIN_IDs.SOLANA_DEVNET]);
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: tokenMessengerMinter,
                            seeds: ["token_messenger"],
                        })];
                case 1:
                    tokenMessengerPda = (_a.sent())[0];
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: tokenMessengerMinter,
                            seeds: ["token_minter"],
                        })];
                case 2:
                    tokenMinterPda = (_a.sent())[0];
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: tokenMessengerMinter,
                            seeds: ["local_token", utils_2.bs58.decode(l2Usdc.toBase58())],
                        })];
                case 3:
                    localTokenPda = (_a.sent())[0];
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: tokenMessengerMinter,
                            seeds: ["__event_authority"],
                        })];
                case 4:
                    tokenMessengerEventAuthorityPda = (_a.sent())[0];
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: tokenMessengerMinter,
                            seeds: ["custody", utils_2.bs58.decode(l2Usdc.toBase58())],
                        })];
                case 5:
                    custodyTokenAccountPda = (_a.sent())[0];
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: tokenMessengerMinter,
                            seeds: [
                                new Uint8Array(Buffer.from("token_pair")),
                                new Uint8Array(Buffer.from(String(message.sourceDomain))),
                                new Uint8Array(Buffer.from(l1Usdc.toBytes32().slice(2), "hex")),
                            ],
                        })];
                case 6:
                    tokenPairPda = (_a.sent())[0];
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: tokenMessengerMinter,
                            seeds: ["remote_token_messenger", String(message.sourceDomain)],
                        })];
                case 7:
                    remoteTokenMessengerPda = (_a.sent())[0];
                    return [2, [
                            { address: tokenMessengerPda, role: kit_1.AccountRole.READONLY },
                            { address: remoteTokenMessengerPda, role: kit_1.AccountRole.READONLY },
                            { address: tokenMinterPda, role: kit_1.AccountRole.WRITABLE },
                            { address: localTokenPda, role: kit_1.AccountRole.WRITABLE },
                            { address: tokenPairPda, role: kit_1.AccountRole.READONLY },
                            { address: (0, _1.toAddress)(recipientAta), role: kit_1.AccountRole.WRITABLE },
                            { address: custodyTokenAccountPda, role: kit_1.AccountRole.WRITABLE },
                            { address: token_1.TOKEN_PROGRAM_ADDRESS, role: kit_1.AccountRole.READONLY },
                            { address: tokenMessengerEventAuthorityPda, role: kit_1.AccountRole.READONLY },
                            { address: tokenMessengerMinter, role: kit_1.AccountRole.READONLY },
                        ]];
            }
        });
    });
}
function getCCTPV1ReceiveMessageTx(solanaClient, signer, message, hubChainId, recipientAta) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var messageTransmitterPda, eventAuthorityPda, cctpMessageReceiver, authorityPda, usedNonces, accountMetas, _a, messageBytes, input;
        return tslib_1.__generator(this, function (_b) {
            switch (_b.label) {
                case 0: return [4, (0, kit_1.getProgramDerivedAddress)({
                        programAddress: contracts_1.MessageTransmitterClient.MESSAGE_TRANSMITTER_PROGRAM_ADDRESS,
                        seeds: ["message_transmitter"],
                    })];
                case 1:
                    messageTransmitterPda = (_b.sent())[0];
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: contracts_1.MessageTransmitterClient.MESSAGE_TRANSMITTER_PROGRAM_ADDRESS,
                            seeds: ["__event_authority"],
                        })];
                case 2:
                    eventAuthorityPda = (_b.sent())[0];
                    cctpMessageReceiver = (0, _1.isDepositForBurnEvent)(message)
                        ? contracts_1.TokenMessengerMinterClient.TOKEN_MESSENGER_MINTER_PROGRAM_ADDRESS
                        : contracts_1.SvmSpokeClient.SVM_SPOKE_PROGRAM_ADDRESS;
                    return [4, (0, kit_1.getProgramDerivedAddress)({
                            programAddress: contracts_1.MessageTransmitterClient.MESSAGE_TRANSMITTER_PROGRAM_ADDRESS,
                            seeds: ["message_transmitter_authority", utils_2.bs58.decode(cctpMessageReceiver)],
                        })];
                case 3:
                    authorityPda = (_b.sent())[0];
                    return [4, (0, _1.getCCTPNoncePda)(solanaClient, signer, message.nonce, message.sourceDomain)];
                case 4:
                    usedNonces = _b.sent();
                    if (!(0, _1.isDepositForBurnEvent)(message)) return [3, 6];
                    return [4, getAccountMetasForDepositMessage(message, hubChainId, contracts_1.TokenMessengerMinterClient.TOKEN_MESSENGER_MINTER_PROGRAM_ADDRESS, recipientAta)];
                case 5:
                    _a = _b.sent();
                    return [3, 8];
                case 6: return [4, getAccountMetasForTokenlessMessage(solanaClient, signer, message.messageBytes)];
                case 7:
                    _a = _b.sent();
                    _b.label = 8;
                case 8:
                    accountMetas = _a;
                    messageBytes = message.messageBytes.startsWith("0x")
                        ? Buffer.from(message.messageBytes.slice(2), "hex")
                        : Buffer.from(message.messageBytes, "hex");
                    input = {
                        program: contracts_1.MessageTransmitterClient.MESSAGE_TRANSMITTER_PROGRAM_ADDRESS,
                        payer: signer,
                        caller: signer,
                        authorityPda: authorityPda,
                        messageTransmitter: messageTransmitterPda,
                        eventAuthority: eventAuthorityPda,
                        usedNonces: usedNonces,
                        receiver: cctpMessageReceiver,
                        systemProgram: system_1.SYSTEM_PROGRAM_ADDRESS,
                        message: messageBytes,
                        attestation: Buffer.from(message.attestation.slice(2), "hex"),
                    };
                    return [2, (0, exports.createReceiveMessageInstruction)(signer, solanaClient, input, accountMetas)];
            }
        });
    });
}
function finalizeCCTPV1Messages(solanaClient, attestedMessages, signer, recipientAta, simulate, hubChainId) {
    var _this = this;
    if (simulate === void 0) { simulate = false; }
    if (hubChainId === void 0) { hubChainId = 1; }
    return (0, utils_2.mapAsync)(attestedMessages, function (message) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
        var receiveMessageIx, result, _a, _b, _c, signedTransaction, signature, encodedTransaction;
        return tslib_1.__generator(this, function (_d) {
            switch (_d.label) {
                case 0: return [4, getCCTPV1ReceiveMessageTx(solanaClient, signer, message, hubChainId, recipientAta)];
                case 1:
                    receiveMessageIx = _d.sent();
                    if (!simulate) return [3, 4];
                    _b = (_a = solanaClient)
                        .simulateTransaction;
                    _c = kit_1.getBase64EncodedWireTransaction;
                    return [4, (0, kit_1.signTransactionMessageWithSigners)(receiveMessageIx)];
                case 2: return [4, _b.apply(_a, [_c.apply(void 0, [_d.sent()]),
                        {
                            encoding: "base64",
                        }])
                        .send()];
                case 3:
                    result = _d.sent();
                    if (result.value.err) {
                        throw new Error(result.value.err.toString());
                    }
                    return [2, ""];
                case 4: return [4, (0, kit_1.signTransactionMessageWithSigners)(receiveMessageIx)];
                case 5:
                    signedTransaction = _d.sent();
                    signature = (0, kit_1.getSignatureFromTransaction)(signedTransaction);
                    encodedTransaction = (0, kit_1.getBase64EncodedWireTransaction)(signedTransaction);
                    return [4, solanaClient
                            .sendTransaction(encodedTransaction, { preflightCommitment: "confirmed", encoding: "base64" })
                            .send()];
                case 6:
                    _d.sent();
                    return [2, signature];
            }
        });
    }); });
}
function getMintInfo(solanaClient, mint, config) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4, (0, token_1.fetchMint)(solanaClient, mint, config)];
                case 1: return [2, _a.sent()];
            }
        });
    });
}
function extractValueAmount(acrossPlusMessageBytes) {
    var VALUE_OFFSET = 32 + 1;
    var VALUE_END = VALUE_OFFSET + 8;
    if (acrossPlusMessageBytes.length < VALUE_END) {
        throw new Error("svm | extractValueAmount: Message too short, need at least ".concat(VALUE_END, " bytes, got ").concat(acrossPlusMessageBytes.length));
    }
    return readU64LEExact(acrossPlusMessageBytes.subarray(VALUE_OFFSET, VALUE_END));
}
function readU64LEExact(bytes) {
    if (bytes.length !== 8) {
        throw new Error("readU64LEExact expected 8 bytes, received ".concat(bytes.length));
    }
    var view = new DataView(bytes.buffer, bytes.byteOffset, 8);
    return view.getBigUint64(0, true);
}
//# sourceMappingURL=SpokeUtils.js.map