raydium-io / raydium-sdk-V2-demo

Open-source Typescript SDK demos
48 stars 31 forks source link

Issue with token swap in CPMM pool: TransactionExpiredBlockheightExceededError #52

Closed 6otah closed 3 months ago

6otah commented 3 months ago

Hello,

I am encountering an issue with token swaps through the CPMM pool: error TransactionExpiredBlockheightExceededError. I noticed similar issues reported previously, where increasing the priority fee was suggested.

There are SOL, WSOL, and the pool token in my wallet. In the code, I set the input amount to 0.005 SOL with const inputAmount = new BN(5_000_000), and the priority fee to 0.002 SOL as follows:

computeBudgetConfig: {
  units: 600000,
  microLamports: 2_000_000_000_000,
},

Despite this, the transaction string is formed, and the transaction expiration error is returned. This issue also occurs when attempting to swap in the reverse direction, using:

const inputAmount = new BN(10_000_000_000_000); // 10_000_000 with 6 digits
const inputMint = poolInfo.mintB.address;

Am I setting the correct values? What else can I do for testing to resolve this issue?

cruzshia commented 3 months ago

could you provide pool id and full code to here? after some testing demo works for both side swapping

6otah commented 3 months ago

Pool id: ELxaXevTkDd2i1jhgi7rkjGWSMwo8pqHUfqpwAyLHGo

import {
  ApiV3PoolInfoStandardItemCpmm,
  CpmmKeys,
  CpmmRpcData,
  CurveCalculator,
  getPdaPoolAuthority,
} from '@raydium-io/raydium-sdk-v2'
import { initSdk } from '../config'
import BN from 'bn.js'
import { isValidCpmm } from './utils'

export const swap = async () => {
  const raydium = await initSdk()

  // SOL - PPUMP pool
  const poolId = 'ELxaXevTkDd2i1jhgi7rkjGWSMwo8pqHUfqpwAyLHGo'
  let poolInfo: ApiV3PoolInfoStandardItemCpmm
  let poolKeys: CpmmKeys | undefined
  let rpcData: CpmmRpcData

  if (raydium.cluster === 'mainnet') {
    // note: api doesn't support get devnet pool info, so in devnet else we go rpc method
    // if you wish to get pool info from rpc, also can modify logic to go rpc method directly
    const data = await raydium.api.fetchPoolById({ ids: poolId })
    poolInfo = data[0] as ApiV3PoolInfoStandardItemCpmm
    if (!isValidCpmm(poolInfo.programId)) throw new Error('target pool is not CPMM pool')
    rpcData = await raydium.cpmm.getRpcPoolInfo(poolInfo.id, true)
  } else {
    const data = await raydium.cpmm.getPoolInfoFromRpc(poolId)
    poolInfo = data.poolInfo
    poolKeys = data.poolKeys
    rpcData = data.rpcData
  }

  const inputAmount = new BN(5_000_000)
  const inputMint = poolInfo.mintA.address
  const baseIn = inputMint === poolInfo.mintA.address

  console.log(`Input mint: ${inputMint}, baseIn: ${baseIn}`)

  // swap pool mintA for mintB
  const swapResult = CurveCalculator.swap(
    inputAmount,
    baseIn ? rpcData.baseReserve : rpcData.quoteReserve,
    baseIn ? rpcData.quoteReserve : rpcData.baseReserve,
    rpcData.configInfo!.tradeFeeRate
  )

  /**
   * swapResult.sourceAmountSwapped -> input amount
   * swapResult.destinationAmountSwapped -> output amount
   * swapResult.tradeFee -> this swap fee, charge input mint
   */
  console.log(`Input amount: ${swapResult.sourceAmountSwapped}\nOutput amount: ${swapResult.destinationAmountSwapped}\nTrade fee: ${swapResult.tradeFee}`)

  const { execute } = await raydium.cpmm.swap({
    poolInfo,
    poolKeys,
    swapResult,
    slippage: 0.1, // range: 1 ~ 0.0001, means 100% ~ 0.01%
    baseIn,
    // optional: set up priority fee here
    computeBudgetConfig: {
      units: 600000,
      microLamports: 2_000_000_000_000, //0.002 * 1_000_000_000 * 1_000_000,
    },
  })

  // don't want to wait confirm, set sendAndConfirm to false or don't pass any params to execute
  const { txId } = await execute({ sendAndConfirm: true })
  console.log(`swapped: ${poolInfo.mintA.symbol} to ${poolInfo.mintB.symbol}:`, { txId })
}

