@coinbase/cdp-sdk
Version:
SDK for interacting with the Coinbase Developer Platform Wallet API
125 lines • 5.38 kB
JavaScript
import { pipe, createTransactionMessage, setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstructions, address, compileTransaction, setTransactionMessageFeePayer, createNoopSigner, getBase64EncodedWireTransaction, } from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
import { findAssociatedTokenPda, getCreateAssociatedTokenInstructionAsync, getTransferCheckedInstruction, fetchToken, fetchMint, TOKEN_PROGRAM_ADDRESS, } from "@solana-program/token";
import { createRpcClient } from "./rpc.js";
import { sendTransaction } from "./sendTransaction.js";
import { getConnectedNetwork, getOrCreateConnection, getUsdcMintAddress, } from "./utils.js";
/**
* Transfers SOL or SPL tokens between accounts
*
* @param apiClient - The API client to use
* @param options - The transfer options
*
* @returns The transfer result
*/
export async function transfer(apiClient, options) {
const connection = getOrCreateConnection({ networkOrConnection: options.network });
const connectedNetwork = await getConnectedNetwork(connection);
const rpc = createRpcClient(connectedNetwork);
const base64Transaction = options.token === "sol"
? await getNativeTransferBase64Transaction({
rpc,
from: options.from,
to: options.to,
amount: options.amount,
})
: await getSplTransferBase64Transaction({
rpc,
from: options.from,
to: options.to,
mintAddress: options.token === "usdc" ? getUsdcMintAddress(connectedNetwork) : options.token,
amount: options.amount,
});
const signature = await sendTransaction(apiClient, {
network: connectedNetwork === "mainnet" ? "solana" : "solana-devnet",
transaction: base64Transaction,
});
return signature;
}
/**
* Gets the transaction for a SOL transfer
*
* @param options - The options for the SOL transfer
*
* @param options.rpc - The Solana RPC client
* @param options.from - The source address
* @param options.to - The destination address
* @param options.amount - The amount in lamports to transfer
*
* @returns The SOL transfer transaction
*/
export async function getNativeTransferBase64Transaction({ rpc, from, to, amount, }) {
const fromAddr = address(from);
const toAddr = address(to);
const instructions = [
getTransferSolInstruction({
source: createNoopSigner(fromAddr),
destination: toAddr,
amount,
}),
];
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const txMsg = pipe(createTransactionMessage({ version: 0 }), tx => setTransactionMessageFeePayer(fromAddr, tx), tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), tx => appendTransactionMessageInstructions(instructions, tx));
const compiledTransaction = compileTransaction(txMsg);
return getBase64EncodedWireTransaction(compiledTransaction);
}
/**
* Gets the transaction for a SPL token transfer
*
* @param options - The options for the SPL token transfer
*
* @param options.rpc - The Solana RPC client
* @param options.from - The source address
* @param options.to - The destination address
* @param options.mintAddress - The mint address of the token
* @param options.amount - The amount in units of the token to transfer
*
* @returns The SPL token transfer transaction
*/
export async function getSplTransferBase64Transaction({ rpc, from, to, mintAddress, amount, }) {
const fromAddr = address(from);
const toAddr = address(to);
const mintAddr = address(mintAddress);
const mintInfo = await fetchMint(rpc, mintAddr);
const [sourceAta] = await findAssociatedTokenPda({
mint: mintAddr,
owner: fromAddr,
tokenProgram: TOKEN_PROGRAM_ADDRESS,
});
const [destAta] = await findAssociatedTokenPda({
mint: mintAddr,
owner: toAddr,
tokenProgram: TOKEN_PROGRAM_ADDRESS,
});
const sourceAcct = await fetchToken(rpc, sourceAta);
if (sourceAcct.data.amount < amount) {
throw new Error(`Insufficient token balance: have ${sourceAcct.data.amount}, need ${amount}`);
}
const instructions = [];
// If destination ATA does not exist, add create instruction
try {
await fetchToken(rpc, destAta);
}
catch {
const createDestIx = await getCreateAssociatedTokenInstructionAsync({
payer: createNoopSigner(fromAddr),
owner: toAddr,
ata: destAta,
mint: mintAddr,
});
instructions.push(createDestIx);
}
instructions.push(getTransferCheckedInstruction({
source: sourceAta,
mint: mintAddr,
destination: destAta,
authority: fromAddr,
amount,
decimals: mintInfo.data.decimals,
}));
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const txMsg = pipe(createTransactionMessage({ version: 0 }), tx => setTransactionMessageFeePayer(fromAddr, tx), tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), tx => appendTransactionMessageInstructions(instructions, tx));
const compiledTransaction = compileTransaction(txMsg);
return getBase64EncodedWireTransaction(compiledTransaction);
}
//# sourceMappingURL=transfer.js.map