diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dfbb38d..2d088483 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,6 +96,7 @@ file(GLOB_RECURSE LIB_SRC ${CMAKE_CURRENT_SOURCE_DIR}/app/src/hdpath.c ${CMAKE_CURRENT_SOURCE_DIR}/app/src/parser_impl.c ${CMAKE_CURRENT_SOURCE_DIR}/app/src/json/json_parser.c + ${CMAKE_CURRENT_SOURCE_DIR}/app/src/tx_metadata.c app/src/base32.c app/src/crypto.c ) diff --git a/app/src/addr.c b/app/src/addr.c index 125c3484..d9ee7797 100644 --- a/app/src/addr.c +++ b/app/src/addr.c @@ -22,130 +22,113 @@ #include "app_mode.h" #include "hdpath.h" +#include "screens.h" + bool hasPubkey; uint8_t pubkey_to_display[SECP256_PK_LEN]; -//Small trick to avoid duplicated code here which was quite error prone: -//displayIdx is either the index of page to display, or may be a negative integer. -//In the second case this is used to count the number of pages -//If displayIdx is negative, all other values are undefined -zxerr_t addr_getItem_internal(int8_t *displayIdx, - char *outKey, uint16_t outKeyLen, - char *outVal, uint16_t outValLen, - uint8_t pageIdx, uint8_t *pageCount) { - zemu_log_stack("addr_getItem_internal"); - - #define SCREEN(condition) if ((condition) && ((*displayIdx)--==0) && pageCount && (*pageCount = 1)) +//this defines addr_internal function +BEGIN_SCREENS_FUNCTION(addr, zxerr_t, zxerr_ok, zxerr_no_data, zxerr_no_data) uint8_t show_address_yes = (show_address == SHOW_ADDRESS_YES || show_address == SHOW_ADDRESS_YES_HASH_MISMATCH); - SCREEN(hasPubkey) { - snprintf(outKey, outKeyLen, "Pub Key"); - // +1 is to skip 0x04 prefix that indicates uncompresed key - pageHexString(outVal, outValLen, pubkey_to_display+1, sizeof(pubkey_to_display)-1, pageIdx, pageCount); - return zxerr_ok; + if (hasPubkey) { + BEGIN_SCREEN + snprintf(outKey, outKeyLen, "Pub Key"); + // +1 is to skip 0x04 prefix that indicates uncompresed key + pageHexString(outVal, outValLen, pubkey_to_display+1, sizeof(pubkey_to_display)-1, pageIdx, pageCount); + END_SCREEN } - - //this indicates error in pubkey derivation (possible only when in menu_handler - in apdu_handler we throw) - SCREEN(!hasPubkey && show_address_yes) { - snprintf(outKey, outKeyLen, "Error"); - pageString(outVal, outValLen, " deriving public key.", pageIdx, pageCount); - return zxerr_ok; + + if (!hasPubkey && show_address_yes) { + BEGIN_SCREEN + snprintf(outKey, outKeyLen, "Error"); + pageString(outVal, outValLen, " deriving public key.", pageIdx, pageCount); + END_SCREEN } - SCREEN(true) { - switch(show_address) { - case SHOW_ADDRESS_ERROR: + //this indicates error in pubkey derivation (possible only when in menu_handler - in apdu_handler we throw) + switch(show_address) { + case SHOW_ADDRESS_ERROR: + BEGIN_SCREEN snprintf(outKey, outKeyLen, "Error reading"); pageString(outVal, outValLen, "account data.", pageIdx, pageCount); - return zxerr_ok; - case SHOW_ADDRESS_EMPTY_SLOT: -#if defined(TARGET_NANOS) - snprintf(outKey, outKeyLen, "Account data"); - pageString(outVal, outValLen, "not saved on the device.", pageIdx, pageCount); -#else - snprintf(outKey, outKeyLen, "Address:"); - pageString(outVal, outValLen, "Account data not saved on the device.", pageIdx, pageCount); -#endif - return zxerr_ok; - case SHOW_ADDRESS_HDPATHS_NOT_EQUAL: + END_SCREEN + break; + case SHOW_ADDRESS_EMPTY_SLOT: + BEGIN_SCREEN + #if defined(TARGET_NANOS) + snprintf(outKey, outKeyLen, "Account data"); + pageString(outVal, outValLen, "not saved on the device.", pageIdx, pageCount); + #else + snprintf(outKey, outKeyLen, "Address:"); + pageString(outVal, outValLen, "Account data not saved on the device.", pageIdx, pageCount); + #endif + END_SCREEN + break; + case SHOW_ADDRESS_HDPATHS_NOT_EQUAL: + BEGIN_SCREEN snprintf(outKey, outKeyLen, "Address:"); pageString(outVal, outValLen, "Other path is saved on the device.", pageIdx, pageCount); - return zxerr_ok; - case SHOW_ADDRESS_YES: - case SHOW_ADDRESS_YES_HASH_MISMATCH: + END_SCREEN + break; + case SHOW_ADDRESS_YES: + case SHOW_ADDRESS_YES_HASH_MISMATCH: + BEGIN_SCREEN snprintf(outKey, outKeyLen, "Address:"); pageHexString(outVal, outValLen, address_to_display.data, sizeof(address_to_display.data), pageIdx, pageCount); return zxerr_ok; - default: - return zxerr_no_data; - } + END_SCREEN + break; + default: + return zxerr_unknown; } - SCREEN(show_address_yes) { -#if defined(TARGET_NANOS) - snprintf(outKey, outKeyLen, "Verify if this"); - snprintf(outVal, outValLen, " public key was added to"); -#else - snprintf(outKey, outKeyLen, "Warning:"); - snprintf(outVal, outValLen, "Verify if this public key was added to"); -#endif - return zxerr_ok; + if (show_address_yes) { + BEGIN_SCREEN + #if defined(TARGET_NANOS) + snprintf(outKey, outKeyLen, "Verify if this"); + snprintf(outVal, outValLen, " public key was added to"); + #else + snprintf(outKey, outKeyLen, "Warning:"); + snprintf(outVal, outValLen, "Verify if this public key was added to"); + #endif + END_SCREEN } - SCREEN(show_address_yes) { - #if defined(TARGET_NANOS) - array_to_hexstr(outKey, outKeyLen, address_to_display.data, sizeof(address_to_display.data)); - snprintf(outVal, outValLen, " using any Flow blockch. explorer."); - #else - char buffer[2*sizeof(address_to_display.data)+1]; - array_to_hexstr(buffer, sizeof(buffer), address_to_display.data, sizeof(address_to_display.data)); - snprintf(outVal, outValLen, "%s using any Flow blockchain explorer.", buffer); - snprintf(outKey, outKeyLen, ""); - #endif - return zxerr_ok; + if (show_address_yes) { + BEGIN_SCREEN + #if defined(TARGET_NANOS) + array_to_hexstr(outKey, outKeyLen, address_to_display.data, sizeof(address_to_display.data)); + snprintf(outVal, outValLen, " using any Flow blockch. explorer."); + #else + char buffer[2*sizeof(address_to_display.data)+1]; + array_to_hexstr(buffer, sizeof(buffer), address_to_display.data, sizeof(address_to_display.data)); + snprintf(outVal, outValLen, "%s using any Flow blockchain explorer.", buffer); + snprintf(outKey, outKeyLen, ""); + #endif + END_SCREEN } - SCREEN(app_mode_expert() && hasPubkey) { - snprintf(outKey, outKeyLen, "Your Path"); - char buffer[100]; - path_options_to_string(buffer, sizeof(buffer), hdPath.data, HDPATH_LEN_DEFAULT, cryptoOptions & 0xFF00); //show curve only - pageString(outVal, outValLen, buffer, pageIdx, pageCount); - return zxerr_ok; + if (app_mode_expert() && hasPubkey) { + BEGIN_SCREEN + snprintf(outKey, outKeyLen, "Your Path"); + char buffer[100]; + path_options_to_string(buffer, sizeof(buffer), hdPath.data, HDPATH_LEN_DEFAULT, cryptoOptions & 0xFF00); //show curve only + pageString(outVal, outValLen, buffer, pageIdx, pageCount); + END_SCREEN } - return zxerr_no_data; - - #undef SCREEN -} +END_SCREENS_FUNCTION -#define ARBITRARY_NEGATIVE_INTEGER -1 zxerr_t addr_getNumItems(uint8_t *num_items) { - int8_t displays = ARBITRARY_NEGATIVE_INTEGER; - zxerr_t err = addr_getItem_internal(&displays, NULL, 0, NULL, 0, 0, NULL); - - int8_t pages = ARBITRARY_NEGATIVE_INTEGER - displays; - - if (pages < 0) { - num_items = 0; - return zxerr_unknown; - } - - *num_items = (uint8_t) pages; - - if (err == zxerr_no_data) { - return zxerr_ok; - } - if (err == zxerr_ok) { - return zxerr_unknown; - } - return err; + return addr_internal(MAX_DISPLAYS, NULL, 0, NULL, 0, 0, num_items); } -zxerr_t addr_getItem(int8_t displayIdx, +zxerr_t addr_getItem(uint8_t displayIdx, char *outKey, uint16_t outKeyLen, char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount) { - return addr_getItem_internal(&displayIdx, outKey, outKeyLen, outVal, outValLen, pageIdx, pageCount); + return addr_internal(displayIdx, outKey, outKeyLen, outVal, outValLen, pageIdx, pageCount); } diff --git a/app/src/parser.c b/app/src/parser.c index d1b1cfea..4dc8af27 100644 --- a/app/src/parser.c +++ b/app/src/parser.c @@ -58,11 +58,6 @@ parser_error_t parser_validate(const parser_context_t *ctx) { return PARSER_OK; } -parser_error_t parser_getNumItems(const parser_context_t *ctx, uint8_t *num_items) { - CHECK_PARSER_ERR(_getNumItems(ctx, &parser_tx_obj, num_items)) - return PARSER_OK; -} - // based on Dapper provided code at https://github.com/onflow/flow-go-sdk/blob/96796f0cabc1847d7879a5230ab55fd3cdd41ae8/address.go#L286 const uint16_t linearCodeN = 64; @@ -163,7 +158,7 @@ parser_error_t parser_printChainID(const flow_payer_t *v, } parser_error_t parser_printArgument(const flow_argument_list_t *v, uint8_t argIndex, - char *expectedType, jsmntype_t jsonType, + const char *expectedType, jsmntype_t jsonType, char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount) { MEMZERO(outVal, outValLen); @@ -177,6 +172,7 @@ parser_error_t parser_printArgument(const flow_argument_list_t *v, uint8_t argIn char bufferUI[ARGUMENT_BUFFER_SIZE_STRING]; uint16_t valueTokenIndex; + CHECK_PARSER_ERR(json_matchKeyValue(&parsedJson, 0, expectedType, jsonType, &valueTokenIndex)) CHECK_PARSER_ERR(json_extractToken(bufferUI, sizeof(bufferUI), &parsedJson, valueTokenIndex)) pageString(outVal, outValLen, bufferUI, pageIdx, pageCount); @@ -190,9 +186,9 @@ parser_error_t parser_printArgument(const flow_argument_list_t *v, uint8_t argIn } parser_error_t parser_printOptionalArgument(const flow_argument_list_t *v, uint8_t argIndex, - char *expectedType, jsmntype_t jsonType, - char *outVal, uint16_t outValLen, - uint8_t pageIdx, uint8_t *pageCount) { + const char *expectedType, jsmntype_t jsonType, + char *outVal, uint16_t outValLen, + uint8_t pageIdx, uint8_t *pageCount) { MEMZERO(outVal, outValLen); if (argIndex >= v->argCount) { @@ -221,7 +217,7 @@ parser_error_t parser_printOptionalArgument(const flow_argument_list_t *v, uint8 } parser_error_t parser_printArgumentArray(const flow_argument_list_t *v, uint8_t argIndex, uint8_t arrayIndex, - char *expectedType, jsmntype_t jsonType, + const char *expectedType, jsmntype_t jsonType, char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount) { MEMZERO(outVal, outValLen); @@ -255,7 +251,7 @@ parser_error_t parser_printArgumentArray(const flow_argument_list_t *v, uint8_t } parser_error_t parser_printArgumentOptionalArray(const flow_argument_list_t *v, uint8_t argIndex, uint8_t arrayIndex, - char *expectedType, jsmntype_t jsonType, + const char *expectedType, jsmntype_t jsonType, char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount) { MEMZERO(outVal, outValLen); @@ -411,44 +407,142 @@ parser_error_t parser_printAuthorizer(const flow_proposal_authorizer_t *v, return PARSER_OK; } -parser_error_t parser_getItemAfterArguments(__Z_UNUSED const parser_context_t *ctx, - uint16_t displayIdx, - char *outKey, uint16_t outKeyLen, - char *outVal, uint16_t outValLen, - uint8_t pageIdx, uint8_t *pageCount) { - switch (displayIdx) { - case 0: - snprintf(outKey, outKeyLen, "Ref Block"); - return parser_printBlockId(&parser_tx_obj.referenceBlockId, outVal, outValLen, pageIdx, pageCount); - case 1: - snprintf(outKey, outKeyLen, "Gas Limit"); - return parser_printGasLimit(&parser_tx_obj.gasLimit, outVal, outValLen, pageIdx, pageCount); - case 2: - snprintf(outKey, outKeyLen, "Prop Key Addr"); - return parser_printPropKeyAddr(&parser_tx_obj.proposalKeyAddress, outVal, outValLen, pageIdx, pageCount); - case 3: - snprintf(outKey, outKeyLen, "Prop Key Id"); - return parser_printPropKeyId(&parser_tx_obj.proposalKeyId, outVal, outValLen, pageIdx, pageCount); - case 4: - snprintf(outKey, outKeyLen, "Prop Key Seq Num"); - return parser_printPropSeqNum(&parser_tx_obj.proposalKeySequenceNumber, outVal, outValLen, pageIdx, - pageCount); - case 5: - snprintf(outKey, outKeyLen, "Payer"); - return parser_printPayer(&parser_tx_obj.payer, outVal, outValLen, pageIdx, pageCount); - default: - break; + +//Small trick to avoid duplicated code here which was quite error prone: +//displayIdx is either the index of page to display, or GET_NUM_ITEMS_DISPLAY_IDX_STARTING_VALUE +//In the second case this is used to count the number of pages +//If displayIdx is GET_NUM_ITEMS_DISPLAY_IDX_STARTING_VALUE, all other values are NULL/0 +//Their use should be hiden behind SCREEN macro +#define GET_NUM_ITEMS_DISPLAY_IDX_STARTING_VALUE (-1) + +parser_error_t parser_getItem_internal(int8_t *displayIdx, + char *outKey, uint16_t outKeyLen, + char *outVal, uint16_t outValLen, + uint8_t pageIdx, uint8_t *pageCount) { + zemu_log_stack("parser_getItem_internal"); + + //validate contract + if ((*displayIdx)>=0) { + if (outKey==NULL || outVal==NULL || pageCount==NULL) { + return PARSER_UNEXPECTED_ERROR; + } + } + else if ((*displayIdx) == GET_NUM_ITEMS_DISPLAY_IDX_STARTING_VALUE) { + if (outKey!=NULL || outVal!=NULL || pageCount!=NULL || outKeyLen!=0 || outValLen!=0 || pageIdx!=0) { + return PARSER_UNEXPECTED_ERROR; + } + } + else { + return PARSER_UNEXPECTED_ERROR; + } + + //(*displayIdx!=INT8_MIN) : this prevents displayIdx to loop around from negative valiues to positive ones + //(*displayIdx)--==0 : If displayIdx is positive (and not INT8_MAX), this finds the right screen in the end + //pageCount && (*pageCount = 1) : We need to set *pageCount (in case it is not set in the screen) but only if it is not NULL + //Do not forget to break after switch/case even if you return from within SCREEN(true) block + #define SCREEN(condition) if ((condition) && (*displayIdx!=INT8_MIN) && ((*displayIdx)--==0) && pageCount && (*pageCount = 1)) + + SCREEN(true) { + snprintf(outKey, outKeyLen, "Type"); + snprintf(outVal, outValLen, "%s", parser_tx_obj.metadata.txName); + return PARSER_OK; } - displayIdx -= 6; - if (displayIdx < parser_tx_obj.authorizers.authorizer_count) { - snprintf(outKey, outKeyLen, "Authorizer %d", displayIdx + 1); - return parser_printAuthorizer(&parser_tx_obj.authorizers.authorizer[displayIdx], outVal, outValLen, pageIdx, - pageCount); + SCREEN(true) { + snprintf(outKey, outKeyLen, "ChainID"); + return parser_printChainID(&parser_tx_obj.payer, outVal, outValLen, pageIdx, pageCount); + } + + //Arguments + uint8_t screenCount = 0; + for(size_t i=0; iargumentType) { + case ARGUMENT_TYPE_NORMAL: + SCREEN(true) { + snprintf(outKey, outKeyLen, "%s", marg->displayKey); + return parser_printArgument(&parser_tx_obj.arguments, marg->argumentIndex, + marg->jsonExpectedType, marg->jsonExpectedKind, + outVal, outValLen, pageIdx, pageCount); + } + break; + case ARGUMENT_TYPE_OPTIONAL: + SCREEN(true) { + snprintf(outKey, outKeyLen, "%s", marg->displayKey); + return parser_printOptionalArgument(&parser_tx_obj.arguments, marg->argumentIndex, + marg->jsonExpectedType, marg->jsonExpectedKind, + outVal, outValLen, pageIdx, pageCount); + } + break; + case ARGUMENT_TYPE_ARRAY: + CHECK_PARSER_ERR(_countArgumentItems(&parser_tx_obj.arguments, marg->argumentIndex, + marg->arrayMinElements, marg->arrayMaxElements, &screenCount)); + for(size_t j=0; jdisplayKey, (int)(j+1)); + return parser_printArgumentArray(&parser_tx_obj.arguments, marg->argumentIndex, j, + marg->jsonExpectedType, marg->jsonExpectedKind, + outVal, outValLen, pageIdx, pageCount); + + } + } + break; + case ARGUMENT_TYPE_OPTIONALARRAY: + CHECK_PARSER_ERR(_countArgumentOptionalItems(&parser_tx_obj.arguments, marg->argumentIndex, + marg->arrayMinElements, marg->arrayMaxElements, &screenCount)); + for(size_t j=0; jdisplayKey, (int)(j+1)); + return parser_printArgumentOptionalArray(&parser_tx_obj.arguments, marg->argumentIndex, j, + marg->jsonExpectedType, marg->jsonExpectedKind, + outVal, outValLen, pageIdx, pageCount); + + } + } + break; + default: + return PARSER_METADATA_ERROR; + } } - displayIdx -= parser_tx_obj.authorizers.authorizer_count; - if (app_mode_expert() && displayIdx-- == 0) { + SCREEN(true) { + snprintf(outKey, outKeyLen, "Ref Block"); + return parser_printBlockId(&parser_tx_obj.referenceBlockId, outVal, outValLen, pageIdx, pageCount); + } + + SCREEN(true) { + snprintf(outKey, outKeyLen, "Gas Limit"); + return parser_printGasLimit(&parser_tx_obj.gasLimit, outVal, outValLen, pageIdx, pageCount); + } + + SCREEN(true) { + snprintf(outKey, outKeyLen, "Prop Key Addr"); + return parser_printPropKeyAddr(&parser_tx_obj.proposalKeyAddress, outVal, outValLen, pageIdx, pageCount); + } + + SCREEN(true) { + snprintf(outKey, outKeyLen, "Prop Key Id"); + return parser_printPropKeyId(&parser_tx_obj.proposalKeyId, outVal, outValLen, pageIdx, pageCount); + } + + SCREEN(true) { + snprintf(outKey, outKeyLen, "Prop Key Seq Num"); + return parser_printPropSeqNum(&parser_tx_obj.proposalKeySequenceNumber, outVal, outValLen, pageIdx, pageCount); + } + + SCREEN(true) { + snprintf(outKey, outKeyLen, "Payer"); + return parser_printPayer(&parser_tx_obj.payer, outVal, outValLen, pageIdx, pageCount); + } + + for(size_t i=0; i= numItems) { - return PARSER_NO_DATA; +parser_error_t parser_getItem(__Z_UNUSED const parser_context_t *ctx, uint8_t displayIdx, + char *outKey, uint16_t outKeyLen, + char *outVal, uint16_t outValLen, + uint8_t pageIdx, uint8_t *pageCount) { + if (displayIdx > INT8_MAX) { + return PARSER_DISPLAY_IDX_OUT_OF_RANGE; } - *pageCount = 1; - - switch (parser_tx_obj.script.type) { - case SCRIPT_UNKNOWN: - return PARSER_UNEXPECTED_SCRIPT; - case SCRIPT_TOKEN_TRANSFER: - return parser_getItemTokenTransfer(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, pageIdx, - pageCount); - case SCRIPT_CREATE_ACCOUNT: - return parser_getItemCreateAccount(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, pageIdx, - pageCount); - case SCRIPT_ADD_NEW_KEY: - return parser_getItemAddNewKey(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, pageIdx, - pageCount); - case SCRIPT_TH01_WITHDRAW_UNLOCKED_TOKENS: - return parser_getItemWithdrawUnlockedTokens(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, - pageIdx, pageCount); - case SCRIPT_TH02_DEPOSIT_UNLOCKED_TOKENS: - return parser_getItemDepositUnlockedTokens(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, - pageIdx, pageCount); - case SCRIPT_TH06_REGISTER_NODE: - return parser_getItemRegisterNode(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, - pageIdx, pageCount); - case SCRIPT_TH08_STAKE_NEW_TOKENS: - return parser_getItemStakeNewTokens(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, - pageIdx, pageCount); - case SCRIPT_TH09_RESTAKE_UNSTAKED_TOKENS: - return parser_getItemRestakeUnstakedTokens(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, - pageIdx, pageCount); - case SCRIPT_TH10_RESTAKE_REWARDED_TOKENS: - return parser_getItemRestakeRewardedTokens(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, - pageIdx, pageCount); - case SCRIPT_TH11_UNSTAKE_TOKENS: - return parser_getItemUnstakeTokens(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, - pageIdx, pageCount); - case SCRIPT_TH12_UNSTAKE_ALL_TOKENS: - return parser_getItemUnstakeAllTokens(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, - pageIdx, pageCount); - case SCRIPT_TH13_WITHDRAW_UNSTAKED_TOKENS: - return parser_getItemWithdrawUnstakedTokens(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, - pageIdx, pageCount); - case SCRIPT_TH14_WITHDRAW_REWARDED_TOKENS: - return parser_getItemWithdrawRewardedTokens(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, - pageIdx, pageCount); - case SCRIPT_TH16_REGISTER_OPERATOR_NODE: - return parser_getItemRegisterOperatorNode(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, - pageIdx, pageCount); - case SCRIPT_TH17_REGISTER_DELEGATOR: - return parser_getItemRegisterDelegator(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, - pageIdx, pageCount); - case SCRIPT_TH19_DELEGATE_NEW_TOKENS: - return parser_getItemDelegateNewTokens(ctx, displayIdx, outKey, outKeyLen, outVal, outValLen, - pageIdx, pageCount); - case SCRIPT_TH20_RESTAKE_UNSTAKED_DELEGATED_TOKENS: - return parser_getItemRestakeUnstakedDelegatedTokens(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_TH21_RESTAKE_REWARDED_DELEGATED_TOKENS: - return parser_getItemRestakeRewardedDelegatedTokens(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_TH22_UNSTAKE_DELEGATED_TOKENS: - return parser_getItemUnstakeDelegatedTokens(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_TH23_WITHDRAW_UNSTAKED_DELEGATED_TOKENS: - return parser_getItemWithdrawUnstakedDelegatedTokens(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_TH24_WITHDRAW_REWARDED_DELEGATED_TOKENS: - return parser_getItemWithdrawRewardedDelegatedTokens(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_TH25_UPDATE_NETWORKING_ADDRESS: - return parser_getItemUpdateNetworkingAddress(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO01_SETUP_STAKING_COLLECTION: - return parser_getItemSetupStaingCollection(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO02_REGISTER_DELEGATOR: - return parser_getItemRegisterDelegatorSCO(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO03_REGISTER_NODE: - return parser_getItemRegisterNodeSCO(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO04_CREATE_MACHINE_ACCOUNT: - return parser_getItemCreateMachineAccount(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO05_REQUEST_UNSTAKING: - return parser_getItemRequestUnstaking(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO06_STAKE_NEW_TOKENS: - return parser_getItemStakeNewTokensSCO(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO07_STAKE_REWARD_TOKENS: - return parser_getItemStakeRewardTokens(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO08_STAKE_UNSTAKED_TOKENS: - return parser_getItemStakeUnstakedTokens(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO09_UNSTAKE_ALL: - return parser_getItemUnstakeAll(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO10_WITHDRAW_REWARD_TOKENS: - return parser_getItemWithdrawRewardTokensSCO(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO11_WITHDRAW_UNSTAKED_TOKENS: - return parser_getItemWithdrawUnstakedTokensSCO(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO12_CLOSE_STAKE: - return parser_getItemCloseStake(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO13_TRANSFER_NODE: - return parser_getItemTransferNode(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO14_TRANSFER_DELEGATOR: - return parser_getItemTransferDelegator(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO15_WITHDRAW_FROM_MACHINE_ACCOUNT: - return parser_getItemWithdrawFromMachineAccount(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_SCO16_UPDATE_NETWORKING_ADDRESS: - return parser_getItemUpdateNetworkingAddressSCO(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_FUSD01_SETUP_FUSD_VAULT: - return parser_getItemSetupFUSDVault(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_FUSD02_TRANSFER_FUSD: - return parser_getItemTransferFUSD(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_TS01_SET_UP_TOPSHOT_COLLECTION: - return parser_getItemSetUpTopShotCollection(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_TS02_TRANSFER_TOP_SHOT_MOMENT: - return parser_getItemTransferTopShotMoment(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_USDC01_SETUP_USDC_VAULT: - return parser_getItemSetupUSDCVault(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - case SCRIPT_USDC02_TRANSFER_USDC: - return parser_getItemTransferUSDC(ctx, displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); - } - - return PARSER_UNEXPECTED_SCRIPT; + return parser_getItem_internal((int8_t *) &displayIdx, outKey, outKeyLen, outVal, outValLen, pageIdx, pageCount); } diff --git a/app/src/parser.h b/app/src/parser.h index f2d15327..e42b8919 100644 --- a/app/src/parser.h +++ b/app/src/parser.h @@ -35,11 +35,10 @@ parser_error_t parser_parse(parser_context_t *ctx, parser_error_t parser_validate(const parser_context_t *ctx); //// returns the number of items in the current parsing context -parser_error_t parser_getNumItems(const parser_context_t *ctx, uint8_t *num_items); +parser_error_t parser_getNumItems(__Z_UNUSED const parser_context_t *ctx, uint8_t *num_items); // retrieves a readable output for each field / page -parser_error_t parser_getItem(const parser_context_t *ctx, - uint16_t displayIdx, +parser_error_t parser_getItem(__Z_UNUSED const parser_context_t *ctx, uint8_t displayIdx, char *outKey, uint16_t outKeyLen, char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount); @@ -49,12 +48,12 @@ parser_error_t parser_getItem(const parser_context_t *ctx, ////for testing purposes parser_error_t parser_printOptionalArgument(const flow_argument_list_t *v, uint8_t argIndex, - char *expectedType, jsmntype_t jsonType, + const char *expectedType, jsmntype_t jsonType, char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount); parser_error_t parser_printArgumentOptionalArray(const flow_argument_list_t *v, uint8_t argIndex, uint8_t arrayIndex, - char *expectedType, jsmntype_t jsonType, + const char *expectedType, jsmntype_t jsonType, char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount); diff --git a/app/src/parser_common.h b/app/src/parser_common.h index 2bda1cbd..96a6e281 100644 --- a/app/src/parser_common.h +++ b/app/src/parser_common.h @@ -74,6 +74,11 @@ typedef enum { // Required fields PARSER_REQUIRED_NONCE, PARSER_REQUIRED_METHOD, + //Template errors + PARSER_METADATA_TOO_MANY_HASHES, + PARSER_METADATA_ERROR, + PARSER_METADATA_TOO_MANY_ARGUMENTS + } parser_error_t; typedef struct { diff --git a/app/src/parser_impl.c b/app/src/parser_impl.c index f8af4dfe..423a3750 100644 --- a/app/src/parser_impl.c +++ b/app/src/parser_impl.c @@ -110,6 +110,12 @@ const char *parser_getErrorDescription(parser_error_t err) { return "Required field nonce"; case PARSER_REQUIRED_METHOD: return "Required field method"; + case PARSER_METADATA_TOO_MANY_HASHES: + return "Metadata too many hashes"; + case PARSER_METADATA_ERROR: + return "Metadata unknown error"; + case PARSER_METADATA_TOO_MANY_ARGUMENTS: + return "Metadata too many arguments"; default: return "Unrecognized error code"; } @@ -125,7 +131,7 @@ __Z_INLINE char hexDigit(uint8_t v) { return '?'; } -parser_error_t json_validateToken(parsed_json_t *parsedJson, uint16_t tokenIdx) { +parser_error_t json_validateToken(const parsed_json_t *parsedJson, uint16_t tokenIdx) { if (!parsedJson->isValid) { return PARSER_JSON_INVALID; } @@ -146,7 +152,7 @@ parser_error_t json_validateToken(parsed_json_t *parsedJson, uint16_t tokenIdx) return PARSER_OK; } -parser_error_t json_extractToken(char *outVal, uint16_t outValLen, parsed_json_t *parsedJson, uint16_t tokenIdx) { +parser_error_t json_extractToken(char *outVal, uint16_t outValLen, const parsed_json_t *parsedJson, uint16_t tokenIdx) { MEMZERO(outVal, outValLen); CHECK_PARSER_ERR(json_validateToken(parsedJson, tokenIdx)) @@ -159,7 +165,7 @@ parser_error_t json_extractToken(char *outVal, uint16_t outValLen, parsed_json_t return PARSER_OK; } -parser_error_t json_matchToken(parsed_json_t *parsedJson, uint16_t tokenIdx, char *expectedValue) { +parser_error_t json_matchToken(const parsed_json_t *parsedJson, uint16_t tokenIdx, const char *expectedValue) { CHECK_PARSER_ERR(json_validateToken(parsedJson, tokenIdx)) const jsmntok_t token = parsedJson->tokens[tokenIdx]; @@ -178,7 +184,7 @@ parser_error_t json_matchToken(parsed_json_t *parsedJson, uint16_t tokenIdx, cha return PARSER_OK; } -parser_error_t json_matchNull(parsed_json_t *parsedJson, uint16_t tokenIdx) { +parser_error_t json_matchNull(const parsed_json_t *parsedJson, uint16_t tokenIdx) { CHECK_PARSER_ERR(json_validateToken(parsedJson, tokenIdx)) const jsmntok_t token = parsedJson->tokens[tokenIdx]; @@ -197,8 +203,8 @@ parser_error_t json_matchNull(parsed_json_t *parsedJson, uint16_t tokenIdx) { return PARSER_OK; } -parser_error_t json_matchKeyValue(parsed_json_t *parsedJson, - uint16_t tokenIdx, char *expectedType, jsmntype_t jsonType, uint16_t *valueTokenIdx) { +parser_error_t json_matchKeyValue(const parsed_json_t *parsedJson, + uint16_t tokenIdx, const char *expectedType, jsmntype_t jsonType, uint16_t *valueTokenIdx) { CHECK_PARSER_ERR(json_validateToken(parsedJson, tokenIdx)) if (! (tokenIdx + 4 < parsedJson->numberOfTokens)) { @@ -228,8 +234,8 @@ parser_error_t json_matchKeyValue(parsed_json_t *parsedJson, } //valueTokenIdx is JSON_MATCH_VALUE_IDX_NONE if the optional is null -parser_error_t json_matchOptionalKeyValue(parsed_json_t *parsedJson, - uint16_t tokenIdx, char *expectedType, jsmntype_t jsonType, uint16_t *valueTokenIdx) { +parser_error_t json_matchOptionalKeyValue(const parsed_json_t *parsedJson, + uint16_t tokenIdx, const char *expectedType, jsmntype_t jsonType, uint16_t *valueTokenIdx) { CHECK_PARSER_ERR(json_validateToken(parsedJson, tokenIdx)) if (!(tokenIdx + 4 < parsedJson->numberOfTokens)) { @@ -263,7 +269,7 @@ parser_error_t json_matchOptionalKeyValue(parsed_json_t *parsedJson, } //valueTokenIdx is JSON_MATCH_VALUE_IDX_NONE if the optional is null -parser_error_t json_matchOptionalArray(parsed_json_t *parsedJson, +parser_error_t json_matchOptionalArray(const parsed_json_t *parsedJson, uint16_t tokenIdx, uint16_t *valueTokenIdx) { CHECK_PARSER_ERR(json_validateToken(parsedJson, tokenIdx)) @@ -327,202 +333,21 @@ parser_error_t formatStrUInt8AsHex(const char *decStr, char *hexStr) { return PARSER_OK; } -parser_error_t json_extractString(char *outVal, uint16_t outValLen, parsed_json_t *parsedJson, uint16_t tokenIdx) { - MEMZERO(outVal, outValLen); - - uint16_t internalTokenElemIdx; - CHECK_PARSER_ERR(json_matchKeyValue( - parsedJson, tokenIdx, (char *) "String", JSMN_STRING, &internalTokenElemIdx)) - - CHECK_PARSER_ERR(json_extractToken(outVal, outValLen, parsedJson, internalTokenElemIdx)) - - return PARSER_OK; -} - -parser_error_t _matchScriptType(uint8_t scriptHash[32], script_type_e *scriptType) { - *scriptType = SCRIPT_UNKNOWN; - - char buffer[100]; - MEMZERO(buffer, sizeof(buffer)); - - // Check it is a known script digest - if (array_to_hexstr(buffer, sizeof(buffer), scriptHash, CX_SHA256_SIZE) != 64) { - return PARSER_UNEXPECTED_ERROR; - } - - struct known_script_entry { - script_type_e script_type; - char* template; - }; - - const struct known_script_entry KNOWN_TYPES[] = { - {SCRIPT_TOKEN_TRANSFER, TEMPLATE_HASH_TOKEN_TRANSFER_EMULATOR}, - {SCRIPT_TOKEN_TRANSFER, TEMPLATE_HASH_TOKEN_TRANSFER_TESTNET}, - {SCRIPT_TOKEN_TRANSFER, TEMPLATE_HASH_TOKEN_TRANSFER_MAINNET}, - - {SCRIPT_CREATE_ACCOUNT, TEMPLATE_HASH_CREATE_ACCOUNT}, - - {SCRIPT_ADD_NEW_KEY, TEMPLATE_HASH_ADD_NEW_KEY}, - - {SCRIPT_TH01_WITHDRAW_UNLOCKED_TOKENS, TEMPLATE_HASH_TH01_WITHDRAW_UNLOCKED_TOKENS_TESTNET}, - {SCRIPT_TH01_WITHDRAW_UNLOCKED_TOKENS, TEMPLATE_HASH_TH01_WITHDRAW_UNLOCKED_TOKENS_MAINNET}, - - {SCRIPT_TH02_DEPOSIT_UNLOCKED_TOKENS, TEMPLATE_HASH_TH02_DEPOSIT_UNLOCKED_TOKENS_TESTNET}, - {SCRIPT_TH02_DEPOSIT_UNLOCKED_TOKENS, TEMPLATE_HASH_TH02_DEPOSIT_UNLOCKED_TOKENS_MAINNET}, - - {SCRIPT_TH06_REGISTER_NODE, TEMPLATE_HASH_TH06_REGISTER_NODE_TESTNET}, - {SCRIPT_TH06_REGISTER_NODE, TEMPLATE_HASH_TH06_REGISTER_NODE_MAINNET}, - - {SCRIPT_TH08_STAKE_NEW_TOKENS, TEMPLATE_HASH_TH08_STAKE_NEW_TOKENS_TESTNET}, - {SCRIPT_TH08_STAKE_NEW_TOKENS, TEMPLATE_HASH_TH08_STAKE_NEW_TOKENS_MAINNET}, - - {SCRIPT_TH09_RESTAKE_UNSTAKED_TOKENS, TEMPLATE_HASH_TH09_RESTAKE_UNSTAKED_TOKENS_TESTNET}, - {SCRIPT_TH09_RESTAKE_UNSTAKED_TOKENS, TEMPLATE_HASH_TH09_RESTAKE_UNSTAKED_TOKENS_MAINNET}, - - {SCRIPT_TH10_RESTAKE_REWARDED_TOKENS, TEMPLATE_HASH_TH10_RESTAKE_REWARDED_TOKENS_TESTNET}, - {SCRIPT_TH10_RESTAKE_REWARDED_TOKENS, TEMPLATE_HASH_TH10_RESTAKE_REWARDED_TOKENS_MAINNET}, - - {SCRIPT_TH11_UNSTAKE_TOKENS, TEMPLATE_HASH_TH11_UNSTAKE_TOKENS_TESTNET}, - {SCRIPT_TH11_UNSTAKE_TOKENS, TEMPLATE_HASH_TH11_UNSTAKE_TOKENS_MAINNET}, - - {SCRIPT_TH12_UNSTAKE_ALL_TOKENS, TEMPLATE_HASH_TH12_UNSTAKE_ALL_TOKENS_TESTNET}, - {SCRIPT_TH12_UNSTAKE_ALL_TOKENS, TEMPLATE_HASH_TH12_UNSTAKE_ALL_TOKENS_MAINNET}, - - {SCRIPT_TH13_WITHDRAW_UNSTAKED_TOKENS, TEMPLATE_HASH_TH13_WITHDRAW_UNSTAKED_TOKENS_TESTNET}, - {SCRIPT_TH13_WITHDRAW_UNSTAKED_TOKENS, TEMPLATE_HASH_TH13_WITHDRAW_UNSTAKED_TOKENS_MAINNET}, - - {SCRIPT_TH14_WITHDRAW_REWARDED_TOKENS, TEMPLATE_HASH_TH14_WITHDRAW_REWARDED_TOKENS_TESTNET}, - {SCRIPT_TH14_WITHDRAW_REWARDED_TOKENS, TEMPLATE_HASH_TH14_WITHDRAW_REWARDED_TOKENS_MAINNET}, - - {SCRIPT_TH16_REGISTER_OPERATOR_NODE, TEMPLATE_HASH_TH16_REGISTER_OPERATOR_NODE_TESTNET}, - {SCRIPT_TH16_REGISTER_OPERATOR_NODE, TEMPLATE_HASH_TH16_REGISTER_OPERATOR_NODE_MAINNET}, - - {SCRIPT_TH17_REGISTER_DELEGATOR, TEMPLATE_HASH_TH17_REGISTER_DELEGATOR_TESTNET}, - {SCRIPT_TH17_REGISTER_DELEGATOR, TEMPLATE_HASH_TH17_REGISTER_DELEGATOR_MAINNET}, - - {SCRIPT_TH19_DELEGATE_NEW_TOKENS, TEMPLATE_HASH_TH19_DELEGATE_NEW_TOKENS_TESTNET}, - {SCRIPT_TH19_DELEGATE_NEW_TOKENS, TEMPLATE_HASH_TH19_DELEGATE_NEW_TOKENS_MAINNET}, - - {SCRIPT_TH20_RESTAKE_UNSTAKED_DELEGATED_TOKENS, TEMPLATE_HASH_TH20_RESTAKE_UNSTAKED_DELEGATED_TOKENS_TESTNET}, - {SCRIPT_TH20_RESTAKE_UNSTAKED_DELEGATED_TOKENS, TEMPLATE_HASH_TH20_RESTAKE_UNSTAKED_DELEGATED_TOKENS_MAINNET}, - - {SCRIPT_TH21_RESTAKE_REWARDED_DELEGATED_TOKENS, TEMPLATE_HASH_TH21_RESTAKE_REWARDED_DELEGATED_TOKENS_TESTNET}, - {SCRIPT_TH21_RESTAKE_REWARDED_DELEGATED_TOKENS, TEMPLATE_HASH_TH21_RESTAKE_REWARDED_DELEGATED_TOKENS_MAINNET}, - - {SCRIPT_TH22_UNSTAKE_DELEGATED_TOKENS, TEMPLATE_HASH_TH22_UNSTAKE_DELEGATED_TOKENS_TESTNET}, - {SCRIPT_TH22_UNSTAKE_DELEGATED_TOKENS, TEMPLATE_HASH_TH22_UNSTAKE_DELEGATED_TOKENS_MAINNET}, - - {SCRIPT_TH23_WITHDRAW_UNSTAKED_DELEGATED_TOKENS, TEMPLATE_HASH_TH23_WITHDRAW_UNSTAKED_DELEGATED_TOKENS_TESTNET}, - {SCRIPT_TH23_WITHDRAW_UNSTAKED_DELEGATED_TOKENS, TEMPLATE_HASH_TH23_WITHDRAW_UNSTAKED_DELEGATED_TOKENS_MAINNET}, - - {SCRIPT_TH24_WITHDRAW_REWARDED_DELEGATED_TOKENS, TEMPLATE_HASH_TH24_WITHDRAW_REWARDED_DELEGATED_TOKENS_TESTNET}, - {SCRIPT_TH24_WITHDRAW_REWARDED_DELEGATED_TOKENS, TEMPLATE_HASH_TH24_WITHDRAW_REWARDED_DELEGATED_TOKENS_MAINNET}, - - {SCRIPT_TH25_UPDATE_NETWORKING_ADDRESS, TEMPLATE_HASH_TH25_UPDATE_NETWORKING_ADDRESS_TESTNET}, - {SCRIPT_TH25_UPDATE_NETWORKING_ADDRESS, TEMPLATE_HASH_TH25_UPDATE_NETWORKING_ADDRESS_MAINNET}, - - {SCRIPT_SCO01_SETUP_STAKING_COLLECTION, TEMPLATE_HASH_SCO01_SETUP_STAKING_COLLECTION_TESTNET}, - {SCRIPT_SCO01_SETUP_STAKING_COLLECTION, TEMPLATE_HASH_SCO01_SETUP_STAKING_COLLECTION_MAINNET}, - - {SCRIPT_SCO02_REGISTER_DELEGATOR, TEMPLATE_HASH_SCO02_REGISTER_DELEGATOR_TESTNET}, - {SCRIPT_SCO02_REGISTER_DELEGATOR, TEMPLATE_HASH_SCO02_REGISTER_DELEGATOR_MAINNET}, - - {SCRIPT_SCO03_REGISTER_NODE, TEMPLATE_HASH_SCO0301_REGISTER_NODE_TESTNET}, - {SCRIPT_SCO03_REGISTER_NODE, TEMPLATE_HASH_SCO0301_REGISTER_NODE_MAINNET}, - - {SCRIPT_SCO04_CREATE_MACHINE_ACCOUNT, TEMPLATE_HASH_SCO0401_CREATE_MACHINE_ACCOUNT_TESTNET}, - {SCRIPT_SCO04_CREATE_MACHINE_ACCOUNT, TEMPLATE_HASH_SCO0401_CREATE_MACHINE_ACCOUNT_MAINNET}, - - {SCRIPT_SCO05_REQUEST_UNSTAKING, TEMPLATE_HASH_SCO05_REQUEST_UNSTAKING_TESTNET}, - {SCRIPT_SCO05_REQUEST_UNSTAKING, TEMPLATE_HASH_SCO05_REQUEST_UNSTAKING_MAINNET}, - - {SCRIPT_SCO06_STAKE_NEW_TOKENS, TEMPLATE_HASH_SCO06_STAKE_NEW_TOKENS_TESTNET}, - {SCRIPT_SCO06_STAKE_NEW_TOKENS, TEMPLATE_HASH_SCO06_STAKE_NEW_TOKENS_MAINNET}, - - {SCRIPT_SCO07_STAKE_REWARD_TOKENS, TEMPLATE_HASH_SCO07_STAKE_REWARD_TOKENS_TESTNET}, - {SCRIPT_SCO07_STAKE_REWARD_TOKENS, TEMPLATE_HASH_SCO07_STAKE_REWARD_TOKENS_MAINNET}, - - {SCRIPT_SCO08_STAKE_UNSTAKED_TOKENS, TEMPLATE_HASH_SCO08_STAKE_UNSTAKED_TOKENS_TESTNET}, - {SCRIPT_SCO08_STAKE_UNSTAKED_TOKENS, TEMPLATE_HASH_SCO08_STAKE_UNSTAKED_TOKENS_MAINNET}, - - {SCRIPT_SCO09_UNSTAKE_ALL, TEMPLATE_HASH_SCO09_UNSTAKE_ALL_TESTNET}, - {SCRIPT_SCO09_UNSTAKE_ALL, TEMPLATE_HASH_SCO09_UNSTAKE_ALL_MAINNET}, - - {SCRIPT_SCO10_WITHDRAW_REWARD_TOKENS, TEMPLATE_HASH_SCO10_WITHDRAW_REWARD_TOKENS_TESTNET}, - {SCRIPT_SCO10_WITHDRAW_REWARD_TOKENS, TEMPLATE_HASH_SCO10_WITHDRAW_REWARD_TOKENS_MAINNET}, - - {SCRIPT_SCO11_WITHDRAW_UNSTAKED_TOKENS, TEMPLATE_HASH_SCO11_WITHDRAW_UNSTAKED_TOKENS_TESTNET}, - {SCRIPT_SCO11_WITHDRAW_UNSTAKED_TOKENS, TEMPLATE_HASH_SCO11_WITHDRAW_UNSTAKED_TOKENS_MAINNET}, - - {SCRIPT_SCO12_CLOSE_STAKE, TEMPLATE_HASH_SCO12_CLOSE_STAKE_TESTNET}, - {SCRIPT_SCO12_CLOSE_STAKE, TEMPLATE_HASH_SCO12_CLOSE_STAKE_MAINNET}, - - {SCRIPT_SCO13_TRANSFER_NODE, TEMPLATE_HASH_SCO13_TRANSFER_NODE_TESTNET}, - {SCRIPT_SCO13_TRANSFER_NODE, TEMPLATE_HASH_SCO13_TRANSFER_NODE_MAINNET}, - - {SCRIPT_SCO14_TRANSFER_DELEGATOR, TEMPLATE_HASH_SCO14_TRANSFER_DELEGATOR_TESTNET}, - {SCRIPT_SCO14_TRANSFER_DELEGATOR, TEMPLATE_HASH_SCO14_TRANSFER_DELEGATOR_MAINNET}, - - {SCRIPT_SCO15_WITHDRAW_FROM_MACHINE_ACCOUNT, TEMPLATE_HASH_SCO15_WITHDRAW_FROM_MACHINE_ACCOUNT_TESTNET}, - {SCRIPT_SCO15_WITHDRAW_FROM_MACHINE_ACCOUNT, TEMPLATE_HASH_SCO15_WITHDRAW_FROM_MACHINE_ACCOUNT_MAINNET}, - - {SCRIPT_SCO16_UPDATE_NETWORKING_ADDRESS, TEMPLATE_HASH_SCO16_UPDATE_NETWORKING_ADDRESS_TESTNET}, - {SCRIPT_SCO16_UPDATE_NETWORKING_ADDRESS, TEMPLATE_HASH_SCO16_UPDATE_NETWORKING_ADDRESS_MAINNET}, - - {SCRIPT_FUSD01_SETUP_FUSD_VAULT, TEMPLATE_HASH_FUSD01_SETUP_FUSD_VAULT_TESTNET}, - {SCRIPT_FUSD01_SETUP_FUSD_VAULT, TEMPLATE_HASH_FUSD01_SETUP_FUSD_VAULT_MAINNET}, - - {SCRIPT_FUSD02_TRANSFER_FUSD, TEMPLATE_HASH_FUSD02_TRANSFER_FUSD_TESTNET}, - {SCRIPT_FUSD02_TRANSFER_FUSD, TEMPLATE_HASH_FUSD02_TRANSFER_FUSD_MAINNET}, - - {SCRIPT_TS01_SET_UP_TOPSHOT_COLLECTION, TEMPLATE_HASH_TS01_SET_UP_TOPSHOT_COLLECTION_TESTNET}, - {SCRIPT_TS01_SET_UP_TOPSHOT_COLLECTION, TEMPLATE_HASH_TS01_SET_UP_TOPSHOT_COLLECTION_MAINNET}, - - {SCRIPT_TS02_TRANSFER_TOP_SHOT_MOMENT, TEMPLATE_HASH_TS02_TRANSFER_TOP_SHOT_MOMENT_TESTNET}, - {SCRIPT_TS02_TRANSFER_TOP_SHOT_MOMENT, TEMPLATE_HASH_TS02_TRANSFER_TOP_SHOT_MOMENT_MAINNET}, - - {SCRIPT_USDC01_SETUP_USDC_VAULT, TEMPLATE_HASH_USDC01_SETUP_USDC_VAULT_TESTNET}, - {SCRIPT_USDC01_SETUP_USDC_VAULT, TEMPLATE_HASH_USDC01_SETUP_USDC_VAULT_MAINNET}, - - {SCRIPT_USDC02_TRANSFER_USDC, TEMPLATE_HASH_USDC02_TRANSFER_USDC_TESTNET}, - {SCRIPT_USDC02_TRANSFER_USDC, TEMPLATE_HASH_USDC02_TRANSFER_USDC_MAINNET}, - - {SCRIPT_SCO03_REGISTER_NODE, TEMPLATE_HASH_SCO0302_REGISTER_NODE_TESTNET}, - {SCRIPT_SCO03_REGISTER_NODE, TEMPLATE_HASH_SCO0302_REGISTER_NODE_MAINNET}, - - {SCRIPT_SCO04_CREATE_MACHINE_ACCOUNT, TEMPLATE_HASH_SCO0402_CREATE_MACHINE_ACCOUNT_TESTNET}, - {SCRIPT_SCO04_CREATE_MACHINE_ACCOUNT, TEMPLATE_HASH_SCO0402_CREATE_MACHINE_ACCOUNT_MAINNET}, - - // sentinel, do not remove - {0, NULL} - }; - - int i = 0; - while (KNOWN_TYPES[i].template) { - if (MEMCMP(PIC(KNOWN_TYPES[i].template), buffer, 64) == 0) { - *scriptType = KNOWN_TYPES[i].script_type; - return PARSER_OK; - } - i++; - } - - return PARSER_UNEXPECTED_SCRIPT; -} - -parser_error_t _readScript(parser_context_t *c, flow_script_t *v) { +parser_error_t _readScript(parser_context_t *c, parsed_tx_metadata_t *m) { rlp_kind_e kind; + parser_context_t script; uint32_t bytesConsumed; + uint8_t digest[CX_SHA256_SIZE]; - MEMZERO(v, sizeof(flow_script_t)); - - CHECK_PARSER_ERR(rlp_decode(c, &v->ctx, &kind, &bytesConsumed)); + CHECK_PARSER_ERR(rlp_decode(c, &script, &kind, &bytesConsumed)); CTX_CHECK_AND_ADVANCE(c, bytesConsumed) CHECK_KIND(kind, RLP_KIND_STRING) - MEMZERO(v->digest, sizeof(v->digest)); - sha256(v->ctx.buffer, v->ctx.bufferLen, v->digest); + MEMZERO(digest, sizeof(digest)); + sha256(script.buffer, script.bufferLen, digest); - CHECK_PARSER_ERR(_matchScriptType(v->digest, &v->type)) + MEMZERO(m, sizeof(parsed_tx_metadata_t)); + CHECK_PARSER_ERR(matchStoredTxMetadata(digest, m)) return PARSER_OK; } @@ -698,7 +523,7 @@ parser_error_t _read(parser_context_t *c, parser_tx_t *v) { CHECK_KIND(kind, RLP_KIND_LIST) // Go through the inner list - CHECK_PARSER_ERR(_readScript(&ctx_rootInnerList, &v->script)) + CHECK_PARSER_ERR(_readScript(&ctx_rootInnerList, &v->metadata)) CHECK_PARSER_ERR(_readArguments(&ctx_rootInnerList, &v->arguments)) CHECK_PARSER_ERR(_readReferenceBlockId(&ctx_rootInnerList, &v->referenceBlockId)) CHECK_PARSER_ERR(_readGasLimit(&ctx_rootInnerList, &v->gasLimit)) @@ -725,7 +550,7 @@ parser_error_t _validateTx(__Z_UNUSED const parser_context_t *c, __Z_UNUSED cons } parser_error_t _countArgumentItems(const flow_argument_list_t *v, uint8_t argumentIndex, - uint8_t max_number_of_items, uint8_t *number_of_items) { + uint8_t min_number_of_items, uint8_t max_number_of_items, uint8_t *number_of_items) { *number_of_items = 0; parsed_json_t parsedJson = {false}; @@ -741,7 +566,7 @@ parser_error_t _countArgumentItems(const flow_argument_list_t *v, uint8_t argume CHECK_PARSER_ERR(json_matchKeyValue(&parsedJson, 0, (char *) "Array", JSMN_ARRAY, &internalTokenElementIdx)); uint16_t arrayTokenCount; CHECK_PARSER_ERR(array_get_element_count(&parsedJson, internalTokenElementIdx, &arrayTokenCount)); - if (arrayTokenCount > max_number_of_items) { + if (arrayTokenCount < min_number_of_items || arrayTokenCount > max_number_of_items) { return PARSER_UNEXPECTED_NUMBER_ITEMS; } @@ -751,7 +576,7 @@ parser_error_t _countArgumentItems(const flow_argument_list_t *v, uint8_t argume //if Optional is null, number_of_items is set to 1 as one screen is needed to dispay "None" parser_error_t _countArgumentOptionalItems(const flow_argument_list_t *v, uint8_t argumentIndex, - uint8_t max_number_of_items, uint8_t *number_of_items) { + uint8_t min_number_of_items, uint8_t max_number_of_items, uint8_t *number_of_items) { *number_of_items = 0; parsed_json_t parsedJson = {false}; @@ -772,7 +597,7 @@ parser_error_t _countArgumentOptionalItems(const flow_argument_list_t *v, uint8_ // Get numnber of items uint16_t arrayTokenCount; CHECK_PARSER_ERR(array_get_element_count(&parsedJson, internalTokenElementIdx, &arrayTokenCount)); - if (arrayTokenCount > max_number_of_items) { + if (arrayTokenCount < min_number_of_items || arrayTokenCount > max_number_of_items) { return PARSER_UNEXPECTED_NUMBER_ITEMS; } @@ -780,161 +605,6 @@ parser_error_t _countArgumentOptionalItems(const flow_argument_list_t *v, uint8_ return PARSER_OK; } -parser_error_t _getNumItems(__Z_UNUSED const parser_context_t *c, const parser_tx_t *v, uint8_t *numItems) { - uint8_t argArrayLength = 0; - - uint8_t show_address_yes = (show_address == SHOW_ADDRESS_YES || show_address == SHOW_ADDRESS_YES_HASH_MISMATCH); - uint8_t extraItems = v->authorizers.authorizer_count; - extraItems += (show_address_yes && !addressUsedInTx) ? 1 : 0; - extraItems += (show_address == SHOW_ADDRESS_YES_HASH_MISMATCH) ? 1 : 0; - extraItems += show_address_yes ? 0 : 1; - extraItems += app_mode_expert() ? 1 : 0; - - switch (v->script.type) { - case SCRIPT_TOKEN_TRANSFER: - *numItems = 10 + extraItems; - return PARSER_OK; - case SCRIPT_CREATE_ACCOUNT: - //array length is checked while we are parsing it - CHECK_PARSER_ERR(_countArgumentItems(&v->arguments, 0, UINT8_MAX, &argArrayLength)) - *numItems = 8 + argArrayLength + extraItems; - return PARSER_OK; - case SCRIPT_ADD_NEW_KEY: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH01_WITHDRAW_UNLOCKED_TOKENS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH02_DEPOSIT_UNLOCKED_TOKENS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH06_REGISTER_NODE: - *numItems = 14 + extraItems; - return PARSER_OK; - case SCRIPT_TH08_STAKE_NEW_TOKENS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH09_RESTAKE_UNSTAKED_TOKENS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH10_RESTAKE_REWARDED_TOKENS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH11_UNSTAKE_TOKENS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH12_UNSTAKE_ALL_TOKENS: - *numItems = 8 + extraItems; - return PARSER_OK; - case SCRIPT_TH13_WITHDRAW_UNSTAKED_TOKENS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH14_WITHDRAW_REWARDED_TOKENS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH16_REGISTER_OPERATOR_NODE: - *numItems = 11 + extraItems; - return PARSER_OK; - case SCRIPT_TH17_REGISTER_DELEGATOR: - *numItems = 10 + extraItems; - return PARSER_OK; - case SCRIPT_TH19_DELEGATE_NEW_TOKENS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH20_RESTAKE_UNSTAKED_DELEGATED_TOKENS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH21_RESTAKE_REWARDED_DELEGATED_TOKENS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH22_UNSTAKE_DELEGATED_TOKENS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH23_WITHDRAW_UNSTAKED_DELEGATED_TOKENS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH24_WITHDRAW_REWARDED_DELEGATED_TOKENS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_TH25_UPDATE_NETWORKING_ADDRESS: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_SCO01_SETUP_STAKING_COLLECTION: - *numItems = 8 + extraItems; - return PARSER_OK; - case SCRIPT_SCO02_REGISTER_DELEGATOR: - *numItems = 10 + extraItems; - return PARSER_OK; - case SCRIPT_SCO03_REGISTER_NODE: - //array length is checked while we are parsing it - CHECK_PARSER_ERR(_countArgumentOptionalItems(&v->arguments, 6, UINT8_MAX, &argArrayLength)); - *numItems = 14 + argArrayLength + extraItems; - return PARSER_OK; - case SCRIPT_SCO04_CREATE_MACHINE_ACCOUNT: - //array length is checked while we are parsing it - CHECK_PARSER_ERR(_countArgumentItems(&v->arguments, 1, UINT8_MAX, &argArrayLength)) - *numItems = 9 + argArrayLength + extraItems; - return PARSER_OK; - case SCRIPT_SCO05_REQUEST_UNSTAKING: - *numItems = 11 + extraItems; - return PARSER_OK; - case SCRIPT_SCO06_STAKE_NEW_TOKENS: - *numItems = 11 + extraItems; - return PARSER_OK; - case SCRIPT_SCO07_STAKE_REWARD_TOKENS: - *numItems = 11 + extraItems; - return PARSER_OK; - case SCRIPT_SCO08_STAKE_UNSTAKED_TOKENS: - *numItems = 11 + extraItems; - return PARSER_OK; - case SCRIPT_SCO09_UNSTAKE_ALL: - *numItems = 9 + extraItems; - return PARSER_OK; - case SCRIPT_SCO10_WITHDRAW_REWARD_TOKENS: - *numItems = 11 + extraItems; - return PARSER_OK; - case SCRIPT_SCO11_WITHDRAW_UNSTAKED_TOKENS: - *numItems = 11 + extraItems; - return PARSER_OK; - case SCRIPT_SCO12_CLOSE_STAKE: - *numItems = 10 + extraItems; - return PARSER_OK; - case SCRIPT_SCO13_TRANSFER_NODE: - *numItems = 10 + extraItems; - return PARSER_OK; - case SCRIPT_SCO14_TRANSFER_DELEGATOR: - *numItems = 11 + extraItems; - return PARSER_OK; - case SCRIPT_SCO15_WITHDRAW_FROM_MACHINE_ACCOUNT: - *numItems = 10 + extraItems; - return PARSER_OK; - case SCRIPT_SCO16_UPDATE_NETWORKING_ADDRESS: - *numItems = 10 + extraItems; - return PARSER_OK; - case SCRIPT_FUSD01_SETUP_FUSD_VAULT: - *numItems = 8 + extraItems; - return PARSER_OK; - case SCRIPT_FUSD02_TRANSFER_FUSD: - *numItems = 10 + extraItems; - return PARSER_OK; - case SCRIPT_TS01_SET_UP_TOPSHOT_COLLECTION: - *numItems = 8 + extraItems; - return PARSER_OK; - case SCRIPT_TS02_TRANSFER_TOP_SHOT_MOMENT: - *numItems = 10 + extraItems; - return PARSER_OK; - case SCRIPT_USDC01_SETUP_USDC_VAULT: - *numItems = 8 + extraItems; - return PARSER_OK; - case SCRIPT_USDC02_TRANSFER_USDC: - *numItems = 10 + extraItems; - return PARSER_OK; - case SCRIPT_UNKNOWN: - default: - return PARSER_UNEXPECTED_SCRIPT; - } -} - void checkAddressUsedInTx() { addressUsedInTx = 0; int authCount = parser_tx_obj.authorizers.authorizer_count; diff --git a/app/src/parser_impl.h b/app/src/parser_impl.h index 89a8b3da..7d6bae2c 100644 --- a/app/src/parser_impl.h +++ b/app/src/parser_impl.h @@ -30,44 +30,38 @@ extern parser_tx_t parser_tx_obj; parser_error_t parser_init(parser_context_t *ctx, const uint8_t *buffer, uint16_t bufferSize); -parser_error_t _matchScriptType(uint8_t scriptHash[32], script_type_e *scriptType); - parser_error_t _read(parser_context_t *c, parser_tx_t *v); parser_error_t _validateTx(const parser_context_t *c, const parser_tx_t *v); -parser_error_t _getNumItems(const parser_context_t *c, const parser_tx_t *v, uint8_t *numItems); - //Called when argumentIndex-th argument is an array. If the array length is more than max_number_of_items //returns parser error, otherwise it sets number_of_items as the array length. parser_error_t _countArgumentItems(const flow_argument_list_t *v, uint8_t argumentIndex, - uint8_t max_number_of_items, uint8_t *number_of_items); + uint8_t min_number_of_items, uint8_t max_number_of_items, uint8_t *number_of_items); //Same as _countArgumentItems, but the array is optional. parser_error_t _countArgumentOptionalItems(const flow_argument_list_t *v, uint8_t argumentIndex, - uint8_t max_number_of_items, uint8_t *number_of_items); + uint8_t min_number_of_items, uint8_t max_number_of_items, uint8_t *number_of_items); -parser_error_t json_validateToken(parsed_json_t *parsedJson, uint16_t tokenIdx); +parser_error_t json_validateToken(const parsed_json_t *parsedJson, uint16_t tokenIdx); -parser_error_t json_extractToken(char *outVal, uint16_t outValLen, parsed_json_t *parsedJson, uint16_t tokenIdx); +parser_error_t json_extractToken(char *outVal, uint16_t outValLen, const parsed_json_t *parsedJson, uint16_t tokenIdx); -parser_error_t json_matchToken(parsed_json_t *parsedJson, uint16_t tokenIdx, char *expectedValue); +parser_error_t json_matchToken(const parsed_json_t *parsedJson, uint16_t tokenIdx, const char *expectedValue); -parser_error_t json_matchNull(parsed_json_t *parsedJson, uint16_t tokenIdx); +parser_error_t json_matchNull(const parsed_json_t *parsedJson, uint16_t tokenIdx); -parser_error_t json_matchKeyValue(parsed_json_t *parsedJson, - uint16_t tokenIdx, char *expectedType, jsmntype_t jsonType, uint16_t *valueTokenIdx); +parser_error_t json_matchKeyValue(const parsed_json_t *parsedJson, + uint16_t tokenIdx, const char *expectedType, jsmntype_t jsonType, uint16_t *valueTokenIdx); #define JSON_MATCH_VALUE_IDX_NONE 65535 -parser_error_t json_matchOptionalKeyValue(parsed_json_t *parsedJson, - uint16_t tokenIdx, char *expectedType, jsmntype_t jsonType, uint16_t *valueTokenIdx); +parser_error_t json_matchOptionalKeyValue(const parsed_json_t *parsedJson, + uint16_t tokenIdx, const char *expectedType, jsmntype_t jsonType, uint16_t *valueTokenIdx); -parser_error_t json_matchOptionalArray(parsed_json_t *parsedJson, uint16_t tokenIdx, uint16_t *valueTokenIdx); +parser_error_t json_matchOptionalArray(const parsed_json_t *parsedJson, uint16_t tokenIdx, uint16_t *valueTokenIdx); parser_error_t formatStrUInt8AsHex(const char *decStr, char *hexStr); -parser_error_t json_extractString(char *outVal, uint16_t outValLen, parsed_json_t *parsedJson, uint16_t tokenIdx); - void checkAddressUsedInTx(); diff --git a/app/src/parser_txdef.h b/app/src/parser_txdef.h index 6f006de0..e998330b 100644 --- a/app/src/parser_txdef.h +++ b/app/src/parser_txdef.h @@ -24,60 +24,10 @@ extern "C" { #endif +#include #include #include #include "crypto.h" -#include "template_hashes.h" - -#define PARSER_MAX_ARGCOUNT 10 - -typedef enum { - SCRIPT_UNKNOWN, - SCRIPT_TOKEN_TRANSFER, - SCRIPT_CREATE_ACCOUNT, - SCRIPT_ADD_NEW_KEY, - SCRIPT_TH01_WITHDRAW_UNLOCKED_TOKENS, - SCRIPT_TH02_DEPOSIT_UNLOCKED_TOKENS, - SCRIPT_TH06_REGISTER_NODE, - SCRIPT_TH08_STAKE_NEW_TOKENS, - SCRIPT_TH09_RESTAKE_UNSTAKED_TOKENS, - SCRIPT_TH10_RESTAKE_REWARDED_TOKENS, - SCRIPT_TH11_UNSTAKE_TOKENS, - SCRIPT_TH12_UNSTAKE_ALL_TOKENS, - SCRIPT_TH13_WITHDRAW_UNSTAKED_TOKENS, - SCRIPT_TH14_WITHDRAW_REWARDED_TOKENS, - SCRIPT_TH16_REGISTER_OPERATOR_NODE, - SCRIPT_TH17_REGISTER_DELEGATOR, - SCRIPT_TH19_DELEGATE_NEW_TOKENS, - SCRIPT_TH20_RESTAKE_UNSTAKED_DELEGATED_TOKENS, - SCRIPT_TH21_RESTAKE_REWARDED_DELEGATED_TOKENS, - SCRIPT_TH22_UNSTAKE_DELEGATED_TOKENS, - SCRIPT_TH23_WITHDRAW_UNSTAKED_DELEGATED_TOKENS, - SCRIPT_TH24_WITHDRAW_REWARDED_DELEGATED_TOKENS, - SCRIPT_TH25_UPDATE_NETWORKING_ADDRESS, - SCRIPT_SCO01_SETUP_STAKING_COLLECTION, - SCRIPT_SCO02_REGISTER_DELEGATOR, - SCRIPT_SCO03_REGISTER_NODE, - SCRIPT_SCO04_CREATE_MACHINE_ACCOUNT, - SCRIPT_SCO05_REQUEST_UNSTAKING, - SCRIPT_SCO06_STAKE_NEW_TOKENS, - SCRIPT_SCO07_STAKE_REWARD_TOKENS, - SCRIPT_SCO08_STAKE_UNSTAKED_TOKENS, - SCRIPT_SCO09_UNSTAKE_ALL, - SCRIPT_SCO10_WITHDRAW_REWARD_TOKENS, - SCRIPT_SCO11_WITHDRAW_UNSTAKED_TOKENS, - SCRIPT_SCO12_CLOSE_STAKE, - SCRIPT_SCO13_TRANSFER_NODE, - SCRIPT_SCO14_TRANSFER_DELEGATOR, - SCRIPT_SCO15_WITHDRAW_FROM_MACHINE_ACCOUNT, - SCRIPT_SCO16_UPDATE_NETWORKING_ADDRESS, - SCRIPT_FUSD01_SETUP_FUSD_VAULT, - SCRIPT_FUSD02_TRANSFER_FUSD, - SCRIPT_TS01_SET_UP_TOPSHOT_COLLECTION, - SCRIPT_TS02_TRANSFER_TOP_SHOT_MOMENT, - SCRIPT_USDC01_SETUP_USDC_VAULT, - SCRIPT_USDC02_TRANSFER_USDC, -} script_type_e; typedef enum { CHAIN_ID_UNKNOWN, @@ -86,12 +36,6 @@ typedef enum { CHAIN_ID_MAINNET, } chain_id_e; -typedef struct { - parser_context_t ctx; - uint8_t digest[CX_SHA256_SIZE]; - script_type_e type; -} flow_script_t; - typedef struct { parser_context_t ctx; } flow_reference_block_id_t; @@ -127,7 +71,7 @@ typedef struct { } flow_proposal_authorizers_t; typedef struct { - flow_script_t script; + parsed_tx_metadata_t metadata; flow_argument_list_t arguments; flow_reference_block_id_t referenceBlockId; flow_gaslimit_t gasLimit; diff --git a/app/src/screens.h b/app/src/screens.h new file mode 100644 index 00000000..928fabf5 --- /dev/null +++ b/app/src/screens.h @@ -0,0 +1,57 @@ +// While displaying screens we need to implemnt *_getItem function and *_getNumItems function. +// There is a big overlap in the logic. These macros generate *_internal function that can be used to implemnt both functions. +// We provide SCREEN macros to achive this efficiently. +// +// Function *_internal parameters: +// displayIdx - display index or MAX_DISPLAYS if we want to count the number of displays +// pageIdx - page index within the display, not used if displayIdx == MAX_DISPLAYS +// outKey, outKeyLen, outVal, outValLen - strings to be displayed, uused if == MAX_DISPLAYS +// pageCount - returns the number of pages (displayIdx MAX_METADATA_NUMBER_OF_HASHES || txMetadataLength < 1+SCRIPT_HASH_SIZE*numberOfHashes) { + return PARSER_METADATA_ERROR; + } + + for(size_t i=0; i MAX_METADATA_STRING_LENGTH) { \ + return PARSER_METADATA_ERROR; \ + } \ + } + #define READ_SKIP(count) { \ + parsed += (count); \ + } + + //read number of hashes and validate script + { + uint8_t numberOfHashes = 0; + READ_CHAR(&numberOfHashes) + if (numberOfHashes > MAX_METADATA_NUMBER_OF_HASHES) { + return PARSER_METADATA_TOO_MANY_HASHES; + } + parser_error_t err = _validateHash(scriptHash, txMetadata, txMetadataLength); + if (err != PARSER_OK) { + return err; + } + READ_SKIP(numberOfHashes*SCRIPT_HASH_SIZE); + } + + //read tx name + READ_STRING(&parsedTxMetadata->txName, &parsedTxMetadata->txNameLength) + + //read arguments + { + READ_CHAR(&parsedTxMetadata->argCount) + if (parsedTxMetadata->argCount > PARSER_MAX_ARGCOUNT) { + return PARSER_METADATA_TOO_MANY_ARGUMENTS; + } + STATIC_ASSERT(sizeof(parsedTxMetadata->arguments) >= PARSER_MAX_ARGCOUNT, "Too few arguments in parsed_tx_metadata_t."); + for(int i=0; iargCount; i++) { + READ_CHAR(&parsedTxMetadata->arguments[i].argumentType); + argument_type_e argumentType = parsedTxMetadata->arguments[i].argumentType; + if (argumentType == ARGUMENT_TYPE_ARRAY || argumentType == ARGUMENT_TYPE_OPTIONALARRAY) { + READ_CHAR(&parsedTxMetadata->arguments[i].arrayMinElements); + READ_CHAR(&parsedTxMetadata->arguments[i].arrayMaxElements); + uint8_t min = parsedTxMetadata->arguments[i].arrayMinElements; + uint8_t max = parsedTxMetadata->arguments[i].arrayMaxElements; + if (min > max || max > MAX_METADATA_MAX_ARRAY_ITEMS) { + return PARSER_METADATA_ERROR; + } + } + READ_STRING(&parsedTxMetadata->arguments[i].displayKey, &parsedTxMetadata->arguments[i].displayKeyLength) + READ_CHAR(&parsedTxMetadata->arguments[i].argumentIndex); + READ_STRING(&parsedTxMetadata->arguments[i].jsonExpectedType, &parsedTxMetadata->arguments[i].jsonExpectedTypeLength); + READ_CHAR(&parsedTxMetadata->arguments[i].jsonExpectedKind); + } + } + + + #undef READ_CHAR + #undef READ_STRING + #undef READ_SKIP + + if (parsed != txMetadataLength) { + return PARSER_METADATA_ERROR; + } + + return PARSER_OK; +} + +parser_error_t matchStoredTxMetadata(uint8_t scriptHash[SCRIPT_HASH_SIZE], parsed_tx_metadata_t *parsedTxTempate) { + size_t i=0; + while(KNOWN_TX_METADATA[i].metadata != NULL) { + parser_error_t err = _validateHash(scriptHash, PIC(KNOWN_TX_METADATA[i].metadata), KNOWN_TX_METADATA[i].metadataLength); + switch (err) { + case PARSER_OK: + return parseTxMetadata(scriptHash, PIC(KNOWN_TX_METADATA[i].metadata), KNOWN_TX_METADATA[i].metadataLength, parsedTxTempate); + case PARSER_UNEXPECTED_SCRIPT: + break; //scripts do not match, we should try next one + default: + return err; + } + i++; + } + + return PARSER_UNEXPECTED_SCRIPT; +} diff --git a/app/src/tx_metadata.h b/app/src/tx_metadata.h new file mode 100644 index 00000000..69614a4f --- /dev/null +++ b/app/src/tx_metadata.h @@ -0,0 +1,71 @@ +/******************************************************************************* +* (c) 2022 Vacuumlabs +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +typedef enum { + ARGUMENT_TYPE_NORMAL = 1, + ARGUMENT_TYPE_OPTIONAL = 2, + ARGUMENT_TYPE_ARRAY = 3, + ARGUMENT_TYPE_OPTIONALARRAY = 4 +} argument_type_e; + +#define PARSER_MAX_ARGCOUNT 10 + +//It is planed that all these strings may be on flash, thus they are volatile (for NanoX and NanoSPlus) +typedef struct { + argument_type_e argumentType; + uint8_t arrayMinElements; //defined only for ARGUMENT_TYPE_ARRAY and ARGUMENT_TYPE_OPTIONALARRAY + uint8_t arrayMaxElements; //defined only for ARGUMENT_TYPE_ARRAY and ARGUMENT_TYPE_OPTIONALARRAY + const NV_VOLATILE char *displayKey; + uint8_t displayKeyLength; + uint8_t argumentIndex; //argument index within transaction + const NV_VOLATILE char *jsonExpectedType; //pointer to null terminated string + uint8_t jsonExpectedTypeLength; + jsmntype_t jsonExpectedKind; +} parsed_tx_metadata_argument_t; + +typedef struct { + const NV_VOLATILE char *txName; + uint8_t txNameLength; + uint8_t argCount; + parsed_tx_metadata_argument_t arguments[PARSER_MAX_ARGCOUNT]; //order of arguments in which they should be displayed +} parsed_tx_metadata_t; + + +#define SCRIPT_HASH_SIZE 32 + +//It is planned that compressedData may be on flash, thus they are volatile (for NanoX and NanoSPlus) +parser_error_t parseTxMetadata(uint8_t scriptHash[SCRIPT_HASH_SIZE], const NV_VOLATILE uint8_t *txMetadata, uint16_t txMetadataLength, + parsed_tx_metadata_t *parsedTxMetadata); + +parser_error_t matchStoredTxMetadata(uint8_t scriptHash[SCRIPT_HASH_SIZE], parsed_tx_metadata_t *parsedTxMetadata); + +#ifdef __cplusplus + +//For C++ unit tests +parser_error_t _validateHash(uint8_t scriptHash[SCRIPT_HASH_SIZE], const NV_VOLATILE uint8_t *txMetadata, uint16_t txMetadataLength); +} +#endif diff --git a/deps/ledger-zxlib/include/zxmacros_x64.h b/deps/ledger-zxlib/include/zxmacros_x64.h index 22d27dc7..282a9283 100644 --- a/deps/ledger-zxlib/include/zxmacros_x64.h +++ b/deps/ledger-zxlib/include/zxmacros_x64.h @@ -30,6 +30,9 @@ #define CX_ECCINFO_PARITY_ODD 1u #define CX_ECCINFO_xGTn 2u +#define NV_CONST +#define NV_VOLATILE + #ifndef __APPLE__ #define MEMZERO explicit_bzero #else diff --git a/tests/json.cpp b/tests/json.cpp index 1b08ae22..361a8fef 100644 --- a/tests/json.cpp +++ b/tests/json.cpp @@ -212,8 +212,7 @@ TEST(JSON, OptionalArrayNull) { parsed_json_t parsedJson = {false}; auto err = json_parse(&parsedJson, sendToken2, strlen(sendToken2)); - - // We could parse valid JSON + EXPECT_THAT(err, PARSER_OK); uint16_t internalTokenElementIdx; ASSERT_THAT( @@ -226,8 +225,7 @@ TEST(JSON, OptionalArrayNotNull) { parsed_json_t parsedJson = {false}; auto err = json_parse(&parsedJson, sendToken4, strlen(sendToken4)); - - // We could parse valid JSON + EXPECT_THAT(err, PARSER_OK); uint16_t internalTokenElementIdx; ASSERT_THAT( diff --git a/tests/tx_metadata.cpp b/tests/tx_metadata.cpp new file mode 100644 index 00000000..f24c6778 --- /dev/null +++ b/tests/tx_metadata.cpp @@ -0,0 +1,187 @@ +/******************************************************************************* +* (c) 2020 Zondax GmbH +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include "gmock/gmock.h" +#include +#include +#include +#include +#include +#include + +const uint8_t TX_METADATA_ADD_NEW_KEY[] = { + 1, //number of hashes + hashes + 0x59, 0x5c, 0x86, 0x56, 0x14, 0x41, 0xb3, 0x2b, 0x2b, 0x91, 0xee, 0x03, 0xf9, 0xe1, 0x0c, 0xa6, 0xef, 0xa7, 0xb4, 0x1b, 0xcc, 0x99, 0x4f, 0x51, 0x31, 0x7e, 0xc0, 0xaa, 0x9d, 0x8f, 0x8a, 0x42, + 'A', 'd', 'd', ' ', 'N', 'e', 'w', ' ', 'K', 'e', 'y', 0, //tx name (to display) + 1, //number of arguments + + //Argument 1 + ARGUMENT_TYPE_NORMAL, + 'P', 'u', 'b', ' ', 'k', 'e', 'y', 0, //arg name (to display) + 0, //argument index + 'S','t', 'r', 'i', 'n', 'g', 0, //expected value type + JSMN_STRING //expected value json token type +}; + +const uint8_t TX_METADATA_TOKEN_TRANSFER[] = { + 3, //number of hashes + hashes + 0xca, 0x80, 0xb6, 0x28, 0xd9, 0x85, 0xb3, 0x58, 0xae, 0x1c, 0xb1, 0x36, 0xbc, 0xd9, 0x76, 0x99, 0x7c, 0x94, 0x2f, 0xa1, 0x0d, 0xba, 0xbf, 0xea, 0xfb, 0x4e, 0x20, 0xfa, 0x66, 0xa5, 0xa5, 0xe2, + 0xd5, 0x6f, 0x4e, 0x1d, 0x23, 0x55, 0xcd, 0xcf, 0xac, 0xfd, 0x01, 0xe4, 0x71, 0x45, 0x9c, 0x6e, 0xf1, 0x68, 0xbf, 0xdf, 0x84, 0x37, 0x1a, 0x68, 0x5c, 0xcf, 0x31, 0xcf, 0x3c, 0xde, 0xdc, 0x2d, + 0x47, 0x85, 0x15, 0x86, 0xd9, 0x62, 0x33, 0x5e, 0x3f, 0x7d, 0x9e, 0x5d, 0x11, 0xa4, 0xc5, 0x27, 0xee, 0x4b, 0x5f, 0xd1, 0xc3, 0x89, 0x5e, 0x3c, 0xe1, 0xb9, 0xc2, 0x82, 0x1f, 0x60, 0xb1, 0x66, + 'T', 'o', 'k', 'e', 'n', ' ', 'T', 'r', 'a', 'n', 's', 'f', 'e', 'r', 0, //tx name (to display) + 2, //number of arguments + + //Argument 1 + ARGUMENT_TYPE_OPTIONALARRAY, 5, 10, + 'A', 'm', 'o', 'u', 'n', 't', 0, //arg name (to display) + 0, //argument index + 'U','I', 'n', 't', '6', '4', 0, //expected value type + JSMN_STRING, //expected value json token type + + //Argument 2 + ARGUMENT_TYPE_NORMAL, + 'D', 'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 'n', 0, //arg name (to display) + 1, //argument index + 'A','d', 'd', 'r', 'e', 's', 's', 0, //expected value type + JSMN_STRING //expected value json token type +}; + +uint8_t hashAddNewKey[32] = {0x59, 0x5c, 0x86, 0x56, 0x14, 0x41, 0xb3, 0x2b, 0x2b, 0x91, 0xee, 0x03, 0xf9, 0xe1, 0x0c, 0xa6, 0xef, 0xa7, 0xb4, 0x1b, 0xcc, 0x99, 0x4f, 0x51, 0x31, 0x7e, 0xc0, 0xaa, 0x9d, 0x8f, 0x8a, 0x42}; +uint8_t hashTokenTranfer1[32] = {0xca, 0x80, 0xb6, 0x28, 0xd9, 0x85, 0xb3, 0x58, 0xae, 0x1c, 0xb1, 0x36, 0xbc, 0xd9, 0x76, 0x99, 0x7c, 0x94, 0x2f, 0xa1, 0x0d, 0xba, 0xbf, 0xea, 0xfb, 0x4e, 0x20, 0xfa, 0x66, 0xa5, 0xa5, 0xe2}; +uint8_t hashTokenTranfer2[32] = {0xd5, 0x6f, 0x4e, 0x1d, 0x23, 0x55, 0xcd, 0xcf, 0xac, 0xfd, 0x01, 0xe4, 0x71, 0x45, 0x9c, 0x6e, 0xf1, 0x68, 0xbf, 0xdf, 0x84, 0x37, 0x1a, 0x68, 0x5c, 0xcf, 0x31, 0xcf, 0x3c, 0xde, 0xdc, 0x2d}; +uint8_t hashTokenTranfer3[32] = {0x47, 0x85, 0x15, 0x86, 0xd9, 0x62, 0x33, 0x5e, 0x3f, 0x7d, 0x9e, 0x5d, 0x11, 0xa4, 0xc5, 0x27, 0xee, 0x4b, 0x5f, 0xd1, 0xc3, 0x89, 0x5e, 0x3c, 0xe1, 0xb9, 0xc2, 0x82, 0x1f, 0x60, 0xb1, 0x66}; + + +TEST(tx_data, validateHash) { + parser_error_t err; + err = _validateHash(hashAddNewKey, TX_METADATA_ADD_NEW_KEY, sizeof(TX_METADATA_ADD_NEW_KEY)); + EXPECT_THAT(err, PARSER_OK); + + err = _validateHash(hashTokenTranfer1, TX_METADATA_ADD_NEW_KEY, sizeof(TX_METADATA_ADD_NEW_KEY)); + EXPECT_THAT(err, PARSER_UNEXPECTED_SCRIPT); + + err = _validateHash(hashTokenTranfer1, TX_METADATA_TOKEN_TRANSFER, sizeof(TX_METADATA_TOKEN_TRANSFER)); + EXPECT_THAT(err, PARSER_OK); + + err = _validateHash(hashTokenTranfer2, TX_METADATA_TOKEN_TRANSFER, sizeof(TX_METADATA_TOKEN_TRANSFER)); + EXPECT_THAT(err, PARSER_OK); + + err = _validateHash(hashTokenTranfer3, TX_METADATA_TOKEN_TRANSFER, sizeof(TX_METADATA_TOKEN_TRANSFER)); + EXPECT_THAT(err, PARSER_OK); + + err = _validateHash(hashAddNewKey, TX_METADATA_TOKEN_TRANSFER, sizeof(TX_METADATA_TOKEN_TRANSFER)); + EXPECT_THAT(err, PARSER_UNEXPECTED_SCRIPT); + + err = _validateHash(hashTokenTranfer3, TX_METADATA_ADD_NEW_KEY, 0); + EXPECT_THAT(err, PARSER_METADATA_ERROR); + + err = _validateHash(hashTokenTranfer3, TX_METADATA_TOKEN_TRANSFER, 3*32); + EXPECT_THAT(err, PARSER_METADATA_ERROR); + + err = _validateHash(hashTokenTranfer3, TX_METADATA_TOKEN_TRANSFER, 3*32+1); + EXPECT_THAT(err, PARSER_OK); +} + + +TEST(tx_data, parseCompressedTxData) { + parser_error_t err; + parsed_tx_metadata_t result; + err = parseTxMetadata(hashTokenTranfer1, TX_METADATA_ADD_NEW_KEY, sizeof(TX_METADATA_ADD_NEW_KEY), &result); + EXPECT_THAT(err, PARSER_UNEXPECTED_SCRIPT); + + err = parseTxMetadata(hashAddNewKey, TX_METADATA_ADD_NEW_KEY, sizeof(TX_METADATA_ADD_NEW_KEY), &result); + EXPECT_THAT(err, PARSER_OK); + EXPECT_THAT(std::string(result.txName), "Add New Key"); + EXPECT_THAT(result.txNameLength, 11); + EXPECT_THAT(result.argCount, 1); + EXPECT_THAT(result.arguments[0].argumentType, ARGUMENT_TYPE_NORMAL); + EXPECT_THAT(std::string(result.arguments[0].displayKey), "Pub key"); + EXPECT_THAT(result.arguments[0].displayKeyLength, 7); + EXPECT_THAT(result.arguments[0].argumentIndex, 0); + EXPECT_THAT(std::string(result.arguments[0].jsonExpectedType), "String"); + EXPECT_THAT(result.arguments[0].jsonExpectedTypeLength, 6); + EXPECT_THAT(result.arguments[0].jsonExpectedKind, JSMN_STRING); + + err = parseTxMetadata(hashTokenTranfer3, TX_METADATA_TOKEN_TRANSFER, sizeof(TX_METADATA_TOKEN_TRANSFER), &result); + EXPECT_THAT(err, PARSER_OK); + EXPECT_THAT(std::string(result.txName), "Token Transfer"); + EXPECT_THAT(result.txNameLength, 14); + EXPECT_THAT(result.argCount, 2); + EXPECT_THAT(result.arguments[0].argumentType, ARGUMENT_TYPE_OPTIONALARRAY); + EXPECT_THAT(result.arguments[0].arrayMinElements, 5); + EXPECT_THAT(result.arguments[0].arrayMaxElements, 10); + EXPECT_THAT(std::string(result.arguments[0].displayKey), "Amount"); + EXPECT_THAT(result.arguments[0].displayKeyLength, 6); + EXPECT_THAT(result.arguments[0].argumentIndex, 0); + EXPECT_THAT(std::string(result.arguments[0].jsonExpectedType), "UInt64"); + EXPECT_THAT(result.arguments[0].jsonExpectedTypeLength, 6); + EXPECT_THAT(result.arguments[0].jsonExpectedKind, JSMN_STRING); + EXPECT_THAT(result.arguments[1].argumentType, ARGUMENT_TYPE_NORMAL); + EXPECT_THAT(std::string(result.arguments[1].displayKey), "Destination"); + EXPECT_THAT(result.arguments[1].displayKeyLength, 11); + EXPECT_THAT(result.arguments[1].argumentIndex, 1); + EXPECT_THAT(std::string(result.arguments[1].jsonExpectedType), "Address"); + EXPECT_THAT(result.arguments[1].jsonExpectedTypeLength, 7); + EXPECT_THAT(result.arguments[1].jsonExpectedKind, JSMN_STRING); + + err = parseTxMetadata(hashAddNewKey, TX_METADATA_ADD_NEW_KEY, sizeof(TX_METADATA_ADD_NEW_KEY)-1, &result); + EXPECT_THAT(err, PARSER_METADATA_ERROR); + err = parseTxMetadata(hashTokenTranfer3, TX_METADATA_TOKEN_TRANSFER, sizeof(TX_METADATA_TOKEN_TRANSFER)+1, &result); + EXPECT_THAT(err, PARSER_METADATA_ERROR); +} + +TEST(tx_data, matchStoreTxMetadata) { + parser_error_t err; + parsed_tx_metadata_t result; + + uint8_t hashWrong[32] = {0x59, 0x5c, 0x86, 0x56, 0x14, 0x41, 0xb3, 0x2b, 0x2b, 0x91, 0xee, 0x03, 0xf9, 0xe1, 0x0c, 0xa6, 0xef, 0xa7, 0xb4, 0x1b, 0xcc, 0x99, 0x4f, 0x51, 0x31, 0x7e, 0xc0, 0xaa, 0x9d, 0x8f, 0x8a, 0x41}; + err = matchStoredTxMetadata(hashWrong, &result); + EXPECT_THAT(err, PARSER_UNEXPECTED_SCRIPT); + + err = matchStoredTxMetadata(hashAddNewKey, &result); + EXPECT_THAT(err, PARSER_OK); + EXPECT_THAT(std::string(result.txName), "Add New Key"); + EXPECT_THAT(result.txNameLength, 11); + EXPECT_THAT(result.argCount, 1); + EXPECT_THAT(result.arguments[0].argumentType, ARGUMENT_TYPE_NORMAL); + EXPECT_THAT(std::string(result.arguments[0].displayKey), "Pub key"); + EXPECT_THAT(result.arguments[0].displayKeyLength, 7); + EXPECT_THAT(result.arguments[0].argumentIndex, 0); + EXPECT_THAT(std::string(result.arguments[0].jsonExpectedType), "String"); + EXPECT_THAT(result.arguments[0].jsonExpectedTypeLength, 6); + EXPECT_THAT(result.arguments[0].jsonExpectedKind, JSMN_STRING); + + err = matchStoredTxMetadata(hashTokenTranfer3, &result); + EXPECT_THAT(err, PARSER_OK); + EXPECT_THAT(std::string(result.txName), "Token Transfer"); + EXPECT_THAT(result.txNameLength, 14); + EXPECT_THAT(result.argCount, 2); + EXPECT_THAT(result.arguments[0].argumentType, ARGUMENT_TYPE_NORMAL); + EXPECT_THAT(std::string(result.arguments[0].displayKey), "Amount"); + EXPECT_THAT(result.arguments[0].displayKeyLength, 6); + EXPECT_THAT(result.arguments[0].argumentIndex, 0); + EXPECT_THAT(std::string(result.arguments[0].jsonExpectedType), "UFix64"); + EXPECT_THAT(result.arguments[0].jsonExpectedTypeLength, 6); + EXPECT_THAT(result.arguments[0].jsonExpectedKind, JSMN_STRING); + EXPECT_THAT(result.arguments[1].argumentType, ARGUMENT_TYPE_NORMAL); + EXPECT_THAT(std::string(result.arguments[1].displayKey), "Destination"); + EXPECT_THAT(result.arguments[1].displayKeyLength, 11); + EXPECT_THAT(result.arguments[1].argumentIndex, 1); + EXPECT_THAT(std::string(result.arguments[1].jsonExpectedType), "Address"); + EXPECT_THAT(result.arguments[1].jsonExpectedTypeLength, 7); + EXPECT_THAT(result.arguments[1].jsonExpectedKind, JSMN_STRING); +} + diff --git a/tests/utils/expected_output.cpp b/tests/utils/expected_output.cpp index 2882e4de..d9180841 100644 --- a/tests/utils/expected_output.cpp +++ b/tests/utils/expected_output.cpp @@ -78,351 +78,48 @@ std::vector GenerateExpectedUIOutput(const testcaseData_t &tcd) { } uint8_t scriptHash[32]; - script_type_e scriptType = SCRIPT_UNKNOWN; sha256((const uint8_t *) tcd.script.c_str(), tcd.script.length(), scriptHash); - _matchScriptType(scriptHash, &scriptType); uint16_t item = 0; uint8_t dummy; - - switch (scriptType) { - case SCRIPT_UNKNOWN: - addTo(answer, "{} | Type :Unknown", item++); - break; - case SCRIPT_TOKEN_TRANSFER: { - addTo(answer, "{} | Type : Token Transfer", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - addTo(answer, "{} | Destination : {}", item++, tcd.arguments[1]["value"].asString()); - break; - } - case SCRIPT_CREATE_ACCOUNT: { - addTo(answer, "{} | Type : Create Account", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - const auto pks = tcd.arguments[0]["value"]; - - for (uint16_t i = 0; i < (uint16_t) pks.size(); i++) { - addMultiStringArgumentTo(answer, fmt::format("Pub key {}", i + 1), item++, pks[i]["value"]); - } - break; - } - case SCRIPT_ADD_NEW_KEY: { - addTo(answer, "{} | Type : Add New Key", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Pub key", item++, tcd.arguments[0]["value"]); - break; - } - case SCRIPT_TH01_WITHDRAW_UNLOCKED_TOKENS: { - addTo(answer, "{} | Type : Withdraw FLOW from Lockbox", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - break; - } - case SCRIPT_TH02_DEPOSIT_UNLOCKED_TOKENS: { - addTo(answer, "{} | Type : Deposit FLOW to Lockbox", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - break; - } - case SCRIPT_TH06_REGISTER_NODE: { - addTo(answer, "{} | Type : Register Staked Node", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - addTo(answer, "{} | Node Role : {}", item++, tcd.arguments[1]["value"].asString()); - addMultiStringArgumentTo(answer, "Networking Address", item++, tcd.arguments[2]["value"]); - addMultiStringArgumentTo(answer, "Networking Key", item++, tcd.arguments[3]["value"]); - addMultiStringArgumentTo(answer, "Staking Key", item++, tcd.arguments[4]["value"]); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[5]["value"].asString()); - break; - } - case SCRIPT_TH08_STAKE_NEW_TOKENS: { - addTo(answer, "{} | Type : Stake FLOW from Lockbox", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - break; - } - case SCRIPT_TH09_RESTAKE_UNSTAKED_TOKENS: { - addTo(answer, "{} | Type : Restake Unstaked FLOW", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - break; - } - case SCRIPT_TH10_RESTAKE_REWARDED_TOKENS: { - addTo(answer, "{} | Type : Restake Rewarded FLOW", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - break; - } - case SCRIPT_TH11_UNSTAKE_TOKENS: { - addTo(answer, "{} | Type : Unstake FLOW", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - break; - } - case SCRIPT_TH12_UNSTAKE_ALL_TOKENS: { - addTo(answer, "{} | Type : Unstake All FLOW", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - break; - } - case SCRIPT_TH13_WITHDRAW_UNSTAKED_TOKENS: { - addTo(answer, "{} | Type : Withdraw Unstaked FLOW to Lockbox", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - break; - } - case SCRIPT_TH14_WITHDRAW_REWARDED_TOKENS: { - addTo(answer, "{} | Type : Withdraw Rewarded FLOW to Lockbox", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - break; - } - case SCRIPT_TH16_REGISTER_OPERATOR_NODE: { - addTo(answer, "{} | Type : Register Operator Node", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Operator Address : {}", item++, tcd.arguments[0]["value"].asString()); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[1]["value"]); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[2]["value"].asString()); - break; - } - case SCRIPT_TH17_REGISTER_DELEGATOR: { - addTo(answer, "{} | Type : Register Delegator", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[1]["value"].asString()); - break; - } - case SCRIPT_TH19_DELEGATE_NEW_TOKENS: { - addTo(answer, "{} | Type : Delegate FLOW from Lockbox", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - break; - } - case SCRIPT_TH20_RESTAKE_UNSTAKED_DELEGATED_TOKENS: { - addTo(answer, "{} | Type : Re-delegate Unstaked FLOW", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - break; - } - case SCRIPT_TH21_RESTAKE_REWARDED_DELEGATED_TOKENS: { - addTo(answer, "{} | Type : Re-delegate Rewarded FLOW", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - break; - } - case SCRIPT_TH22_UNSTAKE_DELEGATED_TOKENS: { - addTo(answer, "{} | Type : Unstake Delegated FLOW", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - break; - } - case SCRIPT_TH23_WITHDRAW_UNSTAKED_DELEGATED_TOKENS: { - addTo(answer, "{} | Type : Withdraw Undelegated FLOW to Lockbox", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - break; - } - case SCRIPT_TH24_WITHDRAW_REWARDED_DELEGATED_TOKENS: { - addTo(answer, "{} | Type : Withdraw Delegate Rewards to Lockbox", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - break; - } - case SCRIPT_TH25_UPDATE_NETWORKING_ADDRESS: { - addTo(answer, "{} | Type : Update Networking Address", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Address", item++, tcd.arguments[0]["value"]); - break; - } - case SCRIPT_SCO01_SETUP_STAKING_COLLECTION: { - addTo(answer, "{} | Type : Setup Staking Collection", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - break; - } - case SCRIPT_SCO02_REGISTER_DELEGATOR: { - addTo(answer, "{} | Type : Register Delegator", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[1]["value"].asString()); - break; - } - case SCRIPT_SCO03_REGISTER_NODE: { - addTo(answer, "{} | Type : Register Node", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - addTo(answer, "{} | Node Role : {}", item++, tcd.arguments[1]["value"].asString()); - addMultiStringArgumentTo(answer, "Netw. Addr.", item++, tcd.arguments[2]["value"]); - addMultiStringArgumentTo(answer, "Netw. Key", item++, tcd.arguments[3]["value"]); - addMultiStringArgumentTo(answer, "Staking Key", item++, tcd.arguments[4]["value"]); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[5]["value"].asString()); - if (tcd.arguments[6]["value"].isObject()) { - for (uint16_t i = 0; i < (uint16_t) tcd.arguments[6]["value"]["value"].size(); i++) { - addMultiStringArgumentTo(answer, fmt::format("Pub key {}", i + 1), item++, tcd.arguments[6]["value"]["value"][i]["value"]); + + parsed_tx_metadata_t m; + matchStoredTxMetadata(scriptHash, &m); + + addTo(answer, "{} | Type : {}", item++, m.txName); + addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); + for(int i=0; iargumentIndex; + + switch(ma->argumentType) { + case ARGUMENT_TYPE_NORMAL: + addMultiStringArgumentTo(answer, ma->displayKey, item++, tcd.arguments[argNo]["value"]); + break; + case ARGUMENT_TYPE_OPTIONAL: + if (tcd.arguments[1]["value"].isObject()) { + addMultiStringArgumentTo(answer, ma->displayKey, item++, tcd.arguments[argNo]["value"]["value"]); } - } - else { - addTo(answer, "{} | Pub key 1 : None", item++); - } - break; - } - case SCRIPT_SCO04_CREATE_MACHINE_ACCOUNT: { - addTo(answer, "{} | Type : Create Machine Account", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - for (uint16_t i = 0; i < (uint16_t) tcd.arguments[1]["value"].size(); i++) { - addMultiStringArgumentTo(answer, fmt::format("Pub key {}", i + 1), item++, tcd.arguments[1]["value"][i]["value"]); - } - break; - } - case SCRIPT_SCO05_REQUEST_UNSTAKING: { - addTo(answer, "{} | Type : Request Unstaking", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - if (tcd.arguments[1]["value"].isObject()) - addTo(answer, "{} | Delegator ID : {}", item++, tcd.arguments[1]["value"]["value"].asString()); - else - addTo(answer, "{} | Delegator ID : None", item++); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[2]["value"].asString()); - break; - } - case SCRIPT_SCO06_STAKE_NEW_TOKENS: { - addTo(answer, "{} | Type : Stake New Tokens", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - if (tcd.arguments[1]["value"].isObject()) - addTo(answer, "{} | Delegator ID : {}", item++, tcd.arguments[1]["value"]["value"].asString()); - else - addTo(answer, "{} | Delegator ID : None", item++); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[2]["value"].asString()); - break; - } - case SCRIPT_SCO07_STAKE_REWARD_TOKENS: { - addTo(answer, "{} | Type : Stake Reward Tokens", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - if (tcd.arguments[1]["value"].isObject()) - addTo(answer, "{} | Delegator ID : {}", item++, tcd.arguments[1]["value"]["value"].asString()); - else - addTo(answer, "{} | Delegator ID : None", item++); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[2]["value"].asString()); - break; - } - case SCRIPT_SCO08_STAKE_UNSTAKED_TOKENS: { - addTo(answer, "{} | Type : Stake Unstaked Tokens", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - if (tcd.arguments[1]["value"].isObject()) - addTo(answer, "{} | Delegator ID : {}", item++, tcd.arguments[1]["value"]["value"].asString()); - else - addTo(answer, "{} | Delegator ID : None", item++); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[2]["value"].asString()); - break; - } - case SCRIPT_SCO09_UNSTAKE_ALL: { - addTo(answer, "{} | Type : Unstake All", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - break; - } - case SCRIPT_SCO10_WITHDRAW_REWARD_TOKENS: { - addTo(answer, "{} | Type : Withdraw Reward Tokens", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - if (tcd.arguments[1]["value"].isObject()) - addTo(answer, "{} | Delegator ID : {}", item++, tcd.arguments[1]["value"]["value"].asString()); - else - addTo(answer, "{} | Delegator ID : None", item++); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[2]["value"].asString()); - break; - } - case SCRIPT_SCO11_WITHDRAW_UNSTAKED_TOKENS: { - addTo(answer, "{} | Type : Withdraw Unstaked Tokens", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - if (tcd.arguments[1]["value"].isObject()) - addTo(answer, "{} | Delegator ID : {}", item++, tcd.arguments[1]["value"]["value"].asString()); - else - addTo(answer, "{} | Delegator ID : None", item++); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[2]["value"].asString()); - break; - } - case SCRIPT_SCO12_CLOSE_STAKE: { - addTo(answer, "{} | Type : Close Stake", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - if (tcd.arguments[1]["value"].isObject()) - addTo(answer, "{} | Delegator ID : {}", item++, tcd.arguments[1]["value"]["value"].asString()); - else - addTo(answer, "{} | Delegator ID : None", item++); - break; - } - case SCRIPT_SCO13_TRANSFER_NODE: { - addTo(answer, "{} | Type : Transfer Node", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - addMultiStringArgumentTo(answer, "Address", item++, tcd.arguments[1]["value"]); - break; - } - case SCRIPT_SCO14_TRANSFER_DELEGATOR: { - addTo(answer, "{} | Type : Transfer Delegator", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - addTo(answer, "{} | Delegator ID : {}", item++, tcd.arguments[1]["value"].asString()); - addMultiStringArgumentTo(answer, "Address", item++, tcd.arguments[2]["value"]); - break; - } - case SCRIPT_SCO15_WITHDRAW_FROM_MACHINE_ACCOUNT: { - addTo(answer, "{} | Type : Withdraw From Machine Account", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[1]["value"].asString()); - break; - } - case SCRIPT_SCO16_UPDATE_NETWORKING_ADDRESS: { - addTo(answer, "{} | Type : Update Networking Address", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addMultiStringArgumentTo(answer, "Node ID", item++, tcd.arguments[0]["value"]); - addMultiStringArgumentTo(answer, "Address", item++, tcd.arguments[1]["value"]); - break; - } - case SCRIPT_FUSD01_SETUP_FUSD_VAULT: { - addTo(answer, "{} | Type : Setup FUSD Vault", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - break; - } - case SCRIPT_FUSD02_TRANSFER_FUSD: { - addTo(answer, "{} | Type : Transfer FUSD", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - addMultiStringArgumentTo(answer, "Recipient", item++, tcd.arguments[1]["value"]); - break; - } - case SCRIPT_TS01_SET_UP_TOPSHOT_COLLECTION: { - addTo(answer, "{} | Type : Set Up Top Shot Collection", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - break; - } - case SCRIPT_TS02_TRANSFER_TOP_SHOT_MOMENT: { - addTo(answer, "{} | Type : Transfer Top Shot Moment", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Moment ID : {}", item++, tcd.arguments[1]["value"].asString()); - addMultiStringArgumentTo(answer, "Address", item++, tcd.arguments[0]["value"]); - break; - } - case SCRIPT_USDC01_SETUP_USDC_VAULT: { - addTo(answer, "{} | Type : Setup USDC Vault", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - break; - } - case SCRIPT_USDC02_TRANSFER_USDC: { - addTo(answer, "{} | Type : Transfer USDC", item++); - addTo(answer, "{} | ChainID : {}", item++, tcd.chainID); - addTo(answer, "{} | Amount : {}", item++, tcd.arguments[0]["value"].asString()); - addMultiStringArgumentTo(answer, "Recipient", item++, tcd.arguments[1]["value"]); - break; + else { + addTo(answer, "{} | {} : None", item++, ma->displayKey); + } + break; + case ARGUMENT_TYPE_ARRAY: + for (uint16_t i = 0; i < (uint16_t) tcd.arguments[argNo]["value"].size(); i++) { + addMultiStringArgumentTo(answer, fmt::format("{} {}", ma->displayKey, i + 1), item++, tcd.arguments[argNo]["value"][i]["value"]); + } + break; + case ARGUMENT_TYPE_OPTIONALARRAY: + if (tcd.arguments[i]["value"].isObject()) { + for (uint16_t i = 0; i < (uint16_t) tcd.arguments[argNo]["value"]["value"].size(); i++) { + addMultiStringArgumentTo(answer, fmt::format("{} {}", ma->displayKey, i + 1), item++, tcd.arguments[argNo]["value"]["value"][i]["value"]); + } + } + else { + addTo(answer, "{} | {} 1 : None", item++, ma->displayKey); + } + break; } - default: - addTo(answer, "{} | Type : ERROR", item++); - break; } addTo(answer, "{} | Ref Block [1/2] : {}", item, formatString(tcd.refBlock, 0, &dummy));