/** uncomment code below to execute */
swap()
cruzshia commented 3 months ago

after did some mintA -> mintB, mintB -> mintA testing, all tx went through smoothly, so this might caught by network congestion or your rpc's issue, provide the code I tested with mintB -> mintA Tx. mintA -> mintB: https://solscan.io/tx/2Xx5GaUvGnNcigXH4ZMdaDAxYdoitfVYgnykiD8y4ds7nbdijYxe7HZfVaULogZRABow8mqBXwzonh8W9bvkBkzx

mintB -> mintA: https://solscan.io/tx/3Hg9mnjXfSfEZfZjWg2VAoM8JvJZzcSw3qCqTcjVmf1Nf88eAs4AYRnfsr7YDVuZShsiC5dSufLVzVQmQhyuraJd

import {
  ApiV3PoolInfoStandardItemCpmm,
  CpmmKeys,
  CpmmRpcData,
  CurveCalculator,
  getPdaPoolAuthority,
} from '@raydium-io/raydium-sdk-v2'
import { initSdk } from '../config'
import BN from 'bn.js'
import { isValidCpmm } from './utils'

export const swap = async () => {
  const raydium = await initSdk()

  // SOL - USDC pool
  const poolId = 'ELxaXevTkDd2i1jhgi7rkjGWSMwo8pqHUfqpwAyLHGo'
  let poolInfo: ApiV3PoolInfoStandardItemCpmm
  let poolKeys: CpmmKeys | undefined
  let rpcData: CpmmRpcData

  if (raydium.cluster === 'mainnet') {
    // note: api doesn't support get devnet pool info, so in devnet else we go rpc method
    // if you wish to get pool info from rpc, also can modify logic to go rpc method directly
    const data = await raydium.api.fetchPoolById({ ids: poolId })
    poolInfo = data[0] as ApiV3PoolInfoStandardItemCpmm
    if (!isValidCpmm(poolInfo.programId)) throw new Error('target pool is not CPMM pool')
    rpcData = await raydium.cpmm.getRpcPoolInfo(poolInfo.id, true)
  } else {
    const data = await raydium.cpmm.getPoolInfoFromRpc(poolId)
    poolInfo = data.poolInfo
    poolKeys = data.poolKeys
    rpcData = data.rpcData
  }

  const inputAmount = new BN(500000)
  const inputMint = poolInfo.mintB.address
  const baseIn = inputMint === poolInfo.mintA.address

  // swap pool mintA for mintB
  const swapResult = CurveCalculator.swap(
    inputAmount,
    baseIn ? rpcData.baseReserve : rpcData.quoteReserve,
    baseIn ? rpcData.quoteReserve : rpcData.baseReserve,
    rpcData.configInfo!.tradeFeeRate
  )

  /**
   * swapResult.sourceAmountSwapped -> input amount
   * swapResult.destinationAmountSwapped -> output amount
   * swapResult.tradeFee -> this swap fee, charge input mint
   */

  const { execute } = await raydium.cpmm.swap({
    poolInfo,
    poolKeys,
    swapResult,
    slippage: 0.1, // range: 1 ~ 0.0001, means 100% ~ 0.01%
    baseIn,
    // optional: set up priority fee here
    computeBudgetConfig: {
      units: 600000,
      microLamports: 100000,
    },
  })

  // don't want to wait confirm, set sendAndConfirm to false or don't pass any params to execute
  const { txId } = await execute({ sendAndConfirm: true })
  console.log(`swapped: ${poolInfo.mintA.symbol} to ${poolInfo.mintB.symbol}:`, { txId })
}

/** uncomment code below to execute */
swap()