I am working on a Solana Token Swap program, and I keep encountering the following error during the swap operation:
Program SwapsVeCiPHMUAtzQWZw7RjsKjgCjhwU55QGu4U1Szw invoke [1]
Program log: Instruction: Swap
Program log: Error: The provided token program does not match the token program
expected by the swap
Program SwapsVeCiPHMUAtzQWZw7RjsKjgCjhwU55QGu4U1Szw consumed 5913 of 200000 compute
units
Program SwapsVeCiPHMUAtzQWZw7RjsKjgCjhwU55QGu4U1Szw failed: custom program error: 0x18
I suspect this error is related to how I reference the token program IDs in the swap instructions. Here is a snippet of my code:
const swapInstruction = TokenSwap.swapInstruction(
tokenSwapStateAccount.publicKey, // The public key of the token swap state account, which holds the swap configuration.
swapAuthority, // The swap authority derived from the swap state account, which controls the swap.
alice.publicKey, // The public key of the user (in this case, Alice)who is initiating the swap.
aliceTokenAATA, // Alice's associated token account (ATA) for Token A.
tokenATokenAccount, // The pool's token A account.
tokenBTokenAccount, // The pool's token B account.
aliceTokenBATA, // Alice's associated token account (ATA) for Token B.
poolTokenMint, // The mint address for the pool token.
tokenFeeAccountAddress, // The token account for fees.
null, // No host fee account provided.
tokenAMint, // The mint address of Token A.
tokenBMint, // The mint address of Token B.
TOKEN_SWAP_PROGRAM_ID, // Token Swap program ID.
token.TOKEN_PROGRAM_ID, // The SPL Token Program ID for Token A (I'm using token.TOKEN_PROGRAM_ID here).
token.TOKEN_PROGRAM_ID, // The SPL Token Program ID for Token B.
token.TOKEN_PROGRAM_ID, // The SPL Token Program ID for the pool tokens.
1000000n, // The amount of Token A for the swap.
0n // The minimum amount of Token B Alice expects to receive.
);
I suspect there might be an issue with the token.TOKEN_PROGRAM_ID I am passing in for the token program, which is likely causing the mismatch. I am using the standard SPL Token Program ID (token.TOKEN_PROGRAM_ID), and I have also seen references to token.TOKEN_2022_PROGRAM_ID in other examples.
Here are the questions I need help with:
Is the token program ID I am using (token.TOKEN_PROGRAM_ID) incorrect for this context?
Should I be using a different program ID like token.TOKEN_2022_PROGRAM_ID when performing a swap, especially if I am using SPL Token 2022 features?
How do I ensure that the token program ID matches what the swap expects?
Here is the full code for context:
import { Transaction, Keypair, SystemProgram, Connection, PublicKey,
TransactionInstruction } from '@solana/web3.js';
import { TokenSwap, TOKEN_SWAP_PROGRAM_ID, TokenSwapLayout, CurveType } from
"@solana/spl-token-swap";
import * as token from "@solana/spl-token";
const fs = require("fs");
// Function to load a keypair from a JSON file
function loadKeypair(filename: string): Keypair {
const secret = JSON.parse(fs.readFileSync(filename).toString()) as number[];
const secretKey = Uint8Array.from(secret);
return Keypair.fromSecretKey(secretKey);
}
// Function to create a token account creation instruction
async function getTokenAccountCreationInstruction(mint: PublicKey, owner: PublicKey,
payer: PublicKey): Promise<[PublicKey, TransactionInstruction]> {
let tokenAccountAddress = await token.getAssociatedTokenAddress(
mint, // mint
owner, // owner
true // allow owner off curve
);
const tokenAccountInstruction = await token.createAssociatedTokenAccountInstruction(
payer, // payer
tokenAccountAddress, // ata
owner, // owner
mint // mint
);
return [tokenAccountAddress, tokenAccountInstruction];
};
async function main() {
const connection = new Connection('https://api.devnet.solana.com');
const wallet = loadKeypair("BobvKCJ5vrThAjcwonS73Dhcv9pD8punaGwMkdXg3rp3.json");
// Transaction to initialize Token Swap state account
let transaction = new Transaction();
const tokenSwapStateAccount =
loadKeypair("TSKrjj1kfu9sCmdEBVysHWgn6mdkeUpTruc7tMMzAwe.json");
const rent = await TokenSwap.getMinBalanceRentForExemptTokenSwap(connection);
const tokenSwapStateAccountCreationInstruction = await SystemProgram.createAccount({
newAccountPubkey: tokenSwapStateAccount.publicKey,
fromPubkey: wallet.publicKey,
lamports: rent,
space: TokenSwapLayout.span,
programId: TOKEN_SWAP_PROGRAM_ID
});
transaction.add(tokenSwapStateAccountCreationInstruction);
// Generate swap authority
const [swapAuthority, bump] = await PublicKey.findProgramAddress(
[tokenSwapStateAccount.publicKey.toBuffer()],
TOKEN_SWAP_PROGRAM_ID,
);
console.log("swap authority: " + swapAuthority.toBase58());
// Token Mints for Token A and Token B
const tokenAMint = new PublicKey("AToi4sm8XMY49wNbsttKDTzJpEFAPLLiT79SdG5Yb49w");
const tokenBMint = new PublicKey("BTonyXJU4aAVq22XyKEzXH2WrBcs6eeTyBVnGJdzEDLQ");
// Create token accounts for Token A and Token B
const [tokenATokenAccount, taci] = await getTokenAccountCreationInstruction(tokenAMint,
swapAuthority, wallet.publicKey);
const [tokenBTokenAccount, tbci] = await getTokenAccountCreationInstruction(tokenBMint,
swapAuthority, wallet.publicKey);
transaction.add(taci, tbci);
console.log("token A account: " + tokenATokenAccount.toBase58());
console.log("token B account: " + tokenBTokenAccount.toBase58());
// Pool Token Mint and associated accounts
transaction = new Transaction();
const poolTokenMint = new PublicKey("LPTBed1dBW88U78HXxhPSpLMr5emcSuoZ31fwUTiR8x");
const tokenAccountPool = Keypair.generate();
const poolAccountRent = await token.getMinimumBalanceForRentExemptAccount(connection);
const createTokenAccountPoolInstruction = SystemProgram.createAccount({
fromPubkey: wallet.publicKey,
newAccountPubkey: tokenAccountPool.publicKey,
space: token.ACCOUNT_SIZE,
lamports: poolAccountRent,
programId: token.TOKEN_PROGRAM_ID,
});
const initializeTokenAccountPoolInstruction = token.createInitializeAccountInstruction(
tokenAccountPool.publicKey,
poolTokenMint,
wallet.publicKey
);
transaction.add(createTokenAccountPoolInstruction,
initializeTokenAccountPoolInstruction);
// Fee account for the swap
const feeOwner = new PublicKey('HfoTxFR1Tm6kGmWgYWD6J7YHVy1UwqSULUGVLXkJqaKN');
const [tokenFeeAccountAddress, tfaci] = await getTokenAccountCreationInstruction(
poolTokenMint,
feeOwner,
wallet.publicKey
);
transaction.add(tfaci);
// Initialize swap instruction
const tokenSwapInitSwapInstruction = TokenSwap.createInitSwapInstruction(
tokenSwapStateAccount,
swapAuthority,
tokenATokenAccount,
tokenBTokenAccount,
poolTokenMint,
tokenFeeAccountAddress,
tokenAccountPool.publicKey,
token.TOKEN_PROGRAM_ID, // Token Program ID
TOKEN_SWAP_PROGRAM_ID, // Token Swap Program ID
0n, // Trade fee numerator
10000n, // Trade fee denominator
5n, // Owner trade fee numerator
10000n, // Owner trade fee denominator
0n, // Owner withdraw fee numerator
0n, // Owner withdraw fee denominator
20n, // Host fee numerator
100n, // Host fee denominator
CurveType.ConstantProduct // Curve type
);
transaction.add(tokenSwapInitSwapInstruction);
// Swap operation by Alice
const alice = loadKeypair("ALicWpLcgsR2aNFbHHWL9i7ibfJXX3dFWTMvvYodUHL1.json");
const aliceTokenAATA = new PublicKey("F5NGfhNZy6LreZhcWd5osZbtRkTmrABBPPQXcnVGnRku");
const aliceTokenBATA = new PublicKey("BcdzVEkVEZ1jJ2XKt1mBVnb8qECcHpE7kzZZ355u3LY3");
// Swap instruction to perform the token swap operation
const swapInstruction = TokenSwap.swapInstruction(
tokenSwapStateAccount.publicKey, // Token Swap state account
swapAuthority, // Swap authority
alice.publicKey, // Alice's public key
aliceTokenAATA, // Alice's token account for Token A
tokenATokenAccount, // Pool token A account
tokenBTokenAccount, // Pool token B account
aliceTokenBATA, // Alice's token account for Token B
poolTokenMint, // Pool token mint
tokenFeeAccountAddress, // Fee account for swap
null, // Host fee account (optional)
tokenAMint, // Mint for Token A
tokenBMint, // Mint for Token B
TOKEN_SWAP_PROGRAM_ID, // Token Swap program ID
token.TOKEN_PROGRAM_ID, // Source token program ID
token.TOKEN_PROGRAM_ID, // Destination token program ID
token.TOKEN_PROGRAM_ID, // Pool token program ID
1000000n, // Amount of Token A Alice provides
0n // Minimum amount of Token B Alice expects
);
// Create transaction for the swap and send it
const ta = new Transaction();
ta.add(swapInstruction);
const sx = await connection.sendTransaction(ta, [alice]);
console.log(sx);
}
main();
Any help is greatly appreciated :)
SwapsVeCiPHMUAtzQWZw7RjsKjgCjhwU55QGu4U1Szw
is just too old -- if you want to test, you're probably better off building / deploying / testing your own token-swap program.