How spl-token manage their token accounts?

Hello. I have a question about spl-tokens’ token accounts

Is any token-accounts for any users are PDA(program derived accounts)?
If this is true, then they should not have secret key associated with its public key.
However, to create spl-token accounts, I can do following in my typescript code(not executable, just for explanation)

In below code, I did following

  1. First create a keypair by using Keypair() method
  2. add ‘createAccount’ transaction, with space 165, which is fixed length of space for token account, and assign it to TOKEN_PROGRAM_ID
  3. And assign it to a token-mint address by adding ‘initializeAccount’ transaction, which initialize the account so that I can use it as my token account.

Then this account is token account for some token and has it’s own secret key.

If token accounts are not PDA, where is PDA used for?


const owner = Keypair.fromSecretKey(~~~);
const newKeypair = new Keypair();

const transaction = new Transaction();

transaction.add(
SystemProgram.createAccount(
fromPubKey: owner.publicKey,
newAccountPubKey: newKeypair.publicKey,
lamports: ~~~,
space: 165,
programId: TOKEN_PROGRAM_ID
)
)

const keys = [
{ pubkey: newKeypair.publicKey, isSigner: false, isWritable: true },
{ pubkey: TARGET_TOKEN_MINT, isSigner: false, isWritable: false },
{ pubkey: owner.publicKey, isSigner: false, isWritable: false },
{ pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
];

transaction.add(
TransactionInstructoin({
keys,
data: properly encoded data,
programId: TOKEN_PROGRAM_ID
})
)

connection.sendTransaction(transactoin, [owner, newKeypair])


No, token accounts aren’t PDAs. As you’ve found, they are just normal accounts that are owned by the token program.

Note that once they are owned by the token program, even if you have the private key, you can’t modify the account however you want at that point. Only the token program can modify it.

PDAs are useful when you need the program to be able to create the account while it runs. I think there are also more use-cases when it comes to inter-program-calls.

With a PDA, the user wouldn’t have to pass in an account to be initialized I don’t think. The program could just derive an account address to use.

Again, I’d have to research or think more about why you would want to use a PDA over creating a new new account that you transfer ownership to, but I think there are good reasons to use them. Or maybe they are just more convenient?

Oh, for one, if a program needed to create multiple addresses, and it had to run processing logic to determine how many addresses to create, that could be a use-case for PDAs maybe. Because the client couldn’t know how many accounts it would need.

Anyway, that probably doesn’t help much, but those are my thoughts. :slight_smile:

2 Likes

You answered my previous questions, and again you gives me great insight! Thank you again. :slight_smile:

1 Like

Hi, I got more questions about it. If token accounts are not PDA, there should be private key for it. Then how can I retrieve its private key?
I think they would be managed with TOKEN_PROGRAM and ASSOCIATED_TOKEN_PROGRAM. So, I think there will be some way to get private key of my spl-token accounts

And I think there are differences between when I trade SOL and when I trade other SPL-TOKEN. I saw this differences while trading in serum dex with serum-api. In the case of normal spl-token, if I don’t have token-account associated with the spl-token, they simply use function ‘create-associated-account’ instruction to create it. But when I trade SOL, it create an account, use it as spl-token account and “CLOSE” it. I can’t understand why they choose such design. You can see details in below transactions

  1. transaction hash of “Sell SOL in serum SOL/USDC pool”
    2BwHxyS41UrEnxb8Fi8C1Fj2bbU8eE96DFgTL8xYGULRdpuUmqsNWAUhGsvoPrFxqsD5KAoVAbtHfXwNNxyghynB

  2. transaction hash of “When I swap SOL to “USDC” for the first time in Raydium”
    41dhQTLEkCppR1GHfCBFySrviwizVrm4VMmjdZcce8xZfGMxpKHDfVEovvty2SYGHMZjXhHsiTfWDiqjDXjtpjkU

You can’t, but you don’t need to. Once the account has it’s ownership transferred to the token program, the token program is in 100% control over access to the token account. That is intentional and allows the token program to dictate all transfers, etc.

There is no way to get the private key, and even if you had it, you couldn’t do anything with it. It’s essentially useless, unless the token program chose to transfer the ownership of the token account back to the system program. And there’s currently no conditions that would cause the token program to do that.

Good investigating! There is indeed a difference when trading native SOL.

SOL is a built-in feature of Solana, and it doesn’t need a smart contract to work like the SPL tokens do. But, other smart contracts such as exchanges, want to be able all tokens in the same way, so the token program invented the concept of WSOL or “wrapped SOL”.

So, what exchanges will do when you want to trade some native SOL for another SPL token, it will create a new token account for holding some WSOL and wrap some of your native SOL into that WSOL token account. Then it will swap the WSOL for whatever token you want.

Or if, for instance, you wanted to trade an SPL token for SOL, it would do a trade that would give you WSOL, and then it would unwrap the WSOL to native SOL, by closing the WSOL token account.

Make sense?

1 Like

I will write everything in my mind to fully show my status. Please fix me if something goes wrong.

The question that I want’ed’ to ask was that why wrapped SOL token account ‘actually’ has some wrapped SOL in it event though it was newly created and no one transfers wrapped SOL to it. But I found the answer in solana-program-library/token/src/instruction.rs. InitializeAccount instruction does initalize an account with its lamport metadata if given mint address is native SOL. So, if I gave lamports to an account when initialize it, it can be wrapped SOL account with non-zero balance!

And second question I still not 100% understand is, why serum CLOSE the wrapped SOL token-account? As if another spl-token account, why don’t they just leave the account for later usage? Because I can convert wrapped SOL to SOL by closing the account, it does not need to close everytime it was made, For example, serumVaultSigner account for SOL-USDC pool have unclosed wrapped SOL token-account . You can checkout this with below link

My answer for this question is, it is just design choice. For user’s perspective, they don’t want to manage their wrapped SOL’s token account, which mean that they should hold their private key. When they want to unwrap SOL, they should call transaction CloseAccount with wrapped SOL token account’s private key, which is not easy task for normal user. And they may want to hold SOL, not wrapped SOL because SOL is original and easy to trade with & send to another chain. In this way, I could understand the reason why serumVaultSigner does not close its wrapped SOL token account. They have the ability to manager accounts, and there will be so many transaction with it, it is better to maintain wrapped SOL token account, rather than initailize & Close account.

And the last thing that, I think token accounts, excepts wrapped SOL token account, are actually PDAs. As you said, users do not need their token accounts’ private key and event if they have it, they can do nothing with it. So it is logical that token accounts does not have private keys, which means they are PDAs. And another strong clue is Create-associated-token instruction. I saw instruction in solana-program-library/associated-token-account/program/src/instruction.rs, and create account uses ‘get_associated_token_address function’ which eventually call the function ‘find_program_address’ that is used for create PDA.

1 Like

Exactly, that’s right! I’ve found the token program source code to be rather readable, and you can learn a lot by looking into it.

Again, good job investigating!

Right again. It can actually be very confusing for users if, in their wallet, they have wrapped SOL instead of normal SOL. In-fact, there have been multiple users who’ve lost money because they sent WSOL to a centralized exchange, but that exchange only supported native SOL, so their money is trapped in a WSOL token account in a centralized exchange that doesn’t know how to give it back to them!

You don’t need to hold a separate private key for a wrapped SOL account. The wrapped SOL account is a token account like the rest of them, and the token program can unwrap it simply with a signature from the owner of the token account.

It is true that it can be hard for a user to unwrap the SOL themselves, though. You either have to use the spl-token CLI, or a dubious soltricks website, an obscure tool in the https://sonar.watch dashboard, or the button that pops up when you have wrapped SOL on Jupiter Aggregator.

It’s not hard for apps to unwrap SOL, but it’s confusing because the user doesn’t necessarily have a direct way to understand what’s going on easily.

Ah, good find!

So, I believe that associated token accounts can be PDAs, but aren’t necessarily PDAs. The point of the Associated Token Account program, as you’ve probably read from the docs is to provide a “default” token account so that programs know which token account to send SPL tokens to, without having to try and figure out which token accounts the user has created and what their addresses are.

It appears that this “default” token account that can be discovered using the Associated Token Account Program, is a PDA which is of the ED25519 curve and therefore has no private key.

But, that doesn’t stop you from creating a token account with the InitializeAccount instruction, that is not a PDA and that does have a private key.

So it seems that many token accounts will be PDAs and some may not be.


Again, good job looking into this stuff. It’s been fun walking though this and helping explain while seeing what you find. :smiley:

1 Like

At this moment, I got all your points. I fully understood your purpose of every sentence you said
. Thank you so much! There was nothing I could be sure of while studying on my own, but thanks to this, I was convinced that I was studying properly. thank you so much! I think I understand pretty much everything about tokens now. Thank you so much again!

1 Like

No problem, so glad I could help! And you pointed out to me what I hadn’t realized before the associated token account program making PDAs, so I learned something too!

Everything I know about Solana I picked up from researching myself, so maybe I’m not 100% right about everything, but I think I’ve gotten it mostly right. :slight_smile: And it shows you how much you can learn by doing your own research, so keep that up, and keep asking questions!

You’ll never know if you don’t ask. And even if you have to answer the question yourself with your own research, you’ll probably learn even more!

1 Like