"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.readProgramEvents = exports.readEvents = exports.findProgramAddress = exports.calculateRelayHashUint8Array = void 0;
exports.printLogs = printLogs;
exports.randomAddress = randomAddress;
exports.randomBigInt = randomBigInt;
exports.buildRelayerRefundMerkleTree = buildRelayerRefundMerkleTree;
exports.testAcrossPlusMessage = testAcrossPlusMessage;
const anchor_1 = require("@coral-xyz/anchor");
const web3_js_1 = require("@solana/web3.js");
const crypto = __importStar(require("crypto"));
const ethers_1 = require("ethers");
const svm_1 = require("../../src/svm");
Object.defineProperty(exports, "calculateRelayHashUint8Array", { enumerable: true, get: function () { return svm_1.calculateRelayHashUint8Array; } });
Object.defineProperty(exports, "findProgramAddress", { enumerable: true, get: function () { return svm_1.findProgramAddress; } });
Object.defineProperty(exports, "readEvents", { enumerable: true, get: function () { return svm_1.readEvents; } });
Object.defineProperty(exports, "readProgramEvents", { enumerable: true, get: function () { return svm_1.readProgramEvents; } });
const common_1 = require("@uma/common");
async function printLogs(connection, program, tx) {
    const latestBlockHash = await connection.getLatestBlockhash();
    await connection.confirmTransaction({
        blockhash: latestBlockHash.blockhash,
        lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
        signature: tx,
    }, "confirmed");
    const txDetails = await program.provider.connection.getTransaction(tx, {
        maxSupportedTransactionVersion: 0,
        commitment: "confirmed",
    });
    const logs = txDetails?.meta?.logMessages || null;
    if (!logs) {
        console.log("No logs found");
    }
}
function randomAddress() {
    const wallet = ethers_1.ethers.Wallet.createRandom();
    return wallet.address;
}
function randomBigInt(bytes = 8, signed = false) {
    const sign = signed && Math.random() < 0.5 ? "-" : "";
    const byteString = "0x" + Buffer.from(crypto.randomBytes(bytes)).toString("hex");
    return BigInt(sign + byteString);
}
function buildRelayerRefundMerkleTree({ totalEvmDistributions, totalSolanaDistributions, mixLeaves, chainId, mint, svmRelayers, evmRelayers, evmTokenAddress, evmRefundAmounts, svmRefundAmounts, }) {
    const relayerRefundLeaves = [];
    const createSolanaLeaf = (index) => ({
        isSolana: true,
        leafId: new anchor_1.BN(index),
        chainId: new anchor_1.BN(chainId),
        amountToReturn: new anchor_1.BN(0),
        mintPublicKey: mint ?? web3_js_1.Keypair.generate().publicKey,
        refundAddresses: svmRelayers || [web3_js_1.Keypair.generate().publicKey, web3_js_1.Keypair.generate().publicKey],
        refundAmounts: svmRefundAmounts || [new anchor_1.BN(randomBigInt(2).toString()), new anchor_1.BN(randomBigInt(2).toString())],
    });
    const createEvmLeaf = (index) => ({
        isSolana: false,
        leafId: ethers_1.BigNumber.from(index),
        chainId: ethers_1.BigNumber.from(chainId),
        amountToReturn: ethers_1.BigNumber.from(0),
        l2TokenAddress: evmTokenAddress ?? randomAddress(),
        refundAddresses: evmRelayers || [randomAddress(), randomAddress()],
        refundAmounts: evmRefundAmounts || [ethers_1.BigNumber.from(randomBigInt()), ethers_1.BigNumber.from(randomBigInt())],
    });
    if (mixLeaves) {
        let solanaIndex = 0;
        let evmIndex = 0;
        const totalDistributions = totalSolanaDistributions + totalEvmDistributions;
        for (let i = 0; i < totalDistributions; i++) {
            if (solanaIndex < totalSolanaDistributions && (i % 2 === 0 || evmIndex >= totalEvmDistributions)) {
                relayerRefundLeaves.push(createSolanaLeaf(solanaIndex));
                solanaIndex++;
            }
            else if (evmIndex < totalEvmDistributions) {
                relayerRefundLeaves.push(createEvmLeaf(evmIndex));
                evmIndex++;
            }
        }
    }
    else {
        for (let i = 0; i < totalSolanaDistributions; i++) {
            relayerRefundLeaves.push(createSolanaLeaf(i));
        }
        for (let i = 0; i < totalEvmDistributions; i++) {
            relayerRefundLeaves.push(createEvmLeaf(i + totalSolanaDistributions));
        }
    }
    const merkleTree = new common_1.MerkleTree(relayerRefundLeaves, svm_1.relayerRefundHashFn);
    return { relayerRefundLeaves, merkleTree };
}
// Encodes empty list of multicall handler instructions to be used as a test message field for fills.
function testAcrossPlusMessage() {
    const handlerProgram = anchor_1.workspace.MulticallHandler;
    const multicallHandlerCoder = new svm_1.MulticallHandlerCoder([]);
    const handlerMessage = multicallHandlerCoder.encode();
    const message = new svm_1.AcrossPlusMessageCoder({
        handler: handlerProgram.programId,
        readOnlyLen: multicallHandlerCoder.readOnlyLen,
        valueAmount: new anchor_1.BN(0),
        accounts: multicallHandlerCoder.compiledMessage.accountKeys,
        handlerMessage,
    });
    const encodedMessage = message.encode();
    const fillRemainingAccounts = [
        { pubkey: handlerProgram.programId, isSigner: false, isWritable: false },
        ...multicallHandlerCoder.compiledKeyMetas,
    ];
    return { encodedMessage, fillRemainingAccounts };
}
