import { __awaiter, __generator, __spreadArray } from "tslib";
import { web3 } from "@coral-xyz/anchor";
import { AddressLookupTableProgram, TransactionMessage, VersionedTransaction, } from "@solana/web3.js";
/**
 * Sends a transaction using an Address Lookup Table for large numbers of accounts.
 */
export function sendTransactionWithLookupTable(connection_1, instructions_1, sender_1) {
    return __awaiter(this, arguments, void 0, function (connection, instructions, sender, additionalSigners) {
        var maxExtendedAccounts, lookupAddresses, _a, lookupTableInstruction, lookupTableAddress, _b, _c, i, extendInstruction, initialSlot, lookupTableAccount, versionedTx, _d, _e, txSignature, block;
        var _f, _g;
        if (additionalSigners === void 0) { additionalSigners = []; }
        return __generator(this, function (_h) {
            switch (_h.label) {
                case 0:
                    maxExtendedAccounts = 30;
                    lookupAddresses = Array.from(new Set(instructions.flatMap(function (instruction) { return __spreadArray([
                        instruction.programId
                    ], instruction.keys.map(function (accountMeta) { return accountMeta.pubkey; }), true); })));
                    _c = (_b = AddressLookupTableProgram).createLookupTable;
                    _f = {
                        authority: sender.publicKey,
                        payer: sender.publicKey
                    };
                    return [4 /*yield*/, connection.getSlot()];
                case 1: return [4 /*yield*/, _c.apply(_b, [(_f.recentSlot = _h.sent(),
                            _f)])];
                case 2:
                    _a = _h.sent(), lookupTableInstruction = _a[0], lookupTableAddress = _a[1];
                    // Submit the ALT creation transaction
                    return [4 /*yield*/, web3.sendAndConfirmTransaction(
                        // eslint-disable-next-line @typescript-eslint/no-explicit-any
                        connection, new web3.Transaction().add(lookupTableInstruction), [sender], {
                            commitment: "confirmed",
                            skipPreflight: true,
                        })];
                case 3:
                    // Submit the ALT creation transaction
                    _h.sent();
                    i = 0;
                    _h.label = 4;
                case 4:
                    if (!(i < lookupAddresses.length)) return [3 /*break*/, 7];
                    extendInstruction = AddressLookupTableProgram.extendLookupTable({
                        lookupTable: lookupTableAddress,
                        authority: sender.publicKey,
                        payer: sender.publicKey,
                        addresses: lookupAddresses.slice(i, i + maxExtendedAccounts),
                    });
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    return [4 /*yield*/, web3.sendAndConfirmTransaction(connection, new web3.Transaction().add(extendInstruction), [sender], {
                            commitment: "confirmed",
                            skipPreflight: true,
                        })];
                case 5:
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    _h.sent();
                    _h.label = 6;
                case 6:
                    i += maxExtendedAccounts;
                    return [3 /*break*/, 4];
                case 7: return [4 /*yield*/, connection.getSlot()];
                case 8:
                    initialSlot = _h.sent();
                    _h.label = 9;
                case 9: return [4 /*yield*/, connection.getSlot()];
                case 10:
                    if (!((_h.sent()) === initialSlot)) return [3 /*break*/, 12];
                    return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 50); })];
                case 11:
                    _h.sent();
                    return [3 /*break*/, 9];
                case 12: return [4 /*yield*/, connection.getAddressLookupTable(lookupTableAddress)];
                case 13:
                    lookupTableAccount = (_h.sent()).value;
                    if (lookupTableAccount === null)
                        throw new Error("AddressLookupTableAccount not fetched");
                    _d = VersionedTransaction.bind;
                    _e = TransactionMessage.bind;
                    _g = {
                        payerKey: sender.publicKey
                    };
                    return [4 /*yield*/, connection.getLatestBlockhash()];
                case 14:
                    versionedTx = new (_d.apply(VersionedTransaction, [void 0, new (_e.apply(TransactionMessage, [void 0, (_g.recentBlockhash = (_h.sent()).blockhash,
                                _g.instructions = instructions,
                                _g)]))().compileToV0Message([lookupTableAccount])]))();
                    // Sign and submit the versioned transaction.
                    versionedTx.sign(__spreadArray([sender], additionalSigners, true));
                    return [4 /*yield*/, connection.sendTransaction(versionedTx)];
                case 15:
                    txSignature = _h.sent();
                    return [4 /*yield*/, connection.getLatestBlockhash()];
                case 16:
                    block = _h.sent();
                    return [4 /*yield*/, connection.confirmTransaction({ signature: txSignature, blockhash: block.blockhash, lastValidBlockHeight: block.lastValidBlockHeight }, "confirmed")];
                case 17:
                    _h.sent();
                    return [2 /*return*/, { txSignature: txSignature, lookupTableAddress: lookupTableAddress }];
            }
        });
    });
}
/**
 * Sends a transaction using existing Address Lookup Table.
 */
export function sendTransactionWithExistingLookupTable(connection_1, instructions_1, lookupTableAccount_1, sender_1) {
    return __awaiter(this, arguments, void 0, function (connection, instructions, lookupTableAccount, sender, additionalSigners) {
        var versionedTx, _a, _b, txSignature, block;
        var _c;
        if (additionalSigners === void 0) { additionalSigners = []; }
        return __generator(this, function (_d) {
            switch (_d.label) {
                case 0:
                    _a = VersionedTransaction.bind;
                    _b = TransactionMessage.bind;
                    _c = {
                        payerKey: sender.publicKey
                    };
                    return [4 /*yield*/, connection.getLatestBlockhash()];
                case 1:
                    versionedTx = new (_a.apply(VersionedTransaction, [void 0, new (_b.apply(TransactionMessage, [void 0, (_c.recentBlockhash = (_d.sent()).blockhash,
                                _c.instructions = instructions,
                                _c)]))().compileToV0Message([lookupTableAccount])]))();
                    // Sign and submit the versioned transaction.
                    versionedTx.sign(__spreadArray([sender], additionalSigners, true));
                    return [4 /*yield*/, connection.sendTransaction(versionedTx)];
                case 2:
                    txSignature = _d.sent();
                    return [4 /*yield*/, connection.getLatestBlockhash()];
                case 3:
                    block = _d.sent();
                    return [4 /*yield*/, connection.confirmTransaction({ signature: txSignature, blockhash: block.blockhash, lastValidBlockHeight: block.lastValidBlockHeight }, "confirmed")];
                case 4:
                    _d.sent();
                    return [2 /*return*/, txSignature];
            }
        });
    });
}
//# sourceMappingURL=transactionUtils.js.map