diff --git a/Makefile b/Makefile old mode 100755 new mode 100644 index d855a87a..3c9f78b2 --- a/Makefile +++ b/Makefile @@ -168,9 +168,16 @@ else ifeq ($(COIN),resistance) DEFINES += COIN_P2PKH_VERSION=7063 COIN_P2SH_VERSION=7068 COIN_FAMILY=1 COIN_COINID=\"Res\" COIN_COINID_HEADER=\"RES\" COIN_COLOR_HDR=0x3790CA COIN_COLOR_DB=0x9BC8E5 COIN_COINID_NAME=\"Res\" COIN_COINID_SHORT=\"RES\" COIN_KIND=COIN_KIND_RESISTANCE APPNAME ="Resistance" APP_LOAD_PARAMS += --path $(APP_PATH) +else ifeq ($(COIN),metaverse) +# Metaverse +DEFINES += COIN_P2PKH_VERSION=50 COIN_P2SH_VERSION=5 COIN_FAMILY=5 COIN_COINID=\"Metaverse\" COIN_COINID_HEADER=\"METAVERSE\" COIN_COLOR_HDR=0xD0DAFB COIN_COLOR_DB=0xE8EDFD COIN_COINID_NAME=\"Metaverse\" COIN_COINID_SHORT=\"ETP\" COIN_KIND=COIN_KIND_METAVERSE +DEFINES_LIB=# while debugging +DEFINES += APP_METAVERSE +APPNAME ="Metaverse" +APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(filter clean,$(MAKECMDGOALS)),) -$(error Unsupported COIN - use bitcoin_testnet, bitcoin, bitcoin_cash, bitcoin_gold, litecoin, dogecoin, dash, zcash, horizen, komodo, stratis, peercoin, pivx, viacoin, vertcoin, stealth, digibyte, qtum, bitcoin_private, zcoin, gamecredits, zclassic, xsn, nix, lbry, resistance) +$(error Unsupported COIN - use bitcoin_testnet, bitcoin, bitcoin_cash, bitcoin_gold, litecoin, dogecoin, dash, zcash, horizen, komodo, stratis, peercoin, pivx, viacoin, vertcoin, stealth, digibyte, qtum, bitcoin_private, zcoin, gamecredits, zclassic, xsn, nix, lbry, resistance, metaverse) endif endif @@ -318,6 +325,6 @@ listvariants: else listvariants: - @echo VARIANTS COIN bitcoin_testnet bitcoin bitcoin_cash bitcoin_gold litecoin dogecoin dash zcash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte qtum bitcoin_private zcoin gamecredits zclassic xsn nix lbry resistance + @echo VARIANTS COIN bitcoin_testnet bitcoin bitcoin_cash bitcoin_gold litecoin dogecoin dash zcash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte qtum bitcoin_private zcoin gamecredits zclassic xsn nix lbry resistance metaverse -endif +endif \ No newline at end of file diff --git a/blue_app_metaverse.gif b/blue_app_metaverse.gif new file mode 100644 index 00000000..f79567be Binary files /dev/null and b/blue_app_metaverse.gif differ diff --git a/blue_badge_metaverse.gif b/blue_badge_metaverse.gif new file mode 100644 index 00000000..f79567be Binary files /dev/null and b/blue_badge_metaverse.gif differ diff --git a/include/btchip_bcd.h b/include/btchip_bcd.h index bb17304d..225d09ca 100644 --- a/include/btchip_bcd.h +++ b/include/btchip_bcd.h @@ -20,6 +20,6 @@ #define BTCHIP_BCD_H unsigned char -btchip_convert_hex_amount_to_displayable(unsigned char *amount); +btchip_convert_hex_amount_to_displayable(unsigned char *amount, unsigned char decimals); #endif diff --git a/include/btchip_context.h b/include/btchip_context.h index 71fa81c8..5a4a4857 100644 --- a/include/btchip_context.h +++ b/include/btchip_context.h @@ -241,7 +241,7 @@ struct btchip_context_s { unsigned int discardSize; unsigned char outputParsingState; unsigned char totalOutputAmount[8]; - unsigned char changeOutputFound; + unsigned char changeOutputFound; /* Overwinter */ unsigned char usingOverwinter; @@ -250,6 +250,11 @@ struct btchip_context_s { unsigned char nExpiryHeight[4]; unsigned char nLockTime[4]; unsigned char sigHashType[4]; + + #ifdef APP_METAVERSE + unsigned char totalTokenInputAmount[8]; // same as totalOutputAmount, but for Tokens + unsigned char decimals[4]; // For Metaverse tokens, need to provide precision for all outputs from external source (maximum can handle 4 outputs with tokens) + #endif }; typedef struct btchip_context_s btchip_context_t; @@ -292,7 +297,8 @@ typedef enum btchip_coin_kind_e { COIN_KIND_XSN, COIN_KIND_NIX, COIN_KIND_LBRY, - COIN_KIND_RESISTANCE + COIN_KIND_RESISTANCE, + COIN_KIND_METAVERSE } btchip_coin_kind_t; typedef struct btchip_altcoin_config_s { @@ -316,4 +322,21 @@ typedef struct btchip_altcoin_config_s { void btchip_context_init(void); +#define DECIMALS (!(G_coin_config->flags & FLAG_PEERCOIN_UNITS) ? 8 : 6) + +#ifdef APP_METAVERSE +// Metaverse reuse context variables to save memory +#define ETP_COUNTER btchip_context_D.trustedInputIndex // unsigned long int +#define ETP_BUFF btchip_context_D.nVersionGroupId // unsigned char[4] +#define ETP_AMOUNT btchip_context_D.inputValue // unsigned char[8] +#define ETP_DECIMALS btchip_context_D.nExpiryHeight[0] // unsigned char +#define ETP_LENGTH btchip_context_D.nExpiryHeight[1] // unsigned char +#define ETP_TMP btchip_context_D.nExpiryHeight[2] // unsigned char +#define ETP_OUT_TYPE btchip_context_D.nExpiryHeight[3] // unsigned char +#define ETP_VERSION btchip_context_D.overwinterSignReady // unsigned char +#define ETP_TLEN btchip_context_D.overwinterSignReady // unsigned char +#define ETP_POINTER (parsePointer + ETP_COUNTER) +#define ETP_MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + #endif diff --git a/include/btchip_filesystem.h b/include/btchip_filesystem.h index 555953c8..77eae7be 100644 --- a/include/btchip_filesystem.h +++ b/include/btchip_filesystem.h @@ -35,7 +35,8 @@ enum btchip_family_e { BTCHIP_FAMILY_BITCOIN = 0x01, BTCHIP_FAMILY_PEERCOIN = 0x02, BTCHIP_FAMILY_QTUM = 0x03, - BTCHIP_FAMILY_STEALTH = 0x04 + BTCHIP_FAMILY_STEALTH = 0x04, + BTCHIP_FAMILY_METAVERSE = 0x05 }; struct btchip_config_s { diff --git a/metaverse.png b/metaverse.png new file mode 100644 index 00000000..da7bbd0c Binary files /dev/null and b/metaverse.png differ diff --git a/nanos_app_metaverse.gif b/nanos_app_metaverse.gif new file mode 100644 index 00000000..838245a8 Binary files /dev/null and b/nanos_app_metaverse.gif differ diff --git a/nanos_badge_metaverse.gif b/nanos_badge_metaverse.gif new file mode 100644 index 00000000..838245a8 Binary files /dev/null and b/nanos_badge_metaverse.gif differ diff --git a/nanox_app_metaverse.gif b/nanox_app_metaverse.gif new file mode 100644 index 00000000..838245a8 Binary files /dev/null and b/nanox_app_metaverse.gif differ diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index 34bc53e3..969e7d16 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -38,6 +38,12 @@ static void btchip_apdu_hash_input_finalize_full_reset(void) { btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; os_memset(btchip_context_D.totalOutputAmount, 0, sizeof(btchip_context_D.totalOutputAmount)); + #ifdef APP_METAVERSE + if (G_coin_config->kind == COIN_KIND_METAVERSE) { + os_memset(btchip_context_D.totalTokenInputAmount, 0, + sizeof(btchip_context_D.totalTokenInputAmount)); + } + #endif btchip_context_D.changeOutputFound = 0; btchip_set_check_internal_structure_integrity(1); } @@ -106,7 +112,30 @@ static bool check_output_displayable() { } } } + + #ifdef APP_METAVERSE + if (G_coin_config->kind == COIN_KIND_METAVERSE) { + if (ETP_OUT_TYPE == 3 || ETP_OUT_TYPE == 21 || ETP_OUT_TYPE == 41 || ETP_OUT_TYPE == 42 || ETP_OUT_TYPE == 61 || ETP_OUT_TYPE == 62) { + changeFound = false; // Always display some transaction output types (even when it is for the same address as input) + } + } + #endif + if (changeFound) { + #ifdef APP_METAVERSE + // Allow 2 change outputs for metaverse (ETP + token) + if (G_coin_config->kind == COIN_KIND_METAVERSE) { + if (btchip_context_D.changeOutputFound >= 2) { + PRINTF("Error : Multiple change output found"); + THROW(EXCEPTION); + } + btchip_context_D.changeOutputFound++; + displayable = false; + + return displayable; + } + #endif + if (btchip_context_D.changeOutputFound) { PRINTF("Error : Multiple change output found"); THROW(EXCEPTION); @@ -171,6 +200,197 @@ static bool handle_output_state() { if (btchip_context_D.currentOutput[8] < 0xFD) { scriptSize = btchip_context_D.currentOutput[8]; discardSize = 1; + + #ifdef APP_METAVERSE + if (G_coin_config->kind == COIN_KIND_METAVERSE) { // Parsing output tx + ETP_OUT_TYPE = 255; + ETP_VERSION = 0; + + unsigned char *parsePointer = btchip_context_D.currentOutput; + ETP_COUNTER = scriptSize + 9; + + os_memmove(ETP_BUFF, ETP_POINTER, 4); // Version + ETP_COUNTER += 4; + + if ( + ETP_BUFF[0] == 1 && + ETP_BUFF[1] == 0 && + ETP_BUFF[2] == 0 && + ETP_BUFF[3] == 0 + ) { + ETP_VERSION = 1; + } else if ( + ETP_BUFF[0] == 207 && + ETP_BUFF[1] == 0 && + ETP_BUFF[2] == 0 && + ETP_BUFF[3] == 0 + ) { + ETP_VERSION = 207; + } + + if (ETP_VERSION != 1 && ETP_VERSION != 207) { + PRINTF("PARSE ERROR ETP_VERSION %d\n", ETP_VERSION); + THROW(EXCEPTION); + } + + os_memmove(ETP_BUFF, ETP_POINTER, 4); // Type + ETP_COUNTER += 4; + + if (ETP_VERSION == 207) { + // to_did + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + // from_did + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + } + + if ( + ETP_BUFF[1] != 0 || + ETP_BUFF[2] != 0 || + ETP_BUFF[3] != 0 + ) { + PRINTF("PARSE ERROR Unknown ETP Type\n"); + THROW(EXCEPTION); + } + + if (ETP_BUFF[0] == 0) { // ATTACHMENT.TYPE.ETP_TRANSFER + ETP_OUT_TYPE = 0; + } else if (ETP_BUFF[0] == 2) { // ATTACHMENT.TYPE.MST + os_memmove(ETP_BUFF, ETP_POINTER, 4); // Status + ETP_COUNTER += 4; + + if ( + ETP_BUFF[1] != 0 || + ETP_BUFF[2] != 0 || + ETP_BUFF[3] != 0 + ) { + PRINTF("PARSE ERROR Unknown ETP Status\n"); + THROW(EXCEPTION); + } + + if (ETP_BUFF[0] == 1) { // MST.STATUS.REGISTER + ETP_COUNTER += *ETP_POINTER + 1 + 16 + 1 + 1 + 2; + // Length varint + Ticker length + maximum supply + precision + secondary issue threshold + '0000' + + ETP_COUNTER += *ETP_POINTER + 1; // issuer + ETP_COUNTER += *ETP_POINTER + 1; // recipient address + ETP_COUNTER += *ETP_POINTER + 1; // description + + ETP_OUT_TYPE = 21; + } else if (ETP_BUFF[0] == 2) { // MST.STATUS.TRANSFER + ETP_COUNTER += *ETP_POINTER + 1 + 8; + // Length varint + Ticker length + Amount length + + btchip_swap_bytes(ETP_AMOUNT, ETP_POINTER - 8, 8); + transaction_amount_sub_be(btchip_context_D.totalTokenInputAmount, btchip_context_D.totalTokenInputAmount, ETP_AMOUNT); + + ETP_OUT_TYPE = 22; + } else { + PRINTF("PARSE ERROR Unknown ETP Status\n"); + THROW(EXCEPTION); + } + } else if (ETP_BUFF[0] == 3) { // ATTACHMENT.TYPE.MESSAGE + // Message + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + ETP_OUT_TYPE = 3; + } else if (ETP_BUFF[0] == 4) { // ATTACHMENT.TYPE.AVATAR + os_memmove(ETP_BUFF, ETP_POINTER, 4); // Status + ETP_COUNTER += 4; + + if ( + ETP_BUFF[1] != 0 || + ETP_BUFF[2] != 0 || + ETP_BUFF[3] != 0 + ) { + PRINTF("PARSE ERROR Unknown ETP Status\n"); + THROW(EXCEPTION); + } + + // Status = 1 | 2 (AVATAR.STATUS.REGISTER | AVATAR.STATUS.TRANSFER) + if (ETP_BUFF[0] == 1 || ETP_BUFF[0] == 2) { + // Symbol text length + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + // Symbol address length + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + ETP_OUT_TYPE = 41; + } else { + PRINTF("PARSE ERROR Unknown ETP Status\n"); + THROW(EXCEPTION); + + //ETP_OUT_TYPE = 42; + } + } else if (ETP_BUFF[0] == 5) { // ATTACHMENT.TYPE.CERT + // Symbol + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + // Owner + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + // Address + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + os_memmove(ETP_BUFF, ETP_POINTER, 4); + ETP_COUNTER += 4; // Cert + + ETP_COUNTER += 1; // Status + + if (true) { // Check currentOutput has more data + // content + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + } + + ETP_OUT_TYPE = 5; + } else if (ETP_BUFF[0] == 6) { // ATTACHMENT.TYPE.MIT + ETP_BUFF[0] = *ETP_POINTER; + ETP_COUNTER += 1; // Status + + if (ETP_BUFF[0] == 1) { // Constants.MIT.STATUS.REGISTER + // Symbol + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + // Address + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + // content + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + ETP_OUT_TYPE = 61; + } else if (ETP_BUFF[0] == 2) { // Constants.MIT.STATUS.TRANSFER + // Symbol + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + // address + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + os_memset(ETP_AMOUNT, 0, sizeof(ETP_AMOUNT)); + ETP_AMOUNT[0] = 1; + transaction_amount_sub_be(btchip_context_D.totalTokenInputAmount, btchip_context_D.totalTokenInputAmount, ETP_AMOUNT); + + ETP_OUT_TYPE = 62; + } else { + PRINTF("PARSE ERROR Unknown ETP Status\n"); + THROW(EXCEPTION); + } + } + scriptSize = ETP_COUNTER - 9; + } + #endif } else if (btchip_context_D.currentOutput[8] == 0xFD) { if (btchip_context_D.currentOutputOffset < 9 + 2) { break; @@ -252,6 +472,12 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( } } + #ifdef APP_METAVERSE + if (G_coin_config->kind == COIN_KIND_METAVERSE) { + btchip_context_D.tmpCtx.output.multipleOutput = 1; // Disable BTCHIP_OUTPUT_HANDLE_LEGACY; + } + #endif + // Check state BEGIN_TRY { TRY { @@ -263,6 +489,19 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( } if (p1 == FINALIZE_P1_CHANGEINFO) { + #ifdef APP_METAVERSE + if (G_coin_config->kind == COIN_KIND_METAVERSE) { + if (G_io_apdu_buffer[ISO_OFFSET_P2] == 0x0E) { + // This command is used to specify decimal precision for tokens outputs + if (apduLength > 4) { // For Metaverse can handle max 4 outputs with tokens + goto discardTransaction; + } + os_memmove(btchip_context_D.decimals, G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength); + goto return_OK; + } + } + #endif + unsigned char keyLength; if (!btchip_context_D.transactionContext.firstSigned) { // Already validated, should be prevented on the client side diff --git a/src/btchip_bcd.c b/src/btchip_bcd.c index a243ffaa..65e51b75 100644 --- a/src/btchip_bcd.c +++ b/src/btchip_bcd.c @@ -20,16 +20,10 @@ #define SCRATCH_SIZE 21 unsigned char -btchip_convert_hex_amount_to_displayable(unsigned char *amount) { - unsigned char LOOP1; - unsigned char LOOP2; - if (!(G_coin_config->flags & FLAG_PEERCOIN_UNITS)) { - LOOP1 = 13; - LOOP2 = 8; - } else { - LOOP1 = 15; - LOOP2 = 6; - } +btchip_convert_hex_amount_to_displayable(unsigned char *amount, unsigned char decimals) { + unsigned char LOOP1 = SCRATCH_SIZE - decimals; + unsigned char LOOP2 = decimals; + unsigned short scratch[SCRATCH_SIZE]; unsigned char offset = 0; unsigned char nonZero = 0; diff --git a/src/btchip_context.c b/src/btchip_context.c index a085ef59..b2f679ac 100644 --- a/src/btchip_context.c +++ b/src/btchip_context.c @@ -31,6 +31,12 @@ void btchip_context_init() { btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; os_memset(btchip_context_D.totalOutputAmount, 0, sizeof(btchip_context_D.totalOutputAmount)); + #ifdef APP_METAVERSE + if (G_coin_config->kind == COIN_KIND_METAVERSE) { + os_memset(btchip_context_D.totalTokenInputAmount, 0, + sizeof(btchip_context_D.totalTokenInputAmount)); + } + #endif btchip_context_D.changeOutputFound = 0; if (N_btchip.config_valid != 0x01) { diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index 4369e884..71dd15e2 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -354,6 +354,20 @@ unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_pa return 1; } + #ifdef APP_METAVERSE + // Allow change path to be 0 or 1 (no security threats here) + if (G_coin_config->kind == COIN_KIND_METAVERSE) { + // If the account or address index is very high or if the change isn't 0 or 1, return a warning + if((bip32PathInt[BIP44_ACCOUNT_OFFSET]^0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || + (bip32PathInt[BIP44_CHANGE_OFFSET] != 0 && bip32PathInt[BIP44_CHANGE_OFFSET] != 1) || + bip32PathInt[BIP44_ADDRESS_INDEX_OFFSET] > MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { + return 1; + } + + return 0; + } + #endif + // If the account or address index is very high or if the change isn't 1, return a warning if((bip32PathInt[BIP44_ACCOUNT_OFFSET]^0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || bip32PathInt[BIP44_CHANGE_OFFSET] != is_change_path?1:0 || diff --git a/src/btchip_transaction.c b/src/btchip_transaction.c index 1afbcc0f..ef8d6653 100644 --- a/src/btchip_transaction.c +++ b/src/btchip_transaction.c @@ -728,6 +728,225 @@ void transaction_parse(unsigned char parseMode) { btchip_context_D.transactionContext.scriptRemaining = transaction_get_varint(); + #ifdef APP_METAVERSE + if (G_coin_config->kind == COIN_KIND_METAVERSE) { // Parsing input tx + ETP_VERSION = 0; + ETP_COUNTER = btchip_context_D.transactionContext.scriptRemaining; + unsigned char *parsePointer = btchip_context_D.transactionBufferPointer; + + os_memmove(ETP_BUFF, ETP_POINTER, 4); // Version + ETP_COUNTER += 4; + + if ( + ETP_BUFF[0] == 1 && + ETP_BUFF[1] == 0 && + ETP_BUFF[2] == 0 && + ETP_BUFF[3] == 0 + ) { + ETP_VERSION = 1; + } else if ( + ETP_BUFF[0] == 207 && + ETP_BUFF[1] == 0 && + ETP_BUFF[2] == 0 && + ETP_BUFF[3] == 0 + ) { + ETP_VERSION = 207; + } + + if (ETP_VERSION != 1 && ETP_VERSION != 207) { + PRINTF("PARSE ERROR ETP_VERSION %d\n", ETP_VERSION); + goto fail; + } + + os_memmove(ETP_BUFF, ETP_POINTER, 4); + ETP_COUNTER += 4; // Type + + if (ETP_VERSION == 207) { + // to_did + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + // from_did + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + } + + if ( + ETP_BUFF[1] != 0 || + ETP_BUFF[2] != 0 || + ETP_BUFF[3] != 0 + ) { + PRINTF("PARSE ERROR Unknown ETP Type\n"); + goto fail; + } + + if (ETP_BUFF[0] == 0) { // ATTACHMENT.TYPE.ETP_TRANSFER + + } else if (ETP_BUFF[0] == 2) { // ATTACHMENT.TYPE.MST + os_memmove(ETP_BUFF, ETP_POINTER, 4); + ETP_COUNTER += 4; // Status + + if ( + ETP_BUFF[1] != 0 || + ETP_BUFF[2] != 0 || + ETP_BUFF[3] != 0 + ) { + PRINTF("PARSE ERROR Unknown ETP Status\n"); + goto fail; + } + + if (ETP_BUFF[0] == 1) { // MST.STATUS.REGISTER + ETP_COUNTER += *ETP_POINTER + 1 + 8; + // Length varint + Ticker length + Amount length + + if ( + parseMode == PARSE_MODE_TRUSTED_INPUT && + btchip_context_D.transactionContext.transactionCurrentInputOutput == btchip_context_D.transactionTargetInput + ) { + btchip_swap_bytes(ETP_AMOUNT, ETP_POINTER - 8, 8); + transaction_amount_add_be( + btchip_context_D.totalTokenInputAmount, + btchip_context_D.totalTokenInputAmount, + ETP_AMOUNT + ); + } + + ETP_COUNTER += 1 + 1 + 2; + // precision + secondary issue threshold + '0000' + + ETP_COUNTER += *ETP_POINTER + 1; // issuer + ETP_COUNTER += *ETP_POINTER + 1; // recipient address + ETP_COUNTER += *ETP_POINTER + 1; // description + } else if (ETP_BUFF[0] == 2) { // MST.STATUS.TRANSFER + ETP_COUNTER += *ETP_POINTER + 1 + 8; + // Length varint + Ticker length + Amount length + + if ( + parseMode == PARSE_MODE_TRUSTED_INPUT && + btchip_context_D.transactionContext.transactionCurrentInputOutput == btchip_context_D.transactionTargetInput + ) { + btchip_swap_bytes(ETP_AMOUNT, ETP_POINTER - 8, 8); + transaction_amount_add_be( + btchip_context_D.totalTokenInputAmount, + btchip_context_D.totalTokenInputAmount, + ETP_AMOUNT + ); + } + } else { + PRINTF("PARSE ERROR Unknown ETP Status\n"); + goto fail; + } + } else if (ETP_BUFF[0] == 3) { // ATTACHMENT.TYPE.MESSAGE + // Message + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + } else if (ETP_BUFF[0] == 4) { // ATTACHMENT.TYPE.AVATAR + os_memmove(ETP_BUFF, ETP_POINTER, 4); + ETP_COUNTER += 4; // Status + + if ( + ETP_BUFF[1] != 0 || + ETP_BUFF[2] != 0 || + ETP_BUFF[3] != 0 + ) { + PRINTF("PARSE ERROR Unknown ETP Status\n"); + goto fail; + } + + // Status = 1 | 2 (AVATAR.STATUS.REGISTER | AVATAR.STATUS.TRANSFER) + if (ETP_BUFF[0] == 1 || ETP_BUFF[0] == 2) { + // Symbol text length + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + // Symbol address length + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + if ( + parseMode == PARSE_MODE_TRUSTED_INPUT && + btchip_context_D.transactionContext.transactionCurrentInputOutput == btchip_context_D.transactionTargetInput + ) { + PRINTF("PARSE ERROR Can not use AVATAR.STATUS.REGISTER | AVATAR.STATUS.TRANSFER as input\n"); + goto fail; + } + } else { + PRINTF("PARSE ERROR Unknown ETP Status\n"); + goto fail; + } + } else if (ETP_BUFF[0] == 5) { // ATTACHMENT.TYPE.CERT + // Symbol + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + // Owner + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + // Address + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + os_memmove(ETP_BUFF, ETP_POINTER, 4); + ETP_COUNTER += 4; // Cert + + ETP_COUNTER += 1; // Status + + if (true) { // Check currentOutput has more data + // content + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + } + + if ( + parseMode == PARSE_MODE_TRUSTED_INPUT && + btchip_context_D.transactionContext.transactionCurrentInputOutput == btchip_context_D.transactionTargetInput + ) { + PRINTF("PARSE ERROR Can not use ATTACHMENT.TYPE.CERT as input\n"); + goto fail; + } + } else if (ETP_BUFF[0] == 6) { // ATTACHMENT.TYPE.MIT + ETP_BUFF[0] = *ETP_POINTER; + ETP_COUNTER += 1; // Status + + if (ETP_BUFF[0] == 1 || ETP_BUFF[0] == 2) { // MIT.STATUS.REGISTER | MIT.STATUS.TRANSFER + // Symbol + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + // Address + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + if (ETP_BUFF[0] == 1) { // MIT.STATUS.REGISTER + // Content + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + } + + if ( + parseMode == PARSE_MODE_TRUSTED_INPUT && + btchip_context_D.transactionContext.transactionCurrentInputOutput == btchip_context_D.transactionTargetInput + ) { + os_memset(ETP_AMOUNT, 0, sizeof(ETP_AMOUNT)); + ETP_AMOUNT[0] = 1; + + transaction_amount_add_be( + btchip_context_D.totalTokenInputAmount, + btchip_context_D.totalTokenInputAmount, + ETP_AMOUNT + ); + } + } else { + PRINTF("PARSE ERROR Unknown ETP Status\n"); + goto fail; + } + } + + btchip_context_D.transactionContext.scriptRemaining = ETP_COUNTER; + } + #endif + PRINTF("Script to read " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); // Move on btchip_context_D.transactionContext.transactionState = diff --git a/src/main.c b/src/main.c index 0a81ac2b..e8a6c526 100644 --- a/src/main.c +++ b/src/main.c @@ -158,6 +158,13 @@ union { char fullAddress[65]; // the address char fullAmount[20]; // full amount char feesAmount[20]; // fees + + #ifdef APP_METAVERSE + // char fullAmount[40]; - Metaverse may have long token names, so maybe increase fullAmount from 20 to 40? + // char metaverse_message[255]; - app freezes when having this var + char metaverse_decimals[3]; // For displaying decimals (0-10) + char metaverse_did[20]; // For displaying destination avatar + #endif } tmp; struct { @@ -986,6 +993,30 @@ const bagl_element_t ui_verify_output_nanos[] = { unsigned int ui_verify_output_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); +#ifdef APP_METAVERSE +const bagl_element_t ui_verify_output_decimals_nanos[] = { + UI_NANOS_BACKGROUND(), + UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), + UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), + UI_NANOS_TEXT(1, 0, 12, 128, "Confirm", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_TEXT(1, 0, 26, 128, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_TEXT(2, 0, 12, 128, "Amount", BAGL_FONT_OPEN_SANS_REGULAR_11px), + UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_TEXT(3, 0, 12, 128, "Decimals", BAGL_FONT_OPEN_SANS_REGULAR_11px), + UI_NANOS_TEXT(3, 0, 26, 128, vars.tmp.metaverse_decimals, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_TEXT(4, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), + UI_NANOS_SCROLLING_TEXT(4, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) +}; + +unsigned int ui_verify_output_decimals_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter); +#endif + + + const bagl_element_t ui_finalize_nanos[] = { UI_NANOS_BACKGROUND(), UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), @@ -1229,6 +1260,22 @@ unsigned int ui_verify_output_nanos_button(unsigned int button_mask, return 0; } +#ifdef APP_METAVERSE +unsigned int ui_verify_output_decimals_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) { + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_verify_cancel(NULL); + break; + + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_verify_ok(NULL); + break; + } + return 0; +} +#endif + unsigned int ui_finalize_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { switch (button_mask) { @@ -1692,6 +1739,124 @@ UX_FLOW(ux_confirm_single_flow, &ux_confirm_single_flow_6_step ); +#ifdef APP_METAVERSE +// confirm_single: confirm output #x(feesAmount) / Amount: fullAmount / Decimals: decimals / Address: fullAddress +UX_STEP_NOCB( + ux_confirm_single_flow_4_step, + bnnn_paging, + { + .title = "Decimals", + .text = vars.tmp.metaverse_decimals, + }); + +UX_FLOW(ux_confirm_metaverse_decimals_flow, + &ux_confirm_single_flow_1_step, + &ux_confirm_single_flow_2_step, + &ux_confirm_single_flow_3_step, + &ux_confirm_single_flow_4_step, + &ux_confirm_single_flow_5_step, + &ux_confirm_single_flow_6_step +); + +UX_STEP_NOCB( + ux_confirm_metaverse_toavatar_step, + bnnn_paging, + { + .title = "To Avatar", + .text = vars.tmp.metaverse_did, + }); +UX_STEP_NOCB( + ux_confirm_metaverse_symbol_step, + bnnn_paging, + { + .title = "New MST", + .text = vars.tmp.fullAmount, + }); +UX_FLOW(ux_confirm_metaverse_mst_create_flow, + &ux_confirm_single_flow_1_step, + &ux_confirm_metaverse_symbol_step, + &ux_confirm_single_flow_3_step, + &ux_confirm_metaverse_toavatar_step, + &ux_confirm_single_flow_5_step, + &ux_confirm_single_flow_6_step +); + +// Avatar +UX_STEP_NOCB( + ux_confirm_metaverse_newavatar_step, + bnnn_paging, + { + .title = "New Avatar", + .text = vars.tmp.fullAmount, + }); +UX_FLOW(ux_confirm_metaverse_avatar_create_flow, + &ux_confirm_single_flow_1_step, + &ux_confirm_metaverse_newavatar_step, + &ux_confirm_single_flow_3_step, + &ux_confirm_single_flow_5_step, + &ux_confirm_single_flow_6_step +); + +// MIT +UX_FLOW(ux_confirm_metaverse_mit_transfer_flow, + &ux_confirm_single_flow_1_step, + &ux_confirm_single_flow_2_step, + &ux_confirm_metaverse_toavatar_step, + &ux_confirm_single_flow_3_step, + &ux_confirm_single_flow_5_step, + &ux_confirm_single_flow_6_step +); +UX_STEP_NOCB( + ux_confirm_metaverse_mit_create_step, + bnnn_paging, + { + .title = "New MIT", + .text = vars.tmp.fullAmount, + }); +UX_FLOW(ux_confirm_metaverse_mit_create_flow, + &ux_confirm_single_flow_1_step, + &ux_confirm_metaverse_mit_create_step, + &ux_confirm_metaverse_toavatar_step, + &ux_confirm_single_flow_3_step, + &ux_confirm_single_flow_5_step, + &ux_confirm_single_flow_6_step +); + +// Message +UX_STEP_NOCB( + ux_confirm_metaverse_message_step, + bnnn_paging, + { + .title = "Message", + .text = vars.tmp.fullAmount, + }); +UX_FLOW(ux_confirm_metaverse_message_flow, + &ux_confirm_single_flow_1_step, + &ux_confirm_metaverse_message_step, + &ux_confirm_single_flow_3_step, + &ux_confirm_single_flow_5_step, + &ux_confirm_single_flow_6_step +); + +// Cert +UX_STEP_NOCB( + ux_confirm_metaverse_cert_step, + bnnn_paging, + { + .title = "Certificate", + .text = vars.tmp.fullAmount, + }); +UX_FLOW(ux_confirm_metaverse_cert_flow, + &ux_confirm_single_flow_1_step, + &ux_confirm_metaverse_cert_step, + &ux_confirm_metaverse_toavatar_step, + &ux_confirm_single_flow_3_step, + &ux_confirm_single_flow_5_step, + &ux_confirm_single_flow_6_step +); + +#endif + ////////////////////////////////////////////////////////////////////// UX_STEP_NOCB( @@ -2013,6 +2178,25 @@ uint8_t prepare_fees() { unsigned short textSize; unsigned char borrow; + #ifdef APP_METAVERSE + if (G_coin_config->kind == COIN_KIND_METAVERSE) { + if ( + btchip_context_D.totalTokenInputAmount[0] != 0 || + btchip_context_D.totalTokenInputAmount[1] != 0 || + btchip_context_D.totalTokenInputAmount[2] != 0 || + btchip_context_D.totalTokenInputAmount[3] != 0 || + btchip_context_D.totalTokenInputAmount[4] != 0 || + btchip_context_D.totalTokenInputAmount[5] != 0 || + btchip_context_D.totalTokenInputAmount[6] != 0 || + btchip_context_D.totalTokenInputAmount[7] != 0 + ) { + // Transaction input tokens amount must be equal to output tokens amount (MIT counts as 1) + PRINTF("Error : Token amount not consistent"); + goto error; + } + } + #endif + borrow = transaction_amount_sub_be( fees, btchip_context_D.transactionContext.transactionAmount, btchip_context_D.totalOutputAmount); @@ -2031,7 +2215,7 @@ uint8_t prepare_fees() { btchip_context_D.tmp = (unsigned char *)(vars.tmp.feesAmount + btchip_context_D.shortCoinIdLength + 1); - textSize = btchip_convert_hex_amount_to_displayable(fees); + textSize = btchip_convert_hex_amount_to_displayable(fees, DECIMALS); vars.tmp.feesAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = '\0'; } @@ -2057,6 +2241,11 @@ uint8_t prepare_single_output() { unsigned short textSize; unsigned char nativeSegwit; + #ifdef APP_METAVERSE + if (G_coin_config->kind == COIN_KIND_METAVERSE) { + vars.tmp.metaverse_decimals[0] = '\0'; + } + #endif vars.tmp.fullAddress[0] = '\0'; btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); offset += 8; @@ -2144,7 +2333,7 @@ uint8_t prepare_single_output() { } headerLength = strlen(vars.tmp.fullAmount); btchip_context_D.tmp = vars.tmp.fullAmount + headerLength; - textSize = btchip_convert_hex_amount_to_displayable(btchip_context_D.currentOutput + offset + 3 + 4 + 4 + 4); + textSize = btchip_convert_hex_amount_to_displayable(btchip_context_D.currentOutput + offset + 3 + 4 + 4 + 4, DECIMALS); vars.tmp.fullAmount[textSize + headerLength] = '\0'; } else { @@ -2154,11 +2343,458 @@ uint8_t prepare_single_output() { btchip_context_D.tmp = (unsigned char *)(vars.tmp.fullAmount + btchip_context_D.shortCoinIdLength + 1); - textSize = btchip_convert_hex_amount_to_displayable(amount); + textSize = btchip_convert_hex_amount_to_displayable(amount, DECIMALS); vars.tmp.fullAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = '\0'; } + #ifdef APP_METAVERSE + // 0 - ETP, 21 - MST REG, 22 - MST TX, 3 - MESSAGE, 41 - AVA REG, 42 - AVA TX, 5 - CERT, 61 - MIT REG, 62 - MIT TX + if (G_coin_config->kind == COIN_KIND_METAVERSE) { // Parsing displayable outputs + ETP_OUT_TYPE = 255; + ETP_VERSION = 0; + ETP_TMP = 0; + ETP_DECIMALS = DECIMALS; + vars.tmp.metaverse_decimals[0] = '\0'; + + unsigned char *parsePointer = btchip_context_D.currentOutput; + ETP_COUNTER = offset + 26; + + ETP_LENGTH = btchip_context_D.shortCoinIdLength; + + os_memmove(ETP_BUFF, ETP_POINTER, 4); + ETP_COUNTER += 4; + + // Version = 1 | 207 (ATTACHMENT.VERSION.DEFAULT | ATTACHMENT.VERSION.DID) + if ( + ETP_BUFF[0] == 1 && + ETP_BUFF[1] == 0 && + ETP_BUFF[2] == 0 && + ETP_BUFF[3] == 0 + ) { + ETP_VERSION = 1; + } else if ( + ETP_BUFF[0] == 207 && + ETP_BUFF[1] == 0 && + ETP_BUFF[2] == 0 && + ETP_BUFF[3] == 0 + ) { + ETP_VERSION = 207; + } + + PRINTF("ETP_VERSION %d\n", ETP_VERSION); + + if (ETP_VERSION != 1 && ETP_VERSION != 207) { + PRINTF("PARSE ERROR ETP_VERSION %d\n", ETP_VERSION); + return 0; + } + + os_memmove(ETP_BUFF, ETP_POINTER, 4); + ETP_COUNTER += 4; + + if (ETP_VERSION == 207) { + // to_did length + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + + ETP_TLEN = ETP_MIN(ETP_TMP, sizeof(vars.tmp.metaverse_did) - 1); + os_memmove(vars.tmp.metaverse_did, ETP_POINTER, ETP_TLEN); + vars.tmp.metaverse_did[ETP_TLEN] = '\0'; + ETP_COUNTER += ETP_TMP; + + // from_did length + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + PRINTF("vars.tmp.metaverse_did = %.*H\n", sizeof(vars.tmp.metaverse_did), vars.tmp.metaverse_did); + } + + PRINTF("ETP_BUFF Type = %.*H\n", sizeof(ETP_BUFF), ETP_BUFF); + + if ( + ETP_BUFF[1] != 0 || + ETP_BUFF[2] != 0 || + ETP_BUFF[3] != 0 + ) { + PRINTF("PARSE ERROR Unknown ETP Type\n"); + return 0; + } + + if (ETP_BUFF[0] == 0) { // ATTACHMENT.TYPE.ETP_TRANSFER + PRINTF("ATTACHMENT.TYPE.ETP_TRANSFER\n"); + ETP_OUT_TYPE = 0; + } else if (ETP_BUFF[0] == 2) { // ATTACHMENT.TYPE.MST + PRINTF("ATTACHMENT.TYPE.MST\n"); + + // Throw error is ETP amount is non zero + if ( + amount[0] != 0 || + amount[1] != 0 || + amount[2] != 0 || + amount[3] != 0 || + amount[4] != 0 || + amount[5] != 0 || + amount[6] != 0 || + amount[7] != 0 + ) { + PRINTF("PARSE ERROR AMOUNT != 0\n"); + return 0; + } + + os_memmove(ETP_BUFF, ETP_POINTER, 4); + ETP_COUNTER += 4; + + if ( + ETP_BUFF[1] != 0 || + ETP_BUFF[2] != 0 || + ETP_BUFF[3] != 0 + ) { + PRINTF("PARSE ERROR Unknown ETP Status\n"); + return 0; + } + + if (ETP_BUFF[0] == 1) { // MST.STATUS.REGISTER + // Symbol + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + ETP_TLEN = ETP_MIN(ETP_TMP, sizeof(vars.tmp.fullAmount) - 1); + os_memmove(vars.tmp.fullAmount, ETP_POINTER, ETP_TLEN); + vars.tmp.fullAmount[ETP_TLEN] = '\0'; + ETP_COUNTER += ETP_TMP; + + // Maximum supply + btchip_swap_bytes(amount, ETP_POINTER, 8); + ETP_COUNTER += 8; + + // Precision + ETP_DECIMALS = *ETP_POINTER; + ETP_COUNTER += 1; + if (ETP_DECIMALS < 0 || ETP_DECIMALS > 8) { + PRINTF("PARSE ERROR Precision not in [0, 8]\n"); + return 0; + } + + // Secondary issue threshold + ETP_COUNTER += 1; + + // 0000 bytes + os_memmove(ETP_BUFF, ETP_POINTER, 2); + ETP_COUNTER += 2; + if ( + ETP_BUFF[0] != 0 || + ETP_BUFF[1] != 0 + ) { + PRINTF("PARSE ERROR Non zero bytes\n"); + return 0; + } + + // Issuer + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + if ( + strlen(vars.tmp.metaverse_did) != ETP_TMP || + os_memcmp(vars.tmp.metaverse_did, ETP_POINTER, ETP_TMP) != 0 + ) { + PRINTF("PARSE ERROR OUTPUT AVATAR != ATTACHMENT AVATAR\n"); + return 0; + } + ETP_COUNTER += ETP_TMP; + + // Recipient address + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + if ( + strlen(vars.tmp.fullAddress) != ETP_TMP || + os_memcmp(vars.tmp.fullAddress, ETP_POINTER, ETP_TMP) != 0 + ) { + PRINTF("PARSE ERROR OUTPUT ADDRESS != ATTACHMENT ADDRESS\n"); + return 0; + } + ETP_COUNTER += ETP_TMP; + + // Description + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + //ETP_TLEN = ETP_MIN(ETP_TMP, sizeof(vars.tmp.metaverse_message) - 1); + //os_memmove(vars.tmp.metaverse_message, ETP_POINTER, ETP_TLEN); + //vars.tmp.metaverse_message[ETP_TLEN] = '\0'; + ETP_COUNTER += ETP_TMP; + + ETP_OUT_TYPE = 21; + } else if (ETP_BUFF[0] == 2) { // MST.STATUS.TRANSFER + // Symbol + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + ETP_LENGTH = ETP_TMP > 10 ? 10 : ETP_TMP; + os_memmove(vars.tmp.fullAmount, ETP_POINTER, ETP_LENGTH); + vars.tmp.fullAmount[ETP_LENGTH] = '\0'; + + // Get token transfer amount + ETP_COUNTER += ETP_TMP; + btchip_swap_bytes(amount, ETP_POINTER, 8); + ETP_COUNTER += 8; + + // Hardcode some tokens with predefined decimals (no need to display decimals confirmation to user) + if (strcmp(vars.tmp.fullAmount, "DNA") == 0) { + ETP_DECIMALS = 4; + } else if (strcmp(vars.tmp.fullAmount, "MVS.ZGC") == 0) { + ETP_DECIMALS = 8; + } else if (strcmp(vars.tmp.fullAmount, "MVS.ZDC") == 0) { + ETP_DECIMALS = 6; + } else if (strcmp(vars.tmp.fullAmount, "SDG") == 0) { + ETP_DECIMALS = 8; + } else { + ETP_DECIMALS = btchip_context_D.decimals[btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs]; + snprintf(vars.tmp.metaverse_decimals, sizeof(vars.tmp.metaverse_decimals), "%d", ETP_DECIMALS); + } + + ETP_OUT_TYPE = 22; + } else { + PRINTF("PARSE ERROR Unknown ETP Status\n"); + return 0; + } + } else if (ETP_BUFF[0] == 3) { // ATTACHMENT.TYPE.MESSAGE + // Throw error is ETP amount is non zero + if ( + amount[0] != 0 || + amount[1] != 0 || + amount[2] != 0 || + amount[3] != 0 || + amount[4] != 0 || + amount[5] != 0 || + amount[6] != 0 || + amount[7] != 0 + ) { + PRINTF("PARSE ERROR AMOUNT != 0\n"); + return 0; + } + + // Message + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + + ETP_TLEN = ETP_MIN(ETP_TMP, sizeof(vars.tmp.fullAmount) - 1); + os_memmove(vars.tmp.fullAmount, ETP_POINTER, ETP_TLEN); + vars.tmp.fullAmount[sizeof(vars.tmp.fullAmount) - 2] = '.'; + vars.tmp.fullAmount[sizeof(vars.tmp.fullAmount) - 3] = '.'; + vars.tmp.fullAmount[sizeof(vars.tmp.fullAmount) - 4] = '.'; + vars.tmp.fullAmount[ETP_TLEN] = '\0'; + ETP_COUNTER += ETP_TMP; + + ETP_OUT_TYPE = 3; + } else if (ETP_BUFF[0] == 4) { // ATTACHMENT.TYPE.AVATAR + PRINTF("ATTACHMENT.TYPE.AVATAR\n"); + // Throw error is ETP amount is non zero + if ( + amount[0] != 0 || + amount[1] != 0 || + amount[2] != 0 || + amount[3] != 0 || + amount[4] != 0 || + amount[5] != 0 || + amount[6] != 0 || + amount[7] != 0 + ) { + PRINTF("PARSE ERROR AMOUNT != 0\n"); + return 0; + } + + os_memmove(ETP_BUFF, ETP_POINTER, 4); // Status + ETP_COUNTER += 4; + + if ( + ETP_BUFF[1] != 0 || + ETP_BUFF[2] != 0 || + ETP_BUFF[3] != 0 + ) { + PRINTF("PARSE ERROR Unknown ETP Status\n"); + return 0; + } + + if (ETP_BUFF[0] == 1) { // AVATAR.STATUS.REGISTER + // Symbol text length + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + ETP_TLEN = ETP_MIN(ETP_TMP, sizeof(vars.tmp.fullAmount) - 1); + os_memmove(vars.tmp.fullAmount, ETP_POINTER, ETP_TLEN); + vars.tmp.fullAmount[ETP_TLEN] = '\0'; + ETP_COUNTER += ETP_TMP; + + // Symbol address length + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + + if ( + strlen(vars.tmp.fullAddress) != ETP_TMP || + os_memcmp(vars.tmp.fullAddress, ETP_POINTER, ETP_TMP) != 0 + ) { + PRINTF("PARSE ERROR OUTPUT ADDRESS != ATTACHMENT ADDRESS\n"); + PRINTF("ADDRESS LENGTHS %d %d\n", strlen(vars.tmp.fullAddress), ETP_TMP); + PRINTF("OUTPUT ADDRESS %.*H\n", sizeof(vars.tmp.fullAddress), vars.tmp.fullAddress); + PRINTF("ATTACHMENT ADDRESS %.*H\n", ETP_TMP, ETP_POINTER); + return 0; + } + ETP_COUNTER += ETP_TMP; + + ETP_OUT_TYPE = 41; + } else if (ETP_BUFF[0] == 2) { // AVATAR.STATUS.TRANSFER + PRINTF("PARSE ERROR Unsupported ETP Status\n"); + return 0; + + //ETP_OUT_TYPE = 42; + } else { + PRINTF("PARSE ERROR Unknown ETP Status\n"); + return 0; + } + } else if (ETP_BUFF[0] == 5) { // ATTACHMENT.TYPE.CERT + // Throw error is ETP amount is non zero + if ( + amount[0] != 0 || + amount[1] != 0 || + amount[2] != 0 || + amount[3] != 0 || + amount[4] != 0 || + amount[5] != 0 || + amount[6] != 0 || + amount[7] != 0 + ) { + PRINTF("PARSE ERROR AMOUNT != 0\n"); + return 0; + } + + // Symbol + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + ETP_TLEN = ETP_MIN(ETP_TMP, sizeof(vars.tmp.fullAmount) - 1); + os_memmove(vars.tmp.fullAmount, ETP_POINTER, ETP_TLEN); + vars.tmp.fullAmount[sizeof(vars.tmp.fullAmount) - 2] = '.'; + vars.tmp.fullAmount[sizeof(vars.tmp.fullAmount) - 3] = '.'; + vars.tmp.fullAmount[sizeof(vars.tmp.fullAmount) - 4] = '.'; + vars.tmp.fullAmount[ETP_TLEN] = '\0'; + ETP_COUNTER += ETP_TMP; + + // Owner + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + if ( + strlen(vars.tmp.metaverse_did) != ETP_TMP || + os_memcmp(vars.tmp.metaverse_did, ETP_POINTER, ETP_TMP) != 0 + ) { + PRINTF("PARSE ERROR OUTPUT AVATAR != ATTACHMENT CERT OWNER\n"); + return 0; + } + ETP_COUNTER += ETP_TMP; + + // Address + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + if ( + strlen(vars.tmp.fullAddress) != ETP_TMP || + os_memcmp(vars.tmp.fullAddress, ETP_POINTER, ETP_TMP) != 0 + ) { + PRINTF("PARSE ERROR OUTPUT ADDRESS != ATTACHMENT CERT ADDRESS\n"); + return 0; + } + ETP_COUNTER += ETP_TMP; + + os_memmove(ETP_BUFF, ETP_POINTER, 4); + ETP_COUNTER += 4; // Cert + + ETP_COUNTER += 1; // Status + + if (true) { // Check currentOutput has more data + // content + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + } + + ETP_OUT_TYPE = 5; + } else if (ETP_BUFF[0] == 6) { // ATTACHMENT.TYPE.MIT + PRINTF("ATTACHMENT.TYPE.MIT\n"); + // Throw error is ETP amount is non zero + if ( + amount[0] != 0 || + amount[1] != 0 || + amount[2] != 0 || + amount[3] != 0 || + amount[4] != 0 || + amount[5] != 0 || + amount[6] != 0 || + amount[7] != 0 + ) { + PRINTF("PARSE ERROR AMOUNT != 0\n"); + return 0; + } + + ETP_BUFF[0] = *ETP_POINTER; + ETP_COUNTER += 1; + + if (ETP_BUFF[0] == 1) { // MIT.STATUS.REGISTER + // Symbol + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + ETP_TLEN = ETP_MIN(ETP_TMP, sizeof(vars.tmp.fullAmount) - 1); + os_memmove(vars.tmp.fullAmount, ETP_POINTER, ETP_TLEN); + vars.tmp.fullAmount[ETP_TLEN] = '\0'; + ETP_COUNTER += ETP_TMP; + + // Address + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + if ( + strlen(vars.tmp.fullAddress) != ETP_TMP || + os_memcmp(vars.tmp.fullAddress, ETP_POINTER, ETP_TMP) != 0 + ) { + PRINTF("PARSE ERROR OUTPUT ADDRESS != ATTACHMENT ADDRESS\n"); + return 0; + } + ETP_COUNTER += ETP_TMP; + + // Content + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1 + ETP_TMP; + + ETP_OUT_TYPE = 61; + } else if (ETP_BUFF[0] == 2) { // MIT.STATUS.TRANSFER + // Symbol + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + ETP_TLEN = ETP_MIN(ETP_TMP, sizeof(vars.tmp.fullAmount) - 1); + os_memmove(vars.tmp.fullAmount, ETP_POINTER, ETP_TLEN); + vars.tmp.fullAmount[ETP_TLEN] = '\0'; + ETP_COUNTER += ETP_TMP; + + // Address + ETP_TMP = *ETP_POINTER; + ETP_COUNTER += 1; + if (os_memcmp(vars.tmp.fullAddress, ETP_POINTER, ETP_TMP) != 0) { + PRINTF("PARSE ERROR OUTPUT ADDRESS != ATTACHMENT ADDRESS\n"); + return 0; + } + ETP_COUNTER += ETP_TMP; + + ETP_OUT_TYPE = 62; + } else { + PRINTF("PARSE ERROR UNKNOWN STATUS\n"); + return 0; + } + } else { + PRINTF("PARSE ERROR UNKNOWN TYPE\n"); + return 0; + } + + PRINTF("ETP_OUT_TYPE %d\n", ETP_OUT_TYPE); + + if (ETP_OUT_TYPE == 0 || ETP_OUT_TYPE == 22) { + vars.tmp.fullAmount[ETP_LENGTH] = ' '; + btchip_context_D.tmp = (unsigned char *)(vars.tmp.fullAmount + ETP_LENGTH + 1); + textSize = btchip_convert_hex_amount_to_displayable(amount, ETP_DECIMALS); + vars.tmp.fullAmount[textSize + ETP_LENGTH + 1] = '\0'; + vars.tmp.fullAmount[sizeof(vars.tmp.fullAmount) - 1] = '\0'; + } + } + #endif + return 1; } @@ -2386,7 +3022,7 @@ uint8_t prepare_full_output(uint8_t checkOnly) { (unsigned char *)(vars.tmp.fullAmount + btchip_context_D.shortCoinIdLength + 1); - textSize = btchip_convert_hex_amount_to_displayable(amount); + textSize = btchip_convert_hex_amount_to_displayable(amount, DECIMALS); vars.tmp .fullAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = @@ -2407,7 +3043,7 @@ uint8_t prepare_full_output(uint8_t checkOnly) { (unsigned char *)(vars.tmp.feesAmount + btchip_context_D.shortCoinIdLength + 1); - textSize = btchip_convert_hex_amount_to_displayable(fees); + textSize = btchip_convert_hex_amount_to_displayable(fees, DECIMALS); vars.tmp .feesAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = @@ -2477,6 +3113,30 @@ unsigned int btchip_bagl_confirm_single_output() { #if defined(TARGET_BLUE) ui_transaction_output_blue_init(); #elif defined(HAVE_UX_FLOW) + #ifdef APP_METAVERSE + if (G_coin_config->kind == COIN_KIND_METAVERSE) { + // 0 - ETP, 21 - MST REG, 22 - MST TX, 3 - MESSAGE, 41 - AVA REG, 42 - AVA TX, 5 - CERT, 61 - MIT REG, 62 - MIT TX + if (ETP_OUT_TYPE == 21) { + ux_flow_init(0, ux_confirm_metaverse_mst_create_flow, NULL); + } else if (ETP_OUT_TYPE == 3) { + ux_flow_init(0, ux_confirm_metaverse_message_flow, NULL); + } else if (ETP_OUT_TYPE == 41 || ETP_OUT_TYPE == 42) { + ux_flow_init(0, ux_confirm_metaverse_avatar_create_flow, NULL); + } else if (ETP_OUT_TYPE == 5) { + ux_flow_init(0, ux_confirm_metaverse_cert_flow, NULL); + } else if (ETP_OUT_TYPE == 61) { + ux_flow_init(0, ux_confirm_metaverse_mit_create_flow, NULL); + } else if (ETP_OUT_TYPE == 62) { + ux_flow_init(0, ux_confirm_metaverse_mit_transfer_flow, NULL); + } else if (vars.tmp.metaverse_decimals[0] != '\0') { + ux_flow_init(0, ux_confirm_metaverse_decimals_flow, NULL); + } else { // 0, 22 + ux_flow_init(0, ux_confirm_single_flow, NULL); + } + + return 1; + } + #endif ux_flow_init(0, ux_confirm_single_flow, NULL); #elif defined(TARGET_NANOS) ux_step = 0;