"use strict";
// This script implements a simple relayer fill against known deposit props. Note that if the deposit data is done wrong
// this script can easily create invalid fills.
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;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const anchor = __importStar(require("@coral-xyz/anchor"));
const anchor_1 = require("@coral-xyz/anchor");
const spl_token_1 = require("@solana/spl-token");
const web3_js_1 = require("@solana/web3.js");
const yargs_1 = __importDefault(require("yargs"));
const helpers_1 = require("yargs/helpers");
const web3_v1_1 = require("../../src/svm/web3-v1");
// Set up the provider
const provider = anchor_1.AnchorProvider.env();
anchor.setProvider(provider);
const program = (0, web3_v1_1.getSpokePoolProgram)(provider);
const programId = program.programId;
// Parse arguments
const argv = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
    .option("seed", { type: "string", demandOption: true, describe: "Seed for the state account PDA" })
    .option("depositor", { type: "string", demandOption: true, describe: "Depositor public key" })
    .option("recipient", { type: "string", demandOption: true, describe: "Recipient public key" })
    .option("exclusiveRelayer", { type: "string", demandOption: false, describe: "Exclusive relayer public key" })
    .option("inputToken", { type: "string", demandOption: true, describe: "Input token public key" })
    .option("outputToken", { type: "string", demandOption: true, describe: "Output token public key" })
    .option("inputAmount", { type: "number", demandOption: true, describe: "Input amount" })
    .option("outputAmount", { type: "number", demandOption: true, describe: "Output amount" })
    .option("originChainId", { type: "string", demandOption: true, describe: "Origin chain ID" })
    .option("depositId", { type: "string", demandOption: true, describe: "Deposit ID" })
    .option("fillDeadline", { type: "number", demandOption: false, describe: "Fill deadline" })
    .option("exclusivityDeadline", { type: "number", demandOption: false, describe: "Exclusivity deadline" }).argv;
async function fillRelay() {
    const resolvedArgv = await argv;
    const depositor = new web3_js_1.PublicKey(resolvedArgv.depositor);
    const recipient = new web3_js_1.PublicKey(resolvedArgv.recipient);
    const exclusiveRelayer = new web3_js_1.PublicKey(resolvedArgv.exclusiveRelayer || "11111111111111111111111111111111");
    const inputToken = new web3_js_1.PublicKey(resolvedArgv.inputToken);
    const outputToken = new web3_js_1.PublicKey(resolvedArgv.outputToken);
    const inputAmount = new anchor_1.BN(resolvedArgv.inputAmount);
    const outputAmount = new anchor_1.BN(resolvedArgv.outputAmount);
    const originChainId = new anchor_1.BN(resolvedArgv.originChainId);
    const depositId = (0, web3_v1_1.intToU8Array32)(new anchor_1.BN(resolvedArgv.depositId));
    const fillDeadline = resolvedArgv.fillDeadline || Math.floor(Date.now() / 1000) + 60; // Current time + 1 minute
    const exclusivityDeadline = resolvedArgv.exclusivityDeadline || Math.floor(Date.now() / 1000) + 30; // Current time + 30 seconds
    const message = Buffer.from("");
    const seed = new anchor_1.BN(resolvedArgv.seed);
    const relayData = {
        depositor,
        recipient,
        exclusiveRelayer,
        inputToken,
        outputToken,
        inputAmount,
        outputAmount,
        originChainId,
        depositId,
        fillDeadline,
        exclusivityDeadline,
        message,
    };
    // Define the signer (replace with your actual signer)
    const signer = provider.wallet.payer;
    console.log("Filling V3 Relay...");
    // Define the state account PDA
    const [statePda, _] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("state"), seed.toArrayLike(Buffer, "le", 8)], programId);
    // Fetch the state from the on-chain program to get chainId
    const state = await program.account.state.fetch(statePda);
    const chainId = new anchor_1.BN(state.chainId);
    const relayHashUint8Array = (0, web3_v1_1.calculateRelayHashUint8Array)(relayData, chainId);
    // Define the fill status account PDA
    const [fillStatusPda] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("fills"), relayHashUint8Array], programId);
    // Create ATA for the relayer and recipient token accounts
    const relayerTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(outputToken, signer.publicKey, true, spl_token_1.TOKEN_PROGRAM_ID, spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID);
    const recipientTokenAccount = (await (0, spl_token_1.getOrCreateAssociatedTokenAccount)(provider.connection, signer, outputToken, recipient, true, undefined, undefined, spl_token_1.TOKEN_PROGRAM_ID, spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID)).address;
    console.table([
        { property: "relayHash", value: Buffer.from(relayHashUint8Array).toString("hex") },
        { property: "chainId", value: chainId.toString() },
        { property: "programId", value: programId.toString() },
        { property: "providerPublicKey", value: provider.wallet.publicKey.toString() },
        { property: "statePda", value: statePda.toString() },
        { property: "fillStatusPda", value: fillStatusPda.toString() },
        { property: "relayerTokenAccount", value: relayerTokenAccount.toString() },
        { property: "recipientTokenAccount", value: recipientTokenAccount.toString() },
        { property: "seed", value: seed.toString() },
    ]);
    console.log("Relay Data:");
    console.table(Object.entries(relayData).map(([key, value]) => ({
        key,
        value: value.toString(),
    })));
    const tokenDecimals = (await (0, spl_token_1.getMint)(provider.connection, outputToken, undefined, spl_token_1.TOKEN_PROGRAM_ID)).decimals;
    // Create the ATA using the create_token_accounts method
    const createTokenAccountsIx = await program.methods
        .createTokenAccounts()
        .accounts({ signer: signer.publicKey, mint: outputToken, tokenProgram: spl_token_1.TOKEN_PROGRAM_ID })
        .remainingAccounts([
        { pubkey: recipient, isWritable: false, isSigner: false },
        { pubkey: recipientTokenAccount, isWritable: true, isSigner: false },
    ])
        .instruction();
    // Delegate state PDA to pull relayer tokens.
    const approveIx = await (0, spl_token_1.createApproveCheckedInstruction)(relayerTokenAccount, outputToken, statePda, signer.publicKey, BigInt(relayData.outputAmount.toString()), tokenDecimals, undefined, spl_token_1.TOKEN_PROGRAM_ID);
    const fillDataValues = [Array.from(relayHashUint8Array), relayData, chainId, signer.publicKey];
    const fillAccounts = {
        state: statePda,
        signer: signer.publicKey,
        instructionParams: program.programId,
        mint: outputToken,
        relayerTokenAccount: relayerTokenAccount,
        recipientTokenAccount: recipientTokenAccount,
        fillStatus: fillStatusPda,
        tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
        associatedTokenProgram: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID,
        systemProgram: web3_js_1.SystemProgram.programId,
        programId: programId,
        program: program.programId,
    };
    const fillIx = await program.methods
        .fillRelay(...fillDataValues)
        .accounts(fillAccounts)
        .instruction();
    const fillTx = new web3_js_1.Transaction().add(createTokenAccountsIx, approveIx, fillIx);
    const tx = await (0, web3_js_1.sendAndConfirmTransaction)(provider.connection, fillTx, [signer]);
    console.log("Transaction signature:", tx);
}
// Run the fillV3Relay function
fillRelay();
