raydium-io / raydium-sdk-V2-demo

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

How does swapping works? #53

Closed Kamigaku closed 3 months ago

Kamigaku commented 3 months ago

Hi everyone,

I'm trying to understand the under-depth of swapping using a pool and the example given in this demo under the name "swap.ts" is giving me nightmares. If I understand correctly, the swap.ts script swap SOL for USDC (input_mint being to money you will use to get the mint_out token. This file simply initialize everything that is needed to do the swap like retrieving the current account's token through the init_sdk function which will then call the fetch_account_data. It will also compute the amount of input_mint required in order to do the swap through the liquidity.computeAmountOut and then, it will do the swap.

But this is where i've issue understanding the code. In the swap function, you do the followings:

And here is my issue. We then retrieve the token based on first, the token_in and then on the token_out through the function getOrCreateTokenAccount. This function doesn't do a lot of thing, it will refresh the current account's token (but we don't do it since it was done in the init_sdk function) and then it will fetch the the raw token account infos. The problem is that, if I want to swap SOL to USDC, the token_in is equals to NATIVE_MINT which basicly is the Sol address (Sol111...2). Inside the function to retrieve token associated to my wallet (https://github.com/raydium-io/raydium-sdk-V2/blob/master/src/raydium/account/account.ts#L70) , this function retrieve sol infos, token infos and token 2022 infos. My sol balance is in the sol infos response (here named solAccountResp). Once we do the parsing (https://github.com/raydium-io/raydium-sdk-V2/blob/master/src/raydium/account/util.ts#L18), the sol account infos are deal with this code :

if (solAccountResp) {
    tokenAccounts.push({
      mint: PublicKey.default,
      amount: new BN(solAccountResp.lamports),
      isNative: true,
      programId: solAccountResp.owner,
    });
}

Basicly, we associate the address to PublicKey.default which is equals to 1111111... (see https://github.com/solana-labs/solana-web3.js/blob/09366737ee6b8b96b2d50c6d3561db5622304b8f/packages/library-legacy/src/publickey.ts#L91)

Back to the getOrCreateTokenAccount, we filter all the token associated to the account to find the one who is equals to the value passed. But we are passing the Sol value and none is equals to it because, when we parsed the sol response, we put 11111 and not Sol1111.... If we keep on going it still works but it crashses when generating the amm swap instructions because a token_in AND a token_out are required.

Have i misunderstood something? If yes, can you guide me on what to do?

Thanks!

cruzshia commented 3 months ago

sol in all pools are Sol1111xxx not Public.default. inputTokeUseSolBalance and inputTokeUseSolBalance pass true just means sdk will create a wsol account and transfer needed amount to it to make instructions, pass false means use your existed wsol token account to make instructions. also you should not pass Public.default 1111xxx to call getOrCreateTokenAccount, sdk use it is just for ui to recognize sol balance but not for any SDK instruction usage, that's why you can't find token accounts when you pass 11111xxx.

most important things:

cruzshia commented 3 months ago

more details, getOrCreateTokenAccount doesn't do nothing, it does select target mint's token account or make a new token account creation instructions for you, for wsol token accounts, it will make create a temp wsol token account -> transfer sol to wsol account -> close temp wsol token account instructions if you are not passing params to tell it to use existed wsol token account.

Kamigaku commented 3 months ago

Hello,

Thanks for your answer! I've never mentioned that I was using the 11111x as an input wallet, just that the fetchWalletAccounts was storing and defining Sol balance under this address (https://github.com/raydium-io/raydium-sdk-V2/blob/master/src/raydium/account/account.ts#L70)

If it is stored as 111x how does the function getOrCreateTokenAccount can find it through it's filter done in line 162 of account.ts? It will not find anything, do the if that comes right after, create_info is undefined because in the liquidity.ts file we specified that we are indeed using the inputTokenUseBalance so it returns an empty dictionary resulting in a crash later on the swap function.

I'm running the example with the same parameters as it is defined in the example file.

cruzshia commented 3 months ago

as I said in previous comment, sdk didn't find any 11111xxx accounts, it's just for ui usage, getOrCreateTokenAccount didn't check you balance, just to find or create token account. and in sdk, all mints pass to getOrCreateTokenAccount is Sol1111xxx, no any 11111xxx. you can think 11111xxx token accounts doesn't exist for getOrCreateTokenAccount function.

cruzshia commented 3 months ago

you can check how sdk handle wsol token accounts here: https://github.com/raydium-io/raydium-sdk-V2/blob/master/src/raydium/liquidity/liquidity.ts#L849 for this example, if inputTokenUseSolBalance it true, it will create a temp wsol token account for you, if false, it will return your existed wsol token account. of course, only when tokenIn or tokenOut is wsol will go into this logic

Kamigaku commented 3 months ago

I'm sorry but i still have hard time understanding something.

For me the function getOrCreateToken purpose is to search for an existing token in the owner's wallet and if it doesn't exist (+ some other params), create an instruction to create an account for it. If i strictly follow the execution order, please tell me where i'm wrong:

And the return being {}, i can't do the makeAMMSwapInstructions because tokenAccountOut is undefined (it crashes in the accountMeta creation inside of the function).

Sorry if i seem stuborn but i've hard time understanding this specific part. How can i expect to retrieve the TokenAccount of a token i don't own?

Thanks again for your time.

Kamigaku commented 3 months ago

I could give you the informations i'm filling (private key + RPC URL) to test on your side, there is no money left on the sol account so i don't care. I've run it and end up with an exception output token account not found

cruzshia commented 3 months ago

swap function are tested for new wallets and don't need your private key, please set inputTokenUseSolBalance/outputTokenUseSolBalance to true, you pass false but you don't have wsol token accounts that's why you have error

cruzshia commented 3 months ago

demo code wrote lots of comment you can reference: outputUseSolBalance: false, // default: true, if you want to use existed wsol token account to receive token out, pass false your wallet don't have wsol token account and still pass false, that's why you always got output token account not found error. https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/amm/swap.ts#L78

also suggest to run demo code without any modification except config.ts to test it, then you could find out which block of code might go wrong

Kamigaku commented 3 months ago

Oh. I feel stupid. It was just because i was trading wSol to USDC ? Damn. I'm gonna try to test to find a poolId to swap SOL/USDC and see if it works. Now i understand though, it was working fine because i don't have wSol. Thanks for the help!

Kamigaku commented 3 months ago

Hey cruzhia,

Actually I've been doing test and still giving me the same error. This time I have wSol in my wallet https://solscan.io/account/HsHkjPBWEhRvyEzpCzSwW8BgtsrZsAw8ywjFn6eyeQjJ and I'm still having the error on the token out.

Again, this is due to the getOrCreateTokenAccount function. You are telling us to put 'outputUseSolBalance' to true or false but this as not impact since the function use outputTokenUseSolBalance and this variable will always be set to false because the mint is equal to the USDC address whose different to the wSolMint address.

I still believe that there is an issue in this function and that the swap function work only if you own both of the token you want to swap.

cruzshia commented 3 months ago

I thinks it's not getOrCreateTokenAccount's issue, I'll check swap method and add more check/logs in that function

cruzshia commented 3 months ago

just pushed a new commit to master, run yarn install to update sdk and try again. it's caused by passing wrong parameters to getOrCreateTokenAccount's function

Kamigaku commented 3 months ago

That's much better, it works now! Thanks! 👍