Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Token2022 (extensions) support #9

Open
wants to merge 24 commits into
base: compute-budget-rf-v2
Choose a base branch
from

Conversation

0xMMBD
Copy link
Member

@0xMMBD 0xMMBD commented Feb 22, 2024

Add support for Token2022 instructions(extensions).
Added:

  • token2022 program id
  • ProgramIdToken2022 enum value
  • switch case to handle token2022 in message and transaction_printer
  • extension names to the token instruction tag enum
  • unit tests

@0xMMBD 0xMMBD self-assigned this Feb 22, 2024
@0xMMBD 0xMMBD changed the base branch from develop to compute-budget-rf-v2 February 22, 2024 13:05
Copy link

@sponomarev sponomarev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there! I performed a functional test on a real hardware and found that none of the basic operations like transfer, burn, mint, etc. are clear-signed. I faced with an issue of unrecognized format that requires blind signing. Please, see my comment where I assume the logic is broken.

libsol/message.c Outdated
@@ -99,6 +100,8 @@ int process_message_body(const uint8_t* message_body,
case ProgramIdUnknown:
display_instruction_info[display_instruction_count++] = info;
break;
//Currently we don't display these instructions
case ProgramIdToken2022:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment it seems that the bug is here. We skip the logic where we count instructions and setting instruction info which leads us to unrecognized format handling upper in handle_sign_message_parse_message since process_message_body returns 1.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello, thanks for the tests and feedback @sponomarev. It is interesting that "that none of the basic operations" does not work, we've tested it on the real hardware too (NanoX and NanoSP) and it looked fine.
I'll double check that this branch contains the correct code (as it was separated from the other feature recently), but I'm quite sure about that.

In addition to that, are you able to share the Transaction that you used to perform tests? It would be great to reproduce the problem with the same data that you have used. After that we will handle this problem asap.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Here is an example https://explorer.solana.com/tx/2DRngy89okvFT9gekHKQv5uAy43FVHKndf7qJvm3Q7JbRcE62PKwdHBc1dWWWsK4hW1uTCqNN9WovfXMUNUcKbWC?cluster=devnet. This transaction contains only one instruction from token2022 program. In that case, if we closely take a look at these lines, display_instruction_count won't be incremented and end up as zero, that's passed down to print_transaction and print_transaction_nonce_processed.

You can recreate this transaction easily with spl-token cli.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, yes, you are right, we will handle this and come back soon

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

@0xMMBD 0xMMBD requested a review from sponomarev March 18, 2024 21:52
Remove separate Token2022 program id.
@0xMMBD 0xMMBD force-pushed the pr/token2022-support-v3 branch from 26f9042 to 5d6fdac Compare March 18, 2024 21:55
@0xMMBD
Copy link
Member Author

0xMMBD commented Mar 18, 2024

@sponomarev Hello, I've made some changes. Hopefully I didn't miss anything :)
I've checked transactions with multiple instructions for old spl token as well as for the Token2022 and the same with simple examples like transfer. On my end it looked fine.

In my opinion the best way to handle this was to unify both token types as the same programId. Otherwise handling transaction_printers was getting a little tricky.

Let me know it there is anything else to change or if you find any other problems.

Copy link

@sponomarev sponomarev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @0xMMBD! It seems that the original issue is resolved. I was able to perform basic token operations for both Token2022 and the original Token program. I've also tried to play with extensions, but nothing was successful. It seems that something goes wrong on that side. Here is my test scenarios report:

✅ Token creation without extensions
✅ Token account creation
✅ Token transfer
✅ Mint token
✅ Burn token

🔴 Token creation with transfer fee extension
🔴 Token creation with confidential transfers extension
🔴 Token creation with default account state extension
🔴 Token account creation with immutable owner extension
🔴 Token account: enable/disable required memo transfers

My raw assumption is that the issue is happening somewhere in print_transaction_nonce_processed where we can mess instruction amount since extensions are enabled with a separate instruction and enable/disable required memo transfers is a separate instruction as well.

@0xMMBD
Copy link
Member Author

0xMMBD commented Mar 21, 2024

The extensions are not supported currently. The main purpose of this PR was to properly handle basic operations on token when using Token2022 program. We wanted to make it backward compatible with existing features without the need of blind signing. So current extensions are recognized and are added in the code but we dont have any special logic for them
This scope was discussed with @jnwng

Copy link

@tiago18c tiago18c left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need clarification on the transfer decoding

@@ -18,6 +19,8 @@ enum ProgramId instruction_program_id(const Instruction* instruction, const Mess
return ProgramIdVote;
} else if (memcmp(program_id, &spl_token_program_id, PUBKEY_SIZE) == 0) {
return ProgramIdSplToken;
} else if(memcmp(program_id, &spl_token2022_program_id, PUBKEY_SIZE) == 0) {
return ProgramIdSplToken;//Treat the Token2022 exactly the same as the SplToken

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the decoding resulting from this used in the user signing loop?
If so this may cause issues, as the user may be unaware that he is signing transactions using the token22 program that may contain transfer fee or transfer hooks with unintended consequences

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main reason behind this is the code thats prints transaction details. If I detect token2022 as something different then it gets more messy to handle basic token instruction like mint, burn etc. At this point, if we use for example TransferFeeExtension we just ignore it - we don't display any additional screens.

What we can do is to throw error(instruction not supported) when we get any extension instruction. This way there will be no chance to sign something that you are not able to verify visually on the screen. Otherwise we would need to redesign this function https://github.com/blockydevs/app-solana/blob/develop/libsol/transaction_printers.c#L535 https://github.com/blockydevs/app-solana/blob/develop/libsol/transaction_printers.c#L535 because it is not able to handle anything with more than 3 instructions and we dont know what extensions someone will send and in what order

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, like main idea in this PR is to allow transactions that use the token2022 program id to be able to perform basic instructions that are also compatible with the old token

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, like main idea in this PR is to allow transactions that use the token2022 program id to be able to perform basic instructions that are also compatible with the old token

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a slight mix up between extension setup and the extension usage.

The TransferFeeExtension instruction is only called to setup the extension, so not supporting it here makes total sense. However, if its setup, any calls to Transfer are going to need extra accounts to correctly execute the transfer with the fee.

The way the decoding is currently setup, any Token22 mint with extensions such as Transfer Fees or Transfer Hooks enabled, are going to execute completely blind to the decoding operation due to the Transfer instruction being ABI compatible between both programs (extra accounts needed by extensions are appended at the end, everything else maintains the same binary structure).

At the very least, during decoding, the user should be aware that its signing a Transfer for a mint with such extensions enabled (fees can go all the way up to 100% and can change over time, on the other end of the spectrum transfer hooks can enable bad actors to effectively wipe accounts).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This simple approach seems reasonable at that stage of token2022 support.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its much better.

However, if I understood this correctly, the warning message only pops up if there are Extensions related instructions on the TX right? For that scenario its the right behaviour.

However, if there is only a TransferChecked instruction in the transaction and it is of a token mint with possible damaging extensions enabled (high transfer fees, draining transfer hook), the user will think he's signing a token transfer from the old Token Program without any side effects as none of that is present in the transaction.

IMO there needs to be another warning on any T22 TransferChecked like:
"Token Extensions" "Cannot verify mint extensions"
"Verify mint issuer before signing"
(not sure of character limits, but something along these lines)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, any extension thats coming from T22 generates this warning, the idea behind this PR was to allow users to use the old backward compatible features.
Due to the current code design we are a little bit limited in terms of detecting any complex cases with different instructions. Transaction printers contains hardcoded switch case that does not allow a lot of flexibility unfortunately.

Can you specify what exact cases should trigger that additional warning? Is it for transactions that only contains single TransferChecked instruction (https://solana-labs.github.io/solana-program-library/token/js/functions/createTransferCheckedInstruction.html) or are they any other cases?

And there is also another issue. On the older nanos devices we are really close to the memory limit, so adding long strings in to the binary may cause problems too, some of them appear only in specific features so maybe we just reuse the same warning text?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The additional warning should be triggered on TransferChecked when programId == token22, regardless of how many instructions are present in the transaction.

I'd say you can recycle the title part of the warnings.

Title: "Extension warning"
Messages: "Can't check mint extensions" -> "Check explorer"

Is the memory available enough for those? If not we can rework these warnings to further reuse strings.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tiago18c ok, I've added additional warning screens and i've also merged latest develop changes to verify that everything is still working as planned.
I did few tests on the nanos model and it looks that we are still within memory limits

0xMMBD and others added 2 commits March 29, 2024 16:57
* Added support for compute budget instructions:
* request heap frame
* set compute unit price
* request units
* set compute unit limit
* added unit tests

Co-authored-by: Piotr Swierzy <[email protected]>
0xMMBD added a commit that referenced this pull request Apr 7, 2024
* Added split-stake instruction support for:
    * SystemTransfer + SystemAllocate + SystemAssign + StakeSplit
    * SystemTransfer + SystemAllocateWithSeed + StakeSplit

Co-authored-by: Maciej Nabiałek <[email protected]>
0xMMBD and others added 4 commits April 8, 2024 01:05
* Added split-stake instruction support for:
    * SystemTransfer + SystemAllocate + SystemAssign + StakeSplit
    * SystemTransfer + SystemAllocateWithSeed + StakeSplit

Co-authored-by: Maciej Nabiałek <[email protected]>
@0xMMBD 0xMMBD requested a review from tiago18c May 9, 2024 17:28
Copy link

@tiago18c tiago18c left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@0xMMBD
Copy link
Member Author

0xMMBD commented May 24, 2024

Hello @tiago18c can you please summarize what are the next steps? Is there anything else from our side that should be done?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants