@wormhole-foundation/sdk-solana-cctp
Version:
SDK for Solana, used in conjunction with @wormhole-foundation/sdk
120 lines • 5.58 kB
JavaScript
"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 sdk_connect_1 = require("@wormhole-foundation/sdk-connect");
const sdk_solana_1 = require("@wormhole-foundation/sdk-solana");
const program_js_1 = require("../program.js");
const index_js_1 = require("./../accounts/index.js");
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, index_js_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(sdk_connect_1.CircleBridge.serialize(circleMessage));
const attestationBytes = Buffer.from(sdk_connect_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 sdk_solana_1.SolanaAddress(circleMessage.payload.mintRecipient).unwrap();
const payerPubkey = payer ? new web3_js_1.PublicKey(payer) : receiver;
const srcDomain = circleMessage.sourceDomain.toString();
// Find pdas
const messageTransmitterAccount = (0, index_js_1.findProgramAddress)('message_transmitter', messageTransmitterProgramId);
const tokenMessenger = (0, index_js_1.findProgramAddress)('token_messenger', tokenMessengerProgramId);
const tokenMinter = (0, index_js_1.findProgramAddress)('token_minter', tokenMessengerProgramId);
const localToken = (0, index_js_1.findProgramAddress)('local_token', tokenMessengerProgramId, [solanaUsdcAddress]);
const remoteTokenMessengerKey = (0, index_js_1.findProgramAddress)('remote_token_messenger', tokenMessengerProgramId, [srcDomain]);
const tokenPair = (0, index_js_1.findProgramAddress)('token_pair', tokenMessengerProgramId, [
srcDomain,
sourceUsdcAddress,
]);
const custodyTokenAccount = (0, index_js_1.findProgramAddress)('custody', tokenMessengerProgramId, [solanaUsdcAddress]);
const authorityPda = (0, index_js_1.findProgramAddress)('message_transmitter_authority', messageTransmitterProgramId, [tokenMessengerProgramId]).publicKey;
// Calculate the nonce PDA.
const usedNonces = nonceAccount(circleMessage.nonce, circleMessage.sourceDomain, messageTransmitterProgramId);
const eventAuthority = (0, index_js_1.findProgramAddress)('__event_authority', messageTransmitterProgramId);
const tokenMessengerEventAuthority = (0, index_js_1.findProgramAddress)('__event_authority', tokenMessengerProgramId);
// 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: receiver,
});
accountMetas.push({
isSigner: false,
isWritable: true,
pubkey: custodyTokenAccount.publicKey,
});
accountMetas.push({
isSigner: false,
isWritable: false,
pubkey: spl_token_1.TOKEN_PROGRAM_ID,
});
accountMetas.push({
isSigner: false,
isWritable: false,
pubkey: tokenMessengerEventAuthority.publicKey,
});
accountMetas.push({
isSigner: false,
isWritable: false,
pubkey: tokenMessengerProgramId,
});
const messageTransmitterProgram = (0, program_js_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,
eventAuthority: eventAuthority.publicKey,
program: messageTransmitterProgram.programId,
})
// Add remainingAccounts needed for TokenMessengerMinter CPI
.remainingAccounts(accountMetas)
.transaction());
}
exports.createReceiveMessageInstruction = createReceiveMessageInstruction;
//# sourceMappingURL=receiveMessage.js.map