"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createReceiveMessageInstruction = exports.nonceAccount = exports.calculateFirstNonce = void 0;
const spl_token_1 = require("@solana/spl-token");
const web3_js_1 = require("@solana/web3.js");
const connect_sdk_1 = require("@wormhole-foundation/connect-sdk");
const connect_sdk_solana_1 = require("@wormhole-foundation/connect-sdk-solana");
const accounts_1 = require("../accounts");
const program_1 = require("../program");
const MAX_NONCES_PER_ACCOUNT = 6400n;
function calculateFirstNonce(nonce) {
    return (((nonce - BigInt(1)) / MAX_NONCES_PER_ACCOUNT) * MAX_NONCES_PER_ACCOUNT +
        BigInt(1));
}
exports.calculateFirstNonce = calculateFirstNonce;
function nonceAccount(nonce, sourceChain, messageTransmitterProgramId) {
    const srcDomain = sourceChain.toString();
    const usedNonces = (0, accounts_1.findProgramAddress)('used_nonces', messageTransmitterProgramId, [srcDomain, calculateFirstNonce(nonce).toString()]).publicKey;
    return usedNonces;
}
exports.nonceAccount = nonceAccount;
async function createReceiveMessageInstruction(messageTransmitterProgramId, tokenMessengerProgramId, usdcAddress, circleMessage, attestation, payer) {
    const messageBytes = Buffer.from(connect_sdk_1.CircleBridge.serialize(circleMessage));
    const attestationBytes = Buffer.from(connect_sdk_1.encoding.hex.decode(attestation));
    const solanaUsdcAddress = new web3_js_1.PublicKey(usdcAddress);
    const sourceUsdcAddress = new web3_js_1.PublicKey(circleMessage.payload.burnToken.toUint8Array());
    const receiver = new connect_sdk_solana_1.SolanaAddress(circleMessage.payload.mintRecipient).unwrap();
    const payerPubkey = payer ? new web3_js_1.PublicKey(payer) : receiver;
    const userTokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(solanaUsdcAddress, receiver);
    const srcDomain = circleMessage.sourceDomain.toString();
    // Find pdas
    const messageTransmitterAccount = (0, accounts_1.findProgramAddress)('message_transmitter', messageTransmitterProgramId);
    const tokenMessenger = (0, accounts_1.findProgramAddress)('token_messenger', tokenMessengerProgramId);
    const tokenMinter = (0, accounts_1.findProgramAddress)('token_minter', tokenMessengerProgramId);
    const localToken = (0, accounts_1.findProgramAddress)('local_token', tokenMessengerProgramId, [solanaUsdcAddress]);
    const remoteTokenMessengerKey = (0, accounts_1.findProgramAddress)('remote_token_messenger', tokenMessengerProgramId, [srcDomain]);
    const tokenPair = (0, accounts_1.findProgramAddress)('token_pair', tokenMessengerProgramId, [
        srcDomain,
        sourceUsdcAddress,
    ]);
    const custodyTokenAccount = (0, accounts_1.findProgramAddress)('custody', tokenMessengerProgramId, [solanaUsdcAddress]);
    const authorityPda = (0, accounts_1.findProgramAddress)('message_transmitter_authority', messageTransmitterProgramId).publicKey;
    // Calculate the nonce PDA.
    const usedNonces = nonceAccount(circleMessage.nonce, circleMessage.sourceDomain, messageTransmitterProgramId);
    // Build the accountMetas list. These are passed as remainingAccounts for the TokenMessengerMinter CPI
    const accountMetas = [];
    accountMetas.push({
        isSigner: false,
        isWritable: false,
        pubkey: tokenMessenger.publicKey,
    });
    accountMetas.push({
        isSigner: false,
        isWritable: false,
        pubkey: remoteTokenMessengerKey.publicKey,
    });
    accountMetas.push({
        isSigner: false,
        isWritable: true,
        pubkey: tokenMinter.publicKey,
    });
    accountMetas.push({
        isSigner: false,
        isWritable: true,
        pubkey: localToken.publicKey,
    });
    accountMetas.push({
        isSigner: false,
        isWritable: false,
        pubkey: tokenPair.publicKey,
    });
    accountMetas.push({
        isSigner: false,
        isWritable: true,
        pubkey: userTokenAccount,
    });
    accountMetas.push({
        isSigner: false,
        isWritable: true,
        pubkey: custodyTokenAccount.publicKey,
    });
    accountMetas.push({
        isSigner: false,
        isWritable: false,
        pubkey: spl_token_1.TOKEN_PROGRAM_ID,
    });
    const messageTransmitterProgram = (0, program_1.createMessageTransmitterProgramInterface)(messageTransmitterProgramId);
    return (messageTransmitterProgram.methods
        .receiveMessage({
        message: messageBytes,
        attestation: attestationBytes,
    })
        .accounts({
        payer: payerPubkey,
        caller: payerPubkey,
        authorityPda,
        messageTransmitter: messageTransmitterAccount.publicKey,
        usedNonces,
        receiver: tokenMessengerProgramId,
        systemProgram: web3_js_1.SystemProgram.programId,
    })
        // Add remainingAccounts needed for TokenMessengerMinter CPI
        .remainingAccounts(accountMetas)
        .transaction());
}
exports.createReceiveMessageInstruction = createReceiveMessageInstruction;
//# sourceMappingURL=receiveMessage.js.map