From 577adfde5a623b1ab35039875d24edc4b3d5b92c Mon Sep 17 00:00:00 2001 From: Vaibhav Sethia Date: Thu, 2 Jan 2025 00:48:28 +0530 Subject: [PATCH 01/19] feat: Add solana token txn parse --- apps/solana_app/solana_contracts.c | 105 ++++++++++++++ apps/solana_app/solana_contracts.h | 45 ++++++ apps/solana_app/solana_priv.h | 3 + apps/solana_app/solana_sign_txn.c | 141 ++++++++++++++++++- apps/solana_app/solana_txn_helpers.c | 72 ++++++++-- apps/solana_app/solana_txn_helpers.h | 32 ++++- common/cypherock-common | 2 +- common/proto-options/solana/sign_txn.options | 2 + src/constant_texts.c | 3 + src/constant_texts.h | 3 + 10 files changed, 393 insertions(+), 15 deletions(-) create mode 100644 apps/solana_app/solana_contracts.c create mode 100644 apps/solana_app/solana_contracts.h diff --git a/apps/solana_app/solana_contracts.c b/apps/solana_app/solana_contracts.c new file mode 100644 index 000000000..332a430b9 --- /dev/null +++ b/apps/solana_app/solana_contracts.c @@ -0,0 +1,105 @@ +/** + * @file solana_contracts.c + * @author Cypherock X1 Team + * @brief TRON whitelisted contracts list + * @copyright Copyright (c) 2023 HODL TECH PTE LTD + *
You may obtain a copy of license at https://mitcc.org/ + * + ****************************************************************************** + * @attention + * + * (c) Copyright 2023 by HODL TECH PTE LTD + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * "Commons Clause" License Condition v1.0 + * + * The Software is provided to you by the Licensor under the License, + * as defined below, subject to the following condition. + * + * Without limiting other conditions in the License, the grant of + * rights under the License will not include, and the License does not + * grant to you, the right to Sell the Software. + * + * For purposes of the foregoing, "Sell" means practicing any or all + * of the rights granted to you under the License to provide to third + * parties, for a fee or other consideration (including without + * limitation fees for hosting or consulting/ support services related + * to the Software), a product or service whose value derives, entirely + * or substantially, from the functionality of the Software. Any license + * notice or attribution required by the License must also include + * this Commons Clause License Condition notice. + * + * Software: All X1Wallet associated files. + * License: MIT + * Licensor: HODL TECH PTE LTD + * + ****************************************************************************** + */ + +/***************************************************************************** + * INCLUDES + *****************************************************************************/ + +#include + +/***************************************************************************** + * EXTERN VARIABLES + *****************************************************************************/ + +/***************************************************************************** + * PRIVATE MACROS AND DEFINES + *****************************************************************************/ + +/***************************************************************************** + * PRIVATE TYPEDEFS + *****************************************************************************/ + +/***************************************************************************** + * STATIC FUNCTION PROTOTYPES + *****************************************************************************/ + +/***************************************************************************** + * STATIC VARIABLES + *****************************************************************************/ + +/***************************************************************************** + * GLOBAL VARIABLES + *****************************************************************************/ + +const solana_token_program_t + solana_token_program[SOLANA_WHITELISTED_TOKEN_PROGRAM_COUNT] = { + // Tether USD + {{0xe9, 0x28, 0x39, 0x55, 0x09, 0x65, 0xff, 0xd4, 0xd6, 0x4a, 0xca, + 0xaf, 0x46, 0xd4, 0x5d, 0xf7, 0x31, 0x8e, 0x5b, 0x4f, 0x57, 0xc9, + 0x0c, 0x48, 0x7d, 0x60, 0x62, 0x5d, 0x82, 0x9b, 0x83, 0x7b}, + "SOLDC", + 6}, +}; + +/***************************************************************************** + * STATIC FUNCTIONS + *****************************************************************************/ + +/***************************************************************************** + * GLOBAL FUNCTIONS + *****************************************************************************/ diff --git a/apps/solana_app/solana_contracts.h b/apps/solana_app/solana_contracts.h new file mode 100644 index 000000000..8e71e071b --- /dev/null +++ b/apps/solana_app/solana_contracts.h @@ -0,0 +1,45 @@ +/** + * @file solana_contracts.h + * @author Cypherock X1 Team + * @brief TRON contract related definitions and types + * @copyright Copyright (c) 2023 HODL TECH PTE LTD + *
You may obtain a copy of license at https://mitcc.org/ + */ +#ifndef SOLANA_CONTRACTS_H +#define SOLANA_CONTRACTS_H +/***************************************************************************** + * INCLUDES + *****************************************************************************/ + +#include "solana_txn_helpers.h" + +/***************************************************************************** + * MACROS AND DEFINES + *****************************************************************************/ + +// Number of entries in whitelisted contracts list +#define SOLANA_WHITELISTED_TOKEN_PROGRAM_COUNT 1 + +/***************************************************************************** + * TYPEDEFS + *****************************************************************************/ + +typedef struct solana_token_program { + /// 32-byte hex coded public address of the program + const uint8_t address[SOLANA_ACCOUNT_ADDRESS_LENGTH]; + /// Symbol (short alphabetical representation) of the contract token + const char *symbol; + /// Decimal value used to display the amount in token transfer in token units + const uint8_t decimal; +} solana_token_program_t; + +/***************************************************************************** + * EXPORTED VARIABLES + *****************************************************************************/ + +/***************************************************************************** + * GLOBAL FUNCTION PROTOTYPES + *****************************************************************************/ + +#endif // SOLANA_CONTRACTS_H diff --git a/apps/solana_app/solana_priv.h b/apps/solana_app/solana_priv.h index 61437a9ec..0df760524 100644 --- a/apps/solana_app/solana_priv.h +++ b/apps/solana_app/solana_priv.h @@ -34,6 +34,9 @@ typedef struct { uint8_t *transaction; /// store for decoded unsigned transaction info solana_unsigned_txn transaction_info; + + bool is_token_transfer_transaction; + solana_sign_txn_initiate_token_data_t token_data; } solana_txn_context_t; /** diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index 5e4b3a71c..f80c3c1b6 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -62,17 +62,26 @@ #include "reconstruct_wallet_flow.h" #include "solana_api.h" +#include "solana_contracts.h" #include "solana_helpers.h" #include "solana_priv.h" +#include "solana_txn_helpers.h" #include "status_api.h" #include "ui_core_confirm.h" #include "ui_screens.h" #include "wallet_list.h" - /***************************************************************************** * EXTERN VARIABLES *****************************************************************************/ - +/** + * @brief Whitelisted contracts with respective token symbol + * @details A map of Solana Token addresses with their token symbols. These + * will enable the device to verify the token transaction in a + * user-friendly manner. + * + * @see solana_token_program_t + */ +extern const solana_token_program_t solana_token_program[]; /***************************************************************************** * PRIVATE MACROS AND DEFINES *****************************************************************************/ @@ -270,6 +279,16 @@ STATIC bool solana_handle_initiate_query(const solana_query_t *query) { memcpy(&solana_txn_context->init_info, &query->sign_txn.initiate, sizeof(solana_sign_txn_initiate_request_t)); + + solana_txn_context->is_token_transfer_transaction = + query->sign_txn.initiate.has_token_data; + + // if it is a token transfer transaction, store the token data + if (solana_txn_context->is_token_transfer_transaction) { + memcpy(&solana_txn_context->token_data, + &query->sign_txn.initiate.token_data, + sizeof(solana_sign_txn_initiate_token_data_t)); + } send_response(SOLANA_SIGN_TXN_RESPONSE_CONFIRMATION_TAG); // show processing screen for a minimum duration (additional time will add due // to actual processing) @@ -337,7 +356,7 @@ STATIC bool solana_fetch_valid_transaction(solana_query_t *query) { return true; } -STATIC bool solana_get_user_verification() { +static bool solana_transfer_sol_transaction() { char address[45] = {0}; size_t address_size = sizeof(address); @@ -363,7 +382,7 @@ STATIC bool solana_get_user_verification() { int i = 8; while (i--) be_lamports[i] = solana_txn_context->transaction_info.instruction.program - .transfer.lamports >> + .transfer.amount >> 8 * (7 - i); byte_array_to_hex_string( @@ -390,6 +409,120 @@ STATIC bool solana_get_user_verification() { return true; } +static bool is_token_whitelisted(const uint8_t *address, + const solana_token_program_t **contract) { + const solana_token_program_t *match = NULL; + bool status = false; + for (int16_t i = 0; i < SOLANA_WHITELISTED_TOKEN_PROGRAM_COUNT; i++) { + if (memcmp(address, + solana_token_program[i].address, + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + match = &solana_token_program[i]; + status = true; + break; + } + } + + if (NULL != contract) { + *contract = match; + } + + // return empty contract if not found in the whitelist + if (!status) { + static solana_token_program_t empty_contract = { + .symbol = "", + .decimal = 0, + }; + *contract = &empty_contract; + } + + return status; +} + +static bool solana_transfer_token_transaction() { + char address[45] = {0}; + size_t address_size = sizeof(address); + + const solana_token_program_t *contract; + if (!is_token_whitelisted(solana_txn_context->token_data.mint_address, + &contract)) { + // Contract Unverifed, Display warning + delay_scr_init(ui_text_unverified_contract, DELAY_TIME); + + char mint_address[45] = {0}; + size_t mint_address_size = sizeof(mint_address); + // verify mint address + if (!b58enc(mint_address, + &mint_address_size, + solana_txn_context->token_data.mint_address, + SOLANA_ACCOUNT_ADDRESS_LENGTH)) { + solana_send_error(ERROR_COMMON_ERROR_UNKNOWN_ERROR_TAG, 2); + return false; + } + + if (!core_scroll_page(ui_text_solana_verify_mint_authority, + mint_address, + solana_send_error)) { + return false; + } + } + + // verify recipient address; + if (!b58enc(address, + &address_size, + solana_txn_context->token_data.recipient_address, + SOLANA_ACCOUNT_ADDRESS_LENGTH)) { + solana_send_error(ERROR_COMMON_ERROR_UNKNOWN_ERROR_TAG, 2); + return false; + } + + if (!core_scroll_page(ui_text_verify_address, address, solana_send_error)) { + return false; + } + + // TODO: Calculate Assc.TA and compare utxn's value + + // verify recipient amount + char amount_string[40] = {'\0'}, amount_decimal_string[30] = {'\0'}; + char display[100] = ""; + + uint8_t be_units[8] = {0}; + int i = 8; + while (i--) + be_units[i] = solana_txn_context->transaction_info.instruction.program + .transfer.amount >> + 8 * (7 - i); + + byte_array_to_hex_string(be_units, 8, amount_string, sizeof(amount_string)); + if (!convert_byte_array_to_decimal_string(16, + contract->decimal, + amount_string, + amount_decimal_string, + sizeof(amount_decimal_string))) { + solana_send_error(ERROR_COMMON_ERROR_UNKNOWN_ERROR_TAG, 1); + return false; + } + + snprintf(display, + sizeof(display), + UI_TEXT_VERIFY_AMOUNT, + amount_decimal_string, + contract->symbol); + if (!core_confirmation(display, solana_send_error)) { + return false; + } + + set_app_flow_status(SOLANA_SIGN_TXN_STATUS_VERIFY); + return true; +} + +STATIC bool solana_get_user_verification() { + if (solana_txn_context->is_token_transfer_transaction == true) { + return solana_transfer_token_transaction(); + } else + return solana_transfer_sol_transaction(); +} + STATIC bool fetch_seed(solana_query_t *query, uint8_t *seed_out) { if (!solana_get_query(query, SOLANA_QUERY_SIGN_TXN_TAG) || !check_which_request(query, SOLANA_SIGN_TXN_REQUEST_VERIFY_TAG)) { diff --git a/apps/solana_app/solana_txn_helpers.c b/apps/solana_app/solana_txn_helpers.c index 21e2787fe..ca681fbba 100644 --- a/apps/solana_app/solana_txn_helpers.c +++ b/apps/solana_app/solana_txn_helpers.c @@ -63,6 +63,7 @@ #include "solana_txn_helpers.h" +#include #include /***************************************************************************** @@ -72,7 +73,8 @@ /***************************************************************************** * PRIVATE MACROS AND DEFINES *****************************************************************************/ - +#define SOLANA_TOKEN_PROGRAM_ADDRESS \ + "06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9" ///< "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" /***************************************************************************** * PRIVATE TYPEDEFS *****************************************************************************/ @@ -180,14 +182,15 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, utxn->instruction.opaque_data = byte_array + offset; offset += utxn->instruction.opaque_data_length; - uint32_t instruction_enum = U32_READ_LE_ARRAY(utxn->instruction.opaque_data); - uint8_t system_program_id[SOLANA_ACCOUNT_ADDRESS_LENGTH] = { - 0}; // System instruction address + 0}; // System instruction address for SOL transfer is 0s if (memcmp(utxn->account_addresses + utxn->instruction.program_id_index * SOLANA_ACCOUNT_ADDRESS_LENGTH, system_program_id, SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + uint32_t instruction_enum = + U32_READ_LE_ARRAY(utxn->instruction.opaque_data); + switch (instruction_enum) { case SSI_TRANSFER: // transfer instruction utxn->instruction.program.transfer.funding_account = @@ -198,13 +201,43 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, utxn->account_addresses + (*(utxn->instruction.account_addresses_index + 1) * SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction.program.transfer.lamports = + utxn->instruction.program.transfer.amount = U64_READ_LE_ARRAY(utxn->instruction.opaque_data + 4); break; default: break; } + } else { + // Set System instruction address for Token Program + hex_string_to_byte_array(SOLANA_TOKEN_PROGRAM_ADDRESS, + SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, + system_program_id); + + if (memcmp(utxn->account_addresses + utxn->instruction.program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id, + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + uint8_t instruction_enum = *(utxn->instruction.opaque_data); + + switch (instruction_enum) { + case STPI_TRANSFER: // transfer instruction + utxn->instruction.program.transfer.funding_account = + utxn->account_addresses + + (*(utxn->instruction.account_addresses_index + 0) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); + utxn->instruction.program.transfer.recipient_account = + utxn->account_addresses + + (*(utxn->instruction.account_addresses_index + 1) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); + utxn->instruction.program.transfer.amount = + U64_READ_LE_ARRAY(utxn->instruction.opaque_data + 1); + break; + + default: + break; + } + } } return ((offset <= byte_array_size) && (offset > 0)) @@ -220,14 +253,15 @@ int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { utxn->instruction.program_id_index < utxn->account_addresses_count)) return SOL_V_INDEX_OUT_OF_RANGE; - uint32_t instruction_enum = U32_READ_LE_ARRAY(utxn->instruction.opaque_data); - uint8_t system_program_id[SOLANA_ACCOUNT_ADDRESS_LENGTH] = { - 0}; // System instruction address + 0}; // System instruction address for SOL transfer is 0s if (memcmp(utxn->account_addresses + utxn->instruction.program_id_index * SOLANA_ACCOUNT_ADDRESS_LENGTH, system_program_id, SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + uint32_t instruction_enum = + U32_READ_LE_ARRAY(utxn->instruction.opaque_data); + switch (instruction_enum) { case SSI_TRANSFER: // transfer instruction break; @@ -236,7 +270,27 @@ int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { break; } } else { - return SOL_V_UNSUPPORTED_PROGRAM; + // Set System instruction address for Token Program + hex_string_to_byte_array(SOLANA_TOKEN_PROGRAM_ADDRESS, + SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, + system_program_id); + + if (memcmp(utxn->account_addresses + utxn->instruction.program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id, + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + uint8_t instruction_enum = *(utxn->instruction.opaque_data); + + switch (instruction_enum) { + case STPI_TRANSFER: // transfer instruction + break; + default: + return SOL_V_UNSUPPORTED_INSTRUCTION; + break; + } + } else { + return SOL_V_UNSUPPORTED_PROGRAM; + } } return SOL_OK; } diff --git a/apps/solana_app/solana_txn_helpers.h b/apps/solana_app/solana_txn_helpers.h index 60f44ab58..c20faf823 100644 --- a/apps/solana_app/solana_txn_helpers.h +++ b/apps/solana_app/solana_txn_helpers.h @@ -50,6 +50,36 @@ enum SOLANA_SYSTEM_INSTRUCTION { SSI_UPGRADE_NONCE_ACCOUNT, }; +/// Ref: +/// https://github.com/solana-labs/solana-program-library/blob/b1c44c171bc95e6ee74af12365cb9cbab68be76c/token/program/src/instruction.rs +enum SOLANA_TOKEN_PROGRAM_INSTRUCTION { + STPI_INITIALIZE_MINT = 0, + STPI_INITIALIZE_ACCOUNT, + STPI_INITIALIZE_MULTISIG, + STPI_TRANSFER, + STPI_APPROVE, + STPI_REVOKE, + STPI_SET_AUTHORITY, + STPI_MINT_TO, + STPI_BURN, + STPI_CLOSE_ACCOUNT, + STPI_FREEZE_ACCOUNT, + STPI_THAW_ACCOUNT, + STPI_TRANSFER_CHECKED, + STPI_APPROVE_CHECKED, + STPI_MINT_TO_CHECKED, + STPI_BURN_CHECKED, + STPI_INITIALIZE_ACCOUNT2, + STPI_SYNC_NATIVE, + STPI_INITIALIZE_ACCOUNT3, + STPI_INITIALIZE_MULTISIG2, + STPI_INITIALIZE_MINT2, + STPI_GET_ACCOUNT_DATA_SIZE, + STPI_INITIALIZE_IMMUTABLE_OWNER, + STPI_AMOUNT_TO_UI_AMOUNT, + STPI_UI_AMOUNT_TO_AMOUNT +}; + enum SOLANA_ERROR_CODES { SOL_OK = 0, SOL_ERROR, @@ -68,7 +98,7 @@ enum SOLANA_ERROR_CODES { typedef struct solana_transfer_data { uint8_t *funding_account; uint8_t *recipient_account; - uint64_t lamports; + uint64_t amount; } solana_transfer_data; // Reference : diff --git a/common/cypherock-common b/common/cypherock-common index 19912e8d0..2d635d251 160000 --- a/common/cypherock-common +++ b/common/cypherock-common @@ -1 +1 @@ -Subproject commit 19912e8d052064c477d6b11ca2e26efa4c483bfe +Subproject commit 2d635d251d71aec29a5f8681cdc987f9cee88c04 diff --git a/common/proto-options/solana/sign_txn.options b/common/proto-options/solana/sign_txn.options index f1901d21a..58354892a 100644 --- a/common/proto-options/solana/sign_txn.options +++ b/common/proto-options/solana/sign_txn.options @@ -1,5 +1,7 @@ # Options for file common/cypherock-common/proto/solana/sign_txn.proto solana.SignTxnInitiateRequest.walletId type:FT_STATIC max_size:32 fixed_length:true solana.SignTxnInitiateRequest.derivationPath type:FT_STATIC max_count:4 fixed_length:true +solana.SignTxnInitiateTokenData.recipient_address type:FT_STATIC max_size:32 fixed_length:true +solana.SignTxnInitiateTokenData.mint_address type:FT_STATIC max_size:32 fixed_length:true solana.SignTxnSignatureResponse.signature type:FT_STATIC max_size:64 fixed_length:true solana.SignTxnSignatureRequest.blockhash type:FT_STATIC max_size:32 fixed_length:true diff --git a/src/constant_texts.c b/src/constant_texts.c index 6e37fe6c3..494496324 100644 --- a/src/constant_texts.c +++ b/src/constant_texts.c @@ -553,6 +553,9 @@ const char *ui_text_inheritance_decryption_flow_confirmation_generic = const char *ui_text_inheritance_decryption_flow_success = "Decryption Success"; const char *ui_text_inheritance_decryption_flow_failure = "Decryption Failed"; +// Solana Specific +const char *ui_text_solana_verify_mint_authority = "Verify Mint Authority"; + #ifdef ALLOW_LOG_EXPORT const char *ui_text_send_logs_prompt = "Send logs to the cySync app?"; #endif diff --git a/src/constant_texts.h b/src/constant_texts.h index cb582947f..fe823bd70 100644 --- a/src/constant_texts.h +++ b/src/constant_texts.h @@ -390,6 +390,9 @@ extern const char *ui_text_inheritance_decryption_flow_confirmation_generic; extern const char *ui_text_inheritance_decryption_flow_success; extern const char *ui_text_inheritance_decryption_flow_failure; +// Solana +extern const char *ui_text_solana_verify_mint_authority; + #ifdef ALLOW_LOG_EXPORT extern const char *ui_text_send_logs_prompt; #endif From 4a3d5e0339f729683c2a1fcdbd68d90592d35c4e Mon Sep 17 00:00:00 2001 From: Vaibhav Sethia Date: Thu, 2 Jan 2025 22:32:30 +0530 Subject: [PATCH 02/19] feat(app): Add solana pda derivation and verification --- apps/solana_app/solana_sign_txn.c | 113 ++++++++++++++++++++++++++- apps/solana_app/solana_txn_helpers.c | 3 +- apps/solana_app/solana_txn_helpers.h | 5 ++ 3 files changed, 118 insertions(+), 3 deletions(-) diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index f80c3c1b6..10c079acf 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -60,6 +60,9 @@ * INCLUDES *****************************************************************************/ +#include +#include + #include "reconstruct_wallet_flow.h" #include "solana_api.h" #include "solana_contracts.h" @@ -409,6 +412,97 @@ static bool solana_transfer_sol_transaction() { return true; } +static bool create_program_address( + const uint8_t seed[][SOLANA_ACCOUNT_ADDRESS_LENGTH], + const uint8_t seeds_size[], + const uint8_t count, + const uint8_t *program_address, + uint8_t *pub_key) { + uint8_t buffer[300] = {0}; + uint8_t buffer_size = 0; + for (uint8_t i = 0; i < count; i++) { + memcpy(buffer + buffer_size, seed[i], seeds_size[i]); + buffer_size += seeds_size[i]; + } + + // Append program id and pda_string + memcpy(buffer + buffer_size, program_address, SOLANA_ACCOUNT_ADDRESS_LENGTH); + buffer_size += SOLANA_ACCOUNT_ADDRESS_LENGTH; + + const char *pda_string = "ProgramDerivedAddress"; + memcpy(buffer + buffer_size, pda_string, strlen(pda_string)); + buffer_size += strlen(pda_string); + + uint8_t hash[SHA256_DIGEST_LENGTH] = {0}; + sha256_Raw(buffer, buffer_size, hash); + + // check if point on curve + ge25519 r; + if (!ge25519_unpack_vartime(&r, hash)) { + // point is off curve; return hash as public key + memcpy(pub_key, hash, SOLANA_ACCOUNT_ADDRESS_LENGTH); + return true; + } + + if (!ge25519_check(&r)) { + // point is off curve; return hash as public key + memcpy(pub_key, hash, SOLANA_ACCOUNT_ADDRESS_LENGTH); + return true; + } + + return false; +} + +static bool find_program_address( + const uint8_t seed[][SOLANA_ACCOUNT_ADDRESS_LENGTH], + const uint8_t count, + const uint8_t *program_address, + uint8_t *address) { + uint8_t nonce = 255; + + // append nonce to seed + uint8_t seed_with_nonce[count + 1][SOLANA_ACCOUNT_ADDRESS_LENGTH]; + uint8_t seeds_size[count + 1]; + // copy initial seeds + for (int i = 0; i < count; i++) { + memcpy(seed_with_nonce[i], seed[i], SOLANA_ACCOUNT_ADDRESS_LENGTH); + seeds_size[i] = SOLANA_ACCOUNT_ADDRESS_LENGTH; + } + seeds_size[count] = 1; // nonce size + + while (nonce != 0) { + seed_with_nonce[count][0] = nonce; + if (create_program_address( + seed_with_nonce, seeds_size, count + 1, program_address, address)) { + return true; + break; + } + nonce -= 1; + } + return false; +} + +static bool get_associated_token_address(const uint8_t *mint, + const uint8_t *owner, + uint8_t *address) { + const uint8_t count = 3; ///< owner + token_program_id + mint + uint8_t seed[count][SOLANA_ACCOUNT_ADDRESS_LENGTH]; + + memcpy(seed[0], owner, SOLANA_ACCOUNT_ADDRESS_LENGTH); + hex_string_to_byte_array( + SOLANA_TOKEN_PROGRAM_ADDRESS, SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, seed[1]); + memcpy(seed[2], mint, SOLANA_ACCOUNT_ADDRESS_LENGTH); + + uint8_t prog_addr[SOLANA_ACCOUNT_ADDRESS_LENGTH] = {0}; + hex_string_to_byte_array( + SOLANA_ASSOCIATED_TOKEN_PROGRAM_ADDRESS, 64, prog_addr); + if (!find_program_address(seed, count, prog_addr, address)) { + return false; + } + + return true; +} + static bool is_token_whitelisted(const uint8_t *address, const solana_token_program_t **contract) { const solana_token_program_t *match = NULL; @@ -480,7 +574,24 @@ static bool solana_transfer_token_transaction() { return false; } - // TODO: Calculate Assc.TA and compare utxn's value + // Upon recipient address confirmwation, calculate associated token address + // and compare with utxn's value + uint8_t associated_token_address[SOLANA_ACCOUNT_ADDRESS_LENGTH] = {0}; + if (!get_associated_token_address( + solana_txn_context->token_data.mint_address, + solana_txn_context->token_data.recipient_address, + associated_token_address)) { + solana_send_error(ERROR_COMMON_ERROR_UNKNOWN_ERROR_TAG, 2); + return false; + } + + if (memcmp(associated_token_address, + solana_txn_context->transaction_info.instruction.program.transfer + .recipient_account, + SOLANA_ACCOUNT_ADDRESS_LENGTH) != 0) { + solana_send_error(ERROR_COMMON_ERROR_CORRUPT_DATA_TAG, 2); + return false; + } // verify recipient amount char amount_string[40] = {'\0'}, amount_decimal_string[30] = {'\0'}; diff --git a/apps/solana_app/solana_txn_helpers.c b/apps/solana_app/solana_txn_helpers.c index ca681fbba..69ee90078 100644 --- a/apps/solana_app/solana_txn_helpers.c +++ b/apps/solana_app/solana_txn_helpers.c @@ -73,8 +73,7 @@ /***************************************************************************** * PRIVATE MACROS AND DEFINES *****************************************************************************/ -#define SOLANA_TOKEN_PROGRAM_ADDRESS \ - "06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9" ///< "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + /***************************************************************************** * PRIVATE TYPEDEFS *****************************************************************************/ diff --git a/apps/solana_app/solana_txn_helpers.h b/apps/solana_app/solana_txn_helpers.h index c20faf823..0b9fbfd43 100644 --- a/apps/solana_app/solana_txn_helpers.h +++ b/apps/solana_app/solana_txn_helpers.h @@ -28,6 +28,11 @@ #define SOLANA_ACCOUNT_ADDRESS_LENGTH 32 #define SOLANA_BLOCKHASH_LENGTH 32 +#define SOLANA_TOKEN_PROGRAM_ADDRESS \ + "06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9" ///< "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + +#define SOLANA_ASSOCIATED_TOKEN_PROGRAM_ADDRESS \ + "8c97258f4e2489f1bb3d1029148e0d830b5a1399daff1084048e7bd8dbe9f859" ///< "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" /***************************************************************************** * TYPEDEFS *****************************************************************************/ From 6d43c7543f16d8d2aefa4105ee6b19f31bf27921 Mon Sep 17 00:00:00 2001 From: Vaibhav Sethia Date: Fri, 3 Jan 2025 18:13:17 +0530 Subject: [PATCH 03/19] chore: Review changes --- apps/solana_app/solana_sign_txn.c | 43 ++++++---- apps/solana_app/solana_txn_helpers.c | 118 ++++++++++++++------------- apps/solana_app/solana_txn_helpers.h | 5 +- 3 files changed, 92 insertions(+), 74 deletions(-) diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index 10c079acf..9be3bd0c9 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -267,31 +267,40 @@ STATIC bool solana_handle_initiate_query(const solana_query_t *query) { return false; } - snprintf(msg, - sizeof(msg), - UI_TEXT_SEND_TOKEN_PROMPT, - SOLANA_LUNIT, - SOLANA_NAME, - wallet_name); - // Take user consent to sign the transaction for the wallet - if (!core_confirmation(msg, solana_send_error)) { - return false; - } - - set_app_flow_status(SOLANA_SIGN_TXN_STATUS_CONFIRM); - memcpy(&solana_txn_context->init_info, - &query->sign_txn.initiate, - sizeof(solana_sign_txn_initiate_request_t)); - solana_txn_context->is_token_transfer_transaction = query->sign_txn.initiate.has_token_data; - // if it is a token transfer transaction, store the token data if (solana_txn_context->is_token_transfer_transaction) { + snprintf( + msg, sizeof(msg), UI_TEXT_SIGN_TXN_PROMPT, SOLANA_NAME, wallet_name); + // Take user consent to sign the transaction for the wallet + if (!core_confirmation(msg, solana_send_error)) { + return false; + } + + // if it is a token transfer transaction, store the token data memcpy(&solana_txn_context->token_data, &query->sign_txn.initiate.token_data, sizeof(solana_sign_txn_initiate_token_data_t)); + + } else { + snprintf(msg, + sizeof(msg), + UI_TEXT_SEND_TOKEN_PROMPT, + SOLANA_LUNIT, + SOLANA_NAME, + wallet_name); + // Take user consent to sign the transaction for the wallet + if (!core_confirmation(msg, solana_send_error)) { + return false; + } } + + set_app_flow_status(SOLANA_SIGN_TXN_STATUS_CONFIRM); + memcpy(&solana_txn_context->init_info, + &query->sign_txn.initiate, + sizeof(solana_sign_txn_initiate_request_t)); + send_response(SOLANA_SIGN_TXN_RESPONSE_CONFIRMATION_TAG); // show processing screen for a minimum duration (additional time will add due // to actual processing) diff --git a/apps/solana_app/solana_txn_helpers.c b/apps/solana_app/solana_txn_helpers.c index 69ee90078..4a49fa358 100644 --- a/apps/solana_app/solana_txn_helpers.c +++ b/apps/solana_app/solana_txn_helpers.c @@ -181,11 +181,20 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, utxn->instruction.opaque_data = byte_array + offset; offset += utxn->instruction.opaque_data_length; - uint8_t system_program_id[SOLANA_ACCOUNT_ADDRESS_LENGTH] = { - 0}; // System instruction address for SOL transfer is 0s + // prepare list of supported program ids + uint8_t system_program_id[SOLANA_PROGRAM_ID_COUNT] + [SOLANA_ACCOUNT_ADDRESS_LENGTH]; + // Set System instruction address for SOL transfer + memzero(system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH); + // Set System instruction address for Token Program + hex_string_to_byte_array(SOLANA_TOKEN_PROGRAM_ADDRESS, + SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, + system_program_id[1]); + if (memcmp(utxn->account_addresses + utxn->instruction.program_id_index * SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id, + system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { uint32_t instruction_enum = U32_READ_LE_ARRAY(utxn->instruction.opaque_data); @@ -207,35 +216,29 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, default: break; } - } else { - // Set System instruction address for Token Program - hex_string_to_byte_array(SOLANA_TOKEN_PROGRAM_ADDRESS, - SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, - system_program_id); - - if (memcmp(utxn->account_addresses + utxn->instruction.program_id_index * - SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id, - SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { - uint8_t instruction_enum = *(utxn->instruction.opaque_data); - - switch (instruction_enum) { - case STPI_TRANSFER: // transfer instruction - utxn->instruction.program.transfer.funding_account = - utxn->account_addresses + - (*(utxn->instruction.account_addresses_index + 0) * - SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction.program.transfer.recipient_account = - utxn->account_addresses + - (*(utxn->instruction.account_addresses_index + 1) * - SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction.program.transfer.amount = - U64_READ_LE_ARRAY(utxn->instruction.opaque_data + 1); - break; - - default: - break; - } + } else if (memcmp( + utxn->account_addresses + utxn->instruction.program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + uint8_t instruction_enum = *(utxn->instruction.opaque_data); + + switch (instruction_enum) { + case STPI_TRANSFER: // transfer instruction + utxn->instruction.program.transfer.funding_account = + utxn->account_addresses + + (*(utxn->instruction.account_addresses_index + 0) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); + utxn->instruction.program.transfer.recipient_account = + utxn->account_addresses + + (*(utxn->instruction.account_addresses_index + 1) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); + utxn->instruction.program.transfer.amount = + U64_READ_LE_ARRAY(utxn->instruction.opaque_data + 1); + break; + + default: + break; } } @@ -252,11 +255,20 @@ int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { utxn->instruction.program_id_index < utxn->account_addresses_count)) return SOL_V_INDEX_OUT_OF_RANGE; - uint8_t system_program_id[SOLANA_ACCOUNT_ADDRESS_LENGTH] = { - 0}; // System instruction address for SOL transfer is 0s + // prepare list of supported program ids + uint8_t system_program_id[SOLANA_PROGRAM_ID_COUNT] + [SOLANA_ACCOUNT_ADDRESS_LENGTH]; + // Set System instruction address for SOL transfer + memzero(system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH); + // Set System instruction address for Token Program + hex_string_to_byte_array(SOLANA_TOKEN_PROGRAM_ADDRESS, + SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, + system_program_id[1]); + if (memcmp(utxn->account_addresses + utxn->instruction.program_id_index * SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id, + system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { uint32_t instruction_enum = U32_READ_LE_ARRAY(utxn->instruction.opaque_data); @@ -268,28 +280,22 @@ int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { return SOL_V_UNSUPPORTED_INSTRUCTION; break; } - } else { - // Set System instruction address for Token Program - hex_string_to_byte_array(SOLANA_TOKEN_PROGRAM_ADDRESS, - SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, - system_program_id); - - if (memcmp(utxn->account_addresses + utxn->instruction.program_id_index * - SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id, - SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { - uint8_t instruction_enum = *(utxn->instruction.opaque_data); - - switch (instruction_enum) { - case STPI_TRANSFER: // transfer instruction - break; - default: - return SOL_V_UNSUPPORTED_INSTRUCTION; - break; - } - } else { - return SOL_V_UNSUPPORTED_PROGRAM; + } else if (memcmp( + utxn->account_addresses + utxn->instruction.program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id, + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + uint8_t instruction_enum = *(utxn->instruction.opaque_data); + + switch (instruction_enum) { + case STPI_TRANSFER: // transfer instruction + break; + default: + return SOL_V_UNSUPPORTED_INSTRUCTION; + break; } + } else { + return SOL_V_UNSUPPORTED_PROGRAM; } return SOL_OK; } diff --git a/apps/solana_app/solana_txn_helpers.h b/apps/solana_app/solana_txn_helpers.h index 0b9fbfd43..61d40a376 100644 --- a/apps/solana_app/solana_txn_helpers.h +++ b/apps/solana_app/solana_txn_helpers.h @@ -28,9 +28,12 @@ #define SOLANA_ACCOUNT_ADDRESS_LENGTH 32 #define SOLANA_BLOCKHASH_LENGTH 32 +#define SOLANA_PROGRAM_ID_COUNT 2 ///< Number of supported program ids +#define SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX 0 +#define SOLANA_TOKEN_PROGRAM_ID_INDEX 1 + #define SOLANA_TOKEN_PROGRAM_ADDRESS \ "06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9" ///< "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - #define SOLANA_ASSOCIATED_TOKEN_PROGRAM_ADDRESS \ "8c97258f4e2489f1bb3d1029148e0d830b5a1399daff1084048e7bd8dbe9f859" ///< "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" /***************************************************************************** From 51adadc186d9e026010f0b13698578e68ac26a6e Mon Sep 17 00:00:00 2001 From: Vaibhav Sethia Date: Fri, 3 Jan 2025 18:39:37 +0530 Subject: [PATCH 04/19] fix: Minor bug --- apps/solana_app/solana_txn_helpers.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/solana_app/solana_txn_helpers.c b/apps/solana_app/solana_txn_helpers.c index 4a49fa358..e0e4b3ab8 100644 --- a/apps/solana_app/solana_txn_helpers.c +++ b/apps/solana_app/solana_txn_helpers.c @@ -190,7 +190,7 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, // Set System instruction address for Token Program hex_string_to_byte_array(SOLANA_TOKEN_PROGRAM_ADDRESS, SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, - system_program_id[1]); + system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX]); if (memcmp(utxn->account_addresses + utxn->instruction.program_id_index * SOLANA_ACCOUNT_ADDRESS_LENGTH, @@ -264,7 +264,7 @@ int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { // Set System instruction address for Token Program hex_string_to_byte_array(SOLANA_TOKEN_PROGRAM_ADDRESS, SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, - system_program_id[1]); + system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX]); if (memcmp(utxn->account_addresses + utxn->instruction.program_id_index * SOLANA_ACCOUNT_ADDRESS_LENGTH, @@ -283,7 +283,7 @@ int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { } else if (memcmp( utxn->account_addresses + utxn->instruction.program_id_index * SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id, + system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX], SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { uint8_t instruction_enum = *(utxn->instruction.opaque_data); From 1f5e55b27e1057ede0955a254d5dc184638b633a Mon Sep 17 00:00:00 2001 From: Vaibhav Sethia Date: Sun, 5 Jan 2025 02:35:57 +0530 Subject: [PATCH 05/19] chore: Add solana tokens whitelist --- apps/solana_app/solana_contracts.c | 279 ++++++++++++++++++++++++++++- apps/solana_app/solana_contracts.h | 2 +- src/constant_texts.c | 2 +- 3 files changed, 276 insertions(+), 7 deletions(-) diff --git a/apps/solana_app/solana_contracts.c b/apps/solana_app/solana_contracts.c index 332a430b9..60b980f78 100644 --- a/apps/solana_app/solana_contracts.c +++ b/apps/solana_app/solana_contracts.c @@ -88,12 +88,281 @@ const solana_token_program_t solana_token_program[SOLANA_WHITELISTED_TOKEN_PROGRAM_COUNT] = { - // Tether USD - {{0xe9, 0x28, 0x39, 0x55, 0x09, 0x65, 0xff, 0xd4, 0xd6, 0x4a, 0xca, - 0xaf, 0x46, 0xd4, 0x5d, 0xf7, 0x31, 0x8e, 0x5b, 0x4f, 0x57, 0xc9, - 0x0c, 0x48, 0x7d, 0x60, 0x62, 0x5d, 0x82, 0x9b, 0x83, 0x7b}, - "SOLDC", + {{0xce, 0x01, 0x0e, 0x60, 0xaf, 0xed, 0xb2, 0x27, 0x17, 0xbd, 0x63, + 0x19, 0x2f, 0x54, 0x14, 0x5a, 0x3f, 0x96, 0x5a, 0x33, 0xbb, 0x82, + 0xd2, 0xc7, 0x02, 0x9e, 0xb2, 0xce, 0x1e, 0x20, 0x82, 0x64}, + "USDT", 6}, + {{0xc6, 0xfa, 0x7a, 0xf3, 0xbe, 0xdb, 0xad, 0x3a, 0x3d, 0x65, 0xf3, + 0x6a, 0xab, 0xc9, 0x74, 0x31, 0xb1, 0xbb, 0xe4, 0xc2, 0xd2, 0xf6, + 0xe0, 0xe4, 0x7c, 0xa6, 0x02, 0x03, 0x45, 0x2f, 0x5d, 0x61}, + "USDC", + 6}, + {{0xb5, 0xd2, 0x5a, 0xf8, 0x1f, 0xdd, 0x47, 0xe2, 0x3f, 0xc5, 0x1c, + 0xb9, 0x29, 0xf2, 0xbf, 0xf3, 0xe1, 0xbf, 0x6a, 0xd6, 0x4d, 0xf7, + 0x7d, 0x3e, 0x52, 0x3a, 0x22, 0x80, 0x23, 0xe7, 0x3e, 0x6c}, + "USDE", + 9}, + {{0x07, 0x07, 0x31, 0x2d, 0x1d, 0x41, 0xda, 0x71, 0xf0, 0xfb, 0x28, + 0x0c, 0x16, 0x62, 0xcd, 0x65, 0xeb, 0xeb, 0x2e, 0x08, 0x59, 0xc0, + 0xcb, 0xae, 0x3f, 0xdb, 0xdc, 0xb2, 0x6c, 0x86, 0xe0, 0xaf}, + "USDS", + 6}, + {{0x0c, 0xc1, 0x0f, 0x51, 0x6a, 0xaa, 0xe9, 0xc1, 0x4b, 0xa9, 0x47, + 0x1f, 0x60, 0xab, 0xd3, 0x92, 0xdc, 0xd7, 0x86, 0xd5, 0x73, 0x54, + 0xab, 0xed, 0xee, 0xe7, 0x28, 0x9d, 0xd4, 0x0a, 0x0a, 0x0a}, + "RENDER", + 8}, + {{0xbc, 0x07, 0xc5, 0x6e, 0x60, 0xad, 0x3d, 0x3f, 0x17, 0x73, 0x82, + 0xea, 0xc6, 0x54, 0x8f, 0xba, 0x1f, 0xd3, 0x2c, 0xfd, 0x90, 0xca, + 0x02, 0xb3, 0xe7, 0xcf, 0xa1, 0x85, 0xfd, 0xce, 0x73, 0x98}, + "BONK", + 5}, + {{0x1d, 0x8c, 0xcf, 0x87, 0xac, 0x01, 0x47, 0xba, 0xe7, 0x56, 0xeb, + 0x96, 0x3a, 0x2e, 0xf6, 0x24, 0x4c, 0x96, 0x91, 0x56, 0x9a, 0x8e, + 0xc0, 0x8f, 0x00, 0x20, 0xa2, 0xeb, 0x8f, 0xbd, 0xb5, 0xa1}, + "PENGU", + 6}, + {{0xf7, 0x4b, 0xe1, 0xd7, 0x6a, 0xb9, 0xa6, 0xc2, 0xbe, 0x49, 0x99, + 0x66, 0x3f, 0xc6, 0xa0, 0xe1, 0x99, 0x74, 0x00, 0x0e, 0x83, 0x6e, + 0xf3, 0x0c, 0x5b, 0x62, 0x86, 0xf4, 0x2c, 0x02, 0x0f, 0x87}, + "AI16Z", + 9}, + {{0xc5, 0xf9, 0xfb, 0x32, 0xf4, 0x91, 0x11, 0xab, 0x20, 0xc3, 0x3f, + 0x25, 0x98, 0xfc, 0x83, 0x6c, 0x11, 0x3e, 0x29, 0x18, 0x81, 0xac, + 0x21, 0xee, 0x29, 0x16, 0x93, 0x94, 0x01, 0x12, 0x44, 0xe4}, + "WIF", + 6}, + {{0x09, 0x1e, 0x73, 0xd1, 0x7a, 0x55, 0x26, 0xd4, 0x48, 0xe5, 0x89, + 0xae, 0xa5, 0xaf, 0xe7, 0xc2, 0x2c, 0xd6, 0x1c, 0x5b, 0x66, 0xa8, + 0x6a, 0x42, 0x7a, 0xb2, 0x62, 0x30, 0x95, 0x14, 0xe5, 0x5c}, + "CBBTC", + 8}, + {{0x37, 0x99, 0x8c, 0xcb, 0xf2, 0xd0, 0x45, 0x8b, 0x61, 0x5c, 0xbc, + 0xc6, 0xb1, 0xa3, 0x67, 0xc4, 0x74, 0x9e, 0x9f, 0xef, 0x73, 0x06, + 0x62, 0x2e, 0x1b, 0x1b, 0x58, 0x91, 0x01, 0x20, 0xbc, 0x9a}, + "RAY", + 6}, + {{0x02, 0xa8, 0x8b, 0x06, 0xfa, 0xb4, 0x0a, 0x8c, 0xd2, 0x93, 0xf0, + 0xc5, 0x27, 0x58, 0x7e, 0x62, 0xd2, 0xff, 0xab, 0x76, 0x6f, 0xca, + 0x08, 0xb7, 0xf6, 0xf3, 0xc9, 0x19, 0xee, 0x73, 0x1b, 0x12}, + "BNSOL", + 9}, + {{0xf5, 0xed, 0xec, 0x84, 0x71, 0xc7, 0x56, 0x24, 0xeb, 0xc4, 0x07, + 0x9a, 0x63, 0x43, 0x26, 0xd9, 0x6a, 0x68, 0x9e, 0x61, 0x57, 0xd7, + 0x9a, 0xbe, 0x8f, 0x5a, 0x6f, 0x94, 0x47, 0x28, 0x53, 0xbc}, + "PYTH", + 6}, + {{0x79, 0x78, 0xb7, 0x14, 0x45, 0x3c, 0xd3, 0xe8, 0x7a, 0xeb, 0x1f, + 0xc0, 0x9b, 0xf0, 0x67, 0xf9, 0x6c, 0xd2, 0xd4, 0xd6, 0x9b, 0x57, + 0x13, 0x95, 0xaa, 0x9b, 0xf1, 0x86, 0xaf, 0xf9, 0xda, 0x3f}, + "FARTCOIN", + 6}, + {{0x04, 0x79, 0xd9, 0xc7, 0xcc, 0x10, 0x35, 0xde, 0x72, 0x11, 0xf9, + 0x9e, 0xb4, 0x8c, 0x09, 0xd7, 0x0b, 0x2b, 0xdf, 0x5b, 0xdf, 0x9e, + 0x2e, 0x56, 0xb8, 0xa1, 0xfb, 0xb5, 0xa2, 0xea, 0x33, 0x27}, + "JUP", + 6}, + {{0xfd, 0x31, 0xf4, 0x30, 0x0c, 0xa5, 0xb0, 0x0a, 0x3e, 0x82, 0x47, + 0xb6, 0xaa, 0xd5, 0x4d, 0x9f, 0x7b, 0xd6, 0x1b, 0x26, 0x7f, 0x60, + 0x89, 0x98, 0xcc, 0x5f, 0xe9, 0xf2, 0xd9, 0x7c, 0x3d, 0x45}, + "SPX", + 8}, + {{0x0a, 0x73, 0x20, 0x93, 0x91, 0x85, 0x61, 0xf7, 0xdd, 0x7f, 0xcb, + 0xec, 0x4a, 0xbd, 0x85, 0x13, 0xde, 0xca, 0x1a, 0x96, 0x7f, 0x7a, + 0xd7, 0xa3, 0x9d, 0x63, 0xb4, 0x1e, 0xd8, 0x93, 0x80, 0x8b}, + "HNT", + 8}, + {{0x0b, 0x62, 0xba, 0x07, 0x4f, 0x72, 0x2c, 0x9d, 0x41, 0x14, 0xf2, + 0xd8, 0xf7, 0x0a, 0x00, 0xc6, 0x60, 0x02, 0x33, 0x7b, 0x9b, 0xf9, + 0x0c, 0x87, 0x36, 0x57, 0xa6, 0xd2, 0x01, 0xdb, 0x4c, 0x80}, + "MSOL", + 9}, + {{0x69, 0x27, 0xfd, 0xc0, 0x1e, 0xa9, 0x06, 0xf9, 0x6d, 0x71, 0x37, + 0x87, 0x4c, 0xdd, 0x7a, 0xda, 0xd0, 0x0c, 0xa3, 0x57, 0x64, 0x61, + 0x93, 0x10, 0xe5, 0x41, 0x96, 0xc7, 0x81, 0xd8, 0x4d, 0x5b}, + "W", + 6}, + {{0x0a, 0xfc, 0xf8, 0x96, 0x8b, 0x8d, 0xab, 0x88, 0x48, 0x1e, 0x2d, + 0x2a, 0xe6, 0x89, 0xc9, 0x52, 0xc7, 0x57, 0xae, 0xba, 0x64, 0x3e, + 0x39, 0x19, 0xe8, 0x9f, 0x2e, 0x55, 0x79, 0x5c, 0x76, 0xc1}, + "JTO", + 9}, + {{0x5d, 0x0b, 0x15, 0x9a, 0xff, 0xcb, 0xcc, 0xf1, 0x65, 0xc0, 0x9b, + 0xc2, 0xf5, 0xd4, 0xba, 0xfb, 0x4a, 0xa6, 0x34, 0x5a, 0xf7, 0x93, + 0xb9, 0xb3, 0x22, 0x2d, 0xaa, 0x40, 0x29, 0x3a, 0x95, 0x0d}, + "POPCAT", + 9}, + {{0x4a, 0xe3, 0xd3, 0x20, 0x82, 0x05, 0x44, 0xff, 0xfa, 0x2e, 0x6d, + 0xae, 0x60, 0xf8, 0xed, 0x2b, 0xc3, 0x42, 0x6d, 0x8d, 0xe3, 0xd7, + 0xf7, 0x7d, 0xdf, 0x35, 0x0c, 0x18, 0xfd, 0x6b, 0x31, 0x94}, + "GIGA", + 5}, + {{0x0a, 0xfe, 0x1d, 0x91, 0x67, 0x14, 0x22, 0xc7, 0x65, 0xc7, 0xa0, + 0x6a, 0x11, 0x39, 0xff, 0x61, 0x39, 0xd3, 0x80, 0xfc, 0xb4, 0x22, + 0xba, 0x78, 0xf7, 0x78, 0xbe, 0xd5, 0x3c, 0x69, 0x7d, 0x81}, + "JUPSOL", + 9}, + {{0xeb, 0x93, 0x11, 0x7f, 0x10, 0xdd, 0x2e, 0x3f, 0xf9, 0x6c, 0x12, + 0xc1, 0x12, 0x67, 0xf8, 0x65, 0x4e, 0xb1, 0x05, 0x0d, 0x05, 0xa5, + 0x5e, 0xaa, 0x08, 0xab, 0x80, 0xa7, 0x7c, 0x40, 0x9d, 0x1e}, + "GRASS", + 9}, + {{0x1b, 0x36, 0x97, 0x4c, 0xca, 0xbe, 0x2b, 0xdb, 0x37, 0xc7, 0xad, + 0xa3, 0xc3, 0x33, 0x45, 0x12, 0x6f, 0x97, 0x3d, 0xa0, 0xb5, 0x43, + 0x00, 0xc1, 0xae, 0x06, 0xb8, 0x80, 0xc2, 0x4a, 0xac, 0xff}, + "PNUT", + 6}, + {{0x0d, 0x5c, 0x23, 0xce, 0x2e, 0x07, 0xbb, 0x83, 0x7d, 0xb3, 0xf8, + 0xa1, 0x7a, 0x19, 0x00, 0x62, 0x49, 0xad, 0x8d, 0x11, 0xb9, 0xb5, + 0x16, 0x63, 0xf5, 0xf2, 0x0c, 0x32, 0x5c, 0xfa, 0x75, 0x63}, + "ORDI", + 9}, + {{0x05, 0x2e, 0xe1, 0x83, 0x38, 0x96, 0x96, 0x9f, 0x8c, 0xd1, 0xcd, + 0x46, 0x83, 0x18, 0xc5, 0x98, 0xc7, 0xe0, 0x58, 0x96, 0x07, 0x4a, + 0x59, 0x1c, 0x2a, 0xe0, 0x98, 0x60, 0x2f, 0x16, 0x80, 0x00}, + "MEW", + 5}, + {{0x62, 0x7d, 0xeb, 0x80, 0xf8, 0xba, 0x2a, 0xc3, 0x95, 0x45, 0x4c, + 0xc6, 0x50, 0xb4, 0xbe, 0x50, 0xd9, 0xdf, 0x61, 0x0a, 0xf3, 0x91, + 0x5b, 0xee, 0x42, 0xbe, 0x79, 0x3d, 0x93, 0xa1, 0xef, 0x9b}, + "BABYDOGE", + 1}, + {{0xb2, 0x20, 0xa6, 0x99, 0x04, 0xb6, 0xee, 0xd8, 0x8a, 0x0b, 0xe9, + 0x89, 0x14, 0x29, 0x80, 0xfc, 0xd1, 0xa8, 0x1e, 0x85, 0x47, 0x33, + 0x32, 0x83, 0x26, 0x31, 0xcb, 0xb6, 0x2e, 0x11, 0x62, 0x8f}, + "GOAT", + 6}, + {{0x76, 0x1d, 0xd6, 0x86, 0x55, 0x8c, 0xa0, 0x1d, 0xf7, 0x5a, 0x12, + 0x0d, 0x2a, 0x50, 0xdd, 0x8f, 0xf7, 0xb2, 0xde, 0xe5, 0x0d, 0xf5, + 0xf2, 0x0d, 0xec, 0x8d, 0x49, 0x23, 0x19, 0xb5, 0xdf, 0x83}, + "ZEREBRO", + 6}, + {{0x53, 0x97, 0xed, 0x2f, 0x2a, 0x5d, 0x3f, 0x90, 0x26, 0xb5, 0x63, + 0x60, 0x02, 0x91, 0x9b, 0x46, 0x61, 0x96, 0x80, 0x24, 0x7b, 0xc7, + 0x2f, 0x07, 0xc5, 0xaf, 0x48, 0x91, 0x0d, 0x42, 0x7d, 0xb1}, + "CHEX", + 8}, + {{0x00, 0x04, 0x82, 0xbe, 0xb7, 0xa2, 0xd9, 0x90, 0x95, 0x2e, 0x43, + 0xfa, 0x1b, 0xf6, 0x4f, 0xd3, 0x34, 0x6e, 0x72, 0xe1, 0xf1, 0x63, + 0xff, 0x39, 0xf2, 0x21, 0x94, 0xbc, 0x50, 0xdb, 0x17, 0xc2}, + "AIXBT", + 8}, + {{0x17, 0x92, 0x48, 0x3b, 0x6c, 0x8a, 0x2a, 0x87, 0xb7, 0x47, 0x1d, + 0x81, 0x4f, 0x95, 0x91, 0xf9, 0x39, 0x5c, 0x84, 0x0a, 0x9c, 0xe3, + 0xd9, 0xf4, 0xd5, 0xba, 0x7d, 0x3a, 0x4b, 0x8a, 0x74, 0x9e}, + "PYUSD", + 6}, + {{0x0d, 0x83, 0x23, 0xc0, 0x76, 0xf0, 0xe2, 0x87, 0x18, 0xca, 0x60, + 0xd7, 0x7e, 0x6b, 0x39, 0xce, 0xe8, 0xf2, 0x3f, 0x43, 0xcf, 0xc4, + 0xff, 0x1f, 0x58, 0x52, 0xb8, 0xfc, 0x1b, 0x94, 0xa2, 0x93}, + "BOME", + 6}, + {{0x9c, 0xdd, 0x9b, 0x46, 0x6a, 0xf3, 0x24, 0xc5, 0x8b, 0x65, 0x3f, + 0x6e, 0xac, 0x5e, 0x78, 0xf7, 0x48, 0xe5, 0x57, 0x78, 0xca, 0xed, + 0x00, 0xa9, 0x0d, 0x61, 0xe7, 0x0c, 0x06, 0x15, 0x87, 0xf8}, + "IO", + 8}, + {{0xc0, 0xee, 0xd3, 0xea, 0x17, 0xc3, 0xb0, 0x0d, 0xcf, 0xbb, 0xbe, + 0x8e, 0xe1, 0x64, 0xfe, 0x76, 0xbe, 0x81, 0x30, 0x3a, 0xf0, 0x93, + 0x42, 0xff, 0x1f, 0xd0, 0xd7, 0x05, 0x9a, 0x36, 0x45, 0xdc}, + "WOO", + 9}, + {{0x4d, 0x75, 0xa4, 0xbf, 0xf3, 0x35, 0x44, 0x72, 0x67, 0x1a, 0x94, + 0xf5, 0x78, 0x50, 0x4a, 0xbf, 0x20, 0x8f, 0xf7, 0xd1, 0xb4, 0x38, + 0xe9, 0xe8, 0x6b, 0x4a, 0x66, 0x0f, 0x5a, 0x42, 0xd5, 0x9d}, + "TBTC", + 8}, + {{0x85, 0xcd, 0xeb, 0xc2, 0x05, 0xdd, 0xdf, 0x95, 0xb8, 0x82, 0x00, + 0xab, 0xa0, 0xac, 0x9b, 0xcb, 0xb7, 0x80, 0x96, 0x32, 0x4e, 0x27, + 0x6f, 0xce, 0x85, 0xd6, 0x3c, 0x69, 0x21, 0x1f, 0x08, 0x45}, + "USDY", + 6}, + {{0x05, 0x2e, 0x98, 0x6a, 0x95, 0x5e, 0x14, 0x29, 0x68, 0xf2, 0x26, + 0xb6, 0xa1, 0x73, 0x45, 0xce, 0xa6, 0x0b, 0xfa, 0x3c, 0x8c, 0xd4, + 0x26, 0x0a, 0xfe, 0xdb, 0xcb, 0x2f, 0xba, 0x37, 0x14, 0x28}, + "ME", + 6}, + {{0x04, 0xab, 0x91, 0xa7, 0xa9, 0x18, 0xf5, 0x78, 0xd8, 0x5e, 0x51, + 0xd0, 0x1b, 0xc9, 0xe4, 0xc2, 0x80, 0x15, 0x3e, 0x5f, 0x5c, 0x77, + 0xed, 0xf8, 0xe4, 0xb5, 0xeb, 0xb3, 0xd1, 0x0c, 0x10, 0xa4}, + "GRIFFAIN", + 6}, + {{0x63, 0xab, 0xd0, 0x96, 0x70, 0x76, 0xf5, 0x8b, 0xa2, 0xed, 0xad, + 0xb4, 0x1f, 0x10, 0x71, 0x9d, 0xf1, 0x35, 0x4a, 0xbe, 0x11, 0x8f, + 0x29, 0xa8, 0xf3, 0x0e, 0xe6, 0x63, 0x94, 0x74, 0xb9, 0x47}, + "GMT", + 9}, + {{0xc6, 0xf5, 0x13, 0x34, 0x4c, 0x63, 0x0c, 0x06, 0x0e, 0x48, 0x78, + 0xe8, 0x96, 0x98, 0xa9, 0x75, 0x73, 0x41, 0xe6, 0x8e, 0x0f, 0x18, + 0xf0, 0xb3, 0x0a, 0x3d, 0xbc, 0x59, 0x59, 0x2a, 0xd3, 0x77}, + "BAT", + 8}, + {{0xbf, 0x08, 0x5a, 0x1b, 0xb5, 0x37, 0x67, 0x52, 0x00, 0xb8, 0x56, + 0xba, 0xa5, 0x6a, 0x97, 0xf0, 0x2a, 0x4f, 0x48, 0x48, 0x4f, 0x1d, + 0x57, 0x69, 0xf6, 0xdf, 0x44, 0xa0, 0xb1, 0xbf, 0xd6, 0x84}, + "DRIFT", + 6}, + {{0x27, 0x0a, 0xd0, 0x02, 0x8e, 0x97, 0x0d, 0xf7, 0x57, 0xd5, 0xf1, + 0x4f, 0x8c, 0xbb, 0x6a, 0x68, 0x10, 0xe4, 0x81, 0x39, 0x12, 0x56, + 0x08, 0xea, 0x95, 0x8b, 0x71, 0x8e, 0xb2, 0x94, 0x49, 0x20}, + "BORG", + 9}, + {{0xad, 0xd0, 0x93, 0xff, 0xa5, 0x4b, 0x9f, 0x21, 0xd5, 0xd6, 0x61, + 0xc9, 0x7c, 0x0f, 0xa0, 0x29, 0x1a, 0xc4, 0x30, 0x38, 0x4e, 0xae, + 0x77, 0x52, 0xcc, 0xf3, 0x37, 0x6b, 0x68, 0x71, 0xec, 0x88}, + "SUSHI", + 8}, + {{0x4a, 0x6a, 0x3f, 0xa9, 0x01, 0x17, 0x16, 0xb8, 0x1e, 0xbe, 0x2e, + 0x6f, 0xb5, 0xa8, 0x14, 0x72, 0xd5, 0xe3, 0x81, 0x08, 0x6d, 0x7e, + 0xf4, 0x75, 0x4e, 0xb4, 0x11, 0x11, 0x55, 0xdb, 0x4e, 0xef}, + "ARC", + 6}, + {{0x4f, 0x4a, 0x87, 0xfa, 0xdc, 0x7f, 0xf3, 0x77, 0x32, 0x91, 0xf9, + 0x9b, 0xcb, 0x3c, 0x8b, 0x6a, 0xf1, 0x58, 0x9f, 0x7a, 0x53, 0xd4, + 0x5d, 0xf1, 0xab, 0xa5, 0x2c, 0xab, 0x29, 0x6a, 0x83, 0x81}, + "FXS", + 8}, + {{0x0b, 0xbc, 0x22, 0x37, 0xbe, 0x47, 0x53, 0x50, 0xaf, 0xd9, 0x8b, + 0xec, 0x57, 0x96, 0x8d, 0xa2, 0xd8, 0xae, 0x7f, 0x47, 0x73, 0xf9, + 0x7f, 0x67, 0x4c, 0x94, 0xa7, 0x2e, 0x02, 0xa5, 0xf5, 0xea}, + "NOS", + 6}, + {{0xe3, 0x44, 0xa5, 0x2e, 0x00, 0x19, 0x39, 0x9b, 0xef, 0x02, 0xf7, + 0x62, 0xe1, 0xed, 0x8c, 0xc0, 0x5f, 0x8c, 0xfd, 0xa7, 0xbd, 0xa5, + 0x57, 0x96, 0xb9, 0xb9, 0x84, 0x1a, 0xaf, 0xe0, 0x06, 0x3f}, + "ACT", + 6}, + {{0x87, 0x90, 0xbe, 0x57, 0x84, 0x2c, 0x24, 0x8c, 0x85, 0x74, 0xd9, + 0x7a, 0x70, 0x39, 0x77, 0x88, 0x32, 0x41, 0x7e, 0xdc, 0xaf, 0xc4, + 0x6e, 0x6d, 0x2b, 0x04, 0x00, 0x83, 0xfd, 0x2e, 0x87, 0x0f}, + "FWOG", + 6}, + {{0x5a, 0x07, 0x56, 0x01, 0x65, 0x14, 0xa1, 0x2c, 0xcb, 0xeb, 0xe5, + 0x41, 0x31, 0x97, 0x7d, 0xf8, 0x8d, 0x24, 0x8d, 0xca, 0x67, 0x28, + 0x34, 0x1f, 0x06, 0x3d, 0x60, 0xb9, 0xd0, 0x36, 0x8a, 0xdf}, + "SWARMS", + 6}, + {{0x0c, 0xec, 0x34, 0x6f, 0xbc, 0x79, 0x23, 0xc8, 0xcb, 0xe3, 0xc9, + 0xfb, 0x4c, 0xfb, 0xe1, 0x2d, 0x84, 0x9a, 0x53, 0x44, 0xc6, 0x72, + 0x10, 0x1d, 0x3f, 0x82, 0xa3, 0xc3, 0x61, 0xcc, 0xef, 0x62}, + "SSOL", + 9}, + {{0xc4, 0x40, 0x51, 0xa9, 0x11, 0xb5, 0x4c, 0x7e, 0xcf, 0xfc, 0x7e, + 0xe0, 0xb0, 0xa4, 0x0a, 0xf4, 0x8b, 0x32, 0x8a, 0xe7, 0x55, 0xa9, + 0x95, 0x33, 0xc8, 0x40, 0x2c, 0xb2, 0x6d, 0xf4, 0x38, 0x07}, + "MOODENG", + 6}, + {{0x3a, 0x3e, 0x72, 0xb6, 0x7e, 0xa9, 0x4e, 0x17, 0x65, 0x00, 0x4e, + 0xf6, 0x82, 0x44, 0xf6, 0xb0, 0xb3, 0x2d, 0xdd, 0xe7, 0x43, 0xa3, + 0x3b, 0x20, 0xf9, 0x14, 0x30, 0xe1, 0xe8, 0x17, 0xc1, 0xac}, + "HONEY", + 9}, + {{0xc8, 0xeb, 0xa0, 0xc4, 0xf4, 0x01, 0x7e, 0x4d, 0x78, 0x46, 0xea, + 0x56, 0x95, 0xb0, 0xc8, 0x26, 0x27, 0xe5, 0xc1, 0x3a, 0x66, 0xfe, + 0x7f, 0x39, 0xfd, 0x84, 0x5f, 0xdd, 0x50, 0x5b, 0xc3, 0x59}, + "PEPECOIN", + 8}, }; /***************************************************************************** diff --git a/apps/solana_app/solana_contracts.h b/apps/solana_app/solana_contracts.h index 8e71e071b..64df51f74 100644 --- a/apps/solana_app/solana_contracts.h +++ b/apps/solana_app/solana_contracts.h @@ -19,7 +19,7 @@ *****************************************************************************/ // Number of entries in whitelisted contracts list -#define SOLANA_WHITELISTED_TOKEN_PROGRAM_COUNT 1 +#define SOLANA_WHITELISTED_TOKEN_PROGRAM_COUNT 55 /***************************************************************************** * TYPEDEFS diff --git a/src/constant_texts.c b/src/constant_texts.c index 494496324..51cf91605 100644 --- a/src/constant_texts.c +++ b/src/constant_texts.c @@ -554,7 +554,7 @@ const char *ui_text_inheritance_decryption_flow_success = "Decryption Success"; const char *ui_text_inheritance_decryption_flow_failure = "Decryption Failed"; // Solana Specific -const char *ui_text_solana_verify_mint_authority = "Verify Mint Authority"; +const char *ui_text_solana_verify_mint_authority = "Verify Token Address"; #ifdef ALLOW_LOG_EXPORT const char *ui_text_send_logs_prompt = "Send logs to the cySync app?"; From 65e83237329f008005a650d0710d7b3a3fcaffc6 Mon Sep 17 00:00:00 2001 From: Vaibhav Sethia Date: Fri, 10 Jan 2025 03:13:58 +0530 Subject: [PATCH 06/19] feat(app): Solana add 2 instructions support --- apps/solana_app/solana_sign_txn.c | 24 +++-- apps/solana_app/solana_txn_helpers.c | 155 ++++++++++++++++----------- apps/solana_app/solana_txn_helpers.h | 3 +- 3 files changed, 111 insertions(+), 71 deletions(-) diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index 9be3bd0c9..3af2593ac 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -372,11 +372,14 @@ static bool solana_transfer_sol_transaction() { char address[45] = {0}; size_t address_size = sizeof(address); + const uint8_t transfer_instruction_index = + solana_txn_context->transaction_info.transfer_instruction_index; // verify recipient address; if (!b58enc(address, &address_size, - solana_txn_context->transaction_info.instruction.program.transfer - .recipient_account, + solana_txn_context->transaction_info + .instruction[transfer_instruction_index] + .program.transfer.recipient_account, SOLANA_ACCOUNT_ADDRESS_LENGTH)) { solana_send_error(ERROR_COMMON_ERROR_UNKNOWN_ERROR_TAG, 2); return false; @@ -393,8 +396,9 @@ static bool solana_transfer_sol_transaction() { uint8_t be_lamports[8] = {0}; int i = 8; while (i--) - be_lamports[i] = solana_txn_context->transaction_info.instruction.program - .transfer.amount >> + be_lamports[i] = solana_txn_context->transaction_info + .instruction[transfer_instruction_index] + .program.transfer.amount >> 8 * (7 - i); byte_array_to_hex_string( @@ -594,9 +598,12 @@ static bool solana_transfer_token_transaction() { return false; } + const uint8_t transfer_instruction_index = + solana_txn_context->transaction_info.transfer_instruction_index; if (memcmp(associated_token_address, - solana_txn_context->transaction_info.instruction.program.transfer - .recipient_account, + solana_txn_context->transaction_info + .instruction[transfer_instruction_index] + .program.transfer.recipient_account, SOLANA_ACCOUNT_ADDRESS_LENGTH) != 0) { solana_send_error(ERROR_COMMON_ERROR_CORRUPT_DATA_TAG, 2); return false; @@ -609,8 +616,9 @@ static bool solana_transfer_token_transaction() { uint8_t be_units[8] = {0}; int i = 8; while (i--) - be_units[i] = solana_txn_context->transaction_info.instruction.program - .transfer.amount >> + be_units[i] = solana_txn_context->transaction_info + .instruction[transfer_instruction_index] + .program.transfer.amount >> 8 * (7 - i); byte_array_to_hex_string(be_units, 8, amount_string, sizeof(amount_string)); diff --git a/apps/solana_app/solana_txn_helpers.c b/apps/solana_app/solana_txn_helpers.c index e0e4b3ab8..88026a5fe 100644 --- a/apps/solana_app/solana_txn_helpers.c +++ b/apps/solana_app/solana_txn_helpers.c @@ -66,6 +66,8 @@ #include #include +#include "ui_core_confirm.h" + /***************************************************************************** * EXTERN VARIABLES *****************************************************************************/ @@ -158,29 +160,33 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, if (utxn->instructions_count == 0) return SOL_D_MIN_LENGTH; - utxn->instruction.program_id_index = *(byte_array + offset++); - - offset += - get_compact_array_size(byte_array + offset, - &(utxn->instruction.account_addresses_index_count), - &error); - if (error != SOL_OK) - return error; - if (utxn->instruction.account_addresses_index_count == 0) - return SOL_D_MIN_LENGTH; - - utxn->instruction.account_addresses_index = byte_array + offset; - offset += utxn->instruction.account_addresses_index_count; - offset += get_compact_array_size( - byte_array + offset, &(utxn->instruction.opaque_data_length), &error); - if (error != SOL_OK) - return error; - if (utxn->instruction.opaque_data_length == 0) - return SOL_D_MIN_LENGTH; - - utxn->instruction.opaque_data = byte_array + offset; - offset += utxn->instruction.opaque_data_length; - + utxn->transfer_instruction_index = ((utxn->instructions_count == 2) ? 1 : 0); + + for (int i = 0; i < utxn->instructions_count; i++) { + utxn->instruction[i].program_id_index = *(byte_array + offset++); + + offset += get_compact_array_size( + byte_array + offset, + &(utxn->instruction[i].account_addresses_index_count), + &error); + if (error != SOL_OK) + return error; + if (utxn->instruction[i].account_addresses_index_count == 0) + return SOL_D_MIN_LENGTH; + + utxn->instruction[i].account_addresses_index = byte_array + offset; + offset += utxn->instruction[i].account_addresses_index_count; + offset += get_compact_array_size(byte_array + offset, + &(utxn->instruction[i].opaque_data_length), + &error); + if (error != SOL_OK) + return error; + // if (utxn->instruction[i].opaque_data_length == 0) + // return SOL_D_MIN_LENGTH; + + utxn->instruction[i].opaque_data = byte_array + offset; + offset += utxn->instruction[i].opaque_data_length; + } // prepare list of supported program ids uint8_t system_program_id[SOLANA_PROGRAM_ID_COUNT] [SOLANA_ACCOUNT_ADDRESS_LENGTH]; @@ -192,49 +198,68 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX]); - if (memcmp(utxn->account_addresses + utxn->instruction.program_id_index * - SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], - SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { - uint32_t instruction_enum = - U32_READ_LE_ARRAY(utxn->instruction.opaque_data); + const uint8_t transfer_instruction_index = utxn->transfer_instruction_index; + if (memcmp( + utxn->account_addresses + + utxn->instruction[transfer_instruction_index].program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + uint32_t instruction_enum = U32_READ_LE_ARRAY( + utxn->instruction[transfer_instruction_index].opaque_data); switch (instruction_enum) { case SSI_TRANSFER: // transfer instruction - utxn->instruction.program.transfer.funding_account = + utxn->instruction[transfer_instruction_index] + .program.transfer.funding_account = utxn->account_addresses + - (*(utxn->instruction.account_addresses_index + 0) * + (*(utxn->instruction[transfer_instruction_index] + .account_addresses_index + + 0) * SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction.program.transfer.recipient_account = + utxn->instruction[transfer_instruction_index] + .program.transfer.recipient_account = utxn->account_addresses + - (*(utxn->instruction.account_addresses_index + 1) * + (*(utxn->instruction[transfer_instruction_index] + .account_addresses_index + + 1) * SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction.program.transfer.amount = - U64_READ_LE_ARRAY(utxn->instruction.opaque_data + 4); + utxn->instruction[transfer_instruction_index].program.transfer.amount = + U64_READ_LE_ARRAY( + utxn->instruction[transfer_instruction_index].opaque_data + 4); break; default: break; } - } else if (memcmp( - utxn->account_addresses + utxn->instruction.program_id_index * - SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX], - SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { - uint8_t instruction_enum = *(utxn->instruction.opaque_data); + } else if (memcmp(utxn->account_addresses + + utxn->instruction[transfer_instruction_index] + .program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + uint8_t instruction_enum = + *(utxn->instruction[transfer_instruction_index].opaque_data); switch (instruction_enum) { case STPI_TRANSFER: // transfer instruction - utxn->instruction.program.transfer.funding_account = + utxn->instruction[transfer_instruction_index] + .program.transfer.funding_account = utxn->account_addresses + - (*(utxn->instruction.account_addresses_index + 0) * + (*(utxn->instruction[transfer_instruction_index] + .account_addresses_index + + 0) * SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction.program.transfer.recipient_account = + utxn->instruction[transfer_instruction_index] + .program.transfer.recipient_account = utxn->account_addresses + - (*(utxn->instruction.account_addresses_index + 1) * + (*(utxn->instruction[transfer_instruction_index] + .account_addresses_index + + 1) * SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction.program.transfer.amount = - U64_READ_LE_ARRAY(utxn->instruction.opaque_data + 1); + utxn->instruction[transfer_instruction_index].program.transfer.amount = + U64_READ_LE_ARRAY( + utxn->instruction[transfer_instruction_index].opaque_data + 1); break; default: @@ -248,11 +273,13 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, } int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { - if (utxn->instructions_count != 1) + if (utxn->instructions_count > 2) return SOL_V_UNSUPPORTED_INSTRUCTION_COUNT; - if (!(0 < utxn->instruction.program_id_index && - utxn->instruction.program_id_index < utxn->account_addresses_count)) + const uint8_t transfer_instruction_index = utxn->transfer_instruction_index; + if (!(0 < utxn->instruction[transfer_instruction_index].program_id_index && + utxn->instruction[transfer_instruction_index].program_id_index < + utxn->account_addresses_count)) return SOL_V_INDEX_OUT_OF_RANGE; // prepare list of supported program ids @@ -266,12 +293,14 @@ int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX]); - if (memcmp(utxn->account_addresses + utxn->instruction.program_id_index * - SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], - SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { - uint32_t instruction_enum = - U32_READ_LE_ARRAY(utxn->instruction.opaque_data); + if (memcmp( + utxn->account_addresses + + utxn->instruction[transfer_instruction_index].program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + uint32_t instruction_enum = U32_READ_LE_ARRAY( + utxn->instruction[transfer_instruction_index].opaque_data); switch (instruction_enum) { case SSI_TRANSFER: // transfer instruction @@ -280,12 +309,14 @@ int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { return SOL_V_UNSUPPORTED_INSTRUCTION; break; } - } else if (memcmp( - utxn->account_addresses + utxn->instruction.program_id_index * - SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX], - SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { - uint8_t instruction_enum = *(utxn->instruction.opaque_data); + } else if (memcmp(utxn->account_addresses + + utxn->instruction[transfer_instruction_index] + .program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + uint8_t instruction_enum = + *(utxn->instruction[transfer_instruction_index].opaque_data); switch (instruction_enum) { case STPI_TRANSFER: // transfer instruction diff --git a/apps/solana_app/solana_txn_helpers.h b/apps/solana_app/solana_txn_helpers.h index 61d40a376..09bad5a0b 100644 --- a/apps/solana_app/solana_txn_helpers.h +++ b/apps/solana_app/solana_txn_helpers.h @@ -136,7 +136,8 @@ typedef struct solana_unsigned_txn { uint16_t instructions_count; // deserialization only supports single instruction - solana_instruction instruction; + solana_instruction instruction[2]; ///< Expects max 2 instructions + uint8_t transfer_instruction_index; } solana_unsigned_txn; From 02ff4c2167d607ac0adaaa3bc30ade65ccfa23fe Mon Sep 17 00:00:00 2001 From: Muzaffar Ahmad Bhat Date: Thu, 16 Jan 2025 16:38:29 +0530 Subject: [PATCH 07/19] fix: Resolve review comments --- apps/solana_app/solana_sign_txn.c | 1 - apps/solana_app/solana_txn_helpers.c | 5 +---- apps/solana_app/solana_txn_helpers.h | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index 3af2593ac..f7a6a36f8 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -61,7 +61,6 @@ *****************************************************************************/ #include -#include #include "reconstruct_wallet_flow.h" #include "solana_api.h" diff --git a/apps/solana_app/solana_txn_helpers.c b/apps/solana_app/solana_txn_helpers.c index 88026a5fe..97be5385e 100644 --- a/apps/solana_app/solana_txn_helpers.c +++ b/apps/solana_app/solana_txn_helpers.c @@ -63,11 +63,8 @@ #include "solana_txn_helpers.h" -#include #include -#include "ui_core_confirm.h" - /***************************************************************************** * EXTERN VARIABLES *****************************************************************************/ @@ -151,7 +148,7 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, utxn->blockhash = byte_array + offset; offset += SOLANA_BLOCKHASH_LENGTH; - // Instructions: Currently expecting count to be only 1. TODO: Handle batch + // Instructions: Currently expecting count to be 1 or 2. TODO: Handle batch // instructions offset += get_compact_array_size( byte_array + offset, &(utxn->instructions_count), &error); diff --git a/apps/solana_app/solana_txn_helpers.h b/apps/solana_app/solana_txn_helpers.h index 09bad5a0b..1f7aa4912 100644 --- a/apps/solana_app/solana_txn_helpers.h +++ b/apps/solana_app/solana_txn_helpers.h @@ -135,7 +135,7 @@ typedef struct solana_unsigned_txn { uint8_t *blockhash; uint16_t - instructions_count; // deserialization only supports single instruction + instructions_count; // deserialization only supports max 2 instructions: create account and transfer solana_instruction instruction[2]; ///< Expects max 2 instructions uint8_t transfer_instruction_index; From c49bf8e87ea368c20cdc29a7894bd319977f899e Mon Sep 17 00:00:00 2001 From: Muzaffar Ahmad Bhat Date: Fri, 17 Jan 2025 12:15:08 +0530 Subject: [PATCH 08/19] fix: Corrected solana send confirmation msg --- apps/solana_app/solana_sign_txn.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index f7a6a36f8..004094dac 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -266,33 +266,23 @@ STATIC bool solana_handle_initiate_query(const solana_query_t *query) { return false; } + snprintf( + msg, sizeof(msg), UI_TEXT_SIGN_TXN_PROMPT, SOLANA_NAME, wallet_name + ); + + // Take user consent to sign the transaction for the wallet + if (!core_confirmation(msg, solana_send_error)) { + return false; + } + solana_txn_context->is_token_transfer_transaction = query->sign_txn.initiate.has_token_data; if (solana_txn_context->is_token_transfer_transaction) { - snprintf( - msg, sizeof(msg), UI_TEXT_SIGN_TXN_PROMPT, SOLANA_NAME, wallet_name); - // Take user consent to sign the transaction for the wallet - if (!core_confirmation(msg, solana_send_error)) { - return false; - } - // if it is a token transfer transaction, store the token data memcpy(&solana_txn_context->token_data, &query->sign_txn.initiate.token_data, sizeof(solana_sign_txn_initiate_token_data_t)); - - } else { - snprintf(msg, - sizeof(msg), - UI_TEXT_SEND_TOKEN_PROMPT, - SOLANA_LUNIT, - SOLANA_NAME, - wallet_name); - // Take user consent to sign the transaction for the wallet - if (!core_confirmation(msg, solana_send_error)) { - return false; - } } set_app_flow_status(SOLANA_SIGN_TXN_STATUS_CONFIRM); From b316c13f2ae7e5f16e63eccee3a39dc333bddc39 Mon Sep 17 00:00:00 2001 From: Muzaffar Ahmad Bhat Date: Sat, 18 Jan 2025 13:24:36 +0530 Subject: [PATCH 09/19] chore: Updated common submodule --- common/cypherock-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/cypherock-common b/common/cypherock-common index 2d635d251..781eb49dc 160000 --- a/common/cypherock-common +++ b/common/cypherock-common @@ -1 +1 @@ -Subproject commit 2d635d251d71aec29a5f8681cdc987f9cee88c04 +Subproject commit 781eb49dc37185ca542d3ac790f1efdf7a1bd2c3 From 6c8f9b339d5c6d72ca31c5aa040b5ed1ec67e4c2 Mon Sep 17 00:00:00 2001 From: Muzaffar Ahmad Bhat Date: Sat, 18 Jan 2025 19:48:51 +0530 Subject: [PATCH 10/19] feat: Added solana token transferchecked instruction type support --- apps/solana_app/solana_sign_txn.c | 71 +++++++++++++------- apps/solana_app/solana_txn_helpers.c | 50 +++++++++----- apps/solana_app/solana_txn_helpers.h | 14 +++- common/proto-options/solana/sign_txn.options | 1 - src/constant_texts.c | 4 ++ src/constant_texts.h | 6 +- 6 files changed, 100 insertions(+), 46 deletions(-) diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index 004094dac..8c3afbcfa 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -357,7 +357,7 @@ STATIC bool solana_fetch_valid_transaction(solana_query_t *query) { return true; } -static bool solana_transfer_sol_transaction() { +static bool verify_solana_transfer_sol_transaction() { char address[45] = {0}; size_t address_size = sizeof(address); @@ -387,7 +387,7 @@ static bool solana_transfer_sol_transaction() { while (i--) be_lamports[i] = solana_txn_context->transaction_info .instruction[transfer_instruction_index] - .program.transfer.amount >> + .program.transfer.lamports >> 8 * (7 - i); byte_array_to_hex_string( @@ -535,35 +535,60 @@ static bool is_token_whitelisted(const uint8_t *address, return status; } -static bool solana_transfer_token_transaction() { - char address[45] = {0}; - size_t address_size = sizeof(address); +static bool verify_solana_transfer_token_transaction() { + const uint8_t transfer_instruction_index = + solana_txn_context->transaction_info.transfer_instruction_index; - const solana_token_program_t *contract; - if (!is_token_whitelisted(solana_txn_context->token_data.mint_address, - &contract)) { + const uint8_t* token_mint = solana_txn_context->transaction_info + .instruction[transfer_instruction_index] + .program.transferChecked.token_mint; + const solana_token_program_t *contract = NULL; + if (!is_token_whitelisted(token_mint, &contract)) { // Contract Unverifed, Display warning - delay_scr_init(ui_text_unverified_contract, DELAY_TIME); + delay_scr_init(ui_text_unverified_token, DELAY_TIME); char mint_address[45] = {0}; size_t mint_address_size = sizeof(mint_address); // verify mint address if (!b58enc(mint_address, &mint_address_size, - solana_txn_context->token_data.mint_address, + token_mint, SOLANA_ACCOUNT_ADDRESS_LENGTH)) { solana_send_error(ERROR_COMMON_ERROR_UNKNOWN_ERROR_TAG, 2); return false; } - if (!core_scroll_page(ui_text_solana_verify_mint_authority, + if (!core_scroll_page(ui_text_verify_token_address, mint_address, solana_send_error)) { return false; } + + const uint8_t token_decimals = solana_txn_context->transaction_info + .instruction[transfer_instruction_index] + .program.transferChecked.decimals; + + char display[50] = {'\0'}; + snprintf(display, + sizeof(display), + ui_text_verify_token_decimals, + token_decimals); + + if (!core_confirmation(display, solana_send_error)) { + return false; + } + + solana_token_program_t empty_contract = { + .symbol = "", + .decimal = token_decimals, + }; + + contract = &empty_contract; } // verify recipient address; + char address[45] = {0}; + size_t address_size = sizeof(address); if (!b58enc(address, &address_size, solana_txn_context->token_data.recipient_address, @@ -572,32 +597,30 @@ static bool solana_transfer_token_transaction() { return false; } - if (!core_scroll_page(ui_text_verify_address, address, solana_send_error)) { - return false; - } - - // Upon recipient address confirmwation, calculate associated token address - // and compare with utxn's value + // Calculate associated token address and compare with utxn's value uint8_t associated_token_address[SOLANA_ACCOUNT_ADDRESS_LENGTH] = {0}; if (!get_associated_token_address( - solana_txn_context->token_data.mint_address, + token_mint, solana_txn_context->token_data.recipient_address, associated_token_address)) { solana_send_error(ERROR_COMMON_ERROR_UNKNOWN_ERROR_TAG, 2); return false; } - const uint8_t transfer_instruction_index = - solana_txn_context->transaction_info.transfer_instruction_index; if (memcmp(associated_token_address, solana_txn_context->transaction_info .instruction[transfer_instruction_index] - .program.transfer.recipient_account, + .program.transferChecked.destination, SOLANA_ACCOUNT_ADDRESS_LENGTH) != 0) { solana_send_error(ERROR_COMMON_ERROR_CORRUPT_DATA_TAG, 2); return false; } + // Now take user verification + if (!core_scroll_page(ui_text_verify_address, address, solana_send_error)) { + return false; + } + // verify recipient amount char amount_string[40] = {'\0'}, amount_decimal_string[30] = {'\0'}; char display[100] = ""; @@ -607,7 +630,7 @@ static bool solana_transfer_token_transaction() { while (i--) be_units[i] = solana_txn_context->transaction_info .instruction[transfer_instruction_index] - .program.transfer.amount >> + .program.transferChecked.amount >> 8 * (7 - i); byte_array_to_hex_string(be_units, 8, amount_string, sizeof(amount_string)); @@ -635,9 +658,9 @@ static bool solana_transfer_token_transaction() { STATIC bool solana_get_user_verification() { if (solana_txn_context->is_token_transfer_transaction == true) { - return solana_transfer_token_transaction(); + return verify_solana_transfer_token_transaction(); } else - return solana_transfer_sol_transaction(); + return verify_solana_transfer_sol_transaction(); } STATIC bool fetch_seed(solana_query_t *query, uint8_t *seed_out) { diff --git a/apps/solana_app/solana_txn_helpers.c b/apps/solana_app/solana_txn_helpers.c index 97be5385e..8016c8906 100644 --- a/apps/solana_app/solana_txn_helpers.c +++ b/apps/solana_app/solana_txn_helpers.c @@ -178,8 +178,8 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, &error); if (error != SOL_OK) return error; - // if (utxn->instruction[i].opaque_data_length == 0) - // return SOL_D_MIN_LENGTH; + if (i == utxn->transfer_instruction_index && utxn->instruction[i].opaque_data_length == 0) + return SOL_D_MIN_LENGTH; utxn->instruction[i].opaque_data = byte_array + offset; offset += utxn->instruction[i].opaque_data_length; @@ -221,7 +221,7 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, .account_addresses_index + 1) * SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction[transfer_instruction_index].program.transfer.amount = + utxn->instruction[transfer_instruction_index].program.transfer.lamports = U64_READ_LE_ARRAY( utxn->instruction[transfer_instruction_index].opaque_data + 4); break; @@ -239,25 +239,41 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, *(utxn->instruction[transfer_instruction_index].opaque_data); switch (instruction_enum) { - case STPI_TRANSFER: // transfer instruction + case STPI_TRANSFER_CHECKED: // transfer checked instruction utxn->instruction[transfer_instruction_index] - .program.transfer.funding_account = - utxn->account_addresses + - (*(utxn->instruction[transfer_instruction_index] - .account_addresses_index + - 0) * - SOLANA_ACCOUNT_ADDRESS_LENGTH); + .program.transferChecked.source = + utxn->account_addresses + + (*(utxn->instruction[transfer_instruction_index] + .account_addresses_index + + 0) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); utxn->instruction[transfer_instruction_index] - .program.transfer.recipient_account = + .program.transferChecked.token_mint = + utxn->account_addresses + + (*(utxn->instruction[transfer_instruction_index] + .account_addresses_index + + 1) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); + utxn->instruction[transfer_instruction_index] + .program.transferChecked.destination = utxn->account_addresses + (*(utxn->instruction[transfer_instruction_index] - .account_addresses_index + - 1) * - SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction[transfer_instruction_index].program.transfer.amount = + .account_addresses_index + + 2) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); + utxn->instruction[transfer_instruction_index] + .program.transferChecked.owner = + utxn->account_addresses + + (*(utxn->instruction[transfer_instruction_index] + .account_addresses_index + + 3) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); + utxn->instruction[transfer_instruction_index].program.transferChecked.amount = U64_READ_LE_ARRAY( utxn->instruction[transfer_instruction_index].opaque_data + 1); - break; + utxn->instruction[transfer_instruction_index].program.transferChecked.decimals = + *(utxn->instruction[transfer_instruction_index].opaque_data + 9); + break; default: break; @@ -316,7 +332,7 @@ int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { *(utxn->instruction[transfer_instruction_index].opaque_data); switch (instruction_enum) { - case STPI_TRANSFER: // transfer instruction + case STPI_TRANSFER_CHECKED: // transfer checked instruction break; default: return SOL_V_UNSUPPORTED_INSTRUCTION; diff --git a/apps/solana_app/solana_txn_helpers.h b/apps/solana_app/solana_txn_helpers.h index 1f7aa4912..2c8835e9d 100644 --- a/apps/solana_app/solana_txn_helpers.h +++ b/apps/solana_app/solana_txn_helpers.h @@ -106,9 +106,20 @@ enum SOLANA_ERROR_CODES { typedef struct solana_transfer_data { uint8_t *funding_account; uint8_t *recipient_account; - uint64_t amount; + uint64_t lamports; } solana_transfer_data; +// Reference : +// https://docs.rs/spl-token/latest/spl_token/instruction/enum.TokenInstruction.html#variant.TransferChecked +typedef struct solana_token_transfer_checked_data { + uint8_t *source; + uint8_t *token_mint; + uint8_t *destination; + uint8_t *owner; // signer/owner of the source account + uint64_t amount; + uint8_t decimals; +} solana_token_transfer_checked_data; + // Reference : // https://docs.solana.com/developing/programming-model/transactions#instruction-format typedef struct solana_instruction { @@ -119,6 +130,7 @@ typedef struct solana_instruction { uint8_t *opaque_data; union { solana_transfer_data transfer; + solana_token_transfer_checked_data transferChecked; } program; } solana_instruction; diff --git a/common/proto-options/solana/sign_txn.options b/common/proto-options/solana/sign_txn.options index 58354892a..c6005f8b5 100644 --- a/common/proto-options/solana/sign_txn.options +++ b/common/proto-options/solana/sign_txn.options @@ -2,6 +2,5 @@ solana.SignTxnInitiateRequest.walletId type:FT_STATIC max_size:32 fixed_length:true solana.SignTxnInitiateRequest.derivationPath type:FT_STATIC max_count:4 fixed_length:true solana.SignTxnInitiateTokenData.recipient_address type:FT_STATIC max_size:32 fixed_length:true -solana.SignTxnInitiateTokenData.mint_address type:FT_STATIC max_size:32 fixed_length:true solana.SignTxnSignatureResponse.signature type:FT_STATIC max_size:64 fixed_length:true solana.SignTxnSignatureRequest.blockhash type:FT_STATIC max_size:32 fixed_length:true diff --git a/src/constant_texts.c b/src/constant_texts.c index 51cf91605..8d94a5bba 100644 --- a/src/constant_texts.c +++ b/src/constant_texts.c @@ -366,6 +366,10 @@ const char *ui_text_verify_amount = "Verify amount"; const char *ui_text_verify_contract = "Verify contract"; const char *ui_text_unverified_contract = LV_SYMBOL_WARNING " Warning!\nUnverified contract"; +const char *ui_text_verify_token_address = "Verify token address"; +const char *ui_text_verify_token_decimals = "Verify token decimals\n%d"; +const char *ui_text_unverified_token = + LV_SYMBOL_WARNING " Warning!\nUnverified token"; const char *ui_text_confirm_wallet_name = "Confirm wallet name"; const char *ui_text_enter_data = "Enter data"; const char *ui_text_confirm_data = "Confirm data"; diff --git a/src/constant_texts.h b/src/constant_texts.h index fe823bd70..44443db3e 100644 --- a/src/constant_texts.h +++ b/src/constant_texts.h @@ -258,6 +258,9 @@ extern const char *ui_text_verify_address; extern const char *ui_text_verify_amount; extern const char *ui_text_verify_contract; extern const char *ui_text_unverified_contract; +extern const char *ui_text_verify_token_address; +extern const char *ui_text_verify_token_decimals; +extern const char *ui_text_unverified_token; extern const char *ui_text_confirm_wallet_name; extern const char *ui_text_enter_data; extern const char *ui_text_confirm_data; @@ -390,9 +393,6 @@ extern const char *ui_text_inheritance_decryption_flow_confirmation_generic; extern const char *ui_text_inheritance_decryption_flow_success; extern const char *ui_text_inheritance_decryption_flow_failure; -// Solana -extern const char *ui_text_solana_verify_mint_authority; - #ifdef ALLOW_LOG_EXPORT extern const char *ui_text_send_logs_prompt; #endif From 04c91e562f0dcf3c00afcd1f1c698b5cedec34e2 Mon Sep 17 00:00:00 2001 From: Muzaffar Ahmad Bhat Date: Sat, 18 Jan 2025 20:14:39 +0530 Subject: [PATCH 11/19] fix: Added solana token txn confirmation msg --- apps/solana_app/solana_sign_txn.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index 8c3afbcfa..4a1eedda9 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -584,6 +584,12 @@ static bool verify_solana_transfer_token_transaction() { }; contract = &empty_contract; + } else { + char msg[100] = ""; + snprintf(msg, sizeof(msg), "Send \n%s on \n%s", contract->symbol, SOLANA_NAME); + if (!core_confirmation(msg, solana_send_error)) { + return false; + } } // verify recipient address; From 925017bdee3a94b1ae4dc17de4ab2f8e645f247f Mon Sep 17 00:00:00 2001 From: Muzaffar Ahmad Bhat Date: Sat, 18 Jan 2025 20:24:14 +0530 Subject: [PATCH 12/19] chore: Updated common --- common/cypherock-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/cypherock-common b/common/cypherock-common index 781eb49dc..01cbef4e5 160000 --- a/common/cypherock-common +++ b/common/cypherock-common @@ -1 +1 @@ -Subproject commit 781eb49dc37185ca542d3ac790f1efdf7a1bd2c3 +Subproject commit 01cbef4e51e06c0edea090c81aef81df5e575107 From e62862e698b0d2c631067f0d483f833327bbdba4 Mon Sep 17 00:00:00 2001 From: Muzaffar Ahmad Bhat Date: Mon, 20 Jan 2025 16:40:00 +0530 Subject: [PATCH 13/19] fix: Resolve review comments --- apps/solana_app/solana_sign_txn.c | 10 +++++----- apps/solana_app/solana_txn_helpers.c | 14 +++++++------- apps/solana_app/solana_txn_helpers.h | 2 +- src/constant_texts.h | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index 4a1eedda9..2fa4bd4c3 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -541,7 +541,7 @@ static bool verify_solana_transfer_token_transaction() { const uint8_t* token_mint = solana_txn_context->transaction_info .instruction[transfer_instruction_index] - .program.transferChecked.token_mint; + .program.transfer_checked.token_mint; const solana_token_program_t *contract = NULL; if (!is_token_whitelisted(token_mint, &contract)) { // Contract Unverifed, Display warning @@ -566,7 +566,7 @@ static bool verify_solana_transfer_token_transaction() { const uint8_t token_decimals = solana_txn_context->transaction_info .instruction[transfer_instruction_index] - .program.transferChecked.decimals; + .program.transfer_checked.decimals; char display[50] = {'\0'}; snprintf(display, @@ -586,7 +586,7 @@ static bool verify_solana_transfer_token_transaction() { contract = &empty_contract; } else { char msg[100] = ""; - snprintf(msg, sizeof(msg), "Send \n%s on \n%s", contract->symbol, SOLANA_NAME); + snprintf(msg, sizeof(msg), UI_TEXT_SEND_TOKEN_PROMPT, contract->symbol, SOLANA_NAME); if (!core_confirmation(msg, solana_send_error)) { return false; } @@ -616,7 +616,7 @@ static bool verify_solana_transfer_token_transaction() { if (memcmp(associated_token_address, solana_txn_context->transaction_info .instruction[transfer_instruction_index] - .program.transferChecked.destination, + .program.transfer_checked.destination, SOLANA_ACCOUNT_ADDRESS_LENGTH) != 0) { solana_send_error(ERROR_COMMON_ERROR_CORRUPT_DATA_TAG, 2); return false; @@ -636,7 +636,7 @@ static bool verify_solana_transfer_token_transaction() { while (i--) be_units[i] = solana_txn_context->transaction_info .instruction[transfer_instruction_index] - .program.transferChecked.amount >> + .program.transfer_checked.amount >> 8 * (7 - i); byte_array_to_hex_string(be_units, 8, amount_string, sizeof(amount_string)); diff --git a/apps/solana_app/solana_txn_helpers.c b/apps/solana_app/solana_txn_helpers.c index 8016c8906..95f891b98 100644 --- a/apps/solana_app/solana_txn_helpers.c +++ b/apps/solana_app/solana_txn_helpers.c @@ -241,38 +241,38 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, switch (instruction_enum) { case STPI_TRANSFER_CHECKED: // transfer checked instruction utxn->instruction[transfer_instruction_index] - .program.transferChecked.source = + .program.transfer_checked.source = utxn->account_addresses + (*(utxn->instruction[transfer_instruction_index] .account_addresses_index + 0) * SOLANA_ACCOUNT_ADDRESS_LENGTH); utxn->instruction[transfer_instruction_index] - .program.transferChecked.token_mint = + .program.transfer_checked.token_mint = utxn->account_addresses + (*(utxn->instruction[transfer_instruction_index] .account_addresses_index + 1) * SOLANA_ACCOUNT_ADDRESS_LENGTH); utxn->instruction[transfer_instruction_index] - .program.transferChecked.destination = + .program.transfer_checked.destination = utxn->account_addresses + (*(utxn->instruction[transfer_instruction_index] .account_addresses_index + 2) * SOLANA_ACCOUNT_ADDRESS_LENGTH); utxn->instruction[transfer_instruction_index] - .program.transferChecked.owner = + .program.transfer_checked.owner = utxn->account_addresses + (*(utxn->instruction[transfer_instruction_index] .account_addresses_index + 3) * SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction[transfer_instruction_index].program.transferChecked.amount = + utxn->instruction[transfer_instruction_index].program.transfer_checked.amount = U64_READ_LE_ARRAY( utxn->instruction[transfer_instruction_index].opaque_data + 1); - utxn->instruction[transfer_instruction_index].program.transferChecked.decimals = - *(utxn->instruction[transfer_instruction_index].opaque_data + 9); + utxn->instruction[transfer_instruction_index].program.transfer_checked.decimals = + *(utxn->instruction[transfer_instruction_index].opaque_data + sizeof(uint64_t) + 1); // decimal value comes after amount(which is a u64) break; default: diff --git a/apps/solana_app/solana_txn_helpers.h b/apps/solana_app/solana_txn_helpers.h index 2c8835e9d..4839f6052 100644 --- a/apps/solana_app/solana_txn_helpers.h +++ b/apps/solana_app/solana_txn_helpers.h @@ -130,7 +130,7 @@ typedef struct solana_instruction { uint8_t *opaque_data; union { solana_transfer_data transfer; - solana_token_transfer_checked_data transferChecked; + solana_token_transfer_checked_data transfer_checked; } program; } solana_instruction; diff --git a/src/constant_texts.h b/src/constant_texts.h index 44443db3e..b5beff051 100644 --- a/src/constant_texts.h +++ b/src/constant_texts.h @@ -31,7 +31,7 @@ #define UI_TEXT_SEND_PROMPT "Send %s on %s" #define UI_TEXT_SIGN_TXN_PROMPT "Sign transaction on %s from %s" #define UI_TEXT_REVIEW_TXN_PROMPT "Review transaction to %s" -#define UI_TEXT_SEND_TOKEN_PROMPT "Send %s on %s from %s" +#define UI_TEXT_SEND_TOKEN_PROMPT "Send \n%s on \n%s" #define UI_TEXT_BTC_RECEIVER "Receiver #%d" #define UI_TEXT_BTC_FEE "Transaction fee" #define UI_TEXT_SIGN_PROMPT "Sign %s message on %s from %s" From 05a0af977a2511b3812303d4cd1563f7ab90aa3f Mon Sep 17 00:00:00 2001 From: Muzaffar Ahmad Bhat Date: Mon, 20 Jan 2025 16:45:01 +0530 Subject: [PATCH 14/19] fix: Code formatting --- apps/solana_app/solana_sign_txn.c | 31 +++++++------ apps/solana_app/solana_txn_helpers.c | 68 +++++++++++++++------------- apps/solana_app/solana_txn_helpers.h | 6 +-- 3 files changed, 55 insertions(+), 50 deletions(-) diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index 2fa4bd4c3..5bea6a4ba 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -266,9 +266,7 @@ STATIC bool solana_handle_initiate_query(const solana_query_t *query) { return false; } - snprintf( - msg, sizeof(msg), UI_TEXT_SIGN_TXN_PROMPT, SOLANA_NAME, wallet_name - ); + snprintf(msg, sizeof(msg), UI_TEXT_SIGN_TXN_PROMPT, SOLANA_NAME, wallet_name); // Take user consent to sign the transaction for the wallet if (!core_confirmation(msg, solana_send_error)) { @@ -539,9 +537,9 @@ static bool verify_solana_transfer_token_transaction() { const uint8_t transfer_instruction_index = solana_txn_context->transaction_info.transfer_instruction_index; - const uint8_t* token_mint = solana_txn_context->transaction_info - .instruction[transfer_instruction_index] - .program.transfer_checked.token_mint; + const uint8_t *token_mint = solana_txn_context->transaction_info + .instruction[transfer_instruction_index] + .program.transfer_checked.token_mint; const solana_token_program_t *contract = NULL; if (!is_token_whitelisted(token_mint, &contract)) { // Contract Unverifed, Display warning @@ -558,21 +556,20 @@ static bool verify_solana_transfer_token_transaction() { return false; } - if (!core_scroll_page(ui_text_verify_token_address, - mint_address, - solana_send_error)) { + if (!core_scroll_page( + ui_text_verify_token_address, mint_address, solana_send_error)) { return false; } const uint8_t token_decimals = solana_txn_context->transaction_info - .instruction[transfer_instruction_index] - .program.transfer_checked.decimals; + .instruction[transfer_instruction_index] + .program.transfer_checked.decimals; char display[50] = {'\0'}; snprintf(display, - sizeof(display), - ui_text_verify_token_decimals, - token_decimals); + sizeof(display), + ui_text_verify_token_decimals, + token_decimals); if (!core_confirmation(display, solana_send_error)) { return false; @@ -586,7 +583,11 @@ static bool verify_solana_transfer_token_transaction() { contract = &empty_contract; } else { char msg[100] = ""; - snprintf(msg, sizeof(msg), UI_TEXT_SEND_TOKEN_PROMPT, contract->symbol, SOLANA_NAME); + snprintf(msg, + sizeof(msg), + UI_TEXT_SEND_TOKEN_PROMPT, + contract->symbol, + SOLANA_NAME); if (!core_confirmation(msg, solana_send_error)) { return false; } diff --git a/apps/solana_app/solana_txn_helpers.c b/apps/solana_app/solana_txn_helpers.c index 95f891b98..c1ecb7806 100644 --- a/apps/solana_app/solana_txn_helpers.c +++ b/apps/solana_app/solana_txn_helpers.c @@ -178,7 +178,8 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, &error); if (error != SOL_OK) return error; - if (i == utxn->transfer_instruction_index && utxn->instruction[i].opaque_data_length == 0) + if (i == utxn->transfer_instruction_index && + utxn->instruction[i].opaque_data_length == 0) return SOL_D_MIN_LENGTH; utxn->instruction[i].opaque_data = byte_array + offset; @@ -221,9 +222,9 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, .account_addresses_index + 1) * SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction[transfer_instruction_index].program.transfer.lamports = - U64_READ_LE_ARRAY( - utxn->instruction[transfer_instruction_index].opaque_data + 4); + utxn->instruction[transfer_instruction_index] + .program.transfer.lamports = U64_READ_LE_ARRAY( + utxn->instruction[transfer_instruction_index].opaque_data + 4); break; default: @@ -239,41 +240,44 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, *(utxn->instruction[transfer_instruction_index].opaque_data); switch (instruction_enum) { - case STPI_TRANSFER_CHECKED: // transfer checked instruction + case STPI_TRANSFER_CHECKED: // transfer checked instruction utxn->instruction[transfer_instruction_index] - .program.transfer_checked.source = - utxn->account_addresses + - (*(utxn->instruction[transfer_instruction_index] - .account_addresses_index + - 0) * - SOLANA_ACCOUNT_ADDRESS_LENGTH); + .program.transfer_checked.source = + utxn->account_addresses + + (*(utxn->instruction[transfer_instruction_index] + .account_addresses_index + + 0) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); utxn->instruction[transfer_instruction_index] - .program.transfer_checked.token_mint = - utxn->account_addresses + - (*(utxn->instruction[transfer_instruction_index] - .account_addresses_index + - 1) * - SOLANA_ACCOUNT_ADDRESS_LENGTH); + .program.transfer_checked.token_mint = + utxn->account_addresses + + (*(utxn->instruction[transfer_instruction_index] + .account_addresses_index + + 1) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); utxn->instruction[transfer_instruction_index] .program.transfer_checked.destination = utxn->account_addresses + (*(utxn->instruction[transfer_instruction_index] - .account_addresses_index + - 2) * - SOLANA_ACCOUNT_ADDRESS_LENGTH); + .account_addresses_index + + 2) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); utxn->instruction[transfer_instruction_index] - .program.transfer_checked.owner = - utxn->account_addresses + - (*(utxn->instruction[transfer_instruction_index] - .account_addresses_index + - 3) * - SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction[transfer_instruction_index].program.transfer_checked.amount = - U64_READ_LE_ARRAY( - utxn->instruction[transfer_instruction_index].opaque_data + 1); - utxn->instruction[transfer_instruction_index].program.transfer_checked.decimals = - *(utxn->instruction[transfer_instruction_index].opaque_data + sizeof(uint64_t) + 1); // decimal value comes after amount(which is a u64) - break; + .program.transfer_checked.owner = + utxn->account_addresses + + (*(utxn->instruction[transfer_instruction_index] + .account_addresses_index + + 3) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); + utxn->instruction[transfer_instruction_index] + .program.transfer_checked.amount = U64_READ_LE_ARRAY( + utxn->instruction[transfer_instruction_index].opaque_data + 1); + utxn->instruction[transfer_instruction_index] + .program.transfer_checked.decimals = + *(utxn->instruction[transfer_instruction_index].opaque_data + + sizeof(uint64_t) + + 1); // decimal value comes after amount(which is a u64) + break; default: break; diff --git a/apps/solana_app/solana_txn_helpers.h b/apps/solana_app/solana_txn_helpers.h index 4839f6052..32915f7af 100644 --- a/apps/solana_app/solana_txn_helpers.h +++ b/apps/solana_app/solana_txn_helpers.h @@ -115,7 +115,7 @@ typedef struct solana_token_transfer_checked_data { uint8_t *source; uint8_t *token_mint; uint8_t *destination; - uint8_t *owner; // signer/owner of the source account + uint8_t *owner; // signer/owner of the source account uint64_t amount; uint8_t decimals; } solana_token_transfer_checked_data; @@ -146,8 +146,8 @@ typedef struct solana_unsigned_txn { uint8_t *blockhash; - uint16_t - instructions_count; // deserialization only supports max 2 instructions: create account and transfer + uint16_t instructions_count; // deserialization only supports max 2 + // instructions: create account and transfer solana_instruction instruction[2]; ///< Expects max 2 instructions uint8_t transfer_instruction_index; From f016ff8d2fa925151e18e926c5e38a49774c51a7 Mon Sep 17 00:00:00 2001 From: Muzaffar Ahmad Bhat Date: Mon, 20 Jan 2025 18:08:09 +0530 Subject: [PATCH 15/19] fix: Remove decimal user verification --- apps/solana_app/solana_sign_txn.c | 10 ---------- src/constant_texts.c | 1 - src/constant_texts.h | 1 - 3 files changed, 12 deletions(-) diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index 5bea6a4ba..862d8f47b 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -565,16 +565,6 @@ static bool verify_solana_transfer_token_transaction() { .instruction[transfer_instruction_index] .program.transfer_checked.decimals; - char display[50] = {'\0'}; - snprintf(display, - sizeof(display), - ui_text_verify_token_decimals, - token_decimals); - - if (!core_confirmation(display, solana_send_error)) { - return false; - } - solana_token_program_t empty_contract = { .symbol = "", .decimal = token_decimals, diff --git a/src/constant_texts.c b/src/constant_texts.c index 8d94a5bba..6bd79af9a 100644 --- a/src/constant_texts.c +++ b/src/constant_texts.c @@ -367,7 +367,6 @@ const char *ui_text_verify_contract = "Verify contract"; const char *ui_text_unverified_contract = LV_SYMBOL_WARNING " Warning!\nUnverified contract"; const char *ui_text_verify_token_address = "Verify token address"; -const char *ui_text_verify_token_decimals = "Verify token decimals\n%d"; const char *ui_text_unverified_token = LV_SYMBOL_WARNING " Warning!\nUnverified token"; const char *ui_text_confirm_wallet_name = "Confirm wallet name"; diff --git a/src/constant_texts.h b/src/constant_texts.h index b5beff051..c89a576ad 100644 --- a/src/constant_texts.h +++ b/src/constant_texts.h @@ -259,7 +259,6 @@ extern const char *ui_text_verify_amount; extern const char *ui_text_verify_contract; extern const char *ui_text_unverified_contract; extern const char *ui_text_verify_token_address; -extern const char *ui_text_verify_token_decimals; extern const char *ui_text_unverified_token; extern const char *ui_text_confirm_wallet_name; extern const char *ui_text_enter_data; From 156e59c1efe413e0e75860f8442454dddbc848ec Mon Sep 17 00:00:00 2001 From: Muzaffar Ahmad Bhat Date: Thu, 23 Jan 2025 13:42:20 +0530 Subject: [PATCH 16/19] feat: Added compute budget program support for priority fee in solana --- apps/solana_app/solana_sign_txn.c | 58 +++++ apps/solana_app/solana_txn_helpers.c | 328 +++++++++++++++------------ apps/solana_app/solana_txn_helpers.h | 35 ++- src/constant_texts.h | 1 + 4 files changed, 275 insertions(+), 147 deletions(-) diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index 862d8f47b..19a8998e0 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -62,6 +62,7 @@ #include +#include "int-util.h" #include "reconstruct_wallet_flow.h" #include "solana_api.h" #include "solana_contracts.h" @@ -355,6 +356,57 @@ STATIC bool solana_fetch_valid_transaction(solana_query_t *query) { return true; } +static bool verify_priority_fee() { + if (solana_txn_context->transaction_info.compute_unit_price_micro_lamports > + 0) { + // verify priority fee + uint64_t priority_fee, carry; + + // Capacity to multiply 2 numbers upto 8-byte value and store the result in + // 2 separate 8-byte variables + priority_fee = mul128( + solana_txn_context->transaction_info.compute_unit_price_micro_lamports, + solana_txn_context->transaction_info.compute_unit_limit, + &carry); + + // prepare the whole 128-bit little-endian representation of priority fee + uint8_t be_micro_lamports[16] = {0}; + memcpy(be_micro_lamports, &priority_fee, sizeof(priority_fee)); + memcpy(be_micro_lamports + sizeof(priority_fee), &carry, sizeof(carry)); + + // outputs 128-bit (16-byte) big-endian representation of priority fee + cy_reverse_byte_array(be_micro_lamports, sizeof(be_micro_lamports)); + + char priority_fee_string[33] = {'\0'}, + priority_fee_decimal_string[34] = {'\0'}; + + byte_array_to_hex_string(be_micro_lamports, + sizeof(be_micro_lamports), + priority_fee_string, + sizeof(priority_fee_string)); + if (!convert_byte_array_to_decimal_string( + sizeof(priority_fee_string) - 1, + solana_get_decimal() + 6, // +6 for micro + priority_fee_string, + priority_fee_decimal_string, + sizeof(priority_fee_decimal_string))) { + solana_send_error(ERROR_COMMON_ERROR_UNKNOWN_ERROR_TAG, 1); + return false; + } + + char display[100] = ""; + snprintf(display, + sizeof(display), + UI_TEXT_VERIFY_PRIORITY_FEE, + priority_fee_decimal_string, + SOLANA_LUNIT); + if (!core_confirmation(display, solana_send_error)) { + return false; + } + } + return true; +} + static bool verify_solana_transfer_sol_transaction() { char address[45] = {0}; size_t address_size = sizeof(address); @@ -408,6 +460,9 @@ static bool verify_solana_transfer_sol_transaction() { return false; } + if (!verify_priority_fee()) + return false; + set_app_flow_status(SOLANA_SIGN_TXN_STATUS_VERIFY); return true; } @@ -649,6 +704,9 @@ static bool verify_solana_transfer_token_transaction() { return false; } + if (!verify_priority_fee()) + return false; + set_app_flow_status(SOLANA_SIGN_TXN_STATUS_VERIFY); return true; } diff --git a/apps/solana_app/solana_txn_helpers.c b/apps/solana_app/solana_txn_helpers.c index c1ecb7806..6eeb813df 100644 --- a/apps/solana_app/solana_txn_helpers.c +++ b/apps/solana_app/solana_txn_helpers.c @@ -148,7 +148,7 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, utxn->blockhash = byte_array + offset; offset += SOLANA_BLOCKHASH_LENGTH; - // Instructions: Currently expecting count to be 1 or 2. TODO: Handle batch + // Instructions: Currently expecting count to be 3 or 4. TODO: Handle batch // instructions offset += get_compact_array_size( byte_array + offset, &(utxn->instructions_count), &error); @@ -157,7 +157,23 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, if (utxn->instructions_count == 0) return SOL_D_MIN_LENGTH; - utxn->transfer_instruction_index = ((utxn->instructions_count == 2) ? 1 : 0); + // prepare list of supported program ids + uint8_t system_program_id[SOLANA_PROGRAM_ID_COUNT] + [SOLANA_ACCOUNT_ADDRESS_LENGTH]; + // Set System instruction address for SOL transfer + memzero(system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH); + // Set System instruction address for Token Program + hex_string_to_byte_array(SOLANA_TOKEN_PROGRAM_ADDRESS, + SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, + system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX]); + // Set Compute Budget Program address + hex_string_to_byte_array( + SOLANA_COMPUTE_BUDGET_PROGRAM_ADDRESS, + SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, + system_program_id[SOLANA_COMPUTE_BUDGET_PROGRAM_ID_INDEX]); + + utxn->compute_unit_limit = utxn->compute_unit_price_micro_lamports = 0; for (int i = 0; i < utxn->instructions_count; i++) { utxn->instruction[i].program_id_index = *(byte_array + offset++); @@ -168,8 +184,6 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, &error); if (error != SOL_OK) return error; - if (utxn->instruction[i].account_addresses_index_count == 0) - return SOL_D_MIN_LENGTH; utxn->instruction[i].account_addresses_index = byte_array + offset; offset += utxn->instruction[i].account_addresses_index_count; @@ -178,109 +192,108 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, &error); if (error != SOL_OK) return error; - if (i == utxn->transfer_instruction_index && - utxn->instruction[i].opaque_data_length == 0) - return SOL_D_MIN_LENGTH; utxn->instruction[i].opaque_data = byte_array + offset; offset += utxn->instruction[i].opaque_data_length; - } - // prepare list of supported program ids - uint8_t system_program_id[SOLANA_PROGRAM_ID_COUNT] - [SOLANA_ACCOUNT_ADDRESS_LENGTH]; - // Set System instruction address for SOL transfer - memzero(system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], - SOLANA_ACCOUNT_ADDRESS_LENGTH); - // Set System instruction address for Token Program - hex_string_to_byte_array(SOLANA_TOKEN_PROGRAM_ADDRESS, - SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, - system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX]); - const uint8_t transfer_instruction_index = utxn->transfer_instruction_index; - if (memcmp( - utxn->account_addresses + - utxn->instruction[transfer_instruction_index].program_id_index * - SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], - SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { - uint32_t instruction_enum = U32_READ_LE_ARRAY( - utxn->instruction[transfer_instruction_index].opaque_data); - - switch (instruction_enum) { - case SSI_TRANSFER: // transfer instruction - utxn->instruction[transfer_instruction_index] - .program.transfer.funding_account = - utxn->account_addresses + - (*(utxn->instruction[transfer_instruction_index] - .account_addresses_index + - 0) * - SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction[transfer_instruction_index] - .program.transfer.recipient_account = - utxn->account_addresses + - (*(utxn->instruction[transfer_instruction_index] - .account_addresses_index + - 1) * - SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction[transfer_instruction_index] - .program.transfer.lamports = U64_READ_LE_ARRAY( - utxn->instruction[transfer_instruction_index].opaque_data + 4); - break; - - default: - break; - } - } else if (memcmp(utxn->account_addresses + - utxn->instruction[transfer_instruction_index] - .program_id_index * - SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX], - SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { - uint8_t instruction_enum = - *(utxn->instruction[transfer_instruction_index].opaque_data); - - switch (instruction_enum) { - case STPI_TRANSFER_CHECKED: // transfer checked instruction - utxn->instruction[transfer_instruction_index] - .program.transfer_checked.source = - utxn->account_addresses + - (*(utxn->instruction[transfer_instruction_index] - .account_addresses_index + - 0) * - SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction[transfer_instruction_index] - .program.transfer_checked.token_mint = - utxn->account_addresses + - (*(utxn->instruction[transfer_instruction_index] - .account_addresses_index + - 1) * - SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction[transfer_instruction_index] - .program.transfer_checked.destination = - utxn->account_addresses + - (*(utxn->instruction[transfer_instruction_index] - .account_addresses_index + - 2) * - SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction[transfer_instruction_index] - .program.transfer_checked.owner = - utxn->account_addresses + - (*(utxn->instruction[transfer_instruction_index] - .account_addresses_index + - 3) * - SOLANA_ACCOUNT_ADDRESS_LENGTH); - utxn->instruction[transfer_instruction_index] - .program.transfer_checked.amount = U64_READ_LE_ARRAY( - utxn->instruction[transfer_instruction_index].opaque_data + 1); - utxn->instruction[transfer_instruction_index] - .program.transfer_checked.decimals = - *(utxn->instruction[transfer_instruction_index].opaque_data + - sizeof(uint64_t) + - 1); // decimal value comes after amount(which is a u64) - break; - - default: - break; + if (memcmp(utxn->account_addresses + utxn->instruction[i].program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + if (utxn->instruction[i].account_addresses_index_count == 0) + return SOL_D_MIN_LENGTH; + + if (utxn->instruction[i].opaque_data_length == 0) + return SOL_D_MIN_LENGTH; + + utxn->transfer_instruction_index = i; + + uint32_t instruction_enum = + U32_READ_LE_ARRAY(utxn->instruction[i].opaque_data); + + switch (instruction_enum) { + case SSI_TRANSFER: // transfer instruction + utxn->instruction[i].program.transfer.funding_account = + utxn->account_addresses + + (*(utxn->instruction[i].account_addresses_index + 0) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); + utxn->instruction[i].program.transfer.recipient_account = + utxn->account_addresses + + (*(utxn->instruction[i].account_addresses_index + 1) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); + utxn->instruction[i].program.transfer.lamports = + U64_READ_LE_ARRAY(utxn->instruction[i].opaque_data + 4); + break; + + default: + break; + } + } else if (memcmp(utxn->account_addresses + + utxn->instruction[i].program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + if (utxn->instruction[i].account_addresses_index_count == 0) + return SOL_D_MIN_LENGTH; + + utxn->transfer_instruction_index = i; + + uint8_t instruction_enum = *(utxn->instruction[i].opaque_data); + + switch (instruction_enum) { + case STPI_TRANSFER_CHECKED: // transfer checked instruction + utxn->instruction[i].program.transfer_checked.source = + utxn->account_addresses + + (*(utxn->instruction[i].account_addresses_index + 0) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); + utxn->instruction[i].program.transfer_checked.token_mint = + utxn->account_addresses + + (*(utxn->instruction[i].account_addresses_index + 1) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); + utxn->instruction[i].program.transfer_checked.destination = + utxn->account_addresses + + (*(utxn->instruction[i].account_addresses_index + 2) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); + utxn->instruction[i].program.transfer_checked.owner = + utxn->account_addresses + + (*(utxn->instruction[i].account_addresses_index + 3) * + SOLANA_ACCOUNT_ADDRESS_LENGTH); + utxn->instruction[i].program.transfer_checked.amount = + U64_READ_LE_ARRAY(utxn->instruction[i].opaque_data + 1); + utxn->instruction[i].program.transfer_checked.decimals = + *(utxn->instruction[i].opaque_data + sizeof(uint64_t) + + 1); // decimal value comes after amount(which is a u64) + break; + + default: + break; + } + } else if (memcmp(utxn->account_addresses + + utxn->instruction[i].program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_COMPUTE_BUDGET_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + if (utxn->instruction[i].opaque_data_length == 0) + return SOL_D_MIN_LENGTH; + + uint8_t instruction_enum = *(utxn->instruction[i].opaque_data); + switch (instruction_enum) { + case SCBI_SET_COMPUTE_UNIT_LIMIT: + utxn->compute_unit_limit = + utxn->instruction[i].program.compute_unit_limit_data.units = + U32_READ_LE_ARRAY(utxn->instruction[i].opaque_data + 1); + break; + + case SCBI_SET_COMPUTE_UNIT_PRICE: + utxn->compute_unit_price_micro_lamports = + utxn->instruction[i] + .program.compute_unit_price_data.micro_lamports = + U64_READ_LE_ARRAY(utxn->instruction[i].opaque_data + 1); + break; + + default: + break; + } } } @@ -290,15 +303,9 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, } int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { - if (utxn->instructions_count > 2) + if (utxn->instructions_count > 4) return SOL_V_UNSUPPORTED_INSTRUCTION_COUNT; - const uint8_t transfer_instruction_index = utxn->transfer_instruction_index; - if (!(0 < utxn->instruction[transfer_instruction_index].program_id_index && - utxn->instruction[transfer_instruction_index].program_id_index < - utxn->account_addresses_count)) - return SOL_V_INDEX_OUT_OF_RANGE; - // prepare list of supported program ids uint8_t system_program_id[SOLANA_PROGRAM_ID_COUNT] [SOLANA_ACCOUNT_ADDRESS_LENGTH]; @@ -309,42 +316,77 @@ int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { hex_string_to_byte_array(SOLANA_TOKEN_PROGRAM_ADDRESS, SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX]); + // Set Compute Budget Program address + hex_string_to_byte_array( + SOLANA_COMPUTE_BUDGET_PROGRAM_ADDRESS, + SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, + system_program_id[SOLANA_COMPUTE_BUDGET_PROGRAM_ID_INDEX]); - if (memcmp( - utxn->account_addresses + - utxn->instruction[transfer_instruction_index].program_id_index * - SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], - SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { - uint32_t instruction_enum = U32_READ_LE_ARRAY( - utxn->instruction[transfer_instruction_index].opaque_data); - - switch (instruction_enum) { - case SSI_TRANSFER: // transfer instruction - break; - default: - return SOL_V_UNSUPPORTED_INSTRUCTION; - break; - } - } else if (memcmp(utxn->account_addresses + - utxn->instruction[transfer_instruction_index] - .program_id_index * - SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX], - SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { - uint8_t instruction_enum = - *(utxn->instruction[transfer_instruction_index].opaque_data); - - switch (instruction_enum) { - case STPI_TRANSFER_CHECKED: // transfer checked instruction - break; - default: - return SOL_V_UNSUPPORTED_INSTRUCTION; - break; + bool transfer_instruction_found = false; + + for (int i = 0; i < utxn->instructions_count; i++) { + if (!(0 < utxn->instruction[i].program_id_index && + utxn->instruction[i].program_id_index < + utxn->account_addresses_count)) + return SOL_V_INDEX_OUT_OF_RANGE; + + if (memcmp(utxn->account_addresses + utxn->instruction[i].program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + uint32_t instruction_enum = + U32_READ_LE_ARRAY(utxn->instruction[i].opaque_data); + + switch (instruction_enum) { + case SSI_TRANSFER: // transfer instruction + if (transfer_instruction_found) + return SOL_ERROR; + transfer_instruction_found = true; + break; + default: + return SOL_V_UNSUPPORTED_INSTRUCTION; + break; + } + } else if (memcmp(utxn->account_addresses + + utxn->instruction[i].program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + uint8_t instruction_enum = *(utxn->instruction[i].opaque_data); + + switch (instruction_enum) { + case STPI_TRANSFER_CHECKED: // transfer checked instruction + if (transfer_instruction_found) + return SOL_ERROR; + transfer_instruction_found = true; + break; + default: + return SOL_V_UNSUPPORTED_INSTRUCTION; + break; + } + } else if (memcmp(utxn->account_addresses + + utxn->instruction[i].program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_COMPUTE_BUDGET_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + uint8_t instruction_enum = *(utxn->instruction[i].opaque_data); + switch (instruction_enum) { + case SCBI_SET_COMPUTE_UNIT_LIMIT: + case SCBI_SET_COMPUTE_UNIT_PRICE: + break; + + default: + return SOL_V_UNSUPPORTED_INSTRUCTION; + break; + } + } else { + return SOL_V_UNSUPPORTED_PROGRAM; } - } else { - return SOL_V_UNSUPPORTED_PROGRAM; } + + if (transfer_instruction_found == false) + return SOL_ERROR; + return SOL_OK; } diff --git a/apps/solana_app/solana_txn_helpers.h b/apps/solana_app/solana_txn_helpers.h index 32915f7af..c4e07590e 100644 --- a/apps/solana_app/solana_txn_helpers.h +++ b/apps/solana_app/solana_txn_helpers.h @@ -28,14 +28,17 @@ #define SOLANA_ACCOUNT_ADDRESS_LENGTH 32 #define SOLANA_BLOCKHASH_LENGTH 32 -#define SOLANA_PROGRAM_ID_COUNT 2 ///< Number of supported program ids +#define SOLANA_PROGRAM_ID_COUNT 3 ///< Number of supported program ids #define SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX 0 #define SOLANA_TOKEN_PROGRAM_ID_INDEX 1 +#define SOLANA_COMPUTE_BUDGET_PROGRAM_ID_INDEX 2 #define SOLANA_TOKEN_PROGRAM_ADDRESS \ "06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9" ///< "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" #define SOLANA_ASSOCIATED_TOKEN_PROGRAM_ADDRESS \ "8c97258f4e2489f1bb3d1029148e0d830b5a1399daff1084048e7bd8dbe9f859" ///< "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" +#define SOLANA_COMPUTE_BUDGET_PROGRAM_ADDRESS \ + "0306466fe5211732ffecadba72c39be7bc8ce5bbc5f7126b2c439b3a40000000" ///< "ComputeBudget111111111111111111111111111111" /***************************************************************************** * TYPEDEFS *****************************************************************************/ @@ -88,6 +91,14 @@ enum SOLANA_TOKEN_PROGRAM_INSTRUCTION { STPI_UI_AMOUNT_TO_AMOUNT }; +enum SOLANA_COMPUTE_BUDGET_INSTRUCTION { + SCBI_UNUSED = 0, + SCBI_REQUEST_HEAP_FRAME, + SCBI_SET_COMPUTE_UNIT_LIMIT, + SCBI_SET_COMPUTE_UNIT_PRICE, + SCBI_SET_LOADED_ACCOUNT_DATA_SIZE_LIMIT +}; + enum SOLANA_ERROR_CODES { SOL_OK = 0, SOL_ERROR, @@ -120,6 +131,18 @@ typedef struct solana_token_transfer_checked_data { uint8_t decimals; } solana_token_transfer_checked_data; +// Reference : +// https://docs.rs/solana-sdk/latest/solana_sdk/compute_budget/enum.ComputeBudgetInstruction.html#method.set_compute_unit_limit +typedef struct { + uint32_t units; +} solana_compute_unit_limit_data; + +// Reference : +// https://docs.rs/solana-sdk/latest/solana_sdk/compute_budget/enum.ComputeBudgetInstruction.html#method.set_compute_unit_price +typedef struct { + uint64_t micro_lamports; +} solana_compute_unit_price_data; + // Reference : // https://docs.solana.com/developing/programming-model/transactions#instruction-format typedef struct solana_instruction { @@ -131,6 +154,8 @@ typedef struct solana_instruction { union { solana_transfer_data transfer; solana_token_transfer_checked_data transfer_checked; + solana_compute_unit_limit_data compute_unit_limit_data; + solana_compute_unit_price_data compute_unit_price_data; } program; } solana_instruction; @@ -146,10 +171,12 @@ typedef struct solana_unsigned_txn { uint8_t *blockhash; - uint16_t instructions_count; // deserialization only supports max 2 + uint16_t instructions_count; // deserialization only supports max 4 // instructions: create account and transfer - solana_instruction instruction[2]; ///< Expects max 2 instructions - uint8_t transfer_instruction_index; + solana_instruction instruction[4]; ///< Expects max 4 instructions + uint8_t transfer_instruction_index; // Expects only 1 transfer instruction + uint32_t compute_unit_limit; // To calculate priority fee + uint64_t compute_unit_price_micro_lamports; } solana_unsigned_txn; diff --git a/src/constant_texts.h b/src/constant_texts.h index c89a576ad..6da9cc898 100644 --- a/src/constant_texts.h +++ b/src/constant_texts.h @@ -55,6 +55,7 @@ #define UI_TEXT_VERIFY_HD_PATH "Verify Derivation Path" #define UI_TEXT_PIN "PIN\n %s" #define UI_TEXT_VERIFY_DESTINATION_TAG "Verify Destination Tag\n%lu" +#define UI_TEXT_VERIFY_PRIORITY_FEE "Verify Priority Fee\n%s\n%s" // product hash extern const char *product_hash; From de7f55443b0b8cfb83799e68ac9953a727ee42a3 Mon Sep 17 00:00:00 2001 From: Muzaffar Ahmad Bhat Date: Fri, 24 Jan 2025 17:31:09 +0530 Subject: [PATCH 17/19] fix: Parse create account instruction --- apps/solana_app/solana_sign_txn.c | 16 +++++++----- apps/solana_app/solana_txn_helpers.c | 37 ++++++++++++++++++++++------ apps/solana_app/solana_txn_helpers.h | 11 ++++++--- 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index 19a8998e0..5e20ca322 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -595,8 +595,9 @@ static bool verify_solana_transfer_token_transaction() { const uint8_t *token_mint = solana_txn_context->transaction_info .instruction[transfer_instruction_index] .program.transfer_checked.token_mint; - const solana_token_program_t *contract = NULL; - if (!is_token_whitelisted(token_mint, &contract)) { + solana_token_program_t contract = {0}; + const solana_token_program_t* contract_pointer = &contract; + if (!is_token_whitelisted(token_mint, &contract_pointer)) { // Contract Unverifed, Display warning delay_scr_init(ui_text_unverified_token, DELAY_TIME); @@ -625,13 +626,16 @@ static bool verify_solana_transfer_token_transaction() { .decimal = token_decimals, }; - contract = &empty_contract; + memcpy(&contract, &empty_contract, sizeof(empty_contract)); + } else { + memcpy(&contract, contract_pointer, sizeof(contract)); + char msg[100] = ""; snprintf(msg, sizeof(msg), UI_TEXT_SEND_TOKEN_PROMPT, - contract->symbol, + contract.symbol, SOLANA_NAME); if (!core_confirmation(msg, solana_send_error)) { return false; @@ -687,7 +691,7 @@ static bool verify_solana_transfer_token_transaction() { byte_array_to_hex_string(be_units, 8, amount_string, sizeof(amount_string)); if (!convert_byte_array_to_decimal_string(16, - contract->decimal, + contract.decimal, amount_string, amount_decimal_string, sizeof(amount_decimal_string))) { @@ -699,7 +703,7 @@ static bool verify_solana_transfer_token_transaction() { sizeof(display), UI_TEXT_VERIFY_AMOUNT, amount_decimal_string, - contract->symbol); + contract.symbol); if (!core_confirmation(display, solana_send_error)) { return false; } diff --git a/apps/solana_app/solana_txn_helpers.c b/apps/solana_app/solana_txn_helpers.c index 6eeb813df..034f8e3d8 100644 --- a/apps/solana_app/solana_txn_helpers.c +++ b/apps/solana_app/solana_txn_helpers.c @@ -148,8 +148,8 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, utxn->blockhash = byte_array + offset; offset += SOLANA_BLOCKHASH_LENGTH; - // Instructions: Currently expecting count to be 3 or 4. TODO: Handle batch - // instructions + // Instructions: Currently expecting count to be 1 to 4, with only 1 transfer instruction. + // TODO: Handle batch instructions offset += get_compact_array_size( byte_array + offset, &(utxn->instructions_count), &error); if (error != SOL_OK) @@ -167,6 +167,10 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, hex_string_to_byte_array(SOLANA_TOKEN_PROGRAM_ADDRESS, SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX]); + // Set Associated Token Program address + hex_string_to_byte_array(SOLANA_ASSOCIATED_TOKEN_PROGRAM_ADDRESS, + SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, + system_program_id[SOLANA_ASSOCIATED_TOKEN_PROGRAM_ID_INDEX]); // Set Compute Budget Program address hex_string_to_byte_array( SOLANA_COMPUTE_BUDGET_PROGRAM_ADDRESS, @@ -200,10 +204,8 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, SOLANA_ACCOUNT_ADDRESS_LENGTH, system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { - if (utxn->instruction[i].account_addresses_index_count == 0) - return SOL_D_MIN_LENGTH; - - if (utxn->instruction[i].opaque_data_length == 0) + if (utxn->instruction[i].account_addresses_index_count == 0 + || utxn->instruction[i].opaque_data_length == 0) return SOL_D_MIN_LENGTH; utxn->transfer_instruction_index = i; @@ -233,7 +235,8 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, SOLANA_ACCOUNT_ADDRESS_LENGTH, system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX], SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { - if (utxn->instruction[i].account_addresses_index_count == 0) + if (utxn->instruction[i].account_addresses_index_count == 0 + || utxn->instruction[i].opaque_data_length == 0) return SOL_D_MIN_LENGTH; utxn->transfer_instruction_index = i; @@ -268,6 +271,14 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, default: break; } + } else if (memcmp(utxn->account_addresses + + utxn->instruction[i].program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_ASSOCIATED_TOKEN_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + if (utxn->instruction[i].account_addresses_index_count == 0) + return SOL_D_MIN_LENGTH; + } else if (memcmp(utxn->account_addresses + utxn->instruction[i].program_id_index * SOLANA_ACCOUNT_ADDRESS_LENGTH, @@ -316,6 +327,10 @@ int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { hex_string_to_byte_array(SOLANA_TOKEN_PROGRAM_ADDRESS, SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX]); + // Set Associated Token Program address + hex_string_to_byte_array(SOLANA_ASSOCIATED_TOKEN_PROGRAM_ADDRESS, + SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, + system_program_id[SOLANA_ASSOCIATED_TOKEN_PROGRAM_ID_INDEX]); // Set Compute Budget Program address hex_string_to_byte_array( SOLANA_COMPUTE_BUDGET_PROGRAM_ADDRESS, @@ -364,6 +379,14 @@ int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { return SOL_V_UNSUPPORTED_INSTRUCTION; break; } + } else if (memcmp(utxn->account_addresses + + utxn->instruction[i].program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_ASSOCIATED_TOKEN_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + // no opaque data or instruction enum to validate + // do nothing + } else if (memcmp(utxn->account_addresses + utxn->instruction[i].program_id_index * SOLANA_ACCOUNT_ADDRESS_LENGTH, diff --git a/apps/solana_app/solana_txn_helpers.h b/apps/solana_app/solana_txn_helpers.h index c4e07590e..81267a73a 100644 --- a/apps/solana_app/solana_txn_helpers.h +++ b/apps/solana_app/solana_txn_helpers.h @@ -28,10 +28,11 @@ #define SOLANA_ACCOUNT_ADDRESS_LENGTH 32 #define SOLANA_BLOCKHASH_LENGTH 32 -#define SOLANA_PROGRAM_ID_COUNT 3 ///< Number of supported program ids +#define SOLANA_PROGRAM_ID_COUNT 4 ///< Number of supported program ids #define SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX 0 #define SOLANA_TOKEN_PROGRAM_ID_INDEX 1 -#define SOLANA_COMPUTE_BUDGET_PROGRAM_ID_INDEX 2 +#define SOLANA_ASSOCIATED_TOKEN_PROGRAM_ID_INDEX 2 +#define SOLANA_COMPUTE_BUDGET_PROGRAM_ID_INDEX 3 #define SOLANA_TOKEN_PROGRAM_ADDRESS \ "06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9" ///< "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" @@ -91,6 +92,8 @@ enum SOLANA_TOKEN_PROGRAM_INSTRUCTION { STPI_UI_AMOUNT_TO_AMOUNT }; +/// Ref : +/// https://docs.rs/solana-sdk/latest/solana_sdk/compute_budget/enum.ComputeBudgetInstruction.html enum SOLANA_COMPUTE_BUDGET_INSTRUCTION { SCBI_UNUSED = 0, SCBI_REQUEST_HEAP_FRAME, @@ -172,8 +175,8 @@ typedef struct solana_unsigned_txn { uint8_t *blockhash; uint16_t instructions_count; // deserialization only supports max 4 - // instructions: create account and transfer - solana_instruction instruction[4]; ///< Expects max 4 instructions + // instructions: compute unit limit, compute unit price, create account and transfer + solana_instruction instruction[4]; ///< Expects max 4 instructions: TODO: HANDLE ANY NUMBER/TYPE OF INSTRUCTIONS uint8_t transfer_instruction_index; // Expects only 1 transfer instruction uint32_t compute_unit_limit; // To calculate priority fee uint64_t compute_unit_price_micro_lamports; From 69517dd4e8727e57f46cc3248317c3f78ab9253c Mon Sep 17 00:00:00 2001 From: Muzaffar Ahmad Bhat Date: Fri, 24 Jan 2025 17:38:25 +0530 Subject: [PATCH 18/19] fix: Code formatting --- apps/solana_app/solana_sign_txn.c | 4 +-- apps/solana_app/solana_txn_helpers.c | 47 +++++++++++++++------------- apps/solana_app/solana_txn_helpers.h | 7 +++-- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index 5e20ca322..001064804 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -596,7 +596,7 @@ static bool verify_solana_transfer_token_transaction() { .instruction[transfer_instruction_index] .program.transfer_checked.token_mint; solana_token_program_t contract = {0}; - const solana_token_program_t* contract_pointer = &contract; + const solana_token_program_t *contract_pointer = &contract; if (!is_token_whitelisted(token_mint, &contract_pointer)) { // Contract Unverifed, Display warning delay_scr_init(ui_text_unverified_token, DELAY_TIME); @@ -627,7 +627,7 @@ static bool verify_solana_transfer_token_transaction() { }; memcpy(&contract, &empty_contract, sizeof(empty_contract)); - + } else { memcpy(&contract, contract_pointer, sizeof(contract)); diff --git a/apps/solana_app/solana_txn_helpers.c b/apps/solana_app/solana_txn_helpers.c index 034f8e3d8..d2f916665 100644 --- a/apps/solana_app/solana_txn_helpers.c +++ b/apps/solana_app/solana_txn_helpers.c @@ -148,7 +148,8 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, utxn->blockhash = byte_array + offset; offset += SOLANA_BLOCKHASH_LENGTH; - // Instructions: Currently expecting count to be 1 to 4, with only 1 transfer instruction. + // Instructions: Currently expecting count to be 1 to 4, with only 1 transfer + // instruction. // TODO: Handle batch instructions offset += get_compact_array_size( byte_array + offset, &(utxn->instructions_count), &error); @@ -168,9 +169,10 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX]); // Set Associated Token Program address - hex_string_to_byte_array(SOLANA_ASSOCIATED_TOKEN_PROGRAM_ADDRESS, - SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, - system_program_id[SOLANA_ASSOCIATED_TOKEN_PROGRAM_ID_INDEX]); + hex_string_to_byte_array( + SOLANA_ASSOCIATED_TOKEN_PROGRAM_ADDRESS, + SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, + system_program_id[SOLANA_ASSOCIATED_TOKEN_PROGRAM_ID_INDEX]); // Set Compute Budget Program address hex_string_to_byte_array( SOLANA_COMPUTE_BUDGET_PROGRAM_ADDRESS, @@ -204,8 +206,8 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, SOLANA_ACCOUNT_ADDRESS_LENGTH, system_program_id[SOLANA_SOL_TRANSFER_PROGRAM_ID_INDEX], SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { - if (utxn->instruction[i].account_addresses_index_count == 0 - || utxn->instruction[i].opaque_data_length == 0) + if (utxn->instruction[i].account_addresses_index_count == 0 || + utxn->instruction[i].opaque_data_length == 0) return SOL_D_MIN_LENGTH; utxn->transfer_instruction_index = i; @@ -235,8 +237,8 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, SOLANA_ACCOUNT_ADDRESS_LENGTH, system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX], SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { - if (utxn->instruction[i].account_addresses_index_count == 0 - || utxn->instruction[i].opaque_data_length == 0) + if (utxn->instruction[i].account_addresses_index_count == 0 || + utxn->instruction[i].opaque_data_length == 0) return SOL_D_MIN_LENGTH; utxn->transfer_instruction_index = i; @@ -271,11 +273,12 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, default: break; } - } else if (memcmp(utxn->account_addresses + - utxn->instruction[i].program_id_index * - SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id[SOLANA_ASSOCIATED_TOKEN_PROGRAM_ID_INDEX], - SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + } else if (memcmp( + utxn->account_addresses + + utxn->instruction[i].program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_ASSOCIATED_TOKEN_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { if (utxn->instruction[i].account_addresses_index_count == 0) return SOL_D_MIN_LENGTH; @@ -328,9 +331,10 @@ int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, system_program_id[SOLANA_TOKEN_PROGRAM_ID_INDEX]); // Set Associated Token Program address - hex_string_to_byte_array(SOLANA_ASSOCIATED_TOKEN_PROGRAM_ADDRESS, - SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, - system_program_id[SOLANA_ASSOCIATED_TOKEN_PROGRAM_ID_INDEX]); + hex_string_to_byte_array( + SOLANA_ASSOCIATED_TOKEN_PROGRAM_ADDRESS, + SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, + system_program_id[SOLANA_ASSOCIATED_TOKEN_PROGRAM_ID_INDEX]); // Set Compute Budget Program address hex_string_to_byte_array( SOLANA_COMPUTE_BUDGET_PROGRAM_ADDRESS, @@ -379,11 +383,12 @@ int solana_validate_unsigned_txn(const solana_unsigned_txn *utxn) { return SOL_V_UNSUPPORTED_INSTRUCTION; break; } - } else if (memcmp(utxn->account_addresses + - utxn->instruction[i].program_id_index * - SOLANA_ACCOUNT_ADDRESS_LENGTH, - system_program_id[SOLANA_ASSOCIATED_TOKEN_PROGRAM_ID_INDEX], - SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { + } else if (memcmp( + utxn->account_addresses + + utxn->instruction[i].program_id_index * + SOLANA_ACCOUNT_ADDRESS_LENGTH, + system_program_id[SOLANA_ASSOCIATED_TOKEN_PROGRAM_ID_INDEX], + SOLANA_ACCOUNT_ADDRESS_LENGTH) == 0) { // no opaque data or instruction enum to validate // do nothing diff --git a/apps/solana_app/solana_txn_helpers.h b/apps/solana_app/solana_txn_helpers.h index 81267a73a..80bb7d0a4 100644 --- a/apps/solana_app/solana_txn_helpers.h +++ b/apps/solana_app/solana_txn_helpers.h @@ -175,8 +175,11 @@ typedef struct solana_unsigned_txn { uint8_t *blockhash; uint16_t instructions_count; // deserialization only supports max 4 - // instructions: compute unit limit, compute unit price, create account and transfer - solana_instruction instruction[4]; ///< Expects max 4 instructions: TODO: HANDLE ANY NUMBER/TYPE OF INSTRUCTIONS + // instructions: compute unit limit, compute + // unit price, create account and transfer + solana_instruction + instruction[4]; ///< Expects max 4 instructions: TODO: HANDLE ANY + ///< NUMBER/TYPE OF INSTRUCTIONS uint8_t transfer_instruction_index; // Expects only 1 transfer instruction uint32_t compute_unit_limit; // To calculate priority fee uint64_t compute_unit_price_micro_lamports; From e80edc641baec437893fd40632bb5b90dc4290a0 Mon Sep 17 00:00:00 2001 From: Muzaffar Ahmad Bhat Date: Fri, 24 Jan 2025 17:55:24 +0530 Subject: [PATCH 19/19] fix: Resolve review comments --- apps/solana_app/solana_priv.h | 1 + apps/solana_app/solana_sign_txn.c | 18 +++++++++--------- apps/solana_app/solana_txn_helpers.c | 14 ++++++++------ apps/solana_app/solana_txn_helpers.h | 9 ++++++--- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/apps/solana_app/solana_priv.h b/apps/solana_app/solana_priv.h index 0df760524..8e1a5a74d 100644 --- a/apps/solana_app/solana_priv.h +++ b/apps/solana_app/solana_priv.h @@ -34,6 +34,7 @@ typedef struct { uint8_t *transaction; /// store for decoded unsigned transaction info solana_unsigned_txn transaction_info; + solana_txn_extra_data extra_data; bool is_token_transfer_transaction; solana_sign_txn_initiate_token_data_t token_data; diff --git a/apps/solana_app/solana_sign_txn.c b/apps/solana_app/solana_sign_txn.c index 001064804..dbda91058 100644 --- a/apps/solana_app/solana_sign_txn.c +++ b/apps/solana_app/solana_sign_txn.c @@ -347,7 +347,8 @@ STATIC bool solana_fetch_valid_transaction(solana_query_t *query) { if (SOL_OK != solana_byte_array_to_unsigned_txn( solana_txn_context->transaction, total_size, - &solana_txn_context->transaction_info) || + &solana_txn_context->transaction_info, + &solana_txn_context->extra_data) || SOL_OK != solana_validate_unsigned_txn(&solana_txn_context->transaction_info)) { return false; @@ -357,17 +358,16 @@ STATIC bool solana_fetch_valid_transaction(solana_query_t *query) { } static bool verify_priority_fee() { - if (solana_txn_context->transaction_info.compute_unit_price_micro_lamports > - 0) { + if (solana_txn_context->extra_data.compute_unit_price_micro_lamports > 0) { // verify priority fee uint64_t priority_fee, carry; // Capacity to multiply 2 numbers upto 8-byte value and store the result in // 2 separate 8-byte variables - priority_fee = mul128( - solana_txn_context->transaction_info.compute_unit_price_micro_lamports, - solana_txn_context->transaction_info.compute_unit_limit, - &carry); + priority_fee = + mul128(solana_txn_context->extra_data.compute_unit_price_micro_lamports, + solana_txn_context->extra_data.compute_unit_limit, + &carry); // prepare the whole 128-bit little-endian representation of priority fee uint8_t be_micro_lamports[16] = {0}; @@ -412,7 +412,7 @@ static bool verify_solana_transfer_sol_transaction() { size_t address_size = sizeof(address); const uint8_t transfer_instruction_index = - solana_txn_context->transaction_info.transfer_instruction_index; + solana_txn_context->extra_data.transfer_instruction_index; // verify recipient address; if (!b58enc(address, &address_size, @@ -590,7 +590,7 @@ static bool is_token_whitelisted(const uint8_t *address, static bool verify_solana_transfer_token_transaction() { const uint8_t transfer_instruction_index = - solana_txn_context->transaction_info.transfer_instruction_index; + solana_txn_context->extra_data.transfer_instruction_index; const uint8_t *token_mint = solana_txn_context->transaction_info .instruction[transfer_instruction_index] diff --git a/apps/solana_app/solana_txn_helpers.c b/apps/solana_app/solana_txn_helpers.c index d2f916665..a7f354d95 100644 --- a/apps/solana_app/solana_txn_helpers.c +++ b/apps/solana_app/solana_txn_helpers.c @@ -119,7 +119,8 @@ uint16_t get_compact_array_size(const uint8_t *data, int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, uint16_t byte_array_size, - solana_unsigned_txn *utxn) { + solana_unsigned_txn *utxn, + solana_txn_extra_data *extra_data) { if (byte_array == NULL || utxn == NULL) return SOL_ERROR; memzero(utxn, sizeof(solana_unsigned_txn)); @@ -179,7 +180,8 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, SOLANA_ACCOUNT_ADDRESS_LENGTH * 2, system_program_id[SOLANA_COMPUTE_BUDGET_PROGRAM_ID_INDEX]); - utxn->compute_unit_limit = utxn->compute_unit_price_micro_lamports = 0; + extra_data->compute_unit_limit = + extra_data->compute_unit_price_micro_lamports = 0; for (int i = 0; i < utxn->instructions_count; i++) { utxn->instruction[i].program_id_index = *(byte_array + offset++); @@ -210,7 +212,7 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, utxn->instruction[i].opaque_data_length == 0) return SOL_D_MIN_LENGTH; - utxn->transfer_instruction_index = i; + extra_data->transfer_instruction_index = i; uint32_t instruction_enum = U32_READ_LE_ARRAY(utxn->instruction[i].opaque_data); @@ -241,7 +243,7 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, utxn->instruction[i].opaque_data_length == 0) return SOL_D_MIN_LENGTH; - utxn->transfer_instruction_index = i; + extra_data->transfer_instruction_index = i; uint8_t instruction_enum = *(utxn->instruction[i].opaque_data); @@ -293,13 +295,13 @@ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, uint8_t instruction_enum = *(utxn->instruction[i].opaque_data); switch (instruction_enum) { case SCBI_SET_COMPUTE_UNIT_LIMIT: - utxn->compute_unit_limit = + extra_data->compute_unit_limit = utxn->instruction[i].program.compute_unit_limit_data.units = U32_READ_LE_ARRAY(utxn->instruction[i].opaque_data + 1); break; case SCBI_SET_COMPUTE_UNIT_PRICE: - utxn->compute_unit_price_micro_lamports = + extra_data->compute_unit_price_micro_lamports = utxn->instruction[i] .program.compute_unit_price_data.micro_lamports = U64_READ_LE_ARRAY(utxn->instruction[i].opaque_data + 1); diff --git a/apps/solana_app/solana_txn_helpers.h b/apps/solana_app/solana_txn_helpers.h index 80bb7d0a4..27dbd4c7c 100644 --- a/apps/solana_app/solana_txn_helpers.h +++ b/apps/solana_app/solana_txn_helpers.h @@ -180,11 +180,13 @@ typedef struct solana_unsigned_txn { solana_instruction instruction[4]; ///< Expects max 4 instructions: TODO: HANDLE ANY ///< NUMBER/TYPE OF INSTRUCTIONS +} solana_unsigned_txn; + +typedef struct { uint8_t transfer_instruction_index; // Expects only 1 transfer instruction uint32_t compute_unit_limit; // To calculate priority fee uint64_t compute_unit_price_micro_lamports; - -} solana_unsigned_txn; +} solana_txn_extra_data; /***************************************************************************** * EXPORTED VARIABLES @@ -227,7 +229,8 @@ uint16_t get_compact_array_size(const uint8_t *data, */ int solana_byte_array_to_unsigned_txn(uint8_t *byte_array, uint16_t byte_array_size, - solana_unsigned_txn *utxn); + solana_unsigned_txn *utxn, + solana_txn_extra_data *extra_data); /** * @brief Validate the deserialized unsigned transaction