raydium-io / raydium-sdk-V2-demo

Open-source Typescript SDK demos
70 stars 35 forks source link

Perform swap/quote across multiple pools with Liquidity #90

Closed PiciuU closed 2 weeks ago

PiciuU commented 3 weeks ago

Hi,

Is it possible to perform a swap/calculate a quote using the Liquidity module when passing through multiple pools?

For example, I can calculate a quote for a single pool using the following method:

const quoteOutput = raydium.liquidity.computeAmountOut({
    poolInfo: {
        ...pool.details.poolInfo,
        baseReserve,
        quoteReserve,
        status,
        version: 4,
    },
    amountIn: new BN(amountIn),
    mintIn: mintIn.publicKey,
    mintOut: mintOut.publicKey,
    slippage: SWAP_SLIPPAGE,
});

However, I want to calculate the quote based on a route involving multiple pools.

In my case, I have two devnet AMM pools:

SOL/WETH: 0xCBCdF9626bC03E24f779434178A73a0B4bad62eD SOL/USDC: 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640 I am trying to perform a swap from WETH to USDC by routing through these two pools.

Is this possible using the liquidity module, or do I need to use tradeV2 for this functionality?

Thank you!

PiciuU commented 3 weeks ago

And one more question while we’re at it. When using swapping methods (such as raydium.liquidity.swap or raydium.tradeV2.swap), the program remains running even after the instruction has been completed, as if there’s a lingering process, like a hanging Promise.

To illustrate the situation, for example, with this code:

const { execute } = await raydium.liquidity.swap({
    poolInfo: pool.details.poolInfo,
    poolKeys: pool.details.poolKeys,
    amountIn: new BN(amountIn),
    amountOut: quote.minAmountOutBN,
    fixedSide: 'in',
    inputMint: mintIn.publicKey.toBase58(),
    txVersion: TxVersion.V0,
});

const { txId } = await execute({ sendAndConfirm: true })

console.log(`Swap transaction sent:`, txId)

The script remains active after completing the instruction. However, if this part of code is commented out, meaning the swap method is not used in the code, the script properly terminates after completing the instructions.

cruzshia commented 3 weeks ago
  1. If you want to use route swap, only trade/swap or api/swap support it, amm/swap is only for "single pool" swap, I would suggest you use api/swap for easier development.
  2. Code here is just for demo usage, if code runs after await execute(xx) and means tx is completed, raydium UI uses the same logic, so there's no problem here.
PiciuU commented 2 weeks ago

Hmm okay, so I use trade/swap for now, but I see another problem that occurs and it is quite problematic.

Thats my code for swap functionality:

try {
    const { execute } = await this.raydium.tradeV2.swap({
        routeProgram: new solana.PublicKey(Config.constants.routerAddress),
        txVersion: TxVersion.V0,
        swapInfo: quote.targetRoute,
        swapPoolKeys: quote.poolKeys,
        ownerInfo: {
            associatedOnly: true,
            checkCreateATAOwner: true,
        },
    })

    Logger.info("Executing transaction:")
    const { txIds } = await execute({ sequentially: true })
    Logger.info('txIds:', txIds)
    txIds.forEach((txId) => Logger.info(`https://explorer.solana.com/tx/${txId}`))

    return true;
} catch(error) {
    Logger.error("Error while sending swap transaction:", error);
    return false;
}

When I use the publicly available rpc solana, https://api.mainnet-beta.solana.com, the code executes correctly and executes this part of the code

Logger.info('txIds:', txIds)
txIds.forEach((txId) => Logger.info(`https://explorer.solana.com/tx/${txId}`))

return true;

But when I use another rpc, for example from chainstack or alchemy, the above lines no longer execute. It looks as if the program is still waiting for await execute({ sequentially: true }) to resolve, until the timeout is finally exceeded and caught by the catch. This means that the code cannot be properly executed even though the only difference is the RPC endpoint. From what I can see, the transaction is recorded correctly on the blockchain, but for an unspecified reason this execute Promise is not resolved. Of course, the endpoint works correctly, for example it returns all information about the wallet or quotes.

My log on https://api.mainnet-beta.solana.com rpc looks like that:

[2024-10-28T22:48:03.791Z] [INFO]: Executing transaction:
simulate tx string: [
  'AZWnafoGllGXoN2/bBDAyfbG/3vu3Ehzbz70G7+7SBW7fOTDwB8MWRNRWBSL2SDzBvmc8GDOm++oSVk4B9+RQAqAAQAIFpZ7URvRk2op8FXXgds1U0nlk7d0DbB0cy6Xn0nCFgtn0C16WN1V2YVd6dgTb+rbGVwUOH6bOyeRawcQbbDm0hEZ0UV/4LJixWG4wVreG23/AlG/h6yvq3RCQ2QPPqJWRKlj7y3DlBi+/zTwDp07JNs8ZK5+9m5gzt0ss30KXe/n15x2BrsPnrQBWfLAPiAFyTI3xWU5ZWAgGqovmA4KwLWSIHSjuYezUH+YlxbJUZHZE9ros6K7+seJrttfdbjwl3BOj8K4rLv11Yf3hv2y3Mty+z0WWO1ksNnE1dOmMn1CF7yzsK0f3qA2cvxIeNoWv1AFO9DXL8WXSE0G+6xrBQWTbZMvpP2x8zS2P8juUT8NXUJHRyLECMPK4c0Q0P7E9w+A1R9swNRLV0Ynd+wzk+O6jJvqypY1BEgXWvLxQa7+7myU01RHag1UDaHH6YUxgT/K/IVza0THyOrz5U/i0mL3iSP/8CAoIb35RNHjqbrr86Bs4d8ETark4gg5yWmUxweNqgPOEqqakZEiFvQe7ef7VBIYSrPXPRM7t1ECwWE++yakOMhKhWoOhFQg85idhH68TPRz4fLRsHtcZpfOR8MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpBpuIV/6rgYT7aH9jRhjANdrEOdwa6ztVmKDwAAAAAAEGp9UXGSxcUSGMyUw9SvF/WNruCJuh/UTj29mKAAAAAPVoKwb8y9umtA0jShSx996di14R5FpyvKqSYj8+Z3obuxzwoysZ3L7WOW8ulnFtBfUR3sAdD2X9dYbdZESqTY/NDrwdm/rd1skt4FKR1S97OZKYlNAN73RBtoNNsze+RJ5vgUlTAl9gn/tNYN+QgQqvGZK++GMB/cI6UVHq1dFy1t8oeRS5i9Q5sHn+/pUUmwsdJVZFAX9ltCw6ona0VygEDgIAAXwDAAAAlntRG9GTainwVdeB2zVTSeWTt3QNsHRzLpefScIWC2cgAAAAAAAAAGh1bVI5TXJuOTl2YTI0ZkRwZW9vWGFRem5nZEI1UFBE8P4UBgAAAAClAAAAAAAAAAbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpDwQBEAARAQESEg8CEwMEBQYUBwgJCgsMFQENABEJAOH1BQAAAABaCDEFAAAAAA8DAQAAAQkA'
]
[2024-10-28T22:48:04.627Z] [INFO]: txIds: [
  '3zYJCnx5DLPSnxmWHEnmdFEXcqxcMTRFJLzcMXaNULVqgT2wzEEaFxwcPawdC2n2k8cyhStq4Fgy1kzuG1fPggXB'
]

Meanwhile on different rpc like alchemy, chainstack (f.e: https://solana-devnet.g.alchemy.com/v2/API_KEY) it looks:

[2024-10-28T22:45:55.605Z] [INFO]: Executing transaction:
simulate tx string: [
  'AamQ/seHwoO3IclmEgEXW1gv2HTipb4n1bI1CoOsN5WoehJL6DfAeMalpFJzNLBGDaI+/uhemw8V0mJapXnd9AGAAQAIFpZ7URvRk2op8FXXgds1U0nlk7d0DbB0cy6Xn0nCFgtnIMZjNlCR3dL+WOhx7P7OHz4/D4LcN4DkTq1uJ2649zUZ0UV/4LJixWG4wVreG23/AlG/h6yvq3RCQ2QPPqJWRKlj7y3DlBi+/zTwDp07JNs8ZK5+9m5gzt0ss30KXe/n15x2BrsPnrQBWfLAPiAFyTI3xWU5ZWAgGqovmA4KwLWSIHSjuYezUH+YlxbJUZHZE9ros6K7+seJrttfdbjwl3BOj8K4rLv11Yf3hv2y3Mty+z0WWO1ksNnE1dOmMn1CF7yzsK0f3qA2cvxIeNoWv1AFO9DXL8WXSE0G+6xrBQWTbZMvpP2x8zS2P8juUT8NXUJHRyLECMPK4c0Q0P7E9w+A1R9swNRLV0Ynd+wzk+O6jJvqypY1BEgXWvLxQa7+7myU01RHag1UDaHH6YUxgT/K/IVza0THyOrz5U/i0mL3iSP/8CAoIb35RNHjqbrr86Bs4d8ETark4gg5yWmUxweNqgPOEqqakZEiFvQe7ef7VBIYSrPXPRM7t1ECwWE++yakOMhKhWoOhFQg85idhH68TPRz4fLRsHtcZpfOR8MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpBpuIV/6rgYT7aH9jRhjANdrEOdwa6ztVmKDwAAAAAAEGp9UXGSxcUSGMyUw9SvF/WNruCJuh/UTj29mKAAAAAPVoKwb8y9umtA0jShSx996di14R5FpyvKqSYj8+Z3obuxzwoysZ3L7WOW8ulnFtBfUR3sAdD2X9dYbdZESqTY/NDrwdm/rd1skt4FKR1S97OZKYlNAN73RBtoNNsze+RJ5vgUlTAl9gn/tNYN+QgQqvGZK++GMB/cI6UVHq1dFyEZZpJ2TPUrfZ3f34UVZvdPzLDqCGxhLW+0YAYMKqAwUEDgIAAXwDAAAAlntRG9GTainwVdeB2zVTSeWTt3QNsHRzLpefScIWC2cgAAAAAAAAADZkVnZHQVR2THg5R01aRHZteDVXa0pzREtkOVpkZ2958P4UBgAAAAClAAAAAAAAAAbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpDwQBEAARAQESEg8CEwMEBQYUBwgJCgsMFQENABEJAOH1BQAAAAAzMkoFAAAAAA8DAQAAAQkA'
]

And in this state the program hangs until it exceeds the timeout and the catch takes over

// EDIT When I change the sequentially parameter in execute to false, the code executes correctly, but I don't really understand where this difference comes from, that on one RPC it works without issues and on the other it doesn't. Generally is there any way in the Raydium SDK to wait until the transaction is confirmed on the blockchain, like in the case of Uniswap where you can use the .wait() method on the transaction, so that only after approval the code will be further executed? Unless the SDK does exactly that, because I draw conclusions based on the fact that after receiving the response from execute() in the form of txIds, which would indicate, if I understand correctly, the acceptance of the transaction on the blockchain. In this case, if the code then fetches the balance of the wallet, these values ​​should already be updated, but from what I can see, only after a few seconds these values ​​are actually correct, taking into account the swap transaction performed

cruzshia commented 2 weeks ago

you can simulate your tx like this way: https://github.com/raydium-io/raydium-sdk-V2-demo/issues/92#issuecomment-2442086716 sequentially must be true or if there're more than 1 tx, txs will not execute in correct order and txs might be fail. sequentially:true means second tx will execute after first one got confirmed, if if shows timeout means you need to set higher priority fees in your tx

computeBudgetConfig: {
      units: 600000,
      microLamports: 1000000,
    },

if your code can run to execute part means good, the only thing you should do is to simulate it check what's going on and adjust the priority fees

more updates:

if you want to end up function, just add process.exit() in last line like this https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/amm/swap.ts#L96, again, this doesn't effect any logic here, just some ts-node mechanism