@locker-labs/sdk
Version:
A utility library for enhancing your ERC-4337 experience
119 lines • 5.42 kB
JavaScript
import * as anchor from "@coral-xyz/anchor";
import { PublicKey, Connection } from '@solana/web3.js';
import fetch from 'node-fetch';
import { getAssociatedTokenAddress, getAccount } from "@solana/spl-token";
import {} from './target/types/message_transmitter';
import {} from './target/types/token_messenger_minter';
import * as MessageTransmitterIDL from './target/idl/message_transmitter.json';
import * as TokenMessengerMinterIDL from './target/idl/token_messenger_minter.json';
import * as evmMessageTransmitterAbi from './abi/evm/message_transmitter.json';
import { EChain } from "../../../accounts/tokens.js";
import { CCTP_DOMAIN_IDS, CCTP_EVM_CONTRACTS } from './cctpConstants.js';
/**
* Returns the Anchor programs for MessageTransmitter + TokenMessengerMinter.
*/
export const getPrograms = (provider) => {
// Initialize contracts
// Initialize workspace with explicit program IDs from devnet
const messageTransmitterProgram = new anchor.Program(
// You'll need to import these IDLs
MessageTransmitterIDL, new PublicKey("CCTPmbSD7gX1bxKPAmg77w8oFzNFpaQiQUWD43TKaecd"), provider);
const tokenMessengerMinterProgram = new anchor.Program(TokenMessengerMinterIDL, new PublicKey("CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3"), provider);
return { messageTransmitterProgram, tokenMessengerMinterProgram };
};
/**
* Finds PDAs needed for depositForBurn.
*/
export const getDepositForBurnPdas = ({ messageTransmitterProgram, tokenMessengerMinterProgram }, usdcAddress, destinationDomain) => {
const messageTransmitterAccount = findProgramAddress("message_transmitter", messageTransmitterProgram.programId);
const tokenMessengerAccount = findProgramAddress("token_messenger", tokenMessengerMinterProgram.programId);
const tokenMinterAccount = findProgramAddress("token_minter", tokenMessengerMinterProgram.programId);
const localToken = findProgramAddress("local_token", tokenMessengerMinterProgram.programId, [usdcAddress]);
const remoteTokenMessengerKey = findProgramAddress("remote_token_messenger", tokenMessengerMinterProgram.programId, [
destinationDomain.toString(),
]);
const authorityPda = findProgramAddress("sender_authority", tokenMessengerMinterProgram.programId);
return {
messageTransmitterAccount,
tokenMessengerAccount,
tokenMinterAccount,
localToken,
remoteTokenMessengerKey,
authorityPda,
};
};
/**
* Helper function to fetch Circle's attestation data for a specific Solana transaction.
*/
export async function getMessages(txHash, irisApiUrl, solanaChain) {
let attestationResponse = {};
const solanaDomain = CCTP_DOMAIN_IDS[solanaChain];
while (attestationResponse.error ||
!attestationResponse.messages ||
attestationResponse.messages?.[0]?.attestation === 'PENDING') {
const response = await fetch(`${irisApiUrl}/messages/${solanaDomain}/${txHash}`);
attestationResponse = await response.json();
// Wait 2 seconds to avoid potential rate-limiting
if (attestationResponse.error ||
!attestationResponse.messages ||
attestationResponse.messages?.[0]?.attestation === 'PENDING') {
await new Promise((resolve) => setTimeout(resolve, 2000));
}
}
return attestationResponse;
}
/**
* Convert an EVM address (0x1234...) into a zero-padded 32-byte hex string.
*/
export function evmAddressToBytes32(address) {
return `0x000000000000000000000000${address.replace('0x', '')}`;
}
/**
* Convenience wrapper for PublicKey.findProgramAddressSync
*/
export function findProgramAddress(label, programId, extraSeeds = []) {
const seeds = [Buffer.from(anchor.utils.bytes.utf8.encode(label))];
for (const extraSeed of extraSeeds) {
if (typeof extraSeed === 'string') {
seeds.push(Buffer.from(anchor.utils.bytes.utf8.encode(extraSeed)));
}
else if (Array.isArray(extraSeed)) {
seeds.push(Buffer.from(new Uint8Array(extraSeed)));
}
else if (Buffer.isBuffer(extraSeed)) {
seeds.push(Buffer.from(extraSeed));
}
else {
seeds.push(Buffer.from(extraSeed.toBuffer()));
}
}
const [publicKey, bump] = PublicKey.findProgramAddressSync(seeds, programId);
return { publicKey, bump };
}
export async function findOrCreateUserTokenAccount(params) {
const { solanaSigner, solanaTokenAddress, solanaRpcUrl } = params;
const solanaTokenPublicKey = new PublicKey(solanaTokenAddress);
const connection = new Connection(solanaRpcUrl);
try {
// Get the associated token account address
const tokenAccount = await getAssociatedTokenAddress(solanaTokenPublicKey, solanaSigner.publicKey);
// Check if the account exists
await getAccount(connection, tokenAccount);
return tokenAccount;
}
catch (error) {
throw new Error("Token account not found");
}
}
export function getMessageTransmitterFromChain(chain) {
if (chain === EChain.SOLANA || chain === EChain.SOLANA_DEVNET) {
throw new Error(`Unsupported chain: ${chain}`);
}
const address = CCTP_EVM_CONTRACTS.V1.MESSAGE_TRANSMITTER[chain];
console.log('Message transmitter address:', address);
return {
abi: evmMessageTransmitterAbi,
address,
};
}
//# sourceMappingURL=cctpUtils.js.map