I am using Jupiter api for my app and on my app I want to swap and directly send the swapped token to merchant account. can I do this on one transaction?
https://station.jup.ag/docs/apis/payments-api
from this document I thought if I set destinationTokenAccount as merchant wallet address then the swapped token can send to the merchant account directly.
// Replace with the Jupiter API endpoint
const JUPITER_QUOTE_API = 'https://quote-api.jup.ag/v6/quote';
const JUPITER_SWAP_API = 'https://quote-api.jup.ag/v6/swap';
// Step 1: Fetch swap info from Jupiter
const fetchSwapInfo = async (inputMint: string, outputMint: string, amount: number) => {
const url = `${JUPITER_QUOTE_API}?inputMint=${inputMint}&outputMint=${outputMint}&amount=${amount}&swapMode=ExactOut&slippageBps=50`;
const response = await fetch(url);
const data = await response.json();
return {
inAmount: data.inAmount,
otherAmountThreshold: data.otherAmountThreshold,
quoteResponse: data,
};
};
// Step 2: Fetch swap transaction from Jupiter
const fetchSwapTransaction = async (
walletAddress: PublicKey | null,
recipientAddress: string,
swapInfo: any
) => {
if (!walletAddress || !recipientAddress || !swapInfo?.quoteResponse) {
throw new Error('Invalid parameters: Ensure walletAddress, recipientAddress, and swapInfo are defined.');
}
const requestBody = {
userPublicKey: walletAddress.toBase58(),
destinationTokenAccount: recipientAddress,
useSharedAccounts: true,
quoteResponse: swapInfo.quoteResponse,
skipUserAccountsRpcCalls: true,
};
const response = await fetch(JUPITER_SWAP_API, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestBody),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Error fetching swap transaction: ${errorText}`);
}
const { swapTransaction, lastValidBlockHeight } = await response.json();
return { swapTransaction, lastValidBlockHeight };
};
// Step 3: Send transaction to Solana blockchain
const sendTransaction = async (swapTransaction: string, walletAdapter: WalletAdapter) => {
const versionedMessage = VersionedMessage.deserialize(Buffer.from(swapTransaction, 'base64'));
const transaction = new VersionedTransaction(versionedMessage);
const bhInfo = await connection.getLatestBlockhashAndContext({ commitment: "finalized" });
transaction.recentBlockhash = bhInfo.value.blockhash;
transaction.feePayer = walletAdapter.publicKey;
console.log(transaction);
const signedTransaction = await (walletAdapter as any).signTransaction(transaction);
const simulation = await connection.simulateTransaction(transaction, { commitment: "finalized" });
if (simulation.value.err) {
throw new Error(`Simulation failed: ${simulation.value.err.toString()}`);
}
// Send the transaction
try {
const signature = await connection.sendTransaction(transaction, {
// NOTE: Adjusting maxRetries to a lower value for trading, as 20 retries can be too much
// Experiment with different maxRetries values based on your tolerance for slippage and speed
// Reference: https://solana.com/docs/core/transactions#retrying-transactions
maxRetries: 5,
skipPreflight: true,
preflightCommitment: "finalized",
});
// Confirm the transaction
// Using 'finalized' commitment to ensure the transaction is fully confirmed
// Reference: https://solana.com/docs/core/transactions#confirmation
const confirmation = await connection.confirmTransaction({
signature,
blockhash: bhInfo.value.blockhash,
lastValidBlockHeight: bhInfo.value.lastValidBlockHeight,
}, "finalized");
if (confirmation.value.err) {
throw new Error(`Transaction not confirmed: ${confirmation.value.err.toString()}`);
}
console.log("Confirmed: ", signature);
} catch (error) {
console.error("Failed: ", error);
throw error;
}
};
// Step 4: Main function to swap and send token
const swapAndSendToken = async (
walletAdapter: WalletAdapter,
recipientAddress: string,
inputMint: string,
outputMint: string,
amount: number
) => {
try {
const walletPublicKey = walletAdapter.publicKey;
// Step 1: Fetch swap info
const swapInfo = await fetchSwapInfo(inputMint, outputMint, amount);
// Step 2: Fetch the swap transaction
const { swapTransaction, lastValidBlockHeight } = await fetchSwapTransaction(walletPublicKey, recipientAddress, swapInfo);
console.log(swapTransaction);
// Step 3: Send the transaction to the blockchain
await sendTransaction(swapTransaction, walletAdapter);
alert("USDC sent successfully!");
console.log('Swap and send transaction completed successfully.');
} catch (error) {
console.error('Error during swap and send:', error);
//alert("Failed! " + error.message);
}
};
const payCoin = async () => {
const wallets = [
new PhantomWalletAdapter(),
new SolflareWalletAdapter(),
new TrustWalletAdapter(),
];
if(connectedWalletIndex == null) return;
const wallet = wallets[connectedWalletIndex];
try {
await wallet.connect();
if(wallet.publicKey == null) return;
console.log("Connected to wallet:", wallet.publicKey.toString());
const publicKey = wallet.publicKey;
await swapAndSendToken(
wallet,
"ANJt85VAVGhknPAhKBaS2qWVZUWW59rkQSbAg4sW4dFA", // Merchant's USDC address
"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", // Input mint address
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // Output mint address
0.1 * 1000000 // Example: 0.1 USDC in micro-lamports
);
} catch (error) {
console.error("Failed to connect to wallet:", error);
}
}
This is my implemented code.
I am going to swap with destination address. I've seen destinationTokenAccount from the https://station.jup.ag/api-v6/post-swap-instructions Is it possible to swap from customer account to merchant address directly? I've tried but it's not succeed. any one can help me? https://solscan.io/tx/37GAcwzCfEbydZknATZXRMjDEzMPKV5b3TF3VtM2JUD5y6cKoKWipQD5qfpB2MLtmkDsLgVhzyWrU5kdHRi9HRqh This is the failed transaction.
For the 'destinationTokenAccount' check your property 'recipientAddress'. It must be Token Account. It is not wallet address for deposit. You can to get it with RPC method getTokenAccountsByOwner (@solana/web3.js) or getAssociatedTokenAddressSync (@solana/spl-token)