diff --git a/.codespellignore b/.codespellignore new file mode 100644 index 0000000..2222453 --- /dev/null +++ b/.codespellignore @@ -0,0 +1 @@ +nin diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index a0d4732..1f78875 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -13,3 +13,5 @@ jobs: uses: ./.github/workflows/reusable_swap_functional_tests.yml with: branch_for_exchange: ${{ github.ref }} + run_for_devices: '["nanos", "nanosp"]' + test_filter: '"tezos_new"' diff --git a/.github/workflows/misspellings_checks.yml b/.github/workflows/misspellings_checks.yml new file mode 100644 index 0000000..288749e --- /dev/null +++ b/.github/workflows/misspellings_checks.yml @@ -0,0 +1,30 @@ +name: Misspellings checks + +# This workflow performs some misspelling checks on the repository +# It is there to help us maintain a level of quality in our codebase and does not have to be kept on forked +# applications. + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + misspell: + name: Check misspellings + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Check misspellings + uses: codespell-project/actions-codespell@v1 + with: + builtin: clear,rare + check_filenames: true + ignore_words_file: .codespellignore + path: src/,test/python/,protocol.md,Makefile,README.md diff --git a/.github/workflows/reusable_swap_functional_tests.yml b/.github/workflows/reusable_swap_functional_tests.yml index 6a39a2c..3fd0bb2 100644 --- a/.github/workflows/reusable_swap_functional_tests.yml +++ b/.github/workflows/reusable_swap_functional_tests.yml @@ -5,7 +5,7 @@ on: inputs: repo_for_exchange: required: false - default: 'LedgerHQ/app-exchange' + default: 'functori/app-exchange' type: string branch_for_exchange: required: false diff --git a/Makefile b/Makefile index 8622fb1..e7b0865 100644 --- a/Makefile +++ b/Makefile @@ -32,8 +32,8 @@ APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS) APPNAME = "Exchange" APPVERSION_M = 3 -APPVERSION_N = 1 -APPVERSION_P = 0 +APPVERSION_N = 3 +APPVERSION_P = 2 APPVERSION = $(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)-dev ifdef TESTING @@ -70,12 +70,11 @@ DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERS DEFINES += OS_IO_SEPROXYHAL DEFINES += HAVE_SPRINTF DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=4 IO_HID_EP_LENGTH=64 HAVE_USB_APDU +DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL="" DEFINES += USB_SEGMENT_SIZE=64 DEFINES += BLE_SEGMENT_SIZE=32 #max MTU, min 20 -DEFINES += UNUSED\(x\)=\(void\)x - ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX)) DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 HAVE_BLE_APDU endif diff --git a/include/swap_lib_calls.h b/include/swap_lib_calls.h deleted file mode 100644 index 213d8b2..0000000 --- a/include/swap_lib_calls.h +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -/* This file is the shared API between Exchange and the apps started in Library mode for Exchange - * - * DO NOT MODIFY THIS FILE IN APPLICATIONS OTHER THAN EXCHANGE - * On modification in Exchange, forward the changes to all applications supporting Exchange - */ - -#include "stdbool.h" -#include "stdint.h" - -#define RUN_APPLICATION 1 - -#define SIGN_TRANSACTION 2 - -#define CHECK_ADDRESS 3 - -#define GET_PRINTABLE_AMOUNT 4 - -/* - * Amounts are stored as bytes, with a max size of 16 (see protobuf - * specifications). Max 16B integer is 340282366920938463463374607431768211455 - * in decimal, which is a 32-long char string. - * The printable amount also contains spaces, the ticker symbol (with variable - * size, up to 12 in Ethereum for instance) and a terminating null byte, so 50 - * bytes total should be a fair maximum. - */ -#define MAX_PRINTABLE_AMOUNT_SIZE 50 - -// structure that should be send to specific coin application to get address -typedef struct check_address_parameters_s { - // IN - uint8_t *coin_configuration; - uint8_t coin_configuration_length; - // serialized path, segwit, version prefix, hash used, dictionary etc. - // fields and serialization format depends on specific coin app - uint8_t *address_parameters; - uint8_t address_parameters_length; - char *address_to_check; - char *extra_id_to_check; - // OUT - int result; -} check_address_parameters_t; - -// structure that should be send to specific coin application to get printable amount -typedef struct get_printable_amount_parameters_s { - // IN - uint8_t *coin_configuration; - uint8_t coin_configuration_length; - uint8_t *amount; - uint8_t amount_length; - bool is_fee; - // OUT - char printable_amount[MAX_PRINTABLE_AMOUNT_SIZE]; -} get_printable_amount_parameters_t; - -typedef struct create_transaction_parameters_s { - // IN - uint8_t *coin_configuration; - uint8_t coin_configuration_length; - uint8_t *amount; - uint8_t amount_length; - uint8_t *fee_amount; - uint8_t fee_amount_length; - char *destination_address; - char *destination_address_extra_id; - // OUT - uint8_t result; -} create_transaction_parameters_t; - -typedef struct libargs_s { - unsigned int id; - unsigned int command; - unsigned int unused; - union { - check_address_parameters_t *check_address; - create_transaction_parameters_t *create_transaction; - get_printable_amount_parameters_t *get_printable_amount; - }; -} libargs_t; diff --git a/ledger_app.toml b/ledger_app.toml new file mode 100644 index 0000000..e7eb565 --- /dev/null +++ b/ledger_app.toml @@ -0,0 +1,7 @@ +[app] +build_directory = "./" +sdk = "C" +devices = ["nanos", "nanox", "nanos+", "stax"] + +[tests] +pytest_directory = "./test/python/" diff --git a/protocol.md b/protocol.md index 39681b6..8cc734d 100644 --- a/protocol.md +++ b/protocol.md @@ -1,6 +1,6 @@ # Protocol to speak with EXCHANGE application -Communication is done through a serie of request-response exchanges (APDU / RAPDU). +Communication is done through a series of request-response exchanges (APDU / RAPDU). ## Request: @@ -19,7 +19,7 @@ Communication is done through a serie of request-response exchanges (APDU / RAPD | Name | Value | Description | | ---------------------------- | ----- | ------------------------------------------------------------------------------------- | -| GET_VERSION | 0x02 | Get application version. This APDU can be sent independantly of the current app state | +| GET_VERSION | 0x02 | Get application version. This APDU can be sent independently of the current app state | | START_NEW_TRANSACTION | 0x03 | Start new EXCHANGE transaction. This APDU resets the app state | | SET_PARTNER_KEY | 0x04 | Set the credentials of the exchange partner | | CHECK_PARTNER | 0x05 | Check that the credentials of the exchange partner are signed by the Ledger key | @@ -111,12 +111,25 @@ No data expected. #### SET_PARTNER_KEY +##### For all LEGACY TYPES, the data for this command is: + | Bytes | Description | | ------------------ | ------------------------------------ | | 1 byte | Length N of the encoded partner name | | N bytes | Partner name encoded with utf-8 | | LC - (1 + N) bytes | Partner public key | +##### For all UNIFIED TYPES, the data for this command is: + +| Bytes | Description | +| ------------------ | ------------------------------------ | +| 1 byte | Length N of the encoded partner name | +| N bytes | Partner name encoded with utf-8 | +| 1 byte | Curve used by the partner | +| LC - (2 + N) bytes | Partner public key | + +With the possible values for the curve being 0x00 for SECP256K1, and 0x01 for SECP256R1. + #### CHECK_PARTNER | Bytes | Description | @@ -125,31 +138,56 @@ No data expected. #### PROCESS_TRANSACTION_RESPONSE -| Bytes | Description | -| ------------ | ----------------------------------------------------------------------------------------------- | -| 1 or 2 bytes | Length N of the encoded transaction proposal. 1 bytes on Legacy TYPES, 2 bytes on new TYPES | -| N bytes | Transaction proposal. No encoding for SWAP_LEGACY, URLsafe base 64 encoding for all other TYPES | -| 1 byte | Length M of the transaction fees | -| M bytes | Transaction fees | - Please refer to the src/protobuf files for the actual transaction proposal content. +##### For all LEGACY TYPES, the data for this command is: + +| Bytes | Description | +| ------- | ----------------------------------------------------------------------------------------------------------- | +| 1 byte | Length N of the encoded transaction proposal | +| N bytes | Transaction proposal. Bytes array for SWAP_LEGACY, URLsafe base 64 encoding for SELL_LEGACY and FUND_LEGACY | +| 1 byte | Length M of the transaction fees | +| M bytes | Transaction fees | + +##### For all UNIFIED TYPES, the data for this command is: + +| Bytes | Description | +| ------- | -------------------------------------------- | +| 1 byte | Format used for the transaction encoding | +| 2 bytes | Length N of the encoded transaction proposal | +| N bytes | Encoded transaction proposal | +| 1 byte | Length M of the transaction fees | +| M bytes | Transaction fees | + +With the possible values for the format being 0x00 for Bytes Array (no encoding), and 0x01 for Base 64 Url encoding. + The DATA of this command may exceed the capacity of a single APDU (255 bytes), in this case use the EXTENSION feature. #### CHECK_TRANSACTION_SIGNATURE -| Bytes | Description | -| -------- | ---------------------------------------------------------------------------------------------------------- | -| LC bytes | Signature of the proposed transaction by the partner. | +##### For all LEGACY TYPES, the data for this command is: + +| Bytes | Description | +| -------- | ------------------------------------------------------------- | +| LC bytes | Signature of the computed transaction proposed by the partner | + +For SWAP_LEGACY TYPE, the signature is computed on the transaction proposal. \ +For SELL_LEGACY and FUND_LEGACY the signature is computed on the transaction proposal prefixed with a DOT ('.'). + +For SWAP_LEGACY and FUND_LEGACY, the signature is in DER format. \ +For SELL_LEGACY the signature is in (R,S) format. + +##### For all UNIFIED TYPES, the data for this command is: -For SWAP_LEGACY TYPE, the signature is computed on the sha256 hash of the transaction. \ -For all other TYPES the signature is computed on the sha256 hash of the transaction prefixed with a DOT ('.'). +| Bytes | Description | +| ------------ | ------------------------------------------------------------- | +| 1 byte | If the signature is computed on a prefixed transaction | +| 1 byte | Format of the signature itself | +| LC - 2 bytes | Signature of the computed transaction proposed by the partner | -For SWAP_LEGACY and FUND_LEGACY TYPES, the signature is in DER format. \ -For all other TYPES the signature is in (R,S) format. +With the possible values for the format of the transaction used for signing being 0x01 if it was DOT ('.') prefixed, 0x00 otherwise. -For SWAP_LEGACY TYPE, the signature is computed on the secp256k1 curve. \ -For all other TYPES the signature is computed on the secp256r1 curve. +With the possible values for the format of the signature itself being 0x00 for DER format, and 0x01 for (R,S) format. #### CHECK_ASSET_IN_LEGACY diff --git a/src/apdu_parser.c b/src/apdu_parser.c index d4ee9c1..631edbf 100644 --- a/src/apdu_parser.c +++ b/src/apdu_parser.c @@ -36,9 +36,9 @@ typedef struct apdu_s { uint8_t rate; uint8_t subcommand; uint16_t data_length; - // We could have put the recontructed apdu buffer here but it would increase the RAM usage by + // We could have put the reconstructed apdu buffer here but it would increase the RAM usage by // 512 bytes which is a lot on NANOS - // Instead the recontructed apdu buffer is G_swap_ctx.raw_transaction + // Instead the reconstructed apdu buffer is G_swap_ctx.raw_transaction // It is unionized with the decoded protobuf transaction requests // Pro: less memory usage // Cons: use cautiously and only during the command PROCESS_TRANSACTION_RESPONSE_COMMAND @@ -48,8 +48,11 @@ apdu_t G_received_apdu; // Dedicated function for instruction checking as it's self contained static uint16_t check_instruction(uint8_t instruction, uint8_t subcommand) { + // True if the instruction is part of a flow and the context must be checked bool check_subcommand_context = false; + // True if the instruction can be received between user approval and child lib start bool allowed_during_waiting_for_signing = false; + // {STATE} if this command is only accepted at a specific state, -1 otherwise int check_current_state = -1; if (instruction == CHECK_ASSET_IN && (subcommand == SWAP || subcommand == SWAP_NG)) { @@ -62,11 +65,16 @@ static uint16_t check_instruction(uint8_t instruction, uint8_t subcommand) { return INVALID_INSTRUCTION; } + if (instruction == CHECK_REFUND_ADDRESS && subcommand != SWAP && subcommand != SWAP_NG) { + PRINTF("Instruction CHECK_REFUND_ADDRESS is only for SWAP based flows\n"); + return INVALID_INSTRUCTION; + } + switch (instruction) { case GET_VERSION_COMMAND: // We ignore the current context for this command as it doesn't modify anything check_subcommand_context = false; - // No strict dependancy on the current state as long as it is not a protected state + // No strict dependency on the current state as long as it is not a protected state // (WAITING_USER_VALIDATION and WAITING_SIGNING) check_current_state = -1; break; diff --git a/src/buffer.c b/src/buffer.c index 0aeb466..8223053 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -2,37 +2,37 @@ #include "os.h" // Parse a buffer at a given offset to read a buf_t, the offset is incremented accordingly -// param[in] the total buffer to parse -// param[in] the total size of the buffer to parse -// param[out] the buf_t read from in_buffer at offset, can by 0 sized -// param[in/out] the current offset at wich we are in +// param[in] the total buffer to parse +// param[in] the total size of the buffer to parse +// param[in] the size of the length field in the header +// param[out] the buf_t read from in_buffer at offset, can by 0 sized +// param[in/out] the current offset at which we are in bool parse_to_sized_buffer(uint8_t *in_buffer, uint16_t in_size, - uint8_t size_of_lenght_field, + uint8_t size_of_length_field, buf_t *out, uint16_t *offset) { - if (*offset + size_of_lenght_field > in_size) { + if (*offset + size_of_length_field > in_size) { // We can't even read the size PRINTF("Failed to read the header sized %d, only %d bytes available\n", - size_of_lenght_field, + size_of_length_field, in_size); return false; } // Read the size - if (size_of_lenght_field == 1) { + if (size_of_length_field == 1) { out->size = in_buffer[*offset]; - } else if (size_of_lenght_field == 2) { + } else if (size_of_length_field == 2) { out->size = U2BE(in_buffer, *offset); - } else if (size_of_lenght_field == 4) { - out->size = U4BE(in_buffer, *offset); } else { - PRINTF("Unable to read a %d sized header\n", size_of_lenght_field); + PRINTF("Unable to read a %d sized header\n", size_of_length_field); return false; } - *offset += size_of_lenght_field; + *offset += size_of_length_field; - if (*offset + out->size > in_size) { + // Cast before comparison to avoid potential int overflow + if (((uint32_t) *offset) + out->size > in_size) { PRINTF("Not enough remaining bytes to read. Total %d, offset %d, claims %d bytes\n", in_size, *offset, @@ -50,3 +50,19 @@ bool parse_to_sized_buffer(uint8_t *in_buffer, return true; } + +// Parse a buffer at a given offset to read a buf_t, the offset is incremented accordingly +// param[in] the total buffer to parse +// param[in] the total size of the buffer to parse +// param[out] the int read from in_buffer at offset +// param[in/out] the current offset at which we are in +bool pop_uint8_from_buffer(uint8_t *in_buffer, uint16_t in_size, uint8_t *out, uint16_t *offset) { + if (*offset + 1 > in_size) { + PRINTF("Failed to read the uint, only %d bytes available\n", in_size); + return false; + } + *out = in_buffer[*offset]; + *offset += 1; + + return true; +} diff --git a/src/buffer.h b/src/buffer.h index ee1dfea..a93dc91 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -11,6 +11,8 @@ typedef struct buf_s { bool parse_to_sized_buffer(uint8_t *in_buffer, uint16_t in_size, - uint8_t size_of_lenght_field, + uint8_t size_of_length_field, buf_t *out, uint16_t *offset); + +bool pop_uint8_from_buffer(uint8_t *in_buffer, uint16_t in_size, uint8_t *out, uint16_t *offset); diff --git a/src/check_addresses_and_amounts.c b/src/check_addresses_and_amounts.c index 655dd1b..9eb8409 100644 --- a/src/check_addresses_and_amounts.c +++ b/src/check_addresses_and_amounts.c @@ -18,13 +18,11 @@ static bool check_coin_configuration_signature(buf_t config, buf_t der) { uint8_t hash[CURVE_SIZE_BYTES]; cx_hash_sha256(config.bytes, config.size, hash, CURVE_SIZE_BYTES); - return cx_ecdsa_verify(&G_swap_ctx.ledger_public_key, - CX_LAST, - CX_SHA256, - hash, - CURVE_SIZE_BYTES, - der.bytes, - der.size); + return cx_ecdsa_verify_no_throw(&G_swap_ctx.ledger_public_key, + hash, + CURVE_SIZE_BYTES, + der.bytes, + der.size); } static bool check_received_ticker_matches_context(buf_t ticker, const command_t *cmd) { @@ -135,7 +133,7 @@ static bool format_fiat_amount(void) { return false; } - strncpy(G_swap_ctx.printable_get_amount, + strlcpy(G_swap_ctx.printable_get_amount, G_swap_ctx.sell_transaction.out_currency, sizeof(G_swap_ctx.printable_get_amount)); G_swap_ctx.printable_get_amount[len] = ' '; @@ -155,7 +153,7 @@ static bool format_fiat_amount(void) { } static void format_account_name(void) { - strncpy(G_swap_ctx.account_name, + strlcpy(G_swap_ctx.account_name, G_swap_ctx.fund_transaction.account_name, sizeof(G_swap_ctx.account_name)); G_swap_ctx.account_name[sizeof(G_swap_ctx.account_name) - 1] = '\x00'; @@ -193,10 +191,11 @@ int check_addresses_and_amounts(const command_t *cmd) { } // Break up the configuration into its individual elements - if (parse_coin_config(config, &ticker, &parsed_application_name, &sub_coin_config) == 0) { + if (!parse_coin_config(config, &ticker, &parsed_application_name, &sub_coin_config)) { PRINTF("Error: Can't parse coin config command\n"); return reply_error(INCORRECT_COMMAND_DATA); } + // We can't use the pointer to the parsed application name as it is not NULL terminated // We have to make a local copy memset(application_name, 0, sizeof(application_name)); diff --git a/src/check_partner.c b/src/check_partner.c index 5edc4fb..0b87ef3 100644 --- a/src/check_partner.c +++ b/src/check_partner.c @@ -15,13 +15,11 @@ int check_partner(const command_t *cmd) { return reply_error(INCORRECT_COMMAND_DATA); } - if (cx_ecdsa_verify(&(G_swap_ctx.ledger_public_key), - CX_LAST, - CX_SHA256, - G_swap_ctx.sha256_digest, - CURVE_SIZE_BYTES, - cmd->data.bytes, - cmd->data.size) == 0) { + if (!cx_ecdsa_verify_no_throw(&(G_swap_ctx.ledger_public_key), + G_swap_ctx.sha256_digest_no_prefix, + CURVE_SIZE_BYTES, + cmd->data.bytes, + cmd->data.size)) { PRINTF("Error: Failed to verify signature of partner data\n"); return reply_error(SIGN_VERIFICATION_FAIL); } diff --git a/src/check_tx_signature.c b/src/check_tx_signature.c index bc2b411..0d09a02 100644 --- a/src/check_tx_signature.c +++ b/src/check_tx_signature.c @@ -22,32 +22,78 @@ int check_tx_signature(const command_t *cmd) { // signature uint8_t der_sig[DER_HEADER_SIZE + MAX_DER_INT_SIZE(R_S_INT_SIZE) * 2]; buf_t signature; + bool signature_is_in_R_S_format; + bool signature_is_computed_on_dot_prefixed_tx; + uint16_t offset = 0; - if (cmd->subcommand == SWAP || cmd->subcommand == FUND) { + if (cmd->subcommand == SWAP) { + signature_is_in_R_S_format = false; + signature_is_computed_on_dot_prefixed_tx = false; + } else if (cmd->subcommand == FUND) { + signature_is_in_R_S_format = false; + signature_is_computed_on_dot_prefixed_tx = true; + } else if (cmd->subcommand == SELL) { + signature_is_in_R_S_format = true; + signature_is_computed_on_dot_prefixed_tx = true; + } else { + uint8_t dot_prefixed_tx; + if (!pop_uint8_from_buffer(cmd->data.bytes, cmd->data.size, &dot_prefixed_tx, &offset)) { + PRINTF("Failed to read prefix selector\n"); + return reply_error(INCORRECT_COMMAND_DATA); + } + if (dot_prefixed_tx == SIGNATURE_COMPUTED_ON_TX) { + signature_is_computed_on_dot_prefixed_tx = false; + } else if (dot_prefixed_tx == SIGNATURE_COMPUTED_ON_DOT_PREFIXED_TX) { + signature_is_computed_on_dot_prefixed_tx = true; + } else { + PRINTF("Error: Incorrect prefix selector %d\n", dot_prefixed_tx); + return reply_error(INCORRECT_COMMAND_DATA); + } + + uint8_t sig_format; + if (!pop_uint8_from_buffer(cmd->data.bytes, cmd->data.size, &sig_format, &offset)) { + PRINTF("Failed to read signature format selector\n"); + return reply_error(INCORRECT_COMMAND_DATA); + } + if (sig_format == DER_FORMAT_SIGNATURE) { + signature_is_in_R_S_format = false; + } else if (sig_format == R_S_FORMAT_SIGNATURE) { + signature_is_in_R_S_format = true; + } else { + PRINTF("Error: Incorrect signature format selector %d\n", sig_format); + return reply_error(INCORRECT_COMMAND_DATA); + } + } + + buf_t remaining_input; + remaining_input.size = cmd->data.size - offset; + remaining_input.bytes = cmd->data.bytes + offset; + if (!signature_is_in_R_S_format) { // We received the signature in DER format, just perform some sanity checks - if (cmd->data.size < MIN_DER_SIGNATURE_LENGTH || - cmd->data.size > MAX_DER_SIGNATURE_LENGTH) { + if (remaining_input.size < MIN_DER_SIGNATURE_LENGTH || + remaining_input.size > MAX_DER_SIGNATURE_LENGTH) { PRINTF("Error: Input buffer length don't correspond to DER length\n"); return reply_error(INCORRECT_COMMAND_DATA); } - uint16_t payload_size = cmd->data.bytes[DER_OFFSET_LENGTH]; - if (payload_size + DER_HEADER_SIZE != cmd->data.size) { - PRINTF("DER signature header advertizes %d bytes, we received %d\n", + uint16_t payload_size = remaining_input.bytes[DER_OFFSET_LENGTH]; + if (payload_size + DER_HEADER_SIZE != remaining_input.size) { + PRINTF("DER signature header advertises %d bytes, we received %d\n", payload_size, - cmd->data.size); + remaining_input.size); return reply_error(INCORRECT_COMMAND_DATA); } - signature = cmd->data; + signature.size = remaining_input.size; + signature.bytes = remaining_input.bytes; } else { // We received the signature in (R,S) format, perform some sanity checks then encode in DER - if (cmd->data.size != R_S_INT_SIZE * 2) { + if (remaining_input.size != R_S_INT_SIZE * 2) { PRINTF("Error: Input buffer length don't correspond to (R, S) length\n"); return reply_error(INCORRECT_COMMAND_DATA); } - uint8_t *r = cmd->data.bytes; - uint8_t *s = cmd->data.bytes + R_S_INT_SIZE; + uint8_t *r = remaining_input.bytes; + uint8_t *s = remaining_input.bytes + R_S_INT_SIZE; size_t der_r_len = asn1_get_encoded_integer_size(r, R_S_INT_SIZE); size_t der_s_len = asn1_get_encoded_integer_size(s, R_S_INT_SIZE); size_t size = der_r_len + der_s_len + DER_HEADER_SIZE; @@ -58,23 +104,35 @@ int check_tx_signature(const command_t *cmd) { return reply_error(SIGN_VERIFICATION_FAIL); } - encode_sig_der(der_sig, size, r, R_S_INT_SIZE, s, R_S_INT_SIZE); + if (encode_sig_der(der_sig, size, r, R_S_INT_SIZE, s, R_S_INT_SIZE) == 0) { + PRINTF("Error: Failed to encode DER signature\n"); + return reply_error(SIGN_VERIFICATION_FAIL); + } signature.size = size; signature.bytes = der_sig; } PRINTF("DER sig: %.*H\n", signature.size, signature.bytes); - PRINTF("SHA256(payload): %.*H\n", sizeof(G_swap_ctx.sha256_digest), G_swap_ctx.sha256_digest); + const uint8_t *hash; + if (signature_is_computed_on_dot_prefixed_tx) { + hash = G_swap_ctx.sha256_digest_prefixed; + PRINTF("SHA256 %.*H\n", + sizeof(G_swap_ctx.sha256_digest_prefixed), + G_swap_ctx.sha256_digest_prefixed); + } else { + hash = G_swap_ctx.sha256_digest_no_prefix; + PRINTF("SHA256 %.*H\n", + sizeof(G_swap_ctx.sha256_digest_no_prefix), + G_swap_ctx.sha256_digest_no_prefix); + } // Check the signature of the sha256_digest we computed from the tx payload - if (cx_ecdsa_verify(&G_swap_ctx.partner.public_key, - CX_LAST, - CX_SHA256, - G_swap_ctx.sha256_digest, - CURVE_SIZE_BYTES, - signature.bytes, - signature.size) == 0) { + if (!cx_ecdsa_verify_no_throw(&G_swap_ctx.partner.public_key, + hash, + CURVE_SIZE_BYTES, + signature.bytes, + signature.size)) { PRINTF("Error: Failed to verify signature of received transaction\n"); return reply_error(SIGN_VERIFICATION_FAIL); } diff --git a/src/currency_lib_calls.c b/src/currency_lib_calls.c index 06f7ff7..82b7ae0 100644 --- a/src/currency_lib_calls.c +++ b/src/currency_lib_calls.c @@ -78,7 +78,10 @@ int get_printable_amount(buf_t *coin_config, PRINTF("Error: Printable amount should be null-terminated\n"); return -1; } - strlcpy(printable_amount, lib_in_out_params.printable_amount, printable_amount_size); + if (strlcpy(printable_amount, lib_in_out_params.printable_amount, printable_amount_size) >= + printable_amount_size) { + PRINTF("strlcpy failed, destination too short for printable_amount\n"); + } PRINTF("Returned printable_amount '%s'\n", printable_amount); return 0; @@ -141,8 +144,8 @@ int create_payin_transaction(create_transaction_parameters_t *lib_in_out_params) #ifdef HAVE_NBGL // Save appname in stack to keep it from being erased // We'll need it later for the failure modale on Stax - char appanme[BOLOS_APPNAME_MAX_SIZE_B]; - strlcpy(appanme, G_swap_ctx.payin_binary_name, sizeof(appanme)); + char appname[BOLOS_APPNAME_MAX_SIZE_B]; + strlcpy(appname, G_swap_ctx.payin_binary_name, sizeof(appname)); #endif os_lib_call(libcall_params); @@ -154,7 +157,7 @@ int create_payin_transaction(create_transaction_parameters_t *lib_in_out_params) #ifdef HAVE_NBGL // Retrieve the appname from the stack and put it back in the BSS strlcpy(G_previous_cycle_data.appname_last_cycle, - appanme, + appname, sizeof(G_previous_cycle_data.appname_last_cycle)); // Remember if this sign was successful G_previous_cycle_data.was_successful = (lib_in_out_params->result == 1); diff --git a/src/currency_lib_calls.h b/src/currency_lib_calls.h index e5c5a37..9872b4e 100644 --- a/src/currency_lib_calls.h +++ b/src/currency_lib_calls.h @@ -1,6 +1,6 @@ #pragma once -#include "swap_lib_calls.h" +#include "lib_standard_app/swap_lib_calls.h" #include "buffer.h" // return 1 if the address match, 0 is not match, diff --git a/src/globals.h b/src/globals.h index 49bdd92..7bf77b8 100644 --- a/src/globals.h +++ b/src/globals.h @@ -6,13 +6,25 @@ #include "commands.h" #include "protocol.pb.h" #include "buffer.h" -#include "swap_lib_calls.h" +#include "lib_standard_app/swap_lib_calls.h" #define CURVE_SIZE_BYTES 32U #define UNCOMPRESSED_KEY_LENGTH 65U #define MIN_DER_SIGNATURE_LENGTH 67U #define MAX_DER_SIGNATURE_LENGTH 72U +#define CURVE_SECP256K1 0x00 +#define CURVE_SECP256R1 0x01 + +#define ENCODING_BYTES_ARRAY 0x00 +#define ENCODING_BASE_64_URL 0x01 + +#define DER_FORMAT_SIGNATURE 0x00 +#define R_S_FORMAT_SIGNATURE 0x01 + +#define SIGNATURE_COMPUTED_ON_TX 0x00 +#define SIGNATURE_COMPUTED_ON_DOT_PREFIXED_TX 0x01 + #define TICKER_MIN_SIZE_B 2 #define TICKER_MAX_SIZE_B 9 #define APPNAME_MIN_SIZE_B 3 @@ -74,7 +86,12 @@ typedef struct swap_app_context_s { }; }; - uint8_t sha256_digest[32]; + // During TX reception, we don't know if we'll receive the signature of the (TX), or the + // signature of the ('.' + TX). + // Storing the whole TX to calculate the hash during signature checking would use too much + // stack, so we calculate the two hashes and we'll decide later which one to use. + uint8_t sha256_digest_prefixed[32]; + uint8_t sha256_digest_no_prefix[32]; cx_ecfp_256_public_key_t ledger_public_key; diff --git a/src/main.c b/src/main.c index d0cefc4..0d4bbd1 100644 --- a/src/main.c +++ b/src/main.c @@ -50,6 +50,7 @@ void app_main(void) { // there was a fatal error during APDU reception, restart from the beginning // Don't bother trying to send a status code, IOs are probably out if (input_length == -1) { + explicit_bzero(&G_swap_ctx, sizeof(G_swap_ctx)); return; } @@ -62,6 +63,7 @@ void app_main(void) { if (dispatch_command(&cmd) < 0) { // some non recoverable error happened + explicit_bzero(&G_swap_ctx, sizeof(G_swap_ctx)); return; } diff --git a/src/parse_check_address_message.c b/src/parse_check_address_message.c index 6797916..b83b993 100644 --- a/src/parse_check_address_message.c +++ b/src/parse_check_address_message.c @@ -5,6 +5,11 @@ // Small wrapper around parse_to_sized_buffer as the DER signature encompasses the // first special byte and the size byte static bool parse_der_signature(uint8_t *in, uint16_t in_size, buf_t *der, uint16_t *offset) { + if (in_size < 3) { + PRINTF("DER signature too small, can't even read header\n"); + return false; + } + // Ignore first bytes 0x30 ++*offset; @@ -12,7 +17,8 @@ static bool parse_der_signature(uint8_t *in, uint16_t in_size, buf_t *der, uint1 if (!parse_to_sized_buffer(in, in_size, 1, der, offset)) { return false; } - // Adapt buffer to encompass the full DER signature + + // Adapt buffer to encompass the full DER signature (first 0x30 byte + length byte) der->size += 2; der->bytes = &der->bytes[-2]; return true; @@ -25,7 +31,7 @@ static bool parse_der_signature(uint8_t *in, uint16_t in_size, buf_t *der, uint1 // 1 byte 0x30 1 + X // 1 byte length C of compound object 2 + X // C bytes -// 1 byte length Y of address paramaters 1 + X + D +// 1 byte length Y of address parameters 1 + X + D // Y bytes of address parameters 2 + X + D int parse_check_address_message(const command_t *cmd, buf_t *config, diff --git a/src/parse_coin_config.c b/src/parse_coin_config.c index 2d3c04e..13fe0e3 100644 --- a/src/parse_coin_config.c +++ b/src/parse_coin_config.c @@ -27,45 +27,47 @@ const app_name_alias_t appnames_aliases[] = { * - T the ticker symbol, Lt its size * - A the application name, La its size * - C the sub configuration, Lc its size + * + * As the sub configuration is optional, we accept Lc == 0 */ -int parse_coin_config(buf_t input, - buf_t *ticker, - buf_t *application_name, - buf_t *sub_configuration) { +bool parse_coin_config(buf_t input, + buf_t *ticker, + buf_t *application_name, + buf_t *sub_configuration) { uint16_t total_read = 0; // Read ticker if (!parse_to_sized_buffer(input.bytes, input.size, 1, ticker, &total_read)) { PRINTF("Cannot read the ticker\n"); - return 0; + return false; } if (!check_ticker_length(ticker)) { - return 0; + return false; } // Read application_name if (!parse_to_sized_buffer(input.bytes, input.size, 1, application_name, &total_read)) { PRINTF("Cannot read the application_name\n"); - return 0; + return false; } if (!check_app_name_length(application_name)) { - return 0; + return false; } // Read sub configuration if (!parse_to_sized_buffer(input.bytes, input.size, 1, sub_configuration, &total_read)) { PRINTF("Cannot read the sub_configuration\n"); - return 0; + return false; } if (sub_configuration->size > MAX_COIN_SUB_CONFIG_SIZE) { PRINTF("Sub coin sub_configuration size %d is too big\n", sub_configuration->size); - return 0; + return false; } // Check that there is nothing else to read if (input.size != total_read) { PRINTF("Bytes to read: %d, bytes read: %d\n", input.size, total_read); - return 0; + return false; } // Update the application name to match Ledger's naming. @@ -82,5 +84,5 @@ int parse_coin_config(buf_t input, } } - return 1; + return true; } diff --git a/src/parse_coin_config.h b/src/parse_coin_config.h index d39c940..c8ba245 100644 --- a/src/parse_coin_config.h +++ b/src/parse_coin_config.h @@ -2,4 +2,4 @@ #include "buffer.h" -int parse_coin_config(buf_t config, buf_t *ticker, buf_t *application_name, buf_t *sub_config); +bool parse_coin_config(buf_t config, buf_t *ticker, buf_t *application_name, buf_t *sub_config); diff --git a/src/process_transaction.c b/src/process_transaction.c index e91d329..1b0febc 100644 --- a/src/process_transaction.c +++ b/src/process_transaction.c @@ -42,7 +42,8 @@ static bool parse_transaction(uint8_t *in, size_t in_size, subcommand_e subcommand, buf_t *payload, - buf_t *fees) { + buf_t *fees, + bool *needs_base64_decoding) { // On legacy flows the length field is 1 byte uint8_t payload_length_field_size = 2; if (subcommand == SWAP || subcommand == SELL || subcommand == FUND) { @@ -50,6 +51,27 @@ static bool parse_transaction(uint8_t *in, } uint16_t offset = 0; + + if (subcommand == SWAP) { + *needs_base64_decoding = false; + } else if (subcommand == SELL || subcommand == FUND) { + *needs_base64_decoding = true; + } else { + uint8_t encoding_selector; + if (!pop_uint8_from_buffer(in, in_size, &encoding_selector, &offset)) { + PRINTF("Failed to read encoding\n"); + return false; + } + if (encoding_selector == ENCODING_BYTES_ARRAY) { + *needs_base64_decoding = false; + } else if (encoding_selector == ENCODING_BASE_64_URL) { + *needs_base64_decoding = true; + } else { + PRINTF("Invalid encoding specified\n"); + return false; + } + } + if (!parse_to_sized_buffer(in, in_size, payload_length_field_size, payload, &offset)) { PRINTF("Failed to parse payload\n"); return false; @@ -75,56 +97,71 @@ static bool parse_transaction(uint8_t *in, return true; } -static bool calculate_sha256_digest(buf_t payload, subcommand_e subcommand) { - cx_sha256_t sha256; +static bool calculate_sha256_digest(buf_t payload) { + cx_sha256_t sha256_prefix; + cx_sha256_t sha256_no_prefix; + cx_sha256_init(&sha256_prefix); + cx_sha256_init(&sha256_no_prefix); - cx_sha256_init(&sha256); - - if (subcommand != SWAP) { - unsigned char dot = '.'; - if (cx_hash_no_throw(&sha256.header, 0, &dot, 1, NULL, 0) != CX_OK) { - PRINTF("Error: cx_hash_no_throw\n"); - return false; - } + // Calculate both WITH and WITHOUT the dot prefix. + // We don't know which one we'll need yet + unsigned char dot = '.'; + if (cx_hash_no_throw(&sha256_prefix.header, 0, &dot, 1, NULL, 0) != CX_OK) { + PRINTF("Error: cx_hash_no_throw\n"); + return false; } - if (cx_hash_no_throw(&sha256.header, + if (cx_hash_no_throw(&sha256_prefix.header, + CX_LAST, + payload.bytes, + payload.size, + G_swap_ctx.sha256_digest_prefixed, + sizeof(G_swap_ctx.sha256_digest_prefixed)) != CX_OK) { + PRINTF("Error: cx_hash_no_throw\n"); + return false; + } + if (cx_hash_no_throw(&sha256_no_prefix.header, CX_LAST, payload.bytes, payload.size, - G_swap_ctx.sha256_digest, - sizeof(G_swap_ctx.sha256_digest)) != CX_OK) { + G_swap_ctx.sha256_digest_no_prefix, + sizeof(G_swap_ctx.sha256_digest_no_prefix)) != CX_OK) { PRINTF("Error: cx_hash_no_throw\n"); return false; } - PRINTF("sha256_digest: %.*H\n", 32, G_swap_ctx.sha256_digest); + PRINTF("sha256_digest_prefixed: %.*H\n", 32, G_swap_ctx.sha256_digest_prefixed); + PRINTF("sha256_digest_no_prefix: %.*H\n", 32, G_swap_ctx.sha256_digest_no_prefix); return true; } -static bool deserialize_protobuf_payload(buf_t payload, subcommand_e subcommand) { +static bool deserialize_protobuf_payload(buf_t payload, + subcommand_e subcommand, + bool needs_base64_decoding) { pb_istream_t stream; const pb_field_t *fields; void *dest_struct; // Temporary buffer if the received payload is encoded. Size is arbitrary - unsigned char decoded[256]; + unsigned char decoded[512]; buf_t to_deserialize; - if (subcommand != SWAP) { + if (needs_base64_decoding) { + PRINTF("Calling base64_decode before deserializing\n"); int n = base64_decode(decoded, sizeof(decoded), (const unsigned char *) payload.bytes, payload.size); - if (n < 0) { + if (n <= 0) { PRINTF("Error: Can't decode SELL/FUND/NG transaction base64\n"); return false; } to_deserialize.bytes = decoded; to_deserialize.size = n; } else { + PRINTF("No need to decode, transaction is bytes array\n"); to_deserialize = payload; } @@ -158,10 +195,16 @@ static bool deserialize_protobuf_payload(buf_t payload, subcommand_e subcommand) static bool check_transaction_id(subcommand_e subcommand) { if (subcommand == SWAP) { + if (G_swap_ctx.swap_transaction.device_transaction_id[10] != '\0') { + PRINTF("Received transaction id string '%.*H' is not 0 terminated\n", + sizeof(G_swap_ctx.swap_transaction.device_transaction_id), + G_swap_ctx.swap_transaction.device_transaction_id); + return false; + } if (memcmp(G_swap_ctx.device_transaction_id.swap, G_swap_ctx.swap_transaction.device_transaction_id, sizeof(G_swap_ctx.device_transaction_id.swap)) != 0) { - PRINTF("Error: Device transaction IDs don't match, expected %.*H, received %.*H\n", + PRINTF("Error: Device transaction IDs don't match, expected '%.*H', received '%.*H'\n", sizeof(G_swap_ctx.device_transaction_id.swap), G_swap_ctx.device_transaction_id.swap, sizeof(G_swap_ctx.device_transaction_id.swap), @@ -202,14 +245,12 @@ static void normalize_currencies(subcommand) { to_uppercase(G_swap_ctx.swap_transaction.currency_from, sizeof(G_swap_ctx.swap_transaction.currency_from)); set_ledger_currency_name(G_swap_ctx.swap_transaction.currency_from, - sizeof(G_swap_ctx.swap_transaction.currency_from) / - sizeof(G_swap_ctx.swap_transaction.currency_from[0])); + sizeof(G_swap_ctx.swap_transaction.currency_from)); to_uppercase(G_swap_ctx.swap_transaction.currency_to, sizeof(G_swap_ctx.swap_transaction.currency_to)); set_ledger_currency_name(G_swap_ctx.swap_transaction.currency_to, - sizeof(G_swap_ctx.swap_transaction.currency_to) / - sizeof(G_swap_ctx.swap_transaction.currency_to[0])); + sizeof(G_swap_ctx.swap_transaction.currency_to)); // strip bcash CashAddr header, and other bicmd->subcommand1 like headers for (size_t i = 0; i < sizeof(G_swap_ctx.swap_transaction.payin_address); i++) { @@ -224,18 +265,16 @@ static void normalize_currencies(subcommand) { to_uppercase(G_swap_ctx.sell_transaction.in_currency, sizeof(G_swap_ctx.sell_transaction.in_currency)); set_ledger_currency_name(G_swap_ctx.sell_transaction.in_currency, - sizeof(G_swap_ctx.sell_transaction.in_currency) / - sizeof(G_swap_ctx.sell_transaction.in_currency[0])); + sizeof(G_swap_ctx.sell_transaction.in_currency)); } else if (subcommand == FUND || subcommand == FUND_NG) { to_uppercase(G_swap_ctx.fund_transaction.in_currency, sizeof(G_swap_ctx.fund_transaction.in_currency)); set_ledger_currency_name(G_swap_ctx.fund_transaction.in_currency, - sizeof(G_swap_ctx.fund_transaction.in_currency) / - sizeof(G_swap_ctx.fund_transaction.in_currency[0])); + sizeof(G_swap_ctx.fund_transaction.in_currency)); } } -// triming leading 0s +// trim leading 0s static void trim_amounts(subcommand) { if (subcommand == SWAP || subcommand == SWAP_NG) { trim_pb_bytes_array( @@ -274,15 +313,21 @@ int process_transaction(const command_t *cmd) { buf_t fees; buf_t payload; - if (!parse_transaction(data, cmd->data.size, cmd->subcommand, &payload, &fees)) { + bool needs_base64_decoding; + if (!parse_transaction(data, + cmd->data.size, + cmd->subcommand, + &payload, + &fees, + &needs_base64_decoding)) { return reply_error(INCORRECT_COMMAND_DATA); } - if (!calculate_sha256_digest(payload, cmd->subcommand)) { + if (!calculate_sha256_digest(payload)) { return reply_error(INTERNAL_ERROR); } - if (!deserialize_protobuf_payload(payload, cmd->subcommand)) { + if (!deserialize_protobuf_payload(payload, cmd->subcommand, needs_base64_decoding)) { return reply_error(DESERIALIZATION_FAILED); } diff --git a/src/set_partner_key.c b/src/set_partner_key.c index 4a28b15..91cd6c9 100644 --- a/src/set_partner_key.c +++ b/src/set_partner_key.c @@ -11,10 +11,12 @@ static uint16_t parse_set_partner_key_command(const command_t *cmd, buf_t *partner_name, - uint8_t **raw_pubkey) { + uint8_t **raw_pubkey, + cx_curve_t *curve) { // data is serialized as // 1 byte - partner name length L // L bytes - partner name + // 1 byte - curve used / NG FLOWS ONLY // 65 bytes - uncompressed partner public key uint16_t offset = 0; if (!parse_to_sized_buffer(cmd->data.bytes, cmd->data.size, 1, partner_name, &offset)) { @@ -30,6 +32,28 @@ static uint16_t parse_set_partner_key_command(const command_t *cmd, return INCORRECT_COMMAND_DATA; } + // On Legacy flows, the curve used depends of the flow + // On NG flows, it is specified in the APDU + if (cmd->subcommand == SWAP) { + *curve = CX_CURVE_SECP256K1; + } else if (cmd->subcommand == SELL || cmd->subcommand == FUND) { + *curve = CX_CURVE_256R1; + } else { + uint8_t curve_id; + if (!pop_uint8_from_buffer(cmd->data.bytes, cmd->data.size, &curve_id, &offset)) { + PRINTF("Failed to read curve ID\n"); + return INCORRECT_COMMAND_DATA; + } + if (curve_id == CURVE_SECP256K1) { + *curve = CX_CURVE_SECP256K1; + } else if (curve_id == CURVE_SECP256R1) { + *curve = CX_CURVE_256R1; + } else { + PRINTF("Error: Incorrect curve specifier %d\n", curve_id); + return INCORRECT_COMMAND_DATA; + } + } + if (offset + UNCOMPRESSED_KEY_LENGTH != cmd->data.size) { PRINTF("Error: Input buffer length doesn't match correct SET_PARTNER_KEY message\n"); return INCORRECT_COMMAND_DATA; @@ -43,7 +67,8 @@ int set_partner_key(const command_t *cmd) { // Use dedicated function to extract the partner name and public key buf_t partner; uint8_t *raw_pubkey; - uint16_t err = parse_set_partner_key_command(cmd, &partner, &raw_pubkey); + cx_curve_t curve; + uint16_t err = parse_set_partner_key_command(cmd, &partner, &raw_pubkey, &curve); if (err != 0) { return reply_error(err); } @@ -54,13 +79,7 @@ int set_partner_key(const command_t *cmd) { memcpy(G_swap_ctx.partner.name, partner.bytes, partner.size); G_swap_ctx.partner.name_length = partner.size; - // Create the verifying key from the raw public key. Curve used depends of the flow - cx_curve_t curve; - if (cmd->subcommand == SWAP) { - curve = CX_CURVE_SECP256K1; - } else { - curve = CX_CURVE_256R1; - } + // Create the verifying key from the raw public key if (cx_ecfp_init_public_key_no_throw(curve, raw_pubkey, UNCOMPRESSED_KEY_LENGTH, @@ -72,8 +91,8 @@ int set_partner_key(const command_t *cmd) { // Save the hash of the entire credentials to check that the Ledger key signed it later if (cx_hash_sha256(cmd->data.bytes, cmd->data.size, - G_swap_ctx.sha256_digest, - sizeof(G_swap_ctx.sha256_digest)) == 0) { + G_swap_ctx.sha256_digest_no_prefix, + sizeof(G_swap_ctx.sha256_digest_no_prefix)) == 0) { PRINTF("cx_hash_sha256 internal error\n"); return reply_error(INTERNAL_ERROR); } diff --git a/src/ticker_normalization.c b/src/ticker_normalization.c index 95f8efe..eaf27f6 100644 --- a/src/ticker_normalization.c +++ b/src/ticker_normalization.c @@ -35,11 +35,11 @@ void set_ledger_currency_name(char *currency, size_t currency_size) { // Check if a given ticker matches the current swap context bool check_matching_ticker(buf_t ticker, const char *reference_ticker) { - char normalized_ticker_name[TICKER_MAX_SIZE_B]; + char normalized_ticker_name[TICKER_MAX_SIZE_B + 1]; uint8_t normalized_ticker_len; // Normalize the ticker name first - memcpy(normalized_ticker_name, ticker.bytes, sizeof(normalized_ticker_name)); + memcpy(normalized_ticker_name, ticker.bytes, ticker.size); normalized_ticker_name[ticker.size] = '\0'; to_uppercase(normalized_ticker_name, ticker.size); set_ledger_currency_name(normalized_ticker_name, sizeof(normalized_ticker_name)); diff --git a/src/ui/validate_transaction_nbgl.c b/src/ui/validate_transaction_nbgl.c index e374248..4e8e759 100644 --- a/src/ui/validate_transaction_nbgl.c +++ b/src/ui/validate_transaction_nbgl.c @@ -23,18 +23,18 @@ static char refusal_text[REFUSAL_TEXT_MAX_SIZE]; #define REVIEW_P1_TITLE "Review transaction" #define REVIEW_P1_CONFIRM "Sign transaction" -// Delimitor ' ' or '\n' +// Delimiter ' ' or '\n' #define REVIEW_P2 "to" -// Delimitor ' ' or '\n' +// Delimiter ' ' or '\n' // One of: #define REVIEW_P3_SWAP "swap " #define REVIEW_P3_SELL "sell " #define REVIEW_P3_FUND "fund account" -// Delimitor ' ' or '\n' +// Delimiter ' ' or '\n' // One of: #define REVIEW_P4_SWAP "to " @@ -187,7 +187,7 @@ void ui_validate_amounts(void) { break; } - // Detect if we shoud display on 2 or 3 lines. + // Detect if we should display on 2 or 3 lines. if ((G_swap_ctx.subcommand == FUND || G_swap_ctx.subcommand == FUND_NG) || (strlen(dyn_string_1) + strlen(dyn_string_2) >= 10)) { PRINTF("Review title and confirm on 3 lines\n"); diff --git a/test/python/apps/bitcoin.py b/test/python/apps/bitcoin.py index f53dc58..32cbef9 100644 --- a/test/python/apps/bitcoin.py +++ b/test/python/apps/bitcoin.py @@ -1,6 +1,44 @@ +import sys +from enum import IntEnum +from pathlib import Path from ragger.utils import create_currency_config from ragger.bip import BtcDerivationPathFormat, bitcoin_pack_derivation_path +from ragger.backend.interface import BackendInterface, RAPDU +from ragger.backend import RaisePolicy + +sys.path.append(f"{Path(__file__).parent.resolve()}/bitcoin_client") +from txmaker import createPsbt +from ledger_bitcoin import Client, WalletPolicy, MultisigWallet, AddressType, PartialSignature, segwit_addr +from ledger_bitcoin import Client, Chain, createClient +from ledger_bitcoin.bip380.descriptors import Descriptor BTC_CONF = create_currency_config("BTC", "Bitcoin") -BTC_PACKED_DERIVATION_PATH = bitcoin_pack_derivation_path(BtcDerivationPathFormat.BECH32, "m/44'/0'/0'/0/0") +BTC_PACKED_DERIVATION_PATH = bitcoin_pack_derivation_path(BtcDerivationPathFormat.BECH32, "m/84'/0'/0'/0/0") + +CHAIN = Chain.MAIN + +class BitcoinErrors(IntEnum): + SW_SWAP_CHECKING_FAIL = 0x6b00 + +class BitcoinClient: + def __init__(self, backend: BackendInterface): + if not isinstance(backend, BackendInterface): + raise TypeError("backend must be an instance of BackendInterface") + self._backend = backend + self._backend.raise_policy = RaisePolicy.RAISE_CUSTOM + self._backend.whitelisted_status = [0x9000, 0xE000] + self.client = createClient(backend, chain=CHAIN, debug=True) + + def send_simple_sign_tx(self, in_wallet: WalletPolicy, fees: int, destination: WalletPolicy, send_amount: int) -> RAPDU: + in_amounts = [send_amount + fees] + out_amounts = [send_amount] + psbt = createPsbt(in_wallet, in_amounts, out_amounts, [False], [destination]) + self.client.sign_psbt(psbt, in_wallet, None) + + def get_address_from_wallet(wallet: WalletPolicy): + desc = Descriptor.from_str(wallet.get_descriptor(False)) + desc.derive(0) + spk = desc.script_pubkey + hrp = "bc" if CHAIN == Chain.MAIN else "tb" + return segwit_addr.encode(hrp, 0, spk[2:]) diff --git a/test/python/apps/bitcoin_client/.flake8 b/test/python/apps/bitcoin_client/.flake8 new file mode 100644 index 0000000..ac830a1 --- /dev/null +++ b/test/python/apps/bitcoin_client/.flake8 @@ -0,0 +1,3 @@ +[flake8] +exclude = *.pyc,__pycache__ +ignore = E261,E302,E305,E501,E722,W5 \ No newline at end of file diff --git a/test/python/apps/bitcoin_client/.gitignore b/test/python/apps/bitcoin_client/.gitignore new file mode 100644 index 0000000..0021b4f --- /dev/null +++ b/test/python/apps/bitcoin_client/.gitignore @@ -0,0 +1 @@ +dist/** \ No newline at end of file diff --git a/test/python/apps/bitcoin_client/CHANGELOG.md b/test/python/apps/bitcoin_client/CHANGELOG.md new file mode 100644 index 0000000..baf9065 --- /dev/null +++ b/test/python/apps/bitcoin_client/CHANGELOG.md @@ -0,0 +1,60 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +Dates are in `dd-mm-yyyy` format. + +## [0.2.1] - 18-04-2023 + +### Changed +- Avoid using miniscript policies containing an `a:` fragment on versions below `2.1.2` of the bitcoin app. + +## [0.2.0] - 3-04-2023 + +This release introduces a breaking change in the return type of the `sign_psbt`method. + +### Added +- Added new `PartialSignature` data class together with support for taproot script signing, which is supported in version `2.1.2` of the bitcoin app. + +## [0.1.2] - 09-01-2023 + +### Fixed +- Added missing dependency. + +## [0.1.1] - 26-10-2022 + +### Changed + +- Improved interface of TransportClient for better interoperability with HID. +- `sign_psbt` now accepts the psbt to be passed as `bytes` or `str`. + +## [0.1.0] - 18-10-2022 + +### Changed + +Upgraded library to version 2.1.0 of the app. + +## [0.0.3] - 25-04-2022 + +### Changed + +Imported upstream changes to auxiliary classes from bitcoin-core/HWI. + +### Fixed + +Solved incorrect handling of signature responses for transactions with more than 252 inputs. + +## [0.0.2] - 09-02-2022 + +### Added + +Support for Bitcoin Message Signing, for Ledger Nano app 2.0.2. + +## [0.0.1] - 02-12-2021 + +### Added + +First public release. 🎉 diff --git a/test/python/apps/bitcoin_client/LICENSE b/test/python/apps/bitcoin_client/LICENSE new file mode 100644 index 0000000..8dada3e --- /dev/null +++ b/test/python/apps/bitcoin_client/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. diff --git a/test/python/apps/bitcoin_client/README.md b/test/python/apps/bitcoin_client/README.md new file mode 100644 index 0000000..2816cc1 --- /dev/null +++ b/test/python/apps/bitcoin_client/README.md @@ -0,0 +1,138 @@ +# Ledger Bitcoin application client + +## Overview + +Client library for Ledger Bitcoin application. + +Main repository and documentation: https://github.com/LedgerHQ/app-bitcoin-new + +## Install + +If you just want to communicate through TCP socket (for example with the Speculos emulator), there is no dependency: + +```bash +$ pip install ledger_bitcoin +``` + +otherwise, [hidapi](https://github.com/trezor/cython-hidapi) must be installed as an extra dependency: + +```bash +$ pip install ledger_bitcoin[hid] +``` + +## Getting started + +The main method exported by the library is `createClient`, which queries the hardware wallet for the version of the running app, and then returns the appropriate implementation of the `Client` class. + +See the documentation of the class and the example below for the supported methods. + +When running on a legacy version of the app (below version `2.0.0`), only the features that were available on the app are supported. Any unsopported method (e.g.: multisig registration or addresses, taproot addresses) will raise a `NotImplementedError`. + +### Running with speculos + +It is possible to run the app and the library with the [speculos](https://github.com/LedgerHQ/speculos) emulator. + +⚠️ Currently, speculos does not correctly emulate the version of the app, always returning a dummy value; in order to use the library, it is necessary to set the `SPECULOS_APPNAME` environment variable before starting speculos, for example with: + +``` +$ export SPECULOS_APPNAME="Bitcoin Test:2.1.0" +``` + +Similarly, to test the library behavior on a legacy version of the app, one can set the version to `1.6.5` (the final version of the 1.X series). + +The expected application name is `Bitcoin` for mainnet, `Bitcoin Test` for testnet. + +### Example + +The following example showcases all the main methods of the `Client`'s interface. + +If you are not using the context manager syntax when creating the client, remember to call the `stop()` method to release the communication channel. + +Testing the `sign_psbt` method requires producing a valid PSBT (with any external tool that supports either PSBTv0 or PSBTv2), and provide the corresponding wallet policy; it is skipped by default in the following example. + + +```python +from typing import Optional +from ledger_bitcoin import createClient, Chain, MultisigWallet, MultisigWallet, WalletPolicy, AddressType, TransportClient +from ledger_bitcoin.psbt import PSBT + + +def main(): + # speculos on default host/port + # with createClient(TransportClient(), chain=Chain.TEST) as client: + + # Ledger Nano connected via USB + with createClient(chain=Chain.TEST) as client: + # ==> Get the master key fingerprint + + fpr = client.get_master_fingerprint().hex() + print(f"Master key fingerprint: {fpr}") + + # ==> Get and display on screen the first taproot address + + first_taproot_account_pubkey = client.get_extended_pubkey("m/86'/1'/0'") + first_taproot_account_policy = WalletPolicy( + "", + "tr(@0/**)", + [ + f"[{fpr}/86'/1'/0']{first_taproot_account_pubkey}/**" + ], + ) + first_taproot_account_address = client.get_wallet_address( + first_taproot_account_policy, + None, + change=0, + address_index=0, + display=True # show address on the wallet's screen + ) + + print(f"First taproot account receive address: {first_taproot_account_address}") + + # ==> Register a multisig wallet named "Cold storage" + + our_pubkey = client.get_extended_pubkey("m/48'/1'/0'/2'") + other_key_info = "[76223a6e/48'/1'/0'/2']tpubDE7NQymr4AFtewpAsWtnreyq9ghkzQBXpCZjWLFVRAvnbf7vya2eMTvT2fPapNqL8SuVvLQdbUbMfWLVDCZKnsEBqp6UK93QEzL8Ck23AwF/**" + + multisig_policy = MultisigWallet( + name="Cold storage", + address_type=AddressType.WIT, + threshold=2, + keys_info=[ + other_key_info, # some other bitcoiner + f"[{fpr}/48'/1'/0'/2']{our_pubkey}", # that's us + ], + ) + + policy_id, policy_hmac = client.register_wallet(multisig_policy) + + print(f"Policy hmac: {policy_hmac.hex()}. Store it safely (together with the policy).") + + assert policy_id == multisig_policy.id # should never fail + + # ==> Derive and show an address for "Cold storage" + + multisig_address = client.get_wallet_address(multisig_policy, policy_hmac, change=0, address_index=0, display=True) + print(f"Multisig wallet address: {multisig_address}") + + # ==> Sign a psbt + + # TODO: set a wallet policy and a valid psbt file in order to test psbt signing + psbt_filename: Optional[str] = None + signing_policy: Optional[WalletPolicy] = None + signing_policy_hmac: Optional[bytes] = None + if not psbt_filename or not signing_policy: + print("Nothing to sign :(") + return + + raw_psbt_base64 = open(psbt_filename, "r").read() + psbt = PSBT() + psbt.deserialize(raw_psbt_base64) + + result = client.sign_psbt(psbt, signing_policy, signing_policy_hmac) + + print("Returned signatures:") + print(result) + +if __name__ == "__main__": + main() +``` \ No newline at end of file diff --git a/test/python/apps/bitcoin_client/__init__.py b/test/python/apps/bitcoin_client/__init__.py new file mode 100644 index 0000000..5bae140 --- /dev/null +++ b/test/python/apps/bitcoin_client/__init__.py @@ -0,0 +1,2 @@ +# this folder is not meant to be a python package, but adding this file allows pytest tests +# to import the test_utils module in the repository's root folder diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/__init__.py b/test/python/apps/bitcoin_client/ledger_bitcoin/__init__.py new file mode 100644 index 0000000..5c2375f --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/__init__.py @@ -0,0 +1,21 @@ + +"""Ledger Nano Bitcoin app client""" + +from .client_base import Client, PartialSignature +from .client import createClient +from .common import Chain + +from .wallet import AddressType, WalletPolicy, MultisigWallet, WalletType + +__version__ = '0.2.1' + +__all__ = [ + "Client", + "PartialSignature", + "createClient", + "Chain", + "AddressType", + "WalletPolicy", + "MultisigWallet", + "WalletType" +] diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/_base58.py b/test/python/apps/bitcoin_client/ledger_bitcoin/_base58.py new file mode 100644 index 0000000..707ce94 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/_base58.py @@ -0,0 +1,152 @@ +""" +Base 58 conversion utilities +**************************** +""" + +# +# base58.py +# +# Revision here from https://github.com/bitcoin-core/HWI/blob/3fe369d0379212fae1c72729a179d133b0adc872/hwilib/_base58.py +# +# Original source: git://github.com/joric/brutus.git +# which was forked from git://github.com/samrushing/caesure.git +# +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +from binascii import hexlify, unhexlify +from typing import List + +from .common import hash256 +from .errors import BadArgumentError + + +b58_digits: str = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' + + +def encode(b: bytes) -> str: + """ + Encode bytes to a base58-encoded string + :param b: Bytes to encode + :return: Base58 encoded string of ``b`` + """ + + # Convert big-endian bytes to integer + n: int = int('0x0' + hexlify(b).decode('utf8'), 16) + + # Divide that integer into base58 + temp: List[str] = [] + while n > 0: + n, r = divmod(n, 58) + temp.append(b58_digits[r]) + res: str = ''.join(temp[::-1]) + + # Encode leading zeros as base58 zeros + czero: int = 0 + pad: int = 0 + for c in b: + if c == czero: + pad += 1 + else: + break + return b58_digits[0] * pad + res + +def decode(s: str) -> bytes: + """ + Decode a base58-encoding string, returning bytes + :param s: Base48 string to decode + :return: Bytes encoded by ``s`` + """ + if not s: + return b'' + + # Convert the string to an integer + n: int = 0 + for c in s: + n *= 58 + if c not in b58_digits: + raise BadArgumentError('Character %r is not a valid base58 character' % c) + digit = b58_digits.index(c) + n += digit + + # Convert the integer to bytes + h: str = '%x' % n + if len(h) % 2: + h = '0' + h + res = unhexlify(h.encode('utf8')) + + # Add padding back. + pad = 0 + for c in s[:-1]: + if c == b58_digits[0]: + pad += 1 + else: + break + return b'\x00' * pad + res + +def get_xpub_fingerprint(s: str) -> bytes: + """ + Get the parent fingerprint from an extended public key + :param s: The extended pubkey + :return: The parent fingerprint bytes + """ + data = decode(s) + fingerprint = data[5:9] + return fingerprint + +def get_xpub_fingerprint_hex(xpub: str) -> str: + """ + Get the parent fingerprint as a hex string from an extended public key + :param s: The extended pubkey + :return: The parent fingerprint as a hex string + """ + data = decode(xpub) + fingerprint = data[5:9] + return hexlify(fingerprint).decode() + +def to_address(b: bytes, version: bytes) -> str: + """ + Base58 Check Encode the data with the version number. + Used to encode legacy style addresses. + :param b: The data to encode + :param version: The version number to encode with + :return: The Base58 Check Encoded string + """ + data = version + b + checksum = hash256(data)[0:4] + data += checksum + return encode(data) + +def xpub_to_pub_hex(xpub: str) -> str: + """ + Get the public key as a string from the extended public key. + :param xpub: The extended pubkey + :return: The pubkey hex string + """ + data = decode(xpub) + pubkey = data[-37:-4] + return hexlify(pubkey).decode() + + +def xpub_to_xonly_pub_hex(xpub: str) -> str: + """ + Get the public key as a string from the extended public key. + :param xpub: The extended pubkey + :return: The pubkey hex string + """ + data = decode(xpub) + pubkey = data[-36:-4] + return hexlify(pubkey).decode() + + +def xpub_main_2_test(xpub: str) -> str: + """ + Convert an extended pubkey from mainnet version to testnet version. + :param xpub: The extended pubkey + :return: The extended pubkey re-encoded using testnet version bytes + """ + data = decode(xpub) + test_data = b'\x04\x35\x87\xCF' + data[4:-4] + checksum = hash256(test_data)[0:4] + return encode(test_data + checksum) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/_script.py b/test/python/apps/bitcoin_client/ledger_bitcoin/_script.py new file mode 100644 index 0000000..f4a645b --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/_script.py @@ -0,0 +1,154 @@ +""" +Original version: https://raw.githubusercontent.com/bitcoin-core/HWI/3fe369d0379212fae1c72729a179d133b0adc872/hwilib/_script.py +Distributed under the MIT License. + +Bitcoin Script utilities +************************ +""" + +from typing import ( + Optional, + Sequence, + Tuple, +) + + +def is_opreturn(script: bytes) -> bool: + """ + Determine whether a script is an OP_RETURN output script. + + :param script: The script + :returns: Whether the script is an OP_RETURN output script + """ + return script[0] == 0x6a + + +def is_p2sh(script: bytes) -> bool: + """ + Determine whether a script is a P2SH output script. + + :param script: The script + :returns: Whether the script is a P2SH output script + """ + return len(script) == 23 and script[0] == 0xa9 and script[1] == 0x14 and script[22] == 0x87 + + +def is_p2pkh(script: bytes) -> bool: + """ + Determine whether a script is a P2PKH output script. + + :param script: The script + :returns: Whether the script is a P2PKH output script + """ + return len(script) == 25 and script[0] == 0x76 and script[1] == 0xa9 and script[2] == 0x14 and script[23] == 0x88 and script[24] == 0xac + + +def is_p2pk(script: bytes) -> bool: + """ + Determine whether a script is a P2PK output script. + + :param script: The script + :returns: Whether the script is a P2PK output script + """ + return (len(script) == 35 or len(script) == 67) and (script[0] == 0x21 or script[0] == 0x41) and script[-1] == 0xac + + +def is_p2tr(script: bytes) -> bool: + """ + Determine whether a script is a P2TR output script. + + :param script: The script + :returns: Whether the script is a P2TR output script + """ + return len(script) == 34 and script[0] == 0x51 and script[1] == 0x20 + + +def is_witness(script: bytes) -> Tuple[bool, int, bytes]: + """ + Determine whether a script is a segwit output script. + If so, also returns the witness version and witness program. + + :param script: The script + :returns: A tuple of a bool indicating whether the script is a segwit output script, + an int representing the witness version, + and the bytes of the witness program. + """ + if len(script) < 4 or len(script) > 42: + return (False, 0, b"") + + if script[0] != 0 and (script[0] < 81 or script[0] > 96): + return (False, 0, b"") + + if script[1] + 2 == len(script): + return (True, script[0] - 0x50 if script[0] else 0, script[2:]) + + return (False, 0, b"") + + +def is_p2wpkh(script: bytes) -> bool: + """ + Determine whether a script is a P2WPKH output script. + + :param script: The script + :returns: Whether the script is a P2WPKH output script + """ + is_wit, wit_ver, wit_prog = is_witness(script) + if not is_wit: + return False + elif wit_ver != 0: + return False + return len(wit_prog) == 20 + + +def is_p2wsh(script: bytes) -> bool: + """ + Determine whether a script is a P2WSH output script. + + :param script: The script + :returns: Whether the script is a P2WSH output script + """ + is_wit, wit_ver, wit_prog = is_witness(script) + if not is_wit: + return False + elif wit_ver != 0: + return False + return len(wit_prog) == 32 + + +# Only handles up to 15 of 15. Returns None if this script is not a +# multisig script. Returns (m, pubkeys) otherwise. +def parse_multisig(script: bytes) -> Optional[Tuple[int, Sequence[bytes]]]: + """ + Determine whether a script is a multisig script. If so, determine the parameters of that multisig. + + :param script: The script + :returns: ``None`` if the script is not multisig. + If multisig, returns a tuple of the number of signers required, + and a sequence of public key bytes. + """ + # Get m + m = script[0] - 80 + if m < 1 or m > 15: + return None + + # Get pubkeys + pubkeys = [] + offset = 1 + while True: + pubkey_len = script[offset] + if pubkey_len != 33: + break + offset += 1 + pubkeys.append(script[offset:offset + 33]) + offset += 33 + + # Check things at the end + n = script[offset] - 80 + if n != len(pubkeys): + return None + offset += 1 + op_cms = script[offset] + if op_cms != 174: + return None + + return (m, pubkeys) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/_serialize.py b/test/python/apps/bitcoin_client/ledger_bitcoin/_serialize.py new file mode 100644 index 0000000..2aa25eb --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/_serialize.py @@ -0,0 +1,260 @@ +# Original version: https://raw.githubusercontent.com/bitcoin-core/HWI/3fe369d0379212fae1c72729a179d133b0adc872/hwilib/_serialize.py +# +#!/usr/bin/env python3 +# Copyright (c) 2010 ArtForz -- public domain half-a-node +# Copyright (c) 2012 Jeff Garzik +# Copyright (c) 2010-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +""" +Bitcoin Object Python Serializations +************************************ + +Modified from the test/test_framework/mininode.py file from the +Bitcoin repository +""" + +import struct + +from typing import ( + List, + Sequence, + TypeVar, + Callable, +) +from typing_extensions import Protocol + +class Readable(Protocol): + def read(self, n: int = -1) -> bytes: + ... + +class Deserializable(Protocol): + def deserialize(self, f: Readable) -> None: + ... + +class Serializable(Protocol): + def serialize(self) -> bytes: + ... + + +# Serialization/deserialization tools +def ser_compact_size(size: int) -> bytes: + """ + Serialize an integer using Bitcoin's compact size unsigned integer serialization. + + :param size: The int to serialize + :returns: The int serialized as a compact size unsigned integer + """ + r = b"" + if size < 253: + r = struct.pack("B", size) + elif size < 0x10000: + r = struct.pack(" int: + """ + Deserialize a compact size unsigned integer from the beginning of the byte stream. + + :param f: The byte stream + :returns: The integer that was serialized + """ + nit: int = struct.unpack(" bytes: + """ + Deserialize a variable length byte string serialized with Bitcoin's variable length string serialization from a byte stream. + + :param f: The byte stream + :returns: The byte string that was serialized + """ + nit = deser_compact_size(f) + return f.read(nit) + +def ser_string(s: bytes) -> bytes: + """ + Serialize a byte string with Bitcoin's variable length string serialization. + + :param s: The byte string to be serialized + :returns: The serialized byte string + """ + return ser_compact_size(len(s)) + s + +def deser_uint256(f: Readable) -> int: + """ + Deserialize a 256 bit integer serialized with Bitcoin's 256 bit integer serialization from a byte stream. + + :param f: The byte stream. + :returns: The integer that was serialized + """ + r = 0 + for i in range(8): + t = struct.unpack(" bytes: + """ + Serialize a 256 bit integer with Bitcoin's 256 bit integer serialization. + + :param u: The integer to serialize + :returns: The serialized 256 bit integer + """ + rs = b"" + for _ in range(8): + rs += struct.pack(">= 32 + return rs + + +def uint256_from_str(s: bytes) -> int: + """ + Deserialize a 256 bit integer serialized with Bitcoin's 256 bit integer serialization from a byte string. + + :param s: The byte string + :returns: The integer that was serialized + """ + r = 0 + t = struct.unpack(" List[D]: + """ + Deserialize a vector of objects with Bitcoin's object vector serialization from a byte stream. + + :param f: The byte stream + :param c: The class of object to deserialize for each object in the vector + :returns: A list of objects that were serialized + """ + nit = deser_compact_size(f) + r = [] + for _ in range(nit): + t = c() + t.deserialize(f) + r.append(t) + return r + + +def ser_vector(v: Sequence[Serializable]) -> bytes: + """ + Serialize a vector of objects with Bitcoin's object vector serialzation. + + :param v: The list of objects to serialize + :returns: The serialized objects + """ + r = ser_compact_size(len(v)) + for i in v: + r += i.serialize() + return r + + +def deser_string_vector(f: Readable) -> List[bytes]: + """ + Deserialize a vector of byte strings from a byte stream. + + :param f: The byte stream + :returns: The list of byte strings that were serialized + """ + nit = deser_compact_size(f) + r = [] + for _ in range(nit): + t = deser_string(f) + r.append(t) + return r + + +def ser_string_vector(v: List[bytes]) -> bytes: + """ + Serialize a list of byte strings as a vector of byte strings. + + :param v: The list of byte strings to serialize + :returns: The serialized list of byte strings + """ + r = ser_compact_size(len(v)) + for sv in v: + r += ser_string(sv) + return r + +def ser_sig_der(r: bytes, s: bytes) -> bytes: + """ + Serialize the ``r`` and ``s`` values of an ECDSA signature using DER. + + :param r: The ``r`` value bytes + :param s: The ``s`` value bytes + :returns: The DER encoded signature + """ + sig = b"\x30" + + # Make r and s as short as possible + ri = 0 + for b in r: + if b == 0: + ri += 1 + else: + break + r = r[ri:] + si = 0 + for b in s: + if b == 0: + si += 1 + else: + break + s = s[si:] + + # Make positive of neg + first = r[0] + if first & (1 << 7) != 0: + r = b"\x00" + r + first = s[0] + if first & (1 << 7) != 0: + s = b"\x00" + s + + # Write total length + total_len = len(r) + len(s) + 4 + sig += struct.pack("B", total_len) + + # write r + sig += b"\x02" + sig += struct.pack("B", len(r)) + sig += r + + # write s + sig += b"\x02" + sig += struct.pack("B", len(s)) + sig += s + + sig += b"\x01" + return sig + +def ser_sig_compact(r: bytes, s: bytes, recid: bytes) -> bytes: + """ + Serialize the ``r`` and ``s`` values of an ECDSA signature using the compact signature serialization scheme. + + :param r: The ``r`` value bytes + :param s: The ``s`` value bytes + :returns: The compact signature + """ + rec = struct.unpack("B", recid)[0] + prefix = struct.pack("B", 27 + 4 + rec) + + sig = b"" + sig += prefix + sig += r + s + + return sig diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/README b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/README new file mode 100644 index 0000000..3609525 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/README @@ -0,0 +1,4 @@ +This folder is based on https://github.com/Eunovo/python-bip380/tree/4226b7f2b70211d696155f6fd39edc611761ed0b, in turn built on https://github.com/darosior/python-bip380/commit/d2f5d8f5b41cba189bd793c1081e9d61d2d160c1. + +The library is "not ready for any real world use", however we _only_ use it in order to generate addresses for descriptors containing miniscript, and compare the result with the address computed by the device. +This is a generic mitigation for any bug related to address generation on the device, like [this](https://donjon.ledger.com/lsb/019/). diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/__init__.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/__init__.py new file mode 100644 index 0000000..27fdca4 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/__init__.py @@ -0,0 +1 @@ +__version__ = "0.0.3" diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/__init__.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/__init__.py new file mode 100644 index 0000000..bc4eaac --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/__init__.py @@ -0,0 +1,220 @@ +from ...bip380.key import DescriptorKey +from ...bip380.miniscript import Node +from ...bip380.utils.hashes import sha256, hash160 +from ...bip380.utils.script import ( + CScript, + OP_1, + OP_DUP, + OP_HASH160, + OP_EQUALVERIFY, + OP_CHECKSIG, +) + +from .checksum import descsum_create +from .errors import DescriptorParsingError +from .parsing import descriptor_from_str +from .utils import taproot_tweak + + +class Descriptor: + """A Bitcoin Output Script Descriptor.""" + + def from_str(desc_str, strict=False): + """Parse a Bitcoin Output Script Descriptor from its string representation. + + :param strict: whether to require the presence of a checksum. + """ + desc = descriptor_from_str(desc_str, strict) + + # BIP389 prescribes that no two multipath key expressions in a single descriptor + # have different length. + multipath_len = None + for key in desc.keys: + if key.is_multipath(): + m_len = len(key.path.paths) + if multipath_len is None: + multipath_len = m_len + elif multipath_len != m_len: + raise DescriptorParsingError( + f"Descriptor contains multipath key expressions with varying length: '{desc_str}'." + ) + + return desc + + @property + def script_pubkey(self): + """Get the ScriptPubKey (output 'locking' Script) for this descriptor.""" + # To be implemented by derived classes + raise NotImplementedError + + @property + def script_sighash(self): + """Get the Script to be committed to by the signature hash of a spending transaction.""" + # To be implemented by derived classes + raise NotImplementedError + + @property + def keys(self): + """Get the list of all keys from this descriptor, in order of apparition.""" + # To be implemented by derived classes + raise NotImplementedError + + def derive(self, index): + """Derive the key at the given derivation index. + + A no-op if the key isn't a wildcard. Will start from 2**31 if the key is a "hardened + wildcard". + """ + assert isinstance(index, int) + for key in self.keys: + key.derive(index) + + def satisfy(self, *args, **kwargs): + """Get the witness stack to spend from this descriptor. + + Various data may need to be passed as parameters to meet the locking + conditions set by the Script. + """ + # To be implemented by derived classes + raise NotImplementedError + + def copy(self): + """Get a copy of this descriptor.""" + # FIXME: do something nicer than roundtripping through string ser + return Descriptor.from_str(str(self)) + + def is_multipath(self): + """Whether this descriptor contains multipath key expression(s).""" + return any(k.is_multipath() for k in self.keys) + + def singlepath_descriptors(self): + """Get a list of descriptors that only contain keys that don't have multiple + derivation paths. + """ + singlepath_descs = [self.copy()] + + # First figure out the number of descriptors there will be + for key in self.keys: + if key.is_multipath(): + singlepath_descs += [ + self.copy() for _ in range(len(key.path.paths) - 1) + ] + break + + # Return early if there was no multipath key expression + if len(singlepath_descs) == 1: + return singlepath_descs + + # Then use one path for each + for i, desc in enumerate(singlepath_descs): + for key in desc.keys: + if key.is_multipath(): + assert len(key.path.paths) == len(singlepath_descs) + key.path.paths = key.path.paths[i: i + 1] + + assert all(not d.is_multipath() for d in singlepath_descs) + return singlepath_descs + + +# TODO: add methods to give access to all the Miniscript analysis +class WshDescriptor(Descriptor): + """A Segwit v0 P2WSH Output Script Descriptor.""" + + def __init__(self, witness_script): + assert isinstance(witness_script, Node) + self.witness_script = witness_script + + def __repr__(self): + return descsum_create(f"wsh({self.witness_script})") + + @property + def script_pubkey(self): + witness_program = sha256(self.witness_script.script) + return CScript([0, witness_program]) + + @property + def script_sighash(self): + return self.witness_script.script + + @property + def keys(self): + return self.witness_script.keys + + def satisfy(self, sat_material=None): + """Get the witness stack to spend from this descriptor. + + :param sat_material: a miniscript.satisfaction.SatisfactionMaterial with data + available to fulfill the conditions set by the Script. + """ + sat = self.witness_script.satisfy(sat_material) + if sat is not None: + return sat + [self.witness_script.script] + + +class WpkhDescriptor(Descriptor): + """A Segwit v0 P2WPKH Output Script Descriptor.""" + + def __init__(self, pubkey): + assert isinstance(pubkey, DescriptorKey) + self.pubkey = pubkey + + def __repr__(self): + return descsum_create(f"wpkh({self.pubkey})") + + @property + def script_pubkey(self): + witness_program = hash160(self.pubkey.bytes()) + return CScript([0, witness_program]) + + @property + def script_sighash(self): + key_hash = hash160(self.pubkey.bytes()) + return CScript([OP_DUP, OP_HASH160, key_hash, OP_EQUALVERIFY, OP_CHECKSIG]) + + @property + def keys(self): + return [self.pubkey] + + def satisfy(self, signature): + """Get the witness stack to spend from this descriptor. + + :param signature: a signature (in bytes) for the pubkey from the descriptor. + """ + assert isinstance(signature, bytes) + return [signature, self.pubkey.bytes()] + + +class TrDescriptor(Descriptor): + """A Pay-to-Taproot Output Script Descriptor.""" + + def __init__(self, internal_key): + assert isinstance(internal_key, DescriptorKey) and internal_key.x_only + self.internal_key = internal_key + + def __repr__(self): + return descsum_create(f"tr({self.internal_key})") + + def output_key(self): + # "If the spending conditions do not require a script path, the output key + # should commit to an unspendable script path" (see BIP341, BIP386) + return taproot_tweak(self.internal_key.bytes(), b"").format() + + @property + def script_pubkey(self): + return CScript([OP_1, self.output_key()]) + + @property + def keys(self): + return [self.internal_key] + + def satisfy(self, sat_material=None): + """Get the witness stack to spend from this descriptor. + + :param sat_material: a miniscript.satisfaction.SatisfactionMaterial with data + available to spend from the key path or any of the leaves. + """ + out_key = self.output_key() + if out_key in sat_material.signatures: + return [sat_material.signatures[out_key]] + + return diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/checksum.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/checksum.py new file mode 100644 index 0000000..9f3e013 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/checksum.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# Copyright (c) 2019 Pieter Wuille +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Utility functions related to output descriptors""" + +import re + +INPUT_CHARSET = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ " +CHECKSUM_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" +GENERATOR = [0xF5DEE51989, 0xA9FDCA3312, 0x1BAB10E32D, 0x3706B1677A, 0x644D626FFD] + + +def descsum_polymod(symbols): + """Internal function that computes the descriptor checksum.""" + chk = 1 + for value in symbols: + top = chk >> 35 + chk = (chk & 0x7FFFFFFFF) << 5 ^ value + for i in range(5): + chk ^= GENERATOR[i] if ((top >> i) & 1) else 0 + return chk + + +def descsum_expand(s): + """Internal function that does the character to symbol expansion""" + groups = [] + symbols = [] + for c in s: + if not c in INPUT_CHARSET: + return None + v = INPUT_CHARSET.find(c) + symbols.append(v & 31) + groups.append(v >> 5) + if len(groups) == 3: + symbols.append(groups[0] * 9 + groups[1] * 3 + groups[2]) + groups = [] + if len(groups) == 1: + symbols.append(groups[0]) + elif len(groups) == 2: + symbols.append(groups[0] * 3 + groups[1]) + return symbols + + +def descsum_create(s): + """Add a checksum to a descriptor without""" + symbols = descsum_expand(s) + [0, 0, 0, 0, 0, 0, 0, 0] + checksum = descsum_polymod(symbols) ^ 1 + return ( + s + + "#" + + "".join(CHECKSUM_CHARSET[(checksum >> (5 * (7 - i))) & 31] for i in range(8)) + ) + + +def descsum_check(s): + """Verify that the checksum is correct in a descriptor""" + if s[-9] != "#": + return False + if not all(x in CHECKSUM_CHARSET for x in s[-8:]): + return False + symbols = descsum_expand(s[:-9]) + [CHECKSUM_CHARSET.find(x) for x in s[-8:]] + return descsum_polymod(symbols) == 1 + + +def drop_origins(s): + """Drop the key origins from a descriptor""" + desc = re.sub(r"\[.+?\]", "", s) + if "#" in s: + desc = desc[: desc.index("#")] + return descsum_create(desc) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/errors.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/errors.py new file mode 100644 index 0000000..f7b5848 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/errors.py @@ -0,0 +1,5 @@ +class DescriptorParsingError(ValueError): + """Error while parsing a Bitcoin Output Descriptor from its string representation""" + + def __init__(self, message): + self.message = message diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/parsing.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/parsing.py new file mode 100644 index 0000000..1d18bff --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/parsing.py @@ -0,0 +1,56 @@ +from ...bip380 import descriptors +from ...bip380.key import DescriptorKey, DescriptorKeyError +from ...bip380.miniscript import Node +from ...bip380.descriptors.checksum import descsum_check + +from .errors import DescriptorParsingError + + +def split_checksum(desc_str, strict=False): + """Removes and check the provided checksum. + If not told otherwise, this won't fail on a missing checksum. + + :param strict: whether to require the presence of the checksum. + """ + desc_split = desc_str.split("#") + if len(desc_split) != 2: + if strict: + raise DescriptorParsingError("Missing checksum") + return desc_split[0] + + descriptor, checksum = desc_split + if not descsum_check(desc_str): + raise DescriptorParsingError( + f"Checksum '{checksum}' is invalid for '{descriptor}'" + ) + + return descriptor + + +def descriptor_from_str(desc_str, strict=False): + """Parse a Bitcoin Output Script Descriptor from its string representation. + + :param strict: whether to require the presence of a checksum. + """ + desc_str = split_checksum(desc_str, strict=strict) + + if desc_str.startswith("wsh(") and desc_str.endswith(")"): + # TODO: decent errors in the Miniscript module to be able to catch them here. + ms = Node.from_str(desc_str[4:-1]) + return descriptors.WshDescriptor(ms) + + if desc_str.startswith("wpkh(") and desc_str.endswith(")"): + try: + pubkey = DescriptorKey(desc_str[5:-1]) + except DescriptorKeyError as e: + raise DescriptorParsingError(str(e)) + return descriptors.WpkhDescriptor(pubkey) + + if desc_str.startswith("tr(") and desc_str.endswith(")"): + try: + pubkey = DescriptorKey(desc_str[3:-1], x_only=True) + except DescriptorKeyError as e: + raise DescriptorParsingError(str(e)) + return descriptors.TrDescriptor(pubkey) + + raise DescriptorParsingError(f"Unknown descriptor fragment: {desc_str}") diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/utils.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/utils.py new file mode 100644 index 0000000..25dbfe9 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/descriptors/utils.py @@ -0,0 +1,21 @@ +"""Utilities for working with descriptors.""" +import coincurve +import hashlib + + +def tagged_hash(tag, data): + ss = hashlib.sha256(tag.encode("utf-8")).digest() + ss += ss + ss += data + return hashlib.sha256(ss).digest() + + +def taproot_tweak(pubkey_bytes, merkle_root): + assert isinstance(pubkey_bytes, bytes) and len(pubkey_bytes) == 32 + assert isinstance(merkle_root, bytes) + + t = tagged_hash("TapTweak", pubkey_bytes + merkle_root) + xonly_pubkey = coincurve.PublicKeyXOnly(pubkey_bytes) + xonly_pubkey.tweak_add(t) # TODO: error handling + + return xonly_pubkey diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/key.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/key.py new file mode 100644 index 0000000..3e05b61 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/key.py @@ -0,0 +1,338 @@ +import coincurve +import copy + +from bip32 import BIP32, HARDENED_INDEX +from bip32.utils import _deriv_path_str_to_list +from .utils.hashes import hash160 +from enum import Enum, auto + + +def is_raw_key(obj): + return isinstance(obj, (coincurve.PublicKey, coincurve.PublicKeyXOnly)) + + +class DescriptorKeyError(Exception): + def __init__(self, message): + self.message = message + + +class DescriporKeyOrigin: + """The origin of a key in a descriptor. + + See https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki#key-expressions. + """ + + def __init__(self, fingerprint, path): + assert isinstance(fingerprint, bytes) and isinstance(path, list) + + self.fingerprint = fingerprint + self.path = path + + def from_str(origin_str): + # Origing starts and ends with brackets + if not origin_str.startswith("[") or not origin_str.endswith("]"): + raise DescriptorKeyError(f"Insane origin: '{origin_str}'") + # At least 8 hex characters + brackets + if len(origin_str) < 10: + raise DescriptorKeyError(f"Insane origin: '{origin_str}'") + + # For the fingerprint, just read the 4 bytes. + try: + fingerprint = bytes.fromhex(origin_str[1:9]) + except ValueError: + raise DescriptorKeyError(f"Insane fingerprint in origin: '{origin_str}'") + # For the path, we (how bad) reuse an internal helper from python-bip32. + path = [] + if len(origin_str) > 10: + if origin_str[9] != "/": + raise DescriptorKeyError(f"Insane path in origin: '{origin_str}'") + # The helper operates on "m/10h/11/12'/13", so give it a "m". + dummy = "m" + try: + path = _deriv_path_str_to_list(dummy + origin_str[9:-1]) + except ValueError: + raise DescriptorKeyError(f"Insane path in origin: '{origin_str}'") + + return DescriporKeyOrigin(fingerprint, path) + + +class KeyPathKind(Enum): + FINAL = auto() + WILDCARD_UNHARDENED = auto() + WILDCARD_HARDENED = auto() + + def is_wildcard(self): + return self in [KeyPathKind.WILDCARD_HARDENED, KeyPathKind.WILDCARD_UNHARDENED] + + +def parse_index(index_str): + """Parse a derivation index, as contained in a derivation path.""" + assert isinstance(index_str, str) + + try: + # if HARDENED + if index_str[-1:] in ["'", "h", "H"]: + return int(index_str[:-1]) + HARDENED_INDEX + else: + return int(index_str) + except ValueError as e: + raise DescriptorKeyError(f"Invalid derivation index {index_str}: '{e}'") + + +class DescriptorKeyPath: + """The derivation path of a key in a descriptor. + + See https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki#key-expressions + as well as BIP389 for multipath expressions. + """ + + def __init__(self, paths, kind): + assert ( + isinstance(paths, list) + and isinstance(kind, KeyPathKind) + and len(paths) > 0 + and all(isinstance(p, list) for p in paths) + ) + + self.paths = paths + self.kind = kind + + def is_multipath(self): + """Whether this derivation path actually contains multiple of them.""" + return len(self.paths) > 1 + + def from_str(path_str): + if len(path_str) < 2: + raise DescriptorKeyError(f"Insane key path: '{path_str}'") + if path_str[0] != "/": + raise DescriptorKeyError(f"Insane key path: '{path_str}'") + + # Determine whether this key may be derived. + kind = KeyPathKind.FINAL + if len(path_str) > 2 and path_str[-3:] in ["/*'", "/*h", "/*H"]: + kind = KeyPathKind.WILDCARD_HARDENED + path_str = path_str[:-3] + elif len(path_str) > 1 and path_str[-2:] == "/*": + kind = KeyPathKind.WILDCARD_UNHARDENED + path_str = path_str[:-2] + + paths = [[]] + if len(path_str) == 0: + return DescriptorKeyPath(paths, kind) + + for index in path_str[1:].split("/"): + # If this is a multipath expression, of the form '' + if ( + index.startswith("<") + and index.endswith(">") + and ";" in index + and len(index) >= 5 + ): + # Can't have more than one multipath expression + if len(paths) > 1: + raise DescriptorKeyError( + f"May only have a single multipath step in derivation path: '{path_str}'" + ) + indexes = index[1:-1].split(";") + paths = [copy.copy(paths[0]) for _ in indexes] + for i, der_index in enumerate(indexes): + paths[i].append(parse_index(der_index)) + else: + # This is a "single index" expression. + for path in paths: + path.append(parse_index(index)) + return DescriptorKeyPath(paths, kind) + + +class DescriptorKey: + """A Bitcoin key to be used in Output Script Descriptors. + + May be an extended or raw public key. + """ + + def __init__(self, key, x_only=False): + # Information about the origin of this key. + self.origin = None + # If it is an xpub, a path toward a child key of that xpub. + self.path = None + # Whether to only create x-only public keys. + self.x_only = x_only + # Whether to serialize to string representation without the sign byte. + # This is necessary to roundtrip 33-bytes keys under Taproot context. + self.ser_x_only = x_only + + if isinstance(key, bytes): + if len(key) == 32: + key_cls = coincurve.PublicKeyXOnly + self.x_only = True + self.ser_x_only = True + elif len(key) == 33: + key_cls = coincurve.PublicKey + self.ser_x_only = False + else: + raise DescriptorKeyError( + "Only compressed and x-only keys are supported" + ) + try: + self.key = key_cls(key) + except ValueError as e: + raise DescriptorKeyError(f"Public key parsing error: '{str(e)}'") + + elif isinstance(key, BIP32): + self.key = key + + elif isinstance(key, str): + # Try parsing an optional origin prepended to the key + splitted_key = key.split("]", maxsplit=1) + if len(splitted_key) == 2: + origin, key = splitted_key + self.origin = DescriporKeyOrigin.from_str(origin + "]") + + # Is it a raw key? + if len(key) in (64, 66): + pk_cls = coincurve.PublicKey + if len(key) == 64: + pk_cls = coincurve.PublicKeyXOnly + self.x_only = True + self.ser_x_only = True + else: + self.ser_x_only = False + try: + self.key = pk_cls(bytes.fromhex(key)) + except ValueError as e: + raise DescriptorKeyError(f"Public key parsing error: '{str(e)}'") + # If not it must be an xpub. + else: + # There may be an optional path appended to the xpub. + splitted_key = key.split("/", maxsplit=1) + if len(splitted_key) == 2: + key, path = splitted_key + self.path = DescriptorKeyPath.from_str("/" + path) + + try: + self.key = BIP32.from_xpub(key) + except ValueError as e: + raise DescriptorKeyError(f"Xpub parsing error: '{str(e)}'") + + else: + raise DescriptorKeyError( + "Invalid parameter type: expecting bytes, hex str or BIP32 instance." + ) + + def __repr__(self): + key = "" + + def ser_index(key, der_index): + # If this a hardened step, deduce the threshold and mark it. + if der_index < HARDENED_INDEX: + return str(der_index) + else: + return f"{der_index - 2**31}'" + + def ser_paths(key, paths): + assert len(paths) > 0 + + for i, der_index in enumerate(paths[0]): + # If this is a multipath expression, write the multi-index step accordingly + if len(paths) > 1 and paths[1][i] != der_index: + key += "/<" + for j, path in enumerate(paths): + key += ser_index(key, path[i]) + if j < len(paths) - 1: + key += ";" + key += ">" + else: + key += "/" + ser_index(key, der_index) + + return key + + if self.origin is not None: + key += f"[{self.origin.fingerprint.hex()}" + key = ser_paths(key, [self.origin.path]) + key += "]" + + if isinstance(self.key, BIP32): + key += self.key.get_xpub() + else: + assert is_raw_key(self.key) + raw_key = self.key.format() + if len(raw_key) == 33 and self.ser_x_only: + raw_key = raw_key[1:] + key += raw_key.hex() + + if self.path is not None: + key = ser_paths(key, self.path.paths) + if self.path.kind == KeyPathKind.WILDCARD_UNHARDENED: + key += "/*" + elif self.path.kind == KeyPathKind.WILDCARD_HARDENED: + key += "/*'" + + return key + + def is_multipath(self): + """Whether this key contains more than one derivation path.""" + return self.path is not None and self.path.is_multipath() + + def derivation_path(self): + """Get the single derivation path for this key. + + Will raise if it has multiple, and return None if it doesn't have any. + """ + if self.path is None: + return None + if self.path.is_multipath(): + raise DescriptorKeyError( + f"Key has multiple derivation paths: {self.path.paths}" + ) + return self.path.paths[0] + + def bytes(self): + """Get this key as raw bytes. + + Will raise if this key contains multiple derivation paths. + """ + if is_raw_key(self.key): + raw = self.key.format() + if self.x_only and len(raw) == 33: + return raw[1:] + assert len(raw) == 32 or not self.x_only + return raw + else: + assert isinstance(self.key, BIP32) + path = self.derivation_path() + if path is None: + return self.key.pubkey + assert not self.path.kind.is_wildcard() # TODO: real errors + return self.key.get_pubkey_from_path(path) + + def derive(self, index): + """Derive the key at the given index. + + Will raise if this key contains multiple derivation paths. + A no-op if the key isn't a wildcard. Will start from 2**31 if the key is a "hardened + wildcard". + """ + assert isinstance(index, int) + if ( + self.path is None + or self.path.is_multipath() + or self.path.kind == KeyPathKind.FINAL + ): + return + assert isinstance(self.key, BIP32) + + if self.path.kind == KeyPathKind.WILDCARD_HARDENED: + index += 2 ** 31 + assert index < 2 ** 32 + + if self.origin is None: + fingerprint = hash160(self.key.pubkey)[:4] + self.origin = DescriporKeyOrigin(fingerprint, [index]) + else: + self.origin.path.append(index) + + # This can't fail now. + path = self.derivation_path() + # TODO(bip32): have a way to derive without roundtripping through string ser. + self.key = BIP32.from_xpub(self.key.get_xpub_from_path(path + [index])) + self.path = None diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/__init__.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/__init__.py new file mode 100644 index 0000000..b0de1f9 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/__init__.py @@ -0,0 +1,13 @@ +""" +Miniscript +========== + +Miniscript is an extension to Bitcoin Output Script descriptors. It is a language for \ +writing (a subset of) Bitcoin Scripts in a structured way, enabling analysis, composition, \ +generic signing and more. + +For more information about Miniscript, see https://bitcoin.sipa.be/miniscript. +""" + +from .fragments import Node +from .satisfaction import SatisfactionMaterial diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/errors.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/errors.py new file mode 100644 index 0000000..7ccd98f --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/errors.py @@ -0,0 +1,20 @@ +""" +All the exceptions raised when dealing with Miniscript. +""" + + +class MiniscriptMalformed(ValueError): + def __init__(self, message): + self.message = message + + +class MiniscriptNodeCreationError(ValueError): + def __init__(self, message): + self.message = message + + +class MiniscriptPropertyError(ValueError): + def __init__(self, message): + self.message = message + +# TODO: errors for type errors, parsing errors, etc.. diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/fragments.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/fragments.py new file mode 100644 index 0000000..d0e572e --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/fragments.py @@ -0,0 +1,1225 @@ +""" +Miniscript AST elements. + +Each element correspond to a Bitcoin Script fragment, and has various type properties. +See the Miniscript website for the specification of the type system: https://bitcoin.sipa.be/miniscript/. +""" + +import copy +from ...bip380.miniscript import parsing + +from ...bip380.key import DescriptorKey +from ...bip380.utils.hashes import hash160 +from ...bip380.utils.script import ( + CScript, + OP_1, + OP_0, + OP_ADD, + OP_BOOLAND, + OP_BOOLOR, + OP_DUP, + OP_ELSE, + OP_ENDIF, + OP_EQUAL, + OP_EQUALVERIFY, + OP_FROMALTSTACK, + OP_IFDUP, + OP_IF, + OP_CHECKLOCKTIMEVERIFY, + OP_CHECKMULTISIG, + OP_CHECKMULTISIGVERIFY, + OP_CHECKSEQUENCEVERIFY, + OP_CHECKSIG, + OP_CHECKSIGVERIFY, + OP_HASH160, + OP_HASH256, + OP_NOTIF, + OP_RIPEMD160, + OP_SHA256, + OP_SIZE, + OP_SWAP, + OP_TOALTSTACK, + OP_VERIFY, + OP_0NOTEQUAL, +) + +from .errors import MiniscriptNodeCreationError +from .property import Property +from .satisfaction import ExecutionInfo, Satisfaction + + +# Threshold for nLockTime: below this value it is interpreted as block number, +# otherwise as UNIX timestamp. +LOCKTIME_THRESHOLD = 500000000 # Tue Nov 5 00:53:20 1985 UTC + +# If CTxIn::nSequence encodes a relative lock-time and this flag +# is set, the relative lock-time has units of 512 seconds, +# otherwise it specifies blocks with a granularity of 1. +SEQUENCE_LOCKTIME_TYPE_FLAG = 1 << 22 + + +class Node: + """A Miniscript fragment.""" + + # The fragment's type and properties + p = None + # List of all sub fragments + subs = [] + # A list of Script elements, a CScript is created all at once in the script() method. + _script = [] + # Whether any satisfaction for this fragment require a signature + needs_sig = None + # Whether any dissatisfaction for this fragment requires a signature + is_forced = None + # Whether this fragment has a unique unconditional satisfaction, and all conditional + # ones require a signature. + is_expressive = None + # Whether for any possible way to satisfy this fragment (may be none), a + # non-malleable satisfaction exists. + is_nonmalleable = None + # Whether this node or any of its subs contains an absolute heightlock + abs_heightlocks = None + # Whether this node or any of its subs contains a relative heightlock + rel_heightlocks = None + # Whether this node or any of its subs contains an absolute timelock + abs_timelocks = None + # Whether this node or any of its subs contains a relative timelock + rel_timelocks = None + # Whether this node does not contain a mix of timelock or heightlock of different types. + # That is, not (abs_heightlocks and rel_heightlocks or abs_timelocks and abs_timelocks) + no_timelock_mix = None + # Information about this Miniscript execution (satisfaction cost, etc..) + exec_info = None + + def __init__(self, *args, **kwargs): + # Needs to be implemented by derived classes. + raise NotImplementedError + + def from_str(ms_str): + """Parse a Miniscript fragment from its string representation.""" + assert isinstance(ms_str, str) + return parsing.miniscript_from_str(ms_str) + + def from_script(script, pkh_preimages={}): + """Decode a Miniscript fragment from its Script representation.""" + assert isinstance(script, CScript) + return parsing.miniscript_from_script(script, pkh_preimages) + + # TODO: have something like BuildScript from Core and get rid of the _script member. + @property + def script(self): + return CScript(self._script) + + @property + def keys(self): + """Get the list of all keys from this Miniscript, in order of apparition.""" + # Overriden by fragments that actually have keys. + return [key for sub in self.subs for key in sub.keys] + + def satisfy(self, sat_material): + """Get the witness of the smallest non-malleable satisfaction for this fragment, + if one exists. + + :param sat_material: a SatisfactionMaterial containing available data to satisfy + challenges. + """ + sat = self.satisfaction(sat_material) + if not sat.has_sig: + return None + return sat.witness + + def satisfaction(self, sat_material): + """Get the satisfaction for this fragment. + + :param sat_material: a SatisfactionMaterial containing available data to satisfy + challenges. + """ + # Needs to be implemented by derived classes. + raise NotImplementedError + + def dissatisfaction(self): + """Get the dissatisfaction for this fragment.""" + # Needs to be implemented by derived classes. + raise NotImplementedError + + +class Just0(Node): + def __init__(self): + + self._script = [OP_0] + + self.p = Property("Bzud") + self.needs_sig = False + self.is_forced = False + self.is_expressive = True + self.is_nonmalleable = True + self.abs_heightlocks = False + self.rel_heightlocks = False + self.abs_timelocks = False + self.rel_timelocks = False + self.no_timelock_mix = True + self.exec_info = ExecutionInfo(0, 0, None, 0) + + def satisfaction(self, sat_material): + return Satisfaction.unavailable() + + def dissatisfaction(self): + return Satisfaction(witness=[]) + + def __repr__(self): + return "0" + + +class Just1(Node): + def __init__(self): + + self._script = [OP_1] + + self.p = Property("Bzu") + self.needs_sig = False + self.is_forced = True # No dissat + self.is_expressive = False # No dissat + self.is_nonmalleable = True # FIXME: how comes? Standardness rules? + self.abs_heightlocks = False + self.rel_heightlocks = False + self.abs_timelocks = False + self.rel_timelocks = False + self.no_timelock_mix = True + self.exec_info = ExecutionInfo(0, 0, 0, None) + + def satisfaction(self, sat_material): + return Satisfaction(witness=[]) + + def dissatisfaction(self): + return Satisfaction.unavailable() + + def __repr__(self): + return "1" + + +class PkNode(Node): + """A virtual class for nodes containing a single public key. + + Should not be instanced directly, use Pk() or Pkh(). + """ + + def __init__(self, pubkey): + + if isinstance(pubkey, bytes) or isinstance(pubkey, str): + self.pubkey = DescriptorKey(pubkey) + elif isinstance(pubkey, DescriptorKey): + self.pubkey = pubkey + else: + raise MiniscriptNodeCreationError("Invalid public key") + + self.needs_sig = True # FIXME: think about having it in 'c:' instead + self.is_forced = False + self.is_expressive = True + self.is_nonmalleable = True + self.abs_heightlocks = False + self.rel_heightlocks = False + self.abs_timelocks = False + self.rel_timelocks = False + self.no_timelock_mix = True + + @property + def keys(self): + return [self.pubkey] + + +class Pk(PkNode): + def __init__(self, pubkey): + PkNode.__init__(self, pubkey) + + self.p = Property("Konud") + self.exec_info = ExecutionInfo(0, 0, 0, 0) + + @property + def _script(self): + return [self.pubkey.bytes()] + + def satisfaction(self, sat_material): + sig = sat_material.signatures.get(self.pubkey.bytes()) + if sig is None: + return Satisfaction.unavailable() + return Satisfaction([sig], has_sig=True) + + def dissatisfaction(self): + return Satisfaction(witness=[b""]) + + def __repr__(self): + return f"pk_k({self.pubkey})" + + +class Pkh(PkNode): + # FIXME: should we support a hash here, like rust-bitcoin? I don't think it's safe. + def __init__(self, pubkey): + PkNode.__init__(self, pubkey) + + self.p = Property("Knud") + self.exec_info = ExecutionInfo(3, 0, 1, 1) + + @property + def _script(self): + return [OP_DUP, OP_HASH160, self.pk_hash(), OP_EQUALVERIFY] + + def satisfaction(self, sat_material): + sig = sat_material.signatures.get(self.pubkey.bytes()) + if sig is None: + return Satisfaction.unavailable() + return Satisfaction(witness=[sig, self.pubkey.bytes()], has_sig=True) + + def dissatisfaction(self): + return Satisfaction(witness=[b"", self.pubkey.bytes()]) + + def __repr__(self): + return f"pk_h({self.pubkey})" + + def pk_hash(self): + assert isinstance(self.pubkey, DescriptorKey) + return hash160(self.pubkey.bytes()) + + +class Older(Node): + def __init__(self, value): + assert value > 0 and value < 2 ** 31 + + self.value = value + self._script = [self.value, OP_CHECKSEQUENCEVERIFY] + + self.p = Property("Bz") + self.needs_sig = False + self.is_forced = True + self.is_expressive = False # No dissat + self.is_nonmalleable = True + self.rel_timelocks = bool(value & SEQUENCE_LOCKTIME_TYPE_FLAG) + self.rel_heightlocks = not self.rel_timelocks + self.abs_heightlocks = False + self.abs_timelocks = False + self.no_timelock_mix = True + self.exec_info = ExecutionInfo(1, 0, 0, None) + + def satisfaction(self, sat_material): + if sat_material.max_sequence < self.value: + return Satisfaction.unavailable() + return Satisfaction(witness=[]) + + def dissatisfaction(self): + return Satisfaction.unavailable() + + def __repr__(self): + return f"older({self.value})" + + +class After(Node): + def __init__(self, value): + assert value > 0 and value < 2 ** 31 + + self.value = value + self._script = [self.value, OP_CHECKLOCKTIMEVERIFY] + + self.p = Property("Bz") + self.needs_sig = False + self.is_forced = True + self.is_expressive = False # No dissat + self.is_nonmalleable = True + self.abs_heightlocks = value < LOCKTIME_THRESHOLD + self.abs_timelocks = not self.abs_heightlocks + self.rel_heightlocks = False + self.rel_timelocks = False + self.no_timelock_mix = True + self.exec_info = ExecutionInfo(1, 0, 0, None) + + def satisfaction(self, sat_material): + if sat_material.max_lock_time < self.value: + return Satisfaction.unavailable() + return Satisfaction(witness=[]) + + def dissatisfaction(self): + return Satisfaction.unavailable() + + def __repr__(self): + return f"after({self.value})" + + +class HashNode(Node): + """A virtual class for fragments with hashlock semantics. + + Should not be instanced directly, use concrete fragments instead. + """ + + def __init__(self, digest, hash_op): + assert isinstance(digest, bytes) # TODO: real errors + + self.digest = digest + self._script = [OP_SIZE, 32, OP_EQUALVERIFY, hash_op, digest, OP_EQUAL] + + self.p = Property("Bonud") + self.needs_sig = False + self.is_forced = False + self.is_expressive = False + self.is_nonmalleable = True + self.abs_heightlocks = False + self.rel_heightlocks = False + self.abs_timelocks = False + self.rel_timelocks = False + self.no_timelock_mix = True + self.exec_info = ExecutionInfo(4, 0, 1, None) + + def satisfaction(self, sat_material): + preimage = sat_material.preimages.get(self.digest) + if preimage is None: + return Satisfaction.unavailable() + return Satisfaction(witness=[preimage]) + + def dissatisfaction(self): + return Satisfaction.unavailable() + return Satisfaction(witness=[b""]) + + +class Sha256(HashNode): + def __init__(self, digest): + assert len(digest) == 32 # TODO: real errors + HashNode.__init__(self, digest, OP_SHA256) + + def __repr__(self): + return f"sha256({self.digest.hex()})" + + +class Hash256(HashNode): + def __init__(self, digest): + assert len(digest) == 32 # TODO: real errors + HashNode.__init__(self, digest, OP_HASH256) + + def __repr__(self): + return f"hash256({self.digest.hex()})" + + +class Ripemd160(HashNode): + def __init__(self, digest): + assert len(digest) == 20 # TODO: real errors + HashNode.__init__(self, digest, OP_RIPEMD160) + + def __repr__(self): + return f"ripemd160({self.digest.hex()})" + + +class Hash160(HashNode): + def __init__(self, digest): + assert len(digest) == 20 # TODO: real errors + HashNode.__init__(self, digest, OP_HASH160) + + def __repr__(self): + return f"hash160({self.digest.hex()})" + + +class Multi(Node): + def __init__(self, k, keys): + assert 1 <= k <= len(keys) + assert all(isinstance(k, DescriptorKey) for k in keys) + + self.k = k + self.pubkeys = keys + + self.p = Property("Bndu") + self.needs_sig = True + self.is_forced = False + self.is_expressive = True + self.is_nonmalleable = True + self.abs_heightlocks = False + self.rel_heightlocks = False + self.abs_timelocks = False + self.rel_timelocks = False + self.no_timelock_mix = True + self.exec_info = ExecutionInfo(1, len(keys), 1 + k, 1 + k) + + @property + def keys(self): + return self.pubkeys + + @property + def _script(self): + return [ + self.k, + *[k.bytes() for k in self.keys], + len(self.keys), + OP_CHECKMULTISIG, + ] + + def satisfaction(self, sat_material): + sigs = [] + for key in self.keys: + sig = sat_material.signatures.get(key.bytes()) + if sig is not None: + assert isinstance(sig, bytes) + sigs.append(sig) + if len(sigs) == self.k: + break + if len(sigs) < self.k: + return Satisfaction.unavailable() + return Satisfaction(witness=[b""] + sigs, has_sig=True) + + def dissatisfaction(self): + return Satisfaction(witness=[b""] * (self.k + 1)) + + def __repr__(self): + return f"multi({','.join([str(self.k)] + [str(k) for k in self.keys])})" + + +class AndV(Node): + def __init__(self, sub_x, sub_y): + assert sub_x.p.V + assert sub_y.p.has_any("BKV") + + self.subs = [sub_x, sub_y] + + self.p = Property( + sub_y.p.type() + + ("z" if sub_x.p.z and sub_y.p.z else "") + + ("o" if sub_x.p.z and sub_y.p.o or sub_x.p.o and sub_y.p.z else "") + + ("n" if sub_x.p.n or sub_x.p.z and sub_y.p.n else "") + + ("u" if sub_y.p.u else "") + ) + self.needs_sig = any(sub.needs_sig for sub in self.subs) + self.is_forced = any(sub.needs_sig for sub in self.subs) + self.is_expressive = False # Not 'd' + self.is_nonmalleable = all(sub.is_nonmalleable for sub in self.subs) + self.abs_heightlocks = any(sub.abs_heightlocks for sub in self.subs) + self.rel_heightlocks = any(sub.rel_heightlocks for sub in self.subs) + self.abs_timelocks = any(sub.abs_timelocks for sub in self.subs) + self.rel_timelocks = any(sub.rel_timelocks for sub in self.subs) + self.no_timelock_mix = not ( + self.abs_heightlocks + and self.abs_timelocks + or self.rel_heightlocks + and self.rel_timelocks + ) + + @property + def _script(self): + return sum((sub._script for sub in self.subs), start=[]) + + @property + def exec_info(self): + exec_info = ExecutionInfo.from_concat( + self.subs[0].exec_info, self.subs[1].exec_info + ) + exec_info.set_undissatisfiable() # it's V. + return exec_info + + def satisfaction(self, sat_material): + return Satisfaction.from_concat(sat_material, *self.subs) + + def dissatisfaction(self): + return Satisfaction.unavailable() # it's V. + + def __repr__(self): + return f"and_v({','.join(map(str, self.subs))})" + + +class AndB(Node): + def __init__(self, sub_x, sub_y): + assert sub_x.p.B and sub_y.p.W + + self.subs = [sub_x, sub_y] + + self.p = Property( + "Bu" + + ("z" if sub_x.p.z and sub_y.p.z else "") + + ("o" if sub_x.p.z and sub_y.p.o or sub_x.p.o and sub_y.p.z else "") + + ("n" if sub_x.p.n or sub_x.p.z and sub_y.p.n else "") + + ("d" if sub_x.p.d and sub_y.p.d else "") + + ("u" if sub_y.p.u else "") + ) + self.needs_sig = any(sub.needs_sig for sub in self.subs) + self.is_forced = ( + sub_x.is_forced + and sub_y.is_forced + or any(sub.is_forced and sub.needs_sig for sub in self.subs) + ) + self.is_expressive = all(sub.is_forced and sub.needs_sig for sub in self.subs) + self.is_nonmalleable = all(sub.is_nonmalleable for sub in self.subs) + self.abs_heightlocks = any(sub.abs_heightlocks for sub in self.subs) + self.rel_heightlocks = any(sub.rel_heightlocks for sub in self.subs) + self.abs_timelocks = any(sub.abs_timelocks for sub in self.subs) + self.rel_timelocks = any(sub.rel_timelocks for sub in self.subs) + self.no_timelock_mix = not ( + self.abs_heightlocks + and self.abs_timelocks + or self.rel_heightlocks + and self.rel_timelocks + ) + + @property + def _script(self): + return sum((sub._script for sub in self.subs), start=[]) + [OP_BOOLAND] + + @property + def exec_info(self): + return ExecutionInfo.from_concat( + self.subs[0].exec_info, self.subs[1].exec_info, ops_count=1 + ) + + def satisfaction(self, sat_material): + return Satisfaction.from_concat(sat_material, self.subs[0], self.subs[1]) + + def dissatisfaction(self): + return self.subs[1].dissatisfaction() + self.subs[0].dissatisfaction() + + def __repr__(self): + return f"and_b({','.join(map(str, self.subs))})" + + +class OrB(Node): + def __init__(self, sub_x, sub_z): + assert sub_x.p.has_all("Bd") + assert sub_z.p.has_all("Wd") + + self.subs = [sub_x, sub_z] + + self.p = Property( + "Bdu" + + ("z" if sub_x.p.z and sub_z.p.z else "") + + ("o" if sub_x.p.z and sub_z.p.o or sub_x.p.o and sub_z.p.z else "") + ) + self.needs_sig = all(sub.needs_sig for sub in self.subs) + self.is_forced = False # Both subs are 'd' + self.is_expressive = all(sub.is_expressive for sub in self.subs) + self.is_nonmalleable = all( + sub.is_nonmalleable and sub.is_expressive for sub in self.subs + ) and any(sub.needs_sig for sub in self.subs) + self.abs_heightlocks = any(sub.abs_heightlocks for sub in self.subs) + self.rel_heightlocks = any(sub.rel_heightlocks for sub in self.subs) + self.abs_timelocks = any(sub.abs_timelocks for sub in self.subs) + self.rel_timelocks = any(sub.rel_timelocks for sub in self.subs) + self.no_timelock_mix = all(sub.no_timelock_mix for sub in self.subs) + + @property + def _script(self): + return sum((sub._script for sub in self.subs), start=[]) + [OP_BOOLOR] + + @property + def exec_info(self): + return ExecutionInfo.from_concat( + self.subs[0].exec_info, + self.subs[1].exec_info, + ops_count=1, + disjunction=True, + ) + + def satisfaction(self, sat_material): + return Satisfaction.from_concat( + sat_material, self.subs[0], self.subs[1], disjunction=True + ) + + def dissatisfaction(self): + return self.subs[1].dissatisfaction() + self.subs[0].dissatisfaction() + + def __repr__(self): + return f"or_b({','.join(map(str, self.subs))})" + + +class OrC(Node): + def __init__(self, sub_x, sub_z): + assert sub_x.p.has_all("Bdu") and sub_z.p.V + + self.subs = [sub_x, sub_z] + + self.p = Property( + "V" + + ("z" if sub_x.p.z and sub_z.p.z else "") + + ("o" if sub_x.p.o and sub_z.p.z else "") + ) + self.needs_sig = all(sub.needs_sig for sub in self.subs) + self.is_forced = True # Because sub_z is 'V' + self.is_expressive = False # V + self.is_nonmalleable = ( + all(sub.is_nonmalleable for sub in self.subs) + and any(sub.needs_sig for sub in self.subs) + and sub_x.is_expressive + ) + self.abs_heightlocks = any(sub.abs_heightlocks for sub in self.subs) + self.rel_heightlocks = any(sub.rel_heightlocks for sub in self.subs) + self.abs_timelocks = any(sub.abs_timelocks for sub in self.subs) + self.rel_timelocks = any(sub.rel_timelocks for sub in self.subs) + self.no_timelock_mix = all(sub.no_timelock_mix for sub in self.subs) + + @property + def _script(self): + return self.subs[0]._script + [OP_NOTIF] + self.subs[1]._script + [OP_ENDIF] + + @property + def exec_info(self): + exec_info = ExecutionInfo.from_or_uneven( + self.subs[0].exec_info, self.subs[1].exec_info, ops_count=2 + ) + exec_info.set_undissatisfiable() # it's V. + return exec_info + + def satisfaction(self, sat_material): + return Satisfaction.from_or_uneven(sat_material, self.subs[0], self.subs[1]) + + def dissatisfaction(self): + return Satisfaction.unavailable() # it's V. + + def __repr__(self): + return f"or_c({','.join(map(str, self.subs))})" + + +class OrD(Node): + def __init__(self, sub_x, sub_z): + assert sub_x.p.has_all("Bdu") + assert sub_z.p.has_all("B") + + self.subs = [sub_x, sub_z] + + self.p = Property( + "B" + + ("z" if sub_x.p.z and sub_z.p.z else "") + + ("o" if sub_x.p.o and sub_z.p.z else "") + + ("d" if sub_z.p.d else "") + + ("u" if sub_z.p.u else "") + ) + self.needs_sig = all(sub.needs_sig for sub in self.subs) + self.is_forced = all(sub.is_forced for sub in self.subs) + self.is_expressive = all(sub.is_expressive for sub in self.subs) + self.is_nonmalleable = ( + all(sub.is_nonmalleable for sub in self.subs) + and any(sub.needs_sig for sub in self.subs) + and sub_x.is_expressive + ) + self.abs_heightlocks = any(sub.abs_heightlocks for sub in self.subs) + self.rel_heightlocks = any(sub.rel_heightlocks for sub in self.subs) + self.abs_timelocks = any(sub.abs_timelocks for sub in self.subs) + self.rel_timelocks = any(sub.rel_timelocks for sub in self.subs) + self.no_timelock_mix = all(sub.no_timelock_mix for sub in self.subs) + + @property + def _script(self): + return ( + self.subs[0]._script + + [OP_IFDUP, OP_NOTIF] + + self.subs[1]._script + + [OP_ENDIF] + ) + + @property + def exec_info(self): + return ExecutionInfo.from_or_uneven( + self.subs[0].exec_info, self.subs[1].exec_info, ops_count=3 + ) + + def satisfaction(self, sat_material): + return Satisfaction.from_or_uneven(sat_material, self.subs[0], self.subs[1]) + + def dissatisfaction(self): + return self.subs[1].dissatisfaction() + self.subs[0].dissatisfaction() + + def __repr__(self): + return f"or_d({','.join(map(str, self.subs))})" + + +class OrI(Node): + def __init__(self, sub_x, sub_z): + assert sub_x.p.type() == sub_z.p.type() and sub_x.p.has_any("BKV") + + self.subs = [sub_x, sub_z] + + self.p = Property( + sub_x.p.type() + + ("o" if sub_x.p.z and sub_z.p.z else "") + + ("d" if sub_x.p.d or sub_z.p.d else "") + + ("u" if sub_x.p.u and sub_z.p.u else "") + ) + self.needs_sig = all(sub.needs_sig for sub in self.subs) + self.is_forced = all(sub.is_forced for sub in self.subs) + self.is_expressive = ( + sub_x.is_expressive + and sub_z.is_forced + or sub_x.is_forced + and sub_z.is_expressive + ) + self.is_nonmalleable = all(sub.is_nonmalleable for sub in self.subs) and any( + sub.needs_sig for sub in self.subs + ) + self.abs_heightlocks = any(sub.abs_heightlocks for sub in self.subs) + self.rel_heightlocks = any(sub.rel_heightlocks for sub in self.subs) + self.abs_timelocks = any(sub.abs_timelocks for sub in self.subs) + self.rel_timelocks = any(sub.rel_timelocks for sub in self.subs) + self.no_timelock_mix = all(sub.no_timelock_mix for sub in self.subs) + + @property + def _script(self): + return ( + [OP_IF] + + self.subs[0]._script + + [OP_ELSE] + + self.subs[1]._script + + [OP_ENDIF] + ) + + @property + def exec_info(self): + return ExecutionInfo.from_or_even( + self.subs[0].exec_info, self.subs[1].exec_info, ops_count=3 + ) + + def satisfaction(self, sat_material): + return (self.subs[0].satisfaction(sat_material) + Satisfaction([b"\x01"])) | ( + self.subs[1].satisfaction(sat_material) + Satisfaction([b""]) + ) + + def dissatisfaction(self): + return (self.subs[0].dissatisfaction() + Satisfaction(witness=[b"\x01"])) | ( + self.subs[1].dissatisfaction() + Satisfaction(witness=[b""]) + ) + + def __repr__(self): + return f"or_i({','.join(map(str, self.subs))})" + + +class AndOr(Node): + def __init__(self, sub_x, sub_y, sub_z): + assert sub_x.p.has_all("Bdu") + assert sub_y.p.type() == sub_z.p.type() and sub_y.p.has_any("BKV") + + self.subs = [sub_x, sub_y, sub_z] + + self.p = Property( + sub_y.p.type() + + ("z" if sub_x.p.z and sub_y.p.z and sub_z.p.z else "") + + ( + "o" + if sub_x.p.z + and sub_y.p.o + and sub_z.p.o + or sub_x.p.o + and sub_y.p.z + and sub_z.p.z + else "" + ) + + ("d" if sub_z.p.d else "") + + ("u" if sub_y.p.u and sub_z.p.u else "") + ) + self.needs_sig = sub_x.needs_sig and (sub_y.needs_sig or sub_z.needs_sig) + self.is_forced = sub_z.is_forced and (sub_x.needs_sig or sub_y.is_forced) + self.is_expressive = ( + sub_x.is_expressive + and sub_z.is_expressive + and (sub_x.needs_sig or sub_y.is_forced) + ) + self.is_nonmalleable = ( + all(sub.is_nonmalleable for sub in self.subs) + and any(sub.needs_sig for sub in self.subs) + and sub_x.is_expressive + ) + self.abs_heightlocks = any(sub.abs_heightlocks for sub in self.subs) + self.rel_heightlocks = any(sub.rel_heightlocks for sub in self.subs) + self.abs_timelocks = any(sub.abs_timelocks for sub in self.subs) + self.rel_timelocks = any(sub.rel_timelocks for sub in self.subs) + # X and Y, or Z. So we have a mix if any contain a timelock mix, or + # there is a mix between X and Y. + self.no_timelock_mix = all(sub.no_timelock_mix for sub in self.subs) and not ( + any(sub.rel_timelocks for sub in [sub_x, sub_y]) + and any(sub.rel_heightlocks for sub in [sub_x, sub_y]) + or any(sub.abs_timelocks for sub in [sub_x, sub_y]) + and any(sub.abs_heightlocks for sub in [sub_x, sub_y]) + ) + + @property + def _script(self): + return ( + self.subs[0]._script + + [OP_NOTIF] + + self.subs[2]._script + + [OP_ELSE] + + self.subs[1]._script + + [OP_ENDIF] + ) + + @property + def exec_info(self): + return ExecutionInfo.from_andor_uneven( + self.subs[0].exec_info, + self.subs[1].exec_info, + self.subs[2].exec_info, + ops_count=3, + ) + + def satisfaction(self, sat_material): + # (A and B) or (!A and C) + return ( + self.subs[1].satisfaction(sat_material) + + self.subs[0].satisfaction(sat_material) + ) | (self.subs[2].satisfaction(sat_material) + self.subs[0].dissatisfaction()) + + def dissatisfaction(self): + # Dissatisfy X and Z + return self.subs[2].dissatisfaction() + self.subs[0].dissatisfaction() + + def __repr__(self): + return f"andor({','.join(map(str, self.subs))})" + + +class AndN(AndOr): + def __init__(self, sub_x, sub_y): + AndOr.__init__(self, sub_x, sub_y, Just0()) + + def __repr__(self): + return f"and_n({self.subs[0]},{self.subs[1]})" + + +class Thresh(Node): + def __init__(self, k, subs): + n = len(subs) + assert 1 <= k <= n + + self.k = k + self.subs = subs + + all_z = True + all_z_but_one_odu = False + all_e = True + all_m = True + s_count = 0 + # If k == 1, just check each child for k + if k > 1: + self.abs_heightlocks = subs[0].abs_heightlocks + self.rel_heightlocks = subs[0].rel_heightlocks + self.abs_timelocks = subs[0].abs_timelocks + self.rel_timelocks = subs[0].rel_timelocks + else: + self.no_timelock_mix = True + + assert subs[0].p.has_all("Bdu") + for sub in subs[1:]: + assert sub.p.has_all("Wdu") + if not sub.p.z: + if all_z_but_one_odu: + # Fails "all 'z' but one" + all_z_but_one_odu = False + if all_z and sub.p.has_all("odu"): + # They were all 'z' up to now. + all_z_but_one_odu = True + all_z = False + all_e = all_e and sub.is_expressive + all_m = all_m and sub.is_nonmalleable + if sub.needs_sig: + s_count += 1 + if k > 1: + self.abs_heightlocks |= sub.abs_heightlocks + self.rel_heightlocks |= sub.rel_heightlocks + self.abs_timelocks |= sub.abs_timelocks + self.rel_timelocks |= sub.rel_timelocks + else: + self.no_timelock_mix &= sub.no_timelock_mix + + self.p = Property( + "Bdu" + ("z" if all_z else "") + ("o" if all_z_but_one_odu else "") + ) + self.needs_sig = s_count >= n - k + self.is_forced = False # All subs need to be 'd' + self.is_expressive = all_e and s_count == n + self.is_nonmalleable = all_e and s_count >= n - k + if k > 1: + self.no_timelock_mix = not ( + self.abs_heightlocks + and self.abs_timelocks + or self.rel_heightlocks + and self.rel_timelocks + ) + + @property + def _script(self): + return ( + self.subs[0]._script + + sum(((sub._script + [OP_ADD]) for sub in self.subs[1:]), start=[]) + + [self.k, OP_EQUAL] + ) + + @property + def exec_info(self): + return ExecutionInfo.from_thresh(self.k, [sub.exec_info for sub in self.subs]) + + def satisfaction(self, sat_material): + return Satisfaction.from_thresh(sat_material, self.k, self.subs) + + def dissatisfaction(self): + return sum( + [sub.dissatisfaction() for sub in self.subs], start=Satisfaction(witness=[]) + ) + + def __repr__(self): + return f"thresh({self.k},{','.join(map(str, self.subs))})" + + +class WrapperNode(Node): + """A virtual base class for wrappers. + + Don't instanciate it directly, use concret wrapper fragments instead. + """ + + def __init__(self, sub): + self.subs = [sub] + + # Properties for most wrappers are directly inherited. When it's not, they + # are overriden in the fragment's __init__. + self.needs_sig = sub.needs_sig + self.is_forced = sub.is_forced + self.is_expressive = sub.is_expressive + self.is_nonmalleable = sub.is_nonmalleable + self.abs_heightlocks = sub.abs_heightlocks + self.rel_heightlocks = sub.rel_heightlocks + self.abs_timelocks = sub.abs_timelocks + self.rel_timelocks = sub.rel_timelocks + self.no_timelock_mix = not ( + self.abs_heightlocks + and self.abs_timelocks + or self.rel_heightlocks + and self.rel_timelocks + ) + + @property + def sub(self): + # Wrapper have a single sub + return self.subs[0] + + def satisfaction(self, sat_material): + # Most wrappers are satisfied this way, for special cases it's overriden. + return self.subs[0].satisfaction(sat_material) + + def dissatisfaction(self): + # Most wrappers are satisfied this way, for special cases it's overriden. + return self.subs[0].dissatisfaction() + + def skip_colon(self): + # We need to check this because of the pk() and pkh() aliases. + if isinstance(self.subs[0], WrapC) and isinstance( + self.subs[0].subs[0], (Pk, Pkh) + ): + return False + return isinstance(self.subs[0], WrapperNode) + + +class WrapA(WrapperNode): + def __init__(self, sub): + assert sub.p.B + WrapperNode.__init__(self, sub) + + self.p = Property("W" + "".join(c for c in "ud" if getattr(sub.p, c))) + + @property + def _script(self): + return [OP_TOALTSTACK] + self.sub._script + [OP_FROMALTSTACK] + + @property + def exec_info(self): + return ExecutionInfo.from_wrap(self.sub.exec_info, ops_count=2) + + def __repr__(self): + # Don't duplicate colons + if self.skip_colon(): + return f"a{self.subs[0]}" + return f"a:{self.subs[0]}" + + +class WrapS(WrapperNode): + def __init__(self, sub): + assert sub.p.has_all("Bo") + WrapperNode.__init__(self, sub) + + self.p = Property("W" + "".join(c for c in "ud" if getattr(sub.p, c))) + + @property + def _script(self): + return [OP_SWAP] + self.sub._script + + @property + def exec_info(self): + return ExecutionInfo.from_wrap(self.sub.exec_info, ops_count=1) + + def __repr__(self): + # Avoid duplicating colons + if self.skip_colon(): + return f"s{self.subs[0]}" + return f"s:{self.subs[0]}" + + +class WrapC(WrapperNode): + def __init__(self, sub): + assert sub.p.K + WrapperNode.__init__(self, sub) + + # FIXME: shouldn't n and d be default props on the website? + self.p = Property("Bu" + "".join(c for c in "dno" if getattr(sub.p, c))) + + @property + def _script(self): + return self.sub._script + [OP_CHECKSIG] + + @property + def exec_info(self): + # FIXME: should need_sig be set to True here instead of in keys? + return ExecutionInfo.from_wrap(self.sub.exec_info, ops_count=1, sat=1, dissat=1) + + def __repr__(self): + # Special case of aliases + if isinstance(self.subs[0], Pk): + return f"pk({self.subs[0].pubkey})" + if isinstance(self.subs[0], Pkh): + return f"pkh({self.subs[0].pubkey})" + # Avoid duplicating colons + if self.skip_colon(): + return f"c{self.subs[0]}" + return f"c:{self.subs[0]}" + + +class WrapT(AndV, WrapperNode): + def __init__(self, sub): + AndV.__init__(self, sub, Just1()) + + def is_wrapper(self): + return True + + def __repr__(self): + # Avoid duplicating colons + if self.skip_colon(): + return f"t{self.subs[0]}" + return f"t:{self.subs[0]}" + + +class WrapD(WrapperNode): + def __init__(self, sub): + assert sub.p.has_all("Vz") + WrapperNode.__init__(self, sub) + + self.p = Property("Bond") + self.is_forced = True # sub is V + self.is_expressive = True # sub is V, and we add a single dissat + + @property + def _script(self): + return [OP_DUP, OP_IF] + self.sub._script + [OP_ENDIF] + + @property + def exec_info(self): + return ExecutionInfo.from_wrap_dissat( + self.sub.exec_info, ops_count=3, sat=1, dissat=1 + ) + + def satisfaction(self, sat_material): + return Satisfaction(witness=[b"\x01"]) + self.subs[0].satisfaction(sat_material) + + def dissatisfaction(self): + return Satisfaction(witness=[b""]) + + def __repr__(self): + # Avoid duplicating colons + if self.skip_colon(): + return f"d{self.subs[0]}" + return f"d:{self.subs[0]}" + + +class WrapV(WrapperNode): + def __init__(self, sub): + assert sub.p.B + WrapperNode.__init__(self, sub) + + self.p = Property("V" + "".join(c for c in "zon" if getattr(sub.p, c))) + self.is_forced = True # V + self.is_expressive = False # V + + @property + def _script(self): + if self.sub._script[-1] == OP_CHECKSIG: + return self.sub._script[:-1] + [OP_CHECKSIGVERIFY] + elif self.sub._script[-1] == OP_CHECKMULTISIG: + return self.sub._script[:-1] + [OP_CHECKMULTISIGVERIFY] + elif self.sub._script[-1] == OP_EQUAL: + return self.sub._script[:-1] + [OP_EQUALVERIFY] + return self.sub._script + [OP_VERIFY] + + @property + def exec_info(self): + verify_cost = int(self._script[-1] == OP_VERIFY) + return ExecutionInfo.from_wrap(self.sub.exec_info, ops_count=verify_cost) + + def dissatisfaction(self): + return Satisfaction.unavailable() # It's V. + + def __repr__(self): + # Avoid duplicating colons + if self.skip_colon(): + return f"v{self.subs[0]}" + return f"v:{self.subs[0]}" + + +class WrapJ(WrapperNode): + def __init__(self, sub): + assert sub.p.has_all("Bn") + WrapperNode.__init__(self, sub) + + self.p = Property("Bnd" + "".join(c for c in "ou" if getattr(sub.p, c))) + self.is_forced = False # d + self.is_expressive = sub.is_forced + + @property + def _script(self): + return [OP_SIZE, OP_0NOTEQUAL, OP_IF, *self.sub._script, OP_ENDIF] + + @property + def exec_info(self): + return ExecutionInfo.from_wrap_dissat(self.sub.exec_info, ops_count=4, dissat=1) + + def dissatisfaction(self): + return Satisfaction(witness=[b""]) + + def __repr__(self): + # Avoid duplicating colons + if self.skip_colon(): + return f"j{self.subs[0]}" + return f"j:{self.subs[0]}" + + +class WrapN(WrapperNode): + def __init__(self, sub): + assert sub.p.B + WrapperNode.__init__(self, sub) + + self.p = Property("Bu" + "".join(c for c in "zond" if getattr(sub.p, c))) + + @property + def _script(self): + return [*self.sub._script, OP_0NOTEQUAL] + + @property + def exec_info(self): + return ExecutionInfo.from_wrap(self.sub.exec_info, ops_count=1) + + def __repr__(self): + # Avoid duplicating colons + if self.skip_colon(): + return f"n{self.subs[0]}" + return f"n:{self.subs[0]}" + + +class WrapL(OrI, WrapperNode): + def __init__(self, sub): + OrI.__init__(self, Just0(), sub) + + def __repr__(self): + # Avoid duplicating colons + if self.skip_colon(): + return f"l{self.subs[1]}" + return f"l:{self.subs[1]}" + + +class WrapU(OrI, WrapperNode): + def __init__(self, sub): + OrI.__init__(self, sub, Just0()) + + def __repr__(self): + # Avoid duplicating colons + if self.skip_colon(): + return f"u{self.subs[0]}" + return f"u:{self.subs[0]}" diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/parsing.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/parsing.py new file mode 100644 index 0000000..2058b7b --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/parsing.py @@ -0,0 +1,736 @@ +""" +Utilities to parse Miniscript from string and Script representations. +""" + +from ...bip380.miniscript import fragments + +from ...bip380.key import DescriptorKey +from ...bip380.miniscript.errors import MiniscriptMalformed +from ...bip380.utils.script import ( + CScriptOp, + OP_ADD, + OP_BOOLAND, + OP_BOOLOR, + OP_CHECKSIGVERIFY, + OP_CHECKMULTISIGVERIFY, + OP_EQUALVERIFY, + OP_DUP, + OP_ELSE, + OP_ENDIF, + OP_EQUAL, + OP_FROMALTSTACK, + OP_IFDUP, + OP_IF, + OP_CHECKLOCKTIMEVERIFY, + OP_CHECKMULTISIG, + OP_CHECKSEQUENCEVERIFY, + OP_CHECKSIG, + OP_HASH160, + OP_HASH256, + OP_NOTIF, + OP_RIPEMD160, + OP_SHA256, + OP_SIZE, + OP_SWAP, + OP_TOALTSTACK, + OP_VERIFY, + OP_0NOTEQUAL, + ScriptNumError, + read_script_number, +) + + +def stack_item_to_int(item): + """ + Convert a stack item to an integer depending on its type. + May raise an exception if the item is bytes, otherwise return None if it + cannot perform the conversion. + """ + if isinstance(item, bytes): + return read_script_number(item) + + if isinstance(item, fragments.Node): + if isinstance(item, fragments.Just1): + return 1 + if isinstance(item, fragments.Just0): + return 0 + + if isinstance(item, int): + return item + + return None + + +def decompose_script(script): + """Create a list of Script element from a CScript, decomposing the compact + -VERIFY opcodes into the non-VERIFY OP and an OP_VERIFY. + """ + elems = [] + for elem in script: + if elem == OP_CHECKSIGVERIFY: + elems += [OP_CHECKSIG, OP_VERIFY] + elif elem == OP_CHECKMULTISIGVERIFY: + elems += [OP_CHECKMULTISIG, OP_VERIFY] + elif elem == OP_EQUALVERIFY: + elems += [OP_EQUAL, OP_VERIFY] + else: + elems.append(elem) + return elems + + +def parse_term_single_elem(expr_list, idx): + """ + Try to parse a terminal node from the element of {expr_list} at {idx}. + """ + # Match against pk_k(key). + if ( + isinstance(expr_list[idx], bytes) + and len(expr_list[idx]) == 33 + and expr_list[idx][0] in [2, 3] + ): + expr_list[idx] = fragments.Pk(expr_list[idx]) + + # Match against JUST_1 and JUST_0. + if expr_list[idx] == 1: + expr_list[idx] = fragments.Just1() + if expr_list[idx] == b"": + expr_list[idx] = fragments.Just0() + + +def parse_term_2_elems(expr_list, idx): + """ + Try to parse a terminal node from two elements of {expr_list}, starting + from {idx}. + Return the new expression list on success, None if there was no match. + """ + elem_a = expr_list[idx] + elem_b = expr_list[idx + 1] + + # Only older() and after() as term with 2 stack items + if not isinstance(elem_b, CScriptOp): + return + try: + n = stack_item_to_int(elem_a) + if n is None: + return + except ScriptNumError: + return + + if n <= 0 or n >= 2 ** 31: + return + + if elem_b == OP_CHECKSEQUENCEVERIFY: + node = fragments.Older(n) + expr_list[idx: idx + 2] = [node] + return expr_list + + if elem_b == OP_CHECKLOCKTIMEVERIFY: + node = fragments.After(n) + expr_list[idx: idx + 2] = [node] + return expr_list + + +def parse_term_5_elems(expr_list, idx, pkh_preimages={}): + """ + Try to parse a terminal node from five elements of {expr_list}, starting + from {idx}. + Return the new expression list on success, None if there was no match. + """ + # The only 3 items node is pk_h + if expr_list[idx: idx + 2] != [OP_DUP, OP_HASH160]: + return + if not isinstance(expr_list[idx + 2], bytes): + return + if len(expr_list[idx + 2]) != 20: + return + if expr_list[idx + 3: idx + 5] != [OP_EQUAL, OP_VERIFY]: + return + + key_hash = expr_list[idx + 2] + key = pkh_preimages.get(key_hash) + assert key is not None # TODO: have a real error here + node = fragments.Pkh(key) + expr_list[idx: idx + 5] = [node] + return expr_list + + +def parse_term_7_elems(expr_list, idx): + """ + Try to parse a terminal node from seven elements of {expr_list}, starting + from {idx}. + Return the new expression list on success, None if there was no match. + """ + # Note how all the hashes are 7 elems because the VERIFY was decomposed + # Match against sha256. + if ( + expr_list[idx: idx + 5] == [OP_SIZE, b"\x20", OP_EQUAL, OP_VERIFY, OP_SHA256] + and isinstance(expr_list[idx + 5], bytes) + and len(expr_list[idx + 5]) == 32 + and expr_list[idx + 6] == OP_EQUAL + ): + node = fragments.Sha256(expr_list[idx + 5]) + expr_list[idx: idx + 7] = [node] + return expr_list + + # Match against hash256. + if ( + expr_list[idx: idx + 5] == [OP_SIZE, b"\x20", OP_EQUAL, OP_VERIFY, OP_HASH256] + and isinstance(expr_list[idx + 5], bytes) + and len(expr_list[idx + 5]) == 32 + and expr_list[idx + 6] == OP_EQUAL + ): + node = fragments.Hash256(expr_list[idx + 5]) + expr_list[idx: idx + 7] = [node] + return expr_list + + # Match against ripemd160. + if ( + expr_list[idx: idx + 5] + == [OP_SIZE, b"\x20", OP_EQUAL, OP_VERIFY, OP_RIPEMD160] + and isinstance(expr_list[idx + 5], bytes) + and len(expr_list[idx + 5]) == 20 + and expr_list[idx + 6] == OP_EQUAL + ): + node = fragments.Ripemd160(expr_list[idx + 5]) + expr_list[idx: idx + 7] = [node] + return expr_list + + # Match against hash160. + if ( + expr_list[idx: idx + 5] == [OP_SIZE, b"\x20", OP_EQUAL, OP_VERIFY, OP_HASH160] + and isinstance(expr_list[idx + 5], bytes) + and len(expr_list[idx + 5]) == 20 + and expr_list[idx + 6] == OP_EQUAL + ): + node = fragments.Hash160(expr_list[idx + 5]) + expr_list[idx: idx + 7] = [node] + return expr_list + + +def parse_nonterm_2_elems(expr_list, idx): + """ + Try to parse a non-terminal node from two elements of {expr_list}, starting + from {idx}. + Return the new expression list on success, None if there was no match. + """ + elem_a = expr_list[idx] + elem_b = expr_list[idx + 1] + + if isinstance(elem_a, fragments.Node): + # Match against and_v. + if isinstance(elem_b, fragments.Node) and elem_a.p.V and elem_b.p.has_any("BKV"): + # Is it a special case of t: wrapper? + if isinstance(elem_b, fragments.Just1): + node = fragments.WrapT(elem_a) + else: + node = fragments.AndV(elem_a, elem_b) + expr_list[idx: idx + 2] = [node] + return expr_list + + # Match against c wrapper. + if elem_b == OP_CHECKSIG and elem_a.p.K: + node = fragments.WrapC(elem_a) + expr_list[idx: idx + 2] = [node] + return expr_list + + # Match against v wrapper. + if elem_b == OP_VERIFY and elem_a.p.B: + node = fragments.WrapV(elem_a) + expr_list[idx: idx + 2] = [node] + return expr_list + + # Match against n wrapper. + if elem_b == OP_0NOTEQUAL and elem_a.p.B: + node = fragments.WrapN(elem_a) + expr_list[idx: idx + 2] = [node] + return expr_list + + # Match against s wrapper. + if isinstance(elem_b, fragments.Node) and elem_a == OP_SWAP and elem_b.p.has_all("Bo"): + node = fragments.WrapS(elem_b) + expr_list[idx: idx + 2] = [node] + return expr_list + + +def parse_nonterm_3_elems(expr_list, idx): + """ + Try to parse a non-terminal node from *at least* three elements of + {expr_list}, starting from {idx}. + Return the new expression list on success, None if there was no match. + """ + elem_a = expr_list[idx] + elem_b = expr_list[idx + 1] + elem_c = expr_list[idx + 2] + + if isinstance(elem_a, fragments.Node) and isinstance(elem_b, fragments.Node): + # Match against and_b. + if elem_c == OP_BOOLAND and elem_a.p.B and elem_b.p.W: + node = fragments.AndB(elem_a, elem_b) + expr_list[idx: idx + 3] = [node] + return expr_list + + # Match against or_b. + if elem_c == OP_BOOLOR and elem_a.p.has_all("Bd") and elem_b.p.has_all("Wd"): + node = fragments.OrB(elem_a, elem_b) + expr_list[idx: idx + 3] = [node] + return expr_list + + # Match against a wrapper. + if ( + elem_a == OP_TOALTSTACK + and isinstance(elem_b, fragments.Node) + and elem_b.p.B + and elem_c == OP_FROMALTSTACK + ): + node = fragments.WrapA(elem_b) + expr_list[idx: idx + 3] = [node] + return expr_list + + # FIXME: multi is a terminal! + # Match against a multi. + try: + k = stack_item_to_int(expr_list[idx]) + except ScriptNumError: + return + if k is None: + return + # ()* CHECKMULTISIG + if k > len(expr_list[idx + 1:]) - 2: + return + # Get the keys + keys = [] + i = idx + 1 + while idx < len(expr_list) - 2: + if not isinstance(expr_list[i], fragments.Pk): + break + keys.append(expr_list[i].pubkey) + i += 1 + if expr_list[i + 1] == OP_CHECKMULTISIG: + if k > len(keys): + return + try: + m = stack_item_to_int(expr_list[i]) + except ScriptNumError: + return + if m is None or m != len(keys): + return + node = fragments.Multi(k, keys) + expr_list[idx: i + 2] = [node] + return expr_list + + +def parse_nonterm_4_elems(expr_list, idx): + """ + Try to parse a non-terminal node from at least four elements of {expr_list}, + starting from {idx}. + Return the new expression list on success, None if there was no match. + """ + (it_a, it_b, it_c, it_d) = expr_list[idx: idx + 4] + + # Match against thresh. It's of the form [X] ([X] ADD)* k EQUAL + if isinstance(it_a, fragments.Node) and it_a.p.has_all("Bdu"): + subs = [it_a] + # The first matches, now do all the ([X] ADD)s and return + # if a pair is of the form (k, EQUAL). + for i in range(idx + 1, len(expr_list) - 1, 2): + if ( + isinstance(expr_list[i], fragments.Node) + and expr_list[i].p.has_all("Wdu") + and expr_list[i + 1] == OP_ADD + ): + subs.append(expr_list[i]) + continue + elif expr_list[i + 1] == OP_EQUAL: + try: + k = stack_item_to_int(expr_list[i]) + if len(subs) >= k >= 1: + node = fragments.Thresh(k, subs) + expr_list[idx: i + 1 + 1] = [node] + return expr_list + except ScriptNumError: + break + else: + break + + # Match against or_c. + if ( + isinstance(it_a, fragments.Node) + and it_a.p.has_all("Bdu") + and it_b == OP_NOTIF + and isinstance(it_c, fragments.Node) + and it_c.p.V + and it_d == OP_ENDIF + ): + node = fragments.OrC(it_a, it_c) + expr_list[idx: idx + 4] = [node] + return expr_list + + # Match against d wrapper. + if ( + [it_a, it_b] == [OP_DUP, OP_IF] + and isinstance(it_c, fragments.Node) + and it_c.p.has_all("Vz") + and it_d == OP_ENDIF + ): + node = fragments.WrapD(it_c) + expr_list[idx: idx + 4] = [node] + return expr_list + + +def parse_nonterm_5_elems(expr_list, idx): + """ + Try to parse a non-terminal node from five elements of {expr_list}, starting + from {idx}. + Return the new expression list on success, None if there was no match. + """ + (it_a, it_b, it_c, it_d, it_e) = expr_list[idx: idx + 5] + + # Match against or_d. + if ( + isinstance(it_a, fragments.Node) + and it_a.p.has_all("Bdu") + and [it_b, it_c] == [OP_IFDUP, OP_NOTIF] + and isinstance(it_d, fragments.Node) + and it_d.p.B + and it_e == OP_ENDIF + ): + node = fragments.OrD(it_a, it_d) + expr_list[idx: idx + 5] = [node] + return expr_list + + # Match against or_i. + if ( + it_a == OP_IF + and isinstance(it_b, fragments.Node) + and it_b.p.has_any("BKV") + and it_c == OP_ELSE + and isinstance(it_d, fragments.Node) + and it_d.p.has_any("BKV") + and it_e == OP_ENDIF + ): + if isinstance(it_b, fragments.Just0): + node = fragments.WrapL(it_d) + elif isinstance(it_d, fragments.Just0): + node = fragments.WrapU(it_b) + else: + node = fragments.OrI(it_b, it_d) + expr_list[idx: idx + 5] = [node] + return expr_list + + # Match against j wrapper. + if ( + [it_a, it_b, it_c] == [OP_SIZE, OP_0NOTEQUAL, OP_IF] + and isinstance(it_d, fragments.Node) + and it_e == OP_ENDIF + ): + node = fragments.WrapJ(expr_list[idx + 3]) + expr_list[idx: idx + 5] = [node] + return expr_list + + +def parse_nonterm_6_elems(expr_list, idx): + """ + Try to parse a non-terminal node from six elements of {expr_list}, starting + from {idx}. + Return the new expression list on success, None if there was no match. + """ + (it_a, it_b, it_c, it_d, it_e, it_f) = expr_list[idx: idx + 6] + + # Match against andor. + if ( + isinstance(it_a, fragments.Node) + and it_a.p.has_all("Bdu") + and it_b == OP_NOTIF + and isinstance(it_c, fragments.Node) + and it_c.p.has_any("BKV") + and it_d == OP_ELSE + and isinstance(it_e, fragments.Node) + and it_e.p.has_any("BKV") + and it_f == OP_ENDIF + ): + if isinstance(it_c, fragments.Just0): + node = fragments.AndN(it_a, it_e) + else: + node = fragments.AndOr(it_a, it_e, it_c) + expr_list[idx: idx + 6] = [node] + return expr_list + + +def parse_expr_list(expr_list): + """Parse a node from a list of Script elements.""" + # Every recursive call must progress the AST construction, + # until it is complete (single root node remains). + expr_list_len = len(expr_list) + + # Root node reached. + if expr_list_len == 1 and isinstance(expr_list[0], fragments.Node): + return expr_list[0] + + # Step through each list index and match against templates. + idx = expr_list_len - 1 + while idx >= 0: + if expr_list_len - idx >= 2: + new_expr_list = parse_nonterm_2_elems(expr_list, idx) + if new_expr_list is not None: + return parse_expr_list(new_expr_list) + + if expr_list_len - idx >= 3: + new_expr_list = parse_nonterm_3_elems(expr_list, idx) + if new_expr_list is not None: + return parse_expr_list(new_expr_list) + + if expr_list_len - idx >= 4: + new_expr_list = parse_nonterm_4_elems(expr_list, idx) + if new_expr_list is not None: + return parse_expr_list(new_expr_list) + + if expr_list_len - idx >= 5: + new_expr_list = parse_nonterm_5_elems(expr_list, idx) + if new_expr_list is not None: + return parse_expr_list(new_expr_list) + + if expr_list_len - idx >= 6: + new_expr_list = parse_nonterm_6_elems(expr_list, idx) + if new_expr_list is not None: + return parse_expr_list(new_expr_list) + + # Right-to-left parsing. + # Step one position left. + idx -= 1 + + # No match found. + raise MiniscriptMalformed(f"{expr_list}") + + +def miniscript_from_script(script, pkh_preimages={}): + """Construct miniscript node from script. + + :param script: The Bitcoin Script to decode. + :param pkh_preimage: A mapping from keyhash to key to decode pk_h() fragments. + """ + expr_list = decompose_script(script) + expr_list_len = len(expr_list) + + # We first parse terminal expressions. + idx = 0 + while idx < expr_list_len: + parse_term_single_elem(expr_list, idx) + + if expr_list_len - idx >= 2: + new_expr_list = parse_term_2_elems(expr_list, idx) + if new_expr_list is not None: + expr_list = new_expr_list + expr_list_len = len(expr_list) + + if expr_list_len - idx >= 5: + new_expr_list = parse_term_5_elems(expr_list, idx, pkh_preimages) + if new_expr_list is not None: + expr_list = new_expr_list + expr_list_len = len(expr_list) + + if expr_list_len - idx >= 7: + new_expr_list = parse_term_7_elems(expr_list, idx) + if new_expr_list is not None: + expr_list = new_expr_list + expr_list_len = len(expr_list) + + idx += 1 + + # fragments.And then recursively parse non-terminal ones. + return parse_expr_list(expr_list) + + +def split_params(string): + """Read a list of values before the next ')'. Split the result by comma.""" + i = string.find(")") + assert i >= 0 + + params, remaining = string[:i], string[i:] + if len(remaining) > 0: + return params.split(","), remaining[1:] + else: + return params.split(","), "" + + +def parse_many(string): + """Read a list of nodes before the next ')'.""" + subs = [] + remaining = string + while True: + sub, remaining = parse_one(remaining) + subs.append(sub) + if remaining[0] == ")": + return subs, remaining[1:] + assert remaining[0] == "," # TODO: real errors + remaining = remaining[1:] + + +def parse_one_num(string): + """Read an integer before the next comma.""" + i = string.find(",") + assert i >= 0 + + return int(string[:i]), string[i + 1:] + + +def parse_one(string): + """Read a node and its subs recursively from a string. + Returns the node and the part of the string not consumed. + """ + + # We special case fragments.Just1 and fragments.Just0 since they are the only one which don't + # have a function syntax. + if string[0] == "0": + return fragments.Just0(), string[1:] + if string[0] == "1": + return fragments.Just1(), string[1:] + + # Now, find the separator for all functions. + for i, char in enumerate(string): + if char in ["(", ":"]: + break + # For wrappers, we may have many of them. + if char == ":" and i > 1: + tag, remaining = string[0], string[1:] + else: + tag, remaining = string[:i], string[i + 1:] + + # fragments.Wrappers + if char == ":": + sub, remaining = parse_one(remaining) + if tag == "a": + return fragments.WrapA(sub), remaining + + if tag == "s": + return fragments.WrapS(sub), remaining + + if tag == "c": + return fragments.WrapC(sub), remaining + + if tag == "t": + return fragments.WrapT(sub), remaining + + if tag == "d": + return fragments.WrapD(sub), remaining + + if tag == "v": + return fragments.WrapV(sub), remaining + + if tag == "j": + return fragments.WrapJ(sub), remaining + + if tag == "n": + return fragments.WrapN(sub), remaining + + if tag == "l": + return fragments.WrapL(sub), remaining + + if tag == "u": + return fragments.WrapU(sub), remaining + + assert False, (tag, sub, remaining) # TODO: real errors + + # Terminal elements other than 0 and 1 + if tag in [ + "pk", + "pkh", + "pk_k", + "pk_h", + "sha256", + "hash256", + "ripemd160", + "hash160", + "older", + "after", + "multi", + ]: + params, remaining = split_params(remaining) + + if tag == "0": + return fragments.Just0(), remaining + + if tag == "1": + return fragments.Just1(), remaining + + if tag == "pk": + return fragments.WrapC(fragments.Pk(params[0])), remaining + + if tag == "pk_k": + return fragments.Pk(params[0]), remaining + + if tag == "pkh": + return fragments.WrapC(fragments.Pkh(params[0])), remaining + + if tag == "pk_h": + return fragments.Pkh(params[0]), remaining + + if tag == "older": + value = int(params[0]) + return fragments.Older(value), remaining + + if tag == "after": + value = int(params[0]) + return fragments.After(value), remaining + + if tag in ["sha256", "hash256", "ripemd160", "hash160"]: + digest = bytes.fromhex(params[0]) + if tag == "sha256": + return fragments.Sha256(digest), remaining + if tag == "hash256": + return fragments.Hash256(digest), remaining + if tag == "ripemd160": + return fragments.Ripemd160(digest), remaining + return fragments.Hash160(digest), remaining + + if tag == "multi": + k = int(params.pop(0)) + key_n = [] + for param in params: + key_obj = DescriptorKey(param) + key_n.append(key_obj) + return fragments.Multi(k, key_n), remaining + + assert False, (tag, params, remaining) + + # Non-terminal elements (connectives) + # We special case fragments.Thresh, as its first sub is an integer. + if tag == "thresh": + k, remaining = parse_one_num(remaining) + # TODO: real errors in place of unpacking + subs, remaining = parse_many(remaining) + + if tag == "and_v": + return fragments.AndV(*subs), remaining + + if tag == "and_b": + return fragments.AndB(*subs), remaining + + if tag == "and_n": + return fragments.AndN(*subs), remaining + + if tag == "or_b": + return fragments.OrB(*subs), remaining + + if tag == "or_c": + return fragments.OrC(*subs), remaining + + if tag == "or_d": + return fragments.OrD(*subs), remaining + + if tag == "or_i": + return fragments.OrI(*subs), remaining + + if tag == "andor": + return fragments.AndOr(*subs), remaining + + if tag == "thresh": + return fragments.Thresh(k, subs), remaining + + assert False, (tag, subs, remaining) # TODO + + +def miniscript_from_str(ms_str): + """Construct miniscript node from string representation""" + node, remaining = parse_one(ms_str) + assert remaining == "" + return node diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/property.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/property.py new file mode 100644 index 0000000..5cff50b --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/property.py @@ -0,0 +1,83 @@ +# Copyright (c) 2020 The Bitcoin Core developers +# Copyright (c) 2021 Antoine Poinsot +# Distributed under the MIT software license, see the accompanying +# file LICENSE or http://www.opensource.org/licenses/mit-license.php. + +from .errors import MiniscriptPropertyError + + +# TODO: implement __eq__ +class Property: + """Miniscript expression property""" + + # "B": Base type + # "V": Verify type + # "K": Key type + # "W": Wrapped type + # "z": Zero-arg property + # "o": One-arg property + # "n": Nonzero arg property + # "d": Dissatisfiable property + # "u": Unit property + types = "BVKW" + props = "zondu" + + def __init__(self, property_str=""): + """Create a property, optionally from a str of property and types""" + allowed = self.types + self.props + invalid = set(property_str).difference(set(allowed)) + + if invalid: + raise MiniscriptPropertyError( + f"Invalid property/type character(s) '{''.join(invalid)}'" + f" (allowed: '{allowed}')" + ) + + for literal in allowed: + setattr(self, literal, literal in property_str) + + self.check_valid() + + def __repr__(self): + """Generate string representation of property""" + return "".join([c for c in self.types + self.props if getattr(self, c)]) + + def has_all(self, properties): + """Given a str of types and properties, return whether we have all of them""" + return all([getattr(self, pt) for pt in properties]) + + def has_any(self, properties): + """Given a str of types and properties, return whether we have at least one of them""" + return any([getattr(self, pt) for pt in properties]) + + def check_valid(self): + """Raises a MiniscriptPropertyError if the types/properties conflict""" + # Can only be of a single type. + if len(self.type()) > 1: + raise MiniscriptPropertyError(f"A Miniscript fragment can only be of a single type, got '{self.type()}'") + + # Check for conflicts in type & properties. + checks = [ + # (type/property, must_be, must_not_be) + ("K", "u", ""), + ("V", "", "du"), + ("z", "", "o"), + ("n", "", "z"), + ] + conflicts = [] + + for (attr, must_be, must_not_be) in checks: + if not getattr(self, attr): + continue + if not self.has_all(must_be): + conflicts.append(f"{attr} must be {must_be}") + if self.has_any(must_not_be): + conflicts.append(f"{attr} must not be {must_not_be}") + if conflicts: + raise MiniscriptPropertyError(f"Conflicting types and properties: {', '.join(conflicts)}") + + def type(self): + return "".join(filter(lambda x: x in self.types, str(self))) + + def properties(self): + return "".join(filter(lambda x: x in self.props, str(self))) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/satisfaction.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/satisfaction.py new file mode 100644 index 0000000..67e8780 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/miniscript/satisfaction.py @@ -0,0 +1,409 @@ +""" +Miniscript satisfaction. + +This module contains logic for "signing for" a Miniscript (constructing a valid witness +that meets the conditions set by the Script) and analysis of such satisfaction(s) (eg the +maximum cost in a given resource). +This is currently focused on non-malleable satisfaction. We take shortcuts to not care about +non-canonical (dis)satisfactions. +""" + + +def add_optional(a, b): + """Add two numbers that may be None together.""" + if a is None or b is None: + return None + return a + b + + +def max_optional(a, b): + """Return the maximum of two numbers that may be None.""" + if a is None: + return b + if b is None: + return a + return max(a, b) + + +class SatisfactionMaterial: + """Data that may be needed in order to satisfy a Minsicript fragment.""" + + def __init__( + self, preimages={}, signatures={}, max_sequence=2 ** 32, max_lock_time=2 ** 32 + ): + """ + :param preimages: Mapping from a hash (as bytes), to its 32-bytes preimage. + :param signatures: Mapping from a public key (as bytes), to a signature for this key. + :param max_sequence: The maximum relative timelock possible (coin age). + :param max_lock_time: The maximum absolute timelock possible (block height). + """ + self.preimages = preimages + self.signatures = signatures + self.max_sequence = max_sequence + self.max_lock_time = max_lock_time + + def clear(self): + self.preimages.clear() + self.signatures.clear() + self.max_sequence = 0 + self.max_lock_time = 0 + + def __repr__(self): + return ( + f"SatisfactionMaterial(preimages: {self.preimages}, signatures: " + f"{self.signatures}, max_sequence: {self.max_sequence}, max_lock_time: " + f"{self.max_lock_time}" + ) + + +class Satisfaction: + """All information about a satisfaction.""" + + def __init__(self, witness, has_sig=False): + assert isinstance(witness, list) or witness is None + self.witness = witness + self.has_sig = has_sig + # TODO: we probably need to take into account non-canon sats, as the algorithm + # described on the website mandates it: + # > Iterate over all the valid satisfactions/dissatisfactions in the table above + # > (including the non-canonical ones), + + def __add__(self, other): + """Concatenate two satisfactions together.""" + witness = add_optional(self.witness, other.witness) + has_sig = self.has_sig or other.has_sig + return Satisfaction(witness, has_sig) + + def __or__(self, other): + """Choose between two (dis)satisfactions.""" + assert isinstance(other, Satisfaction) + + # If one isn't available, return the other one. + if self.witness is None: + return other + if other.witness is None: + return self + + # > If among all valid solutions (including DONTUSE ones) more than one does not + # > have the HASSIG marker, return DONTUSE, as this is malleable because of reason + # > 1. + # TODO + # if not (self.has_sig or other.has_sig): + # return Satisfaction.unavailable() + + # > If instead exactly one does not have the HASSIG marker, return that solution + # > because of reason 2. + if self.has_sig and not other.has_sig: + return other + if not self.has_sig and other.has_sig: + return self + + # > Otherwise, all not-DONTUSE options are valid, so return the smallest one (in + # > terms of witness size). + if self.size() > other.size(): + return other + + # > If all valid solutions have the HASSIG marker, but all of them are DONTUSE, return DONTUSE-HASSIG. + # TODO + + return self + + def unavailable(): + return Satisfaction(witness=None) + + def is_unavailable(self): + return self.witness is None + + def size(self): + return len(self.witness) + sum(len(elem) for elem in self.witness) + + def from_concat(sat_material, sub_a, sub_b, disjunction=False): + """Get the satisfaction for a Miniscript whose Script corresponds to a + concatenation of two subscripts A and B. + + :param sub_a: The sub-fragment A. + :param sub_b: The sub-fragment B. + :param disjunction: Whether this fragment has an 'or()' semantic. + """ + if disjunction: + return (sub_b.dissatisfaction() + sub_a.satisfaction(sat_material)) | ( + sub_b.satisfaction(sat_material) + sub_a.dissatisfaction() + ) + return sub_b.satisfaction(sat_material) + sub_a.satisfaction(sat_material) + + def from_or_uneven(sat_material, sub_a, sub_b): + """Get the satisfaction for a Miniscript which unconditionally executes a first + sub A and only executes B if A was dissatisfied. + + :param sub_a: The sub-fragment A. + :param sub_b: The sub-fragment B. + """ + return sub_a.satisfaction(sat_material) | ( + sub_b.satisfaction(sat_material) + sub_a.dissatisfaction() + ) + + def from_thresh(sat_material, k, subs): + """Get the satisfaction for a Miniscript which satisfies k of the given subs, + and dissatisfies all the others. + + :param sat_material: The material to satisfy the challenges. + :param k: The number of subs that need to be satisfied. + :param subs: The list of all subs of the threshold. + """ + # Pick the k sub-fragments to satisfy, prefering (in order): + # 1. Fragments that don't require a signature to be satisfied + # 2. Fragments whose satisfaction's size is smaller + # Record the unavailable (in either way) ones as we go. + arbitrage, unsatisfiable, undissatisfiable = [], [], [] + for sub in subs: + sat, dissat = sub.satisfaction(sat_material), sub.dissatisfaction() + if sat.witness is None: + unsatisfiable.append(sub) + elif dissat.witness is None: + undissatisfiable.append(sub) + else: + arbitrage.append( + (int(sat.has_sig), len(sat.witness) - len(dissat.witness), sub) + ) + + # If not enough (dis)satisfactions are available, fail. + if len(unsatisfiable) > len(subs) - k or len(undissatisfiable) > k: + return Satisfaction.unavailable() + + # Otherwise, satisfy the k most optimal ones. + arbitrage = sorted(arbitrage, key=lambda x: x[:2]) + optimal_sat = undissatisfiable + [a[2] for a in arbitrage] + unsatisfiable + to_satisfy = set(optimal_sat[:k]) + return sum( + [ + sub.satisfaction(sat_material) + if sub in to_satisfy + else sub.dissatisfaction() + for sub in subs[::-1] + ], + start=Satisfaction(witness=[]), + ) + + +class ExecutionInfo: + """Information about the execution of a Miniscript.""" + + def __init__(self, stat_ops, _dyn_ops, sat_size, dissat_size): + # The *maximum* number of *always* executed non-PUSH Script OPs to satisfy this + # Miniscript fragment non-malleably. + self._static_ops_count = stat_ops + # The maximum possible number of counted-as-executed-by-interpreter OPs if this + # fragment is executed. + # It is only >0 for an executed multi() branch. That is, for a CHECKMULTISIG that + # is not part of an unexecuted branch of an IF .. ENDIF. + self._dyn_ops_count = _dyn_ops + # The *maximum* number of stack elements to satisfy this Miniscript fragment + # non-malleably. + self.sat_elems = sat_size + # The *maximum* number of stack elements to dissatisfy this Miniscript fragment + # non-malleably. + self.dissat_elems = dissat_size + + @property + def ops_count(self): + """ + The worst-case number of OPs that would be considered executed by the Script + interpreter. + Note it is considered alone and not necessarily coherent with the other maxima. + """ + return self._static_ops_count + self._dyn_ops_count + + def is_dissatisfiable(self): + """Whether the Miniscript is *non-malleably* dissatisfiable.""" + return self.dissat_elems is not None + + def set_undissatisfiable(self): + """Set the Miniscript as being impossible to dissatisfy.""" + self.dissat_elems = None + + def from_concat(sub_a, sub_b, ops_count=0, disjunction=False): + """Compute the execution info from a Miniscript whose Script corresponds to + a concatenation of two subscript A and B. + + :param sub_a: The execution information of the subscript A. + :param sub_b: The execution information of the subscript B. + :param ops_count: The added number of static OPs added on top. + :param disjunction: Whether this fragment has an 'or()' semantic. + """ + # Number of static OPs is simple, they are all executed. + static_ops = sub_a._static_ops_count + sub_b._static_ops_count + ops_count + # Same for the dynamic ones, there is no conditional branch here. + dyn_ops = sub_a._dyn_ops_count + sub_b._dyn_ops_count + # If this is an 'or', only one needs to be satisfied. Pick the most expensive + # satisfaction/dissatisfaction pair. + # If not, both need to be anyways. + if disjunction: + first = add_optional(sub_a.sat_elems, sub_b.dissat_elems) + second = add_optional(sub_a.dissat_elems, sub_b.sat_elems) + sat_elems = max_optional(first, second) + else: + sat_elems = add_optional(sub_a.sat_elems, sub_b.sat_elems) + # In any case dissatisfying the fragment requires dissatisfying both concatenated + # subs. + dissat_elems = add_optional(sub_a.dissat_elems, sub_b.dissat_elems) + + return ExecutionInfo(static_ops, dyn_ops, sat_elems, dissat_elems) + + def from_or_uneven(sub_a, sub_b, ops_count=0): + """Compute the execution info from a Miniscript which always executes A and only + executes B depending on the outcome of A's execution. + + :param sub_a: The execution information of the subscript A. + :param sub_b: The execution information of the subscript B. + :param ops_count: The added number of static OPs added on top. + """ + # Number of static OPs is simple, they are all executed. + static_ops = sub_a._static_ops_count + sub_b._static_ops_count + ops_count + # If the first sub is non-malleably dissatisfiable, the worst case is executing + # both. Otherwise it is necessarily satisfying only the first one. + if sub_a.is_dissatisfiable(): + dyn_ops = sub_a._dyn_ops_count + sub_b._dyn_ops_count + else: + dyn_ops = sub_a._dyn_ops_count + # Either we satisfy A, or satisfy B (and thereby dissatisfy A). Pick the most + # expensive. + first = sub_a.sat_elems + second = add_optional(sub_a.dissat_elems, sub_b.sat_elems) + sat_elems = max_optional(first, second) + # We only take canonical dissatisfactions into account. + dissat_elems = add_optional(sub_a.dissat_elems, sub_b.dissat_elems) + + return ExecutionInfo(static_ops, dyn_ops, sat_elems, dissat_elems) + + def from_or_even(sub_a, sub_b, ops_count): + """Compute the execution info from a Miniscript which executes either A or B, but + never both. + + :param sub_a: The execution information of the subscript A. + :param sub_b: The execution information of the subscript B. + :param ops_count: The added number of static OPs added on top. + """ + # Number of static OPs is simple, they are all executed. + static_ops = sub_a._static_ops_count + sub_b._static_ops_count + ops_count + # Only one of the branch is executed, pick the most expensive one. + dyn_ops = max(sub_a._dyn_ops_count, sub_b._dyn_ops_count) + # Same. Also, we add a stack element used to tell which branch to take. + sat_elems = add_optional(max_optional(sub_a.sat_elems, sub_b.sat_elems), 1) + # Same here. + dissat_elems = add_optional( + max_optional(sub_a.dissat_elems, sub_b.dissat_elems), 1 + ) + + return ExecutionInfo(static_ops, dyn_ops, sat_elems, dissat_elems) + + def from_andor_uneven(sub_a, sub_b, sub_c, ops_count=0): + """Compute the execution info from a Miniscript which always executes A, and then + executes B if A returned True else executes C. Semantic: or(and(A,B), C). + + :param sub_a: The execution information of the subscript A. + :param sub_b: The execution information of the subscript B. + :param sub_b: The execution information of the subscript C. + :param ops_count: The added number of static OPs added on top. + """ + # Number of static OPs is simple, they are all executed. + static_ops = ( + sum(sub._static_ops_count for sub in [sub_a, sub_b, sub_c]) + ops_count + ) + # If the first sub is non-malleably dissatisfiable, the worst case is executing + # it and the most expensive between B and C. + # If it isn't the worst case is then necessarily to execute A and B. + if sub_a.is_dissatisfiable(): + dyn_ops = sub_a._dyn_ops_count + max( + sub_b._dyn_ops_count, sub_c._dyn_ops_count + ) + else: + # If the first isn't non-malleably dissatisfiable, the worst case is + # satisfying it (and necessarily satisfying the second one too) + dyn_ops = sub_a._dyn_ops_count + sub_b._dyn_ops_count + # Same for the number of stack elements (implicit from None here). + first = add_optional(sub_a.sat_elems, sub_b.sat_elems) + second = add_optional(sub_a.dissat_elems, sub_c.sat_elems) + sat_elems = max_optional(first, second) + # The only canonical dissatisfaction is dissatisfying A and C. + dissat_elems = add_optional(sub_a.dissat_elems, sub_c.dissat_elems) + + return ExecutionInfo(static_ops, dyn_ops, sat_elems, dissat_elems) + + # TODO: i think it'd be possible to not have this be special-cased to 'thresh()' + def from_thresh(k, subs): + """Compute the execution info from a Miniscript 'thresh()' fragment. Specialized + to this specifc fragment for now. + + :param k: The actual threshold of the 'thresh()' fragment. + :param subs: All the possible sub scripts. + """ + # All the OPs from the subs + n-1 * OP_ADD + 1 * OP_EQUAL + static_ops = sum(sub._static_ops_count for sub in subs) + len(subs) + # dyn_ops = sum(sorted([sub._dyn_ops_count for sub in subs], reverse=True)[:k]) + # All subs are executed, there is no OP_IF branch. + dyn_ops = sum([sub._dyn_ops_count for sub in subs]) + + # In order to estimate the worst case we simulate to satisfy the k subs whose + # sat/dissat ratio is the largest, and dissatisfy the others. + # We do so by iterating through all the subs, recording their sat-dissat "score" + # and those that either cannot be satisfied or dissatisfied. + arbitrage, unsatisfiable, undissatisfiable = [], [], [] + for sub in subs: + if sub.sat_elems is None: + unsatisfiable.append(sub) + elif sub.dissat_elems is None: + undissatisfiable.append(sub) + else: + arbitrage.append((sub.sat_elems - sub.dissat_elems, sub)) + # Of course, if too many can't be (dis)satisfied, we have a problem. + # Otherwise, simulate satisfying first the subs that must be (no dissatisfaction) + # then the most expensive ones, and then dissatisfy all the others. + if len(unsatisfiable) > len(subs) - k or len(undissatisfiable) > k: + sat_elems = None + else: + arbitrage = sorted(arbitrage, key=lambda x: x[0], reverse=True) + worst_sat = undissatisfiable + [a[1] for a in arbitrage] + unsatisfiable + sat_elems = sum( + [sub.sat_elems for sub in worst_sat[:k]] + + [sub.dissat_elems for sub in worst_sat[k:]] + ) + if len(undissatisfiable) > 0: + dissat_elems = None + else: + dissat_elems = sum([sub.dissat_elems for sub in subs]) + + return ExecutionInfo(static_ops, dyn_ops, sat_elems, dissat_elems) + + def from_wrap(sub, ops_count, dyn=0, sat=0, dissat=0): + """Compute the execution info from a Miniscript which always executes a subscript + but adds some logic around. + + :param sub: The execution information of the single subscript. + :param ops_count: The added number of static OPs added on top. + :param dyn: The added number of dynamic OPs added on top. + :param sat: The added number of satisfaction stack elements added on top. + :param dissat: The added number of dissatisfcation stack elements added on top. + """ + return ExecutionInfo( + sub._static_ops_count + ops_count, + sub._dyn_ops_count + dyn, + add_optional(sub.sat_elems, sat), + add_optional(sub.dissat_elems, dissat), + ) + + def from_wrap_dissat(sub, ops_count, dyn=0, sat=0, dissat=0): + """Compute the execution info from a Miniscript which always executes a subscript + but adds some logic around. + + :param sub: The execution information of the single subscript. + :param ops_count: The added number of static OPs added on top. + :param dyn: The added number of dynamic OPs added on top. + :param sat: The added number of satisfaction stack elements added on top. + :param dissat: The added number of dissatisfcation stack elements added on top. + """ + return ExecutionInfo( + sub._static_ops_count + ops_count, + sub._dyn_ops_count + dyn, + add_optional(sub.sat_elems, sat), + dissat, + ) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/utils/__init__.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/utils/bignum.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/utils/bignum.py new file mode 100644 index 0000000..1384939 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/utils/bignum.py @@ -0,0 +1,64 @@ +# Copyright (c) 2015-2020 The Bitcoin Core developers +# Copyright (c) 2021 Antoine Poinsot +# Distributed under the MIT software license, see the accompanying +# file LICENSE or http://www.opensource.org/licenses/mit-license.php. +"""Big number routines. + +This file is taken from the Bitcoin Core test framework. It was previously +copied from python-bitcoinlib. +""" + +import struct + + +# generic big endian MPI format + + +def bn_bytes(v, have_ext=False): + ext = 0 + if have_ext: + ext = 1 + return ((v.bit_length() + 7) // 8) + ext + + +def bn2bin(v): + s = bytearray() + i = bn_bytes(v) + while i > 0: + s.append((v >> ((i - 1) * 8)) & 0xFF) + i -= 1 + return s + + +def bn2mpi(v): + have_ext = False + if v.bit_length() > 0: + have_ext = (v.bit_length() & 0x07) == 0 + + neg = False + if v < 0: + neg = True + v = -v + + s = struct.pack(b">I", bn_bytes(v, have_ext)) + ext = bytearray() + if have_ext: + ext.append(0) + v_bin = bn2bin(v) + if neg: + if have_ext: + ext[0] |= 0x80 + else: + v_bin[0] |= 0x80 + return s + ext + v_bin + + +# bitcoin-specific little endian format, with implicit size +def mpi2vch(s): + r = s[4:] # strip size + r = r[::-1] # reverse string, converting BE->LE + return r + + +def bn2vch(v): + return bytes(mpi2vch(bn2mpi(v))) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/utils/hashes.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/utils/hashes.py new file mode 100644 index 0000000..1124dc5 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/utils/hashes.py @@ -0,0 +1,20 @@ +""" +Common Bitcoin hashes. +""" + +import hashlib +from .ripemd_fallback import ripemd160_fallback + + +def sha256(data): + """{data} must be bytes, returns sha256(data)""" + assert isinstance(data, bytes) + return hashlib.sha256(data).digest() + + +def hash160(data): + """{data} must be bytes, returns ripemd160(sha256(data))""" + assert isinstance(data, bytes) + if 'ripemd160' in hashlib.algorithms_available: + return hashlib.new("ripemd160", sha256(data)).digest() + return ripemd160_fallback(sha256(data)) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/utils/ripemd_fallback.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/utils/ripemd_fallback.py new file mode 100644 index 0000000..a4043de --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/utils/ripemd_fallback.py @@ -0,0 +1,117 @@ +# Copyright (c) 2021 Pieter Wuille +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# +# Taken from https://github.com/bitcoin/bitcoin/blob/124e75a41ea0f3f0e90b63b0c41813184ddce2ab/test/functional/test_framework/ripemd160.py + +# fmt: off + +""" +Pure Python RIPEMD160 implementation. + +WARNING: This implementation is NOT constant-time. +Do not use without understanding the implications. +""" + +# Message schedule indexes for the left path. +ML = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 +] + +# Message schedule indexes for the right path. +MR = [ + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 +] + +# Rotation counts for the left path. +RL = [ + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 +] + +# Rotation counts for the right path. +RR = [ + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 +] + +# K constants for the left path. +KL = [0, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e] + +# K constants for the right path. +KR = [0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0] + + +def fi(x, y, z, i): + """The f1, f2, f3, f4, and f5 functions from the specification.""" + if i == 0: + return x ^ y ^ z + elif i == 1: + return (x & y) | (~x & z) + elif i == 2: + return (x | ~y) ^ z + elif i == 3: + return (x & z) | (y & ~z) + elif i == 4: + return x ^ (y | ~z) + else: + assert False + + +def rol(x, i): + """Rotate the bottom 32 bits of x left by i bits.""" + return ((x << i) | ((x & 0xffffffff) >> (32 - i))) & 0xffffffff + + +def compress(h0, h1, h2, h3, h4, block): + """Compress state (h0, h1, h2, h3, h4) with block.""" + # Left path variables. + al, bl, cl, dl, el = h0, h1, h2, h3, h4 + # Right path variables. + ar, br, cr, dr, er = h0, h1, h2, h3, h4 + # Message variables. + x = [int.from_bytes(block[4*i:4*(i+1)], 'little') for i in range(16)] + + # Iterate over the 80 rounds of the compression. + for j in range(80): + rnd = j >> 4 + # Perform left side of the transformation. + al = rol(al + fi(bl, cl, dl, rnd) + x[ML[j]] + KL[rnd], RL[j]) + el + al, bl, cl, dl, el = el, al, bl, rol(cl, 10), dl + # Perform right side of the transformation. + ar = rol(ar + fi(br, cr, dr, 4 - rnd) + x[MR[j]] + KR[rnd], RR[j]) + er + ar, br, cr, dr, er = er, ar, br, rol(cr, 10), dr + + # Compose old state, left transform, and right transform into new state. + return h1 + cl + dr, h2 + dl + er, h3 + el + ar, h4 + al + br, h0 + bl + cr + + +def ripemd160_fallback(data): + """Compute the RIPEMD-160 hash of data.""" + # Initialize state. + state = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0) + # Process full 64-byte blocks in the input. + for b in range(len(data) >> 6): + state = compress(*state, data[64*b:64*(b+1)]) + # Construct final blocks (with padding and size). + pad = b"\x80" + b"\x00" * ((119 - len(data)) & 63) + fin = data[len(data) & ~63:] + pad + (8 * len(data)).to_bytes(8, 'little') + # Process final blocks. + for b in range(len(fin) >> 6): + state = compress(*state, fin[64*b:64*(b+1)]) + # Produce output. + return b"".join((h & 0xffffffff).to_bytes(4, 'little') for h in state) \ No newline at end of file diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/utils/script.py b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/utils/script.py new file mode 100644 index 0000000..9ff0e70 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/bip380/utils/script.py @@ -0,0 +1,473 @@ +# Copyright (c) 2015-2020 The Bitcoin Core developers +# Copyright (c) 2021 Antoine Poinsot +# Distributed under the MIT software license, see the accompanying +# file LICENSE or http://www.opensource.org/licenses/mit-license.php. +"""Script utilities + +This file was taken from Bitcoin Core test framework, and was previously +modified from python-bitcoinlib. +""" +import struct + +from .bignum import bn2vch + + +OPCODE_NAMES = {} + + +class CScriptOp(int): + """A single script opcode""" + + __slots__ = () + + @staticmethod + def encode_op_pushdata(d): + """Encode a PUSHDATA op, returning bytes""" + if len(d) < 0x4C: + return b"" + bytes([len(d)]) + d # OP_PUSHDATA + elif len(d) <= 0xFF: + return b"\x4c" + bytes([len(d)]) + d # OP_PUSHDATA1 + elif len(d) <= 0xFFFF: + return b"\x4d" + struct.pack(b" 4: + raise ScriptNumError("Too large push") + + if size == 0: + return 0 + + # We always check for minimal encoding + if (data[size - 1] & 0x7f) == 0: + if size == 1 or (data[size - 2] & 0x80) == 0: + raise ScriptNumError("Non minimal encoding") + + res = int.from_bytes(data, byteorder="little") + + # Remove the sign bit if set, and negate the result + if data[size - 1] & 0x80: + return -(res & ~(0x80 << (size - 1))) + return res + + +class CScriptInvalidError(Exception): + """Base class for CScript exceptions""" + + pass + + +class CScriptTruncatedPushDataError(CScriptInvalidError): + """Invalid pushdata due to truncation""" + + def __init__(self, msg, data): + self.data = data + super(CScriptTruncatedPushDataError, self).__init__(msg) + + +# This is used, eg, for blockchain heights in coinbase scripts (bip34) +class CScriptNum: + __slots__ = ("value",) + + def __init__(self, d=0): + self.value = d + + @staticmethod + def encode(obj): + r = bytearray(0) + if obj.value == 0: + return bytes(r) + neg = obj.value < 0 + absvalue = -obj.value if neg else obj.value + while absvalue: + r.append(absvalue & 0xFF) + absvalue >>= 8 + if r[-1] & 0x80: + r.append(0x80 if neg else 0) + elif neg: + r[-1] |= 0x80 + return bytes([len(r)]) + r + + @staticmethod + def decode(vch): + result = 0 + # We assume valid push_size and minimal encoding + value = vch[1:] + if len(value) == 0: + return result + for i, byte in enumerate(value): + result |= int(byte) << 8 * i + if value[-1] >= 0x80: + # Mask for all but the highest result bit + num_mask = (2 ** (len(value) * 8) - 1) >> 1 + result &= num_mask + result *= -1 + return result + + +class CScript(bytes): + """Serialized script + + A bytes subclass, so you can use this directly whenever bytes are accepted. + Note that this means that indexing does *not* work - you'll get an index by + byte rather than opcode. This format was chosen for efficiency so that the + general case would not require creating a lot of little CScriptOP objects. + + iter(script) however does iterate by opcode. + """ + + __slots__ = () + + @classmethod + def __coerce_instance(cls, other): + # Coerce other into bytes + if isinstance(other, CScriptOp): + other = bytes([other]) + elif isinstance(other, CScriptNum): + if other.value == 0: + other = bytes([CScriptOp(OP_0)]) + else: + other = CScriptNum.encode(other) + elif isinstance(other, int): + if 0 <= other <= 16: + other = bytes([CScriptOp.encode_op_n(other)]) + elif other == -1: + other = bytes([OP_1NEGATE]) + else: + other = CScriptOp.encode_op_pushdata(bn2vch(other)) + elif isinstance(other, (bytes, bytearray)): + other = CScriptOp.encode_op_pushdata(other) + return other + + def __add__(self, other): + # Do the coercion outside of the try block so that errors in it are + # noticed. + other = self.__coerce_instance(other) + + try: + # bytes.__add__ always returns bytes instances unfortunately + return CScript(super(CScript, self).__add__(other)) + except TypeError: + raise TypeError("Can not add a %r instance to a CScript" % other.__class__) + + def join(self, iterable): + # join makes no sense for a CScript() + raise NotImplementedError + + def __new__(cls, value=b""): + if isinstance(value, bytes) or isinstance(value, bytearray): + return super(CScript, cls).__new__(cls, value) + else: + + def coerce_iterable(iterable): + for instance in iterable: + yield cls.__coerce_instance(instance) + + # Annoyingly on both python2 and python3 bytes.join() always + # returns a bytes instance even when subclassed. + return super(CScript, cls).__new__(cls, b"".join(coerce_iterable(value))) + + def raw_iter(self): + """Raw iteration + + Yields tuples of (opcode, data, sop_idx) so that the different possible + PUSHDATA encodings can be accurately distinguished, as well as + determining the exact opcode byte indexes. (sop_idx) + """ + i = 0 + while i < len(self): + sop_idx = i + opcode = self[i] + i += 1 + + if opcode > OP_PUSHDATA4: + yield (opcode, None, sop_idx) + else: + datasize = None + pushdata_type = None + if opcode < OP_PUSHDATA1: + pushdata_type = "PUSHDATA(%d)" % opcode + datasize = opcode + + elif opcode == OP_PUSHDATA1: + pushdata_type = "PUSHDATA1" + if i >= len(self): + raise CScriptInvalidError("PUSHDATA1: missing data length") + datasize = self[i] + i += 1 + + elif opcode == OP_PUSHDATA2: + pushdata_type = "PUSHDATA2" + if i + 1 >= len(self): + raise CScriptInvalidError("PUSHDATA2: missing data length") + datasize = self[i] + (self[i + 1] << 8) + i += 2 + + elif opcode == OP_PUSHDATA4: + pushdata_type = "PUSHDATA4" + if i + 3 >= len(self): + raise CScriptInvalidError("PUSHDATA4: missing data length") + datasize = ( + self[i] + + (self[i + 1] << 8) + + (self[i + 2] << 16) + + (self[i + 3] << 24) + ) + i += 4 + + else: + assert False # shouldn't happen + + data = bytes(self[i: i + datasize]) + + # Check for truncation + if len(data) < datasize: + raise CScriptTruncatedPushDataError( + "%s: truncated data" % pushdata_type, data + ) + + i += datasize + + yield (opcode, data, sop_idx) + + def __iter__(self): + """'Cooked' iteration + + Returns either a CScriptOP instance, an integer, or bytes, as + appropriate. + + See raw_iter() if you need to distinguish the different possible + PUSHDATA encodings. + """ + for (opcode, data, sop_idx) in self.raw_iter(): + if data is not None: + yield data + else: + opcode = CScriptOp(opcode) + + if opcode.is_small_int(): + yield opcode.decode_op_n() + else: + yield CScriptOp(opcode) + + def __repr__(self): + def _repr(o): + if isinstance(o, bytes): + return "x('%s')" % o.hex() + else: + return repr(o) + + ops = [] + i = iter(self) + while True: + op = None + try: + op = _repr(next(i)) + except CScriptTruncatedPushDataError as err: + op = "%s..." % (_repr(err.data), err) + break + except CScriptInvalidError as err: + op = "" % err + break + except StopIteration: + break + finally: + if op is not None: + ops.append(op) + + return "CScript([%s])" % ", ".join(ops) + + def GetSigOpCount(self, fAccurate): + """Get the SigOp count. + + fAccurate - Accurately count CHECKMULTISIG, see BIP16 for details. + + Note that this is consensus-critical. + """ + n = 0 + lastOpcode = OP_INVALIDOPCODE + for (opcode, data, sop_idx) in self.raw_iter(): + if opcode in (OP_CHECKSIG, OP_CHECKSIGVERIFY): + n += 1 + elif opcode in (OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY): + if fAccurate and (OP_1 <= lastOpcode <= OP_16): + n += opcode.decode_op_n() + else: + n += 20 + lastOpcode = opcode + return n diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/README.md b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/README.md new file mode 100644 index 0000000..43c7d70 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/README.md @@ -0,0 +1,11 @@ +# Ledger Nano S and Nano X Library + +This is a stripped down and modified version of the official [btchip-python](https://github.com/LedgerHQ/btchip-python) library. + +This stripped down version was made at commit [17f27c1996c75145b8eb5d16583bddcb6e2bf691](https://github.com/LedgerHQ/btchip-python/tree/17f27c1996c75145b8eb5d16583bddcb6e2bf691). + +## Changes + +- Removed support for Ledger HW.1 and other unused things + +See c141b6effa78fb7a3ed52acbe17314078fe93c86 for the specific changes. diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/__init__.py b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/__init__.py new file mode 100644 index 0000000..2e30a63 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/__init__.py @@ -0,0 +1,20 @@ +""" +******************************************************************************* +* BTChip Bitcoin Hardware Wallet Python API +* (c) 2014 BTChip - 1BTChip7VfTnrPra5jqci7ejnMguuHogTn +* +* 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. +******************************************************************************** +""" +__version__ = "0.1.31" + diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/bitcoinTransaction.py b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/bitcoinTransaction.py new file mode 100644 index 0000000..35276e9 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/bitcoinTransaction.py @@ -0,0 +1,165 @@ +""" +******************************************************************************* +* BTChip Bitcoin Hardware Wallet Python API +* (c) 2014 BTChip - 1BTChip7VfTnrPra5jqci7ejnMguuHogTn +* +* 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. +******************************************************************************** +""" + +from .bitcoinVarint import * +from binascii import hexlify + +class bitcoinInput: + + def __init__(self, bufferOffset=None): + self.prevOut = "" + self.script = "" + self.sequence = "" + if bufferOffset is not None: + buf = bufferOffset['buffer'] + offset = bufferOffset['offset'] + self.prevOut = buf[offset:offset + 36] + offset += 36 + scriptSize = readVarint(buf, offset) + offset += scriptSize['size'] + self.script = buf[offset:offset + scriptSize['value']] + offset += scriptSize['value'] + self.sequence = buf[offset:offset + 4] + offset += 4 + bufferOffset['offset'] = offset + + def serialize(self): + result = [] + result.extend(self.prevOut) + writeVarint(len(self.script), result) + result.extend(self.script) + result.extend(self.sequence) + return result + + def __str__(self): + buf = "Prevout : " + hexlify(self.prevOut) + "\r\n" + buf += "Script : " + hexlify(self.script) + "\r\n" + buf += "Sequence : " + hexlify(self.sequence) + "\r\n" + return buf + +class bitcoinOutput: + + def __init__(self, bufferOffset=None): + self.amount = "" + self.script = "" + if bufferOffset is not None: + buf = bufferOffset['buffer'] + offset = bufferOffset['offset'] + self.amount = buf[offset:offset + 8] + offset += 8 + scriptSize = readVarint(buf, offset) + offset += scriptSize['size'] + self.script = buf[offset:offset + scriptSize['value']] + offset += scriptSize['value'] + bufferOffset['offset'] = offset + + def serialize(self): + result = [] + result.extend(self.amount) + writeVarint(len(self.script), result) + result.extend(self.script) + return result + + def __str__(self): + buf = "Amount : " + hexlify(self.amount) + "\r\n" + buf += "Script : " + hexlify(self.script) + "\r\n" + return buf + + +class bitcoinTransaction: + + def __init__(self, data=None): + self.version = "" + self.inputs = [] + self.outputs = [] + self.lockTime = "" + self.witness = False + self.witnessScript = "" + if data is not None: + offset = 0 + self.version = data[offset:offset + 4] + offset += 4 + if (data[offset] == 0) and (data[offset + 1] != 0): + offset += 2 + self.witness = True + inputSize = readVarint(data, offset) + offset += inputSize['size'] + numInputs = inputSize['value'] + for i in range(numInputs): + tmp = { 'buffer': data, 'offset' : offset} + self.inputs.append(bitcoinInput(tmp)) + offset = tmp['offset'] + outputSize = readVarint(data, offset) + offset += outputSize['size'] + numOutputs = outputSize['value'] + for i in range(numOutputs): + tmp = { 'buffer': data, 'offset' : offset} + self.outputs.append(bitcoinOutput(tmp)) + offset = tmp['offset'] + if self.witness: + self.witnessScript = data[offset : len(data) - 4] + self.lockTime = data[len(data) - 4:] + else: + self.lockTime = data[offset:offset + 4] + + def serialize(self, skipOutputLocktime=False, skipWitness=False): + if skipWitness or (not self.witness): + useWitness = False + else: + useWitness = True + result = [] + result.extend(self.version) + if useWitness: + result.append(0x00) + result.append(0x01) + writeVarint(len(self.inputs), result) + for trinput in self.inputs: + result.extend(trinput.serialize()) + if not skipOutputLocktime: + writeVarint(len(self.outputs), result) + for troutput in self.outputs: + result.extend(troutput.serialize()) + if useWitness: + result.extend(self.witnessScript) + result.extend(self.lockTime) + return result + + def serializeOutputs(self): + result = [] + writeVarint(len(self.outputs), result) + for troutput in self.outputs: + result.extend(troutput.serialize()) + return result + + def __str__(self): + buf = "Version : " + hexlify(self.version) + "\r\n" + index = 1 + for trinput in self.inputs: + buf += "Input #" + str(index) + "\r\n" + buf += str(trinput) + index+=1 + index = 1 + for troutput in self.outputs: + buf += "Output #" + str(index) + "\r\n" + buf += str(troutput) + index+=1 + buf += "Locktime : " + hexlify(self.lockTime) + "\r\n" + if self.witness: + buf += "Witness script : " + hexlify(self.witnessScript) + "\r\n" + return buf diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/bitcoinVarint.py b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/bitcoinVarint.py new file mode 100644 index 0000000..a0dd868 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/bitcoinVarint.py @@ -0,0 +1,63 @@ +""" +******************************************************************************* +* BTChip Bitcoin Hardware Wallet Python API +* (c) 2014 BTChip - 1BTChip7VfTnrPra5jqci7ejnMguuHogTn +* +* 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. +******************************************************************************** +""" + +from .btchipException import BTChipException + +def readVarint(buffer, offset): + varintSize = 0 + value = 0 + if (buffer[offset] < 0xfd): + value = buffer[offset] + varintSize = 1 + elif (buffer[offset] == 0xfd): + value = (buffer[offset + 2] << 8) | (buffer[offset + 1]) + varintSize = 3 + elif (buffer[offset] == 0xfe): + value = (buffer[offset + 4] << 24) | (buffer[offset + 3] << 16) | (buffer[offset + 2] << 8) | (buffer[offset + 1]) + varintSize = 5 + else: + raise BTChipException("unsupported varint") + return { "value": value, "size": varintSize } + +def writeVarint(value, buffer): + if (value < 0xfd): + buffer.append(value) + elif (value <= 0xffff): + buffer.append(0xfd) + buffer.append(value & 0xff) + buffer.append((value >> 8) & 0xff) + elif (value <= 0xffffffff): + buffer.append(0xfe) + buffer.append(value & 0xff) + buffer.append((value >> 8) & 0xff) + buffer.append((value >> 16) & 0xff) + buffer.append((value >> 24) & 0xff) + else: + raise BTChipException("unsupported encoding") + return buffer + +def getVarintSize(value): + if (value < 0xfd): + return 1 + elif (value <= 0xffff): + return 3 + elif (value <= 0xffffffff): + return 5 + else: + raise BTChipException("unsupported encoding") diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchip.py b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchip.py new file mode 100644 index 0000000..65a54c6 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchip.py @@ -0,0 +1,446 @@ +""" +******************************************************************************* +* BTChip Bitcoin Hardware Wallet Python API +* (c) 2014 BTChip - 1BTChip7VfTnrPra5jqci7ejnMguuHogTn +* +* 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. +******************************************************************************** +""" + +from .btchipComm import * +from .bitcoinTransaction import * +from .bitcoinVarint import * +from .btchipException import * +from .btchipHelpers import * +from binascii import hexlify, unhexlify + +class btchip: + BTCHIP_CLA = 0xe0 + BTCHIP_CLA_COMMON_SDK = 0xb0 + BTCHIP_JC_EXT_CLA = 0xf0 + + BTCHIP_INS_GET_APP_NAME_AND_VERSION = 0x01 + BTCHIP_INS_SET_ALTERNATE_COIN_VERSION = 0x14 + BTCHIP_INS_SETUP = 0x20 + BTCHIP_INS_VERIFY_PIN = 0x22 + BTCHIP_INS_GET_OPERATION_MODE = 0x24 + BTCHIP_INS_SET_OPERATION_MODE = 0x26 + BTCHIP_INS_SET_KEYMAP = 0x28 + BTCHIP_INS_SET_COMM_PROTOCOL = 0x2a + BTCHIP_INS_GET_WALLET_PUBLIC_KEY = 0x40 + BTCHIP_INS_GET_TRUSTED_INPUT = 0x42 + BTCHIP_INS_HASH_INPUT_START = 0x44 + BTCHIP_INS_HASH_INPUT_FINALIZE = 0x46 + BTCHIP_INS_HASH_SIGN = 0x48 + BTCHIP_INS_HASH_INPUT_FINALIZE_FULL = 0x4a + BTCHIP_INS_GET_INTERNAL_CHAIN_INDEX = 0x4c + BTCHIP_INS_SIGN_MESSAGE = 0x4e + BTCHIP_INS_GET_TRANSACTION_LIMIT = 0xa0 + BTCHIP_INS_SET_TRANSACTION_LIMIT = 0xa2 + BTCHIP_INS_IMPORT_PRIVATE_KEY = 0xb0 + BTCHIP_INS_GET_PUBLIC_KEY = 0xb2 + BTCHIP_INS_DERIVE_BIP32_KEY = 0xb4 + BTCHIP_INS_SIGNVERIFY_IMMEDIATE = 0xb6 + BTCHIP_INS_GET_RANDOM = 0xc0 + BTCHIP_INS_GET_ATTESTATION = 0xc2 + BTCHIP_INS_GET_FIRMWARE_VERSION = 0xc4 + BTCHIP_INS_COMPOSE_MOFN_ADDRESS = 0xc6 + BTCHIP_INS_GET_POS_SEED = 0xca + + BTCHIP_INS_EXT_GET_HALF_PUBLIC_KEY = 0x20 + BTCHIP_INS_EXT_CACHE_PUT_PUBLIC_KEY = 0x22 + BTCHIP_INS_EXT_CACHE_HAS_PUBLIC_KEY = 0x24 + BTCHIP_INS_EXT_CACHE_GET_FEATURES = 0x26 + + OPERATION_MODE_WALLET = 0x01 + OPERATION_MODE_RELAXED_WALLET = 0x02 + OPERATION_MODE_SERVER = 0x04 + OPERATION_MODE_DEVELOPER = 0x08 + + FEATURE_UNCOMPRESSED_KEYS = 0x01 + FEATURE_RFC6979 = 0x02 + FEATURE_FREE_SIGHASHTYPE = 0x04 + FEATURE_NO_2FA_P2SH = 0x08 + + QWERTY_KEYMAP = bytearray(unhexlify("000000000000000000000000760f00d4ffffffc7000000782c1e3420212224342627252e362d3738271e1f202122232425263333362e37381f0405060708090a0b0c0d0e0f101112131415161718191a1b1c1d2f3130232d350405060708090a0b0c0d0e0f101112131415161718191a1b1c1d2f313035")) + QWERTZ_KEYMAP = bytearray(unhexlify("000000000000000000000000760f00d4ffffffc7000000782c1e3420212224342627252e362d3738271e1f202122232425263333362e37381f0405060708090a0b0c0d0e0f101112131415161718191a1b1d1c2f3130232d350405060708090a0b0c0d0e0f101112131415161718191a1b1d1c2f313035")) + AZERTY_KEYMAP = bytearray(unhexlify("08000000010000200100007820c8ffc3feffff07000000002c38202030341e21222d352e102e3637271e1f202122232425263736362e37101f1405060708090a0b0c0d0e0f331112130415161718191d1b1c1a2f64302f2d351405060708090a0b0c0d0e0f331112130415161718191d1b1c1a2f643035")) + + def __init__(self, dongle): + self.dongle = dongle + self.needKeyCache = False + try: + firmware = self.getFirmwareVersion()['version'] + self.multiOutputSupported = tuple(map(int, (firmware.split(".")))) >= (1, 1, 4) + if self.multiOutputSupported: + self.scriptBlockLength = 50 + else: + self.scriptBlockLength = 255 + except Exception: + pass + + def getWalletPublicKey(self, path, showOnScreen=False, segwit=False, segwitNative=False, cashAddr=False): + result = {} + donglePath = parse_bip32_path(path) + if self.needKeyCache: + self.resolvePublicKeysInPath(path) + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_GET_WALLET_PUBLIC_KEY, 0x01 if showOnScreen else 0x00, 0x03 if cashAddr else 0x02 if segwitNative else 0x01 if segwit else 0x00, len(donglePath) ] + apdu.extend(donglePath) + response = self.dongle.exchange(bytearray(apdu)) + offset = 0 + result['publicKey'] = response[offset + 1 : offset + 1 + response[offset]] + offset = offset + 1 + response[offset] + result['address'] = str(response[offset + 1 : offset + 1 + response[offset]]) + offset = offset + 1 + response[offset] + result['chainCode'] = response[offset : offset + 32] + return result + + def getTrustedInput(self, transaction, index): + result = {} + # Header + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_GET_TRUSTED_INPUT, 0x00, 0x00 ] + params = bytearray.fromhex("%.8x" % (index)) + params.extend(transaction.version) + writeVarint(len(transaction.inputs), params) + apdu.append(len(params)) + apdu.extend(params) + self.dongle.exchange(bytearray(apdu)) + # Each input + for trinput in transaction.inputs: + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_GET_TRUSTED_INPUT, 0x80, 0x00 ] + params = bytearray(trinput.prevOut) + writeVarint(len(trinput.script), params) + apdu.append(len(params)) + apdu.extend(params) + self.dongle.exchange(bytearray(apdu)) + offset = 0 + while True: + blockLength = 251 + if ((offset + blockLength) < len(trinput.script)): + dataLength = blockLength + else: + dataLength = len(trinput.script) - offset + params = bytearray(trinput.script[offset : offset + dataLength]) + if ((offset + dataLength) == len(trinput.script)): + params.extend(trinput.sequence) + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_GET_TRUSTED_INPUT, 0x80, 0x00, len(params) ] + apdu.extend(params) + self.dongle.exchange(bytearray(apdu)) + offset += dataLength + if (offset >= len(trinput.script)): + break + # Number of outputs + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_GET_TRUSTED_INPUT, 0x80, 0x00 ] + params = [] + writeVarint(len(transaction.outputs), params) + apdu.append(len(params)) + apdu.extend(params) + self.dongle.exchange(bytearray(apdu)) + # Each output + indexOutput = 0 + for troutput in transaction.outputs: + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_GET_TRUSTED_INPUT, 0x80, 0x00 ] + params = bytearray(troutput.amount) + writeVarint(len(troutput.script), params) + apdu.append(len(params)) + apdu.extend(params) + self.dongle.exchange(bytearray(apdu)) + offset = 0 + while (offset < len(troutput.script)): + blockLength = 255 + if ((offset + blockLength) < len(troutput.script)): + dataLength = blockLength + else: + dataLength = len(troutput.script) - offset + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_GET_TRUSTED_INPUT, 0x80, 0x00, dataLength ] + apdu.extend(troutput.script[offset : offset + dataLength]) + self.dongle.exchange(bytearray(apdu)) + offset += dataLength + # Locktime + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_GET_TRUSTED_INPUT, 0x80, 0x00, len(transaction.lockTime) ] + apdu.extend(transaction.lockTime) + response = self.dongle.exchange(bytearray(apdu)) + result['trustedInput'] = True + result['value'] = response + return result + + def startUntrustedTransaction(self, newTransaction, inputIndex, outputList, redeemScript, version=0x01, cashAddr=False, continueSegwit=False): + # Start building a fake transaction with the passed inputs + segwit = False + if newTransaction: + for passedOutput in outputList: + if ('witness' in passedOutput) and passedOutput['witness']: + segwit = True + break + if newTransaction: + if segwit: + p2 = 0x03 if cashAddr else 0x02 + else: + p2 = 0x00 + else: + p2 = 0x10 if continueSegwit else 0x80 + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_HASH_INPUT_START, 0x00, p2 ] + params = bytearray([version, 0x00, 0x00, 0x00]) + writeVarint(len(outputList), params) + apdu.append(len(params)) + apdu.extend(params) + self.dongle.exchange(bytearray(apdu)) + # Loop for each input + currentIndex = 0 + for passedOutput in outputList: + if ('sequence' in passedOutput) and passedOutput['sequence']: + sequence = bytearray(unhexlify(passedOutput['sequence'])) + else: + sequence = bytearray([0xFF, 0xFF, 0xFF, 0xFF]) # default sequence + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_HASH_INPUT_START, 0x80, 0x00 ] + params = [] + script = bytearray(redeemScript) + if ('trustedInput' in passedOutput) and passedOutput['trustedInput']: + params.append(0x01) + elif ('witness' in passedOutput) and passedOutput['witness']: + params.append(0x02) + else: + params.append(0x00) + if ('trustedInput' in passedOutput) and passedOutput['trustedInput']: + params.append(len(passedOutput['value'])) + params.extend(passedOutput['value']) + if currentIndex != inputIndex: + script = bytearray() + writeVarint(len(script), params) + apdu.append(len(params)) + apdu.extend(params) + self.dongle.exchange(bytearray(apdu)) + offset = 0 + while(offset < len(script)): + blockLength = 255 + if ((offset + blockLength) < len(script)): + dataLength = blockLength + else: + dataLength = len(script) - offset + params = script[offset : offset + dataLength] + if ((offset + dataLength) == len(script)): + params.extend(sequence) + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_HASH_INPUT_START, 0x80, 0x00, len(params) ] + apdu.extend(params) + self.dongle.exchange(bytearray(apdu)) + offset += blockLength + if len(script) == 0: + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_HASH_INPUT_START, 0x80, 0x00, len(sequence) ] + apdu.extend(sequence) + self.dongle.exchange(bytearray(apdu)) + currentIndex += 1 + + def finalizeInput(self, outputAddress, amount, fees, changePath, rawTx=None): + alternateEncoding = False + donglePath = parse_bip32_path(changePath) + if self.needKeyCache: + self.resolvePublicKeysInPath(changePath) + result = {} + outputs = None + if rawTx is not None: + try: + fullTx = bitcoinTransaction(bytearray(rawTx)) + outputs = fullTx.serializeOutputs() + if len(donglePath) != 0: + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_HASH_INPUT_FINALIZE_FULL, 0xFF, 0x00 ] + params = [] + params.extend(donglePath) + apdu.append(len(params)) + apdu.extend(params) + response = self.dongle.exchange(bytearray(apdu)) + offset = 0 + while (offset < len(outputs)): + blockLength = self.scriptBlockLength + if ((offset + blockLength) < len(outputs)): + dataLength = blockLength + p1 = 0x00 + else: + dataLength = len(outputs) - offset + p1 = 0x80 + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_HASH_INPUT_FINALIZE_FULL, \ + p1, 0x00, dataLength ] + apdu.extend(outputs[offset : offset + dataLength]) + response = self.dongle.exchange(bytearray(apdu)) + offset += dataLength + alternateEncoding = True + except Exception: + pass + if not alternateEncoding: + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_HASH_INPUT_FINALIZE, 0x02, 0x00 ] + params = [] + params.append(len(outputAddress)) + params.extend(bytearray(outputAddress)) + writeHexAmountBE(btc_to_satoshi(str(amount)), params) + writeHexAmountBE(btc_to_satoshi(str(fees)), params) + params.extend(donglePath) + apdu.append(len(params)) + apdu.extend(params) + response = self.dongle.exchange(bytearray(apdu)) + result['confirmationNeeded'] = response[1 + response[0]] != 0x00 + result['confirmationType'] = response[1 + response[0]] + if result['confirmationType'] == 0x02: + result['keycardData'] = response[1 + response[0] + 1:] + if result['confirmationType'] == 0x03: + offset = 1 + response[0] + 1 + keycardDataLength = response[offset] + offset = offset + 1 + result['keycardData'] = response[offset : offset + keycardDataLength] + offset = offset + keycardDataLength + result['secureScreenData'] = response[offset:] + if result['confirmationType'] == 0x04: + offset = 1 + response[0] + 1 + keycardDataLength = response[offset] + result['keycardData'] = response[offset + 1 : offset + 1 + keycardDataLength] + if outputs == None: + result['outputData'] = response[1 : 1 + response[0]] + else: + result['outputData'] = outputs + return result + + def untrustedHashSign(self, path, pin="", lockTime=0, sighashType=0x01): + if isinstance(pin, str): + pin = pin.encode('utf-8') + donglePath = parse_bip32_path(path) + if self.needKeyCache: + self.resolvePublicKeysInPath(path) + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_HASH_SIGN, 0x00, 0x00 ] + params = [] + params.extend(donglePath) + params.append(len(pin)) + params.extend(bytearray(pin)) + writeUint32BE(lockTime, params) + params.append(sighashType) + apdu.append(len(params)) + apdu.extend(params) + result = self.dongle.exchange(bytearray(apdu)) + result[0] = 0x30 + return result + + def signMessagePrepareV1(self, path, message): + donglePath = parse_bip32_path(path) + if self.needKeyCache: + self.resolvePublicKeysInPath(path) + result = {} + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_SIGN_MESSAGE, 0x00, 0x00 ] + params = [] + params.extend(donglePath) + params.append(len(message)) + params.extend(bytearray(message)) + apdu.append(len(params)) + apdu.extend(params) + response = self.dongle.exchange(bytearray(apdu)) + result['confirmationNeeded'] = response[0] != 0x00 + result['confirmationType'] = response[0] + if result['confirmationType'] == 0x02: + result['keycardData'] = response[1:] + if result['confirmationType'] == 0x03: + result['secureScreenData'] = response[1:] + return result + + def signMessagePrepareV2(self, path, message): + donglePath = parse_bip32_path(path) + if self.needKeyCache: + self.resolvePublicKeysInPath(path) + result = {} + offset = 0 + encryptedOutputData = b"" + while (offset < len(message)): + params = []; + if offset == 0: + params.extend(donglePath) + params.append((len(message) >> 8) & 0xff) + params.append(len(message) & 0xff) + p2 = 0x01 + else: + p2 = 0x80 + blockLength = 255 - len(params) + if ((offset + blockLength) < len(message)): + dataLength = blockLength + else: + dataLength = len(message) - offset + params.extend(bytearray(message[offset : offset + dataLength])) + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_SIGN_MESSAGE, 0x00, p2 ] + apdu.append(len(params)) + apdu.extend(params) + response = self.dongle.exchange(bytearray(apdu)) + encryptedOutputData = encryptedOutputData + response[1 : 1 + response[0]] + offset += blockLength + result['confirmationNeeded'] = response[1 + response[0]] != 0x00 + result['confirmationType'] = response[1 + response[0]] + if result['confirmationType'] == 0x03: + offset = 1 + response[0] + 1 + result['secureScreenData'] = response[offset:] + result['encryptedOutputData'] = encryptedOutputData + + return result + + def signMessagePrepare(self, path, message): + try: + result = self.signMessagePrepareV2(path, message) + except BTChipException as e: + if (e.sw == 0x6b00): # Old firmware version, try older method + result = self.signMessagePrepareV1(path, message) + else: + raise + return result + + def signMessageSign(self, pin=""): + if isinstance(pin, str): + pin = pin.encode('utf-8') + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_SIGN_MESSAGE, 0x80, 0x00 ] + params = [] + if pin is not None: + params.append(len(pin)) + params.extend(bytearray(pin)) + else: + params.append(0x00) + apdu.append(len(params)) + apdu.extend(params) + response = self.dongle.exchange(bytearray(apdu)) + return response + + def getAppName(self): + apdu = [ self.BTCHIP_CLA_COMMON_SDK, self.BTCHIP_INS_GET_APP_NAME_AND_VERSION, 0x00, 0x00, 0x00 ] + try: + response = self.dongle.exchange(bytearray(apdu)) + name_len = response[1] + name = response[2:][:name_len] + if b'OLOS' not in name: + return name.decode('ascii') + except BTChipException as e: + if e.sw == 0x6faa: + # ins not implemented" + return None + if e.sw == 0x6d00: + # Not in an app, return just a string saying that + return "not in an app" + raise + + def getFirmwareVersion(self): + result = {} + apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_GET_FIRMWARE_VERSION, 0x00, 0x00, 0x00 ] + try: + response = self.dongle.exchange(bytearray(apdu)) + except BTChipException as e: + if (e.sw == 0x6985): + response = [0x00, 0x00, 0x01, 0x04, 0x03 ] + pass + else: + raise + result['compressedKeys'] = (response[0] == 0x01) + result['version'] = "%d.%d.%d" % (response[2], response[3], response[4]) + result['major_version'] = response[2] + result['minor_version'] = response[3] + result['patch_version'] = response[4] + result['specialVersion'] = response[1] + return result diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchipComm.py b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchipComm.py new file mode 100644 index 0000000..012fbb8 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchipComm.py @@ -0,0 +1,179 @@ +""" +******************************************************************************* +* BTChip Bitcoin Hardware Wallet Python API +* (c) 2014 BTChip - 1BTChip7VfTnrPra5jqci7ejnMguuHogTn +* +* 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. +******************************************************************************** +""" + +from abc import ABCMeta, abstractmethod +from .btchipException import * +from .ledgerWrapper import wrapCommandAPDU, unwrapResponseAPDU +from binascii import hexlify +import time +import os +import struct +import socket + +try: + import hid + HID = True +except ImportError: + HID = False + +try: + from smartcard.Exceptions import NoCardException + from smartcard.System import readers + from smartcard.util import toHexString, toBytes + SCARD = True +except ImportError: + SCARD = False + +class DongleWait(object): + __metaclass__ = ABCMeta + + @abstractmethod + def waitFirstResponse(self, timeout): + pass + +class Dongle(object): + __metaclass__ = ABCMeta + + @abstractmethod + def exchange(self, apdu, timeout=20000): + pass + + @abstractmethod + def close(self): + pass + + def setWaitImpl(self, waitImpl): + self.waitImpl = waitImpl + +class HIDDongleHIDAPI(Dongle, DongleWait): + + def __init__(self, device, ledger=False, debug=False): + self.device = device + self.ledger = ledger + self.debug = debug + self.waitImpl = self + self.opened = True + + def exchange(self, apdu, timeout=20000): + if self.debug: + print("=> %s" % hexlify(apdu)) + if self.ledger: + apdu = wrapCommandAPDU(0x0101, apdu, 64) + padSize = len(apdu) % 64 + tmp = apdu + if padSize != 0: + tmp.extend([0] * (64 - padSize)) + offset = 0 + while(offset != len(tmp)): + data = tmp[offset:offset + 64] + data = bytearray([0]) + data + self.device.write(data) + offset += 64 + dataLength = 0 + dataStart = 2 + result = self.waitImpl.waitFirstResponse(timeout) + if not self.ledger: + if result[0] == 0x61: # 61xx : data available + self.device.set_nonblocking(False) + dataLength = result[1] + dataLength += 2 + if dataLength > 62: + remaining = dataLength - 62 + while(remaining != 0): + if remaining > 64: + blockLength = 64 + else: + blockLength = remaining + result.extend(bytearray(self.device.read(65))[0:blockLength]) + remaining -= blockLength + swOffset = dataLength + dataLength -= 2 + self.device.set_nonblocking(True) + else: + swOffset = 0 + else: + self.device.set_nonblocking(False) + while True: + response = unwrapResponseAPDU(0x0101, result, 64) + if response is not None: + result = response + dataStart = 0 + swOffset = len(response) - 2 + dataLength = len(response) - 2 + self.device.set_nonblocking(True) + break + result.extend(bytearray(self.device.read(65))) + sw = (result[swOffset] << 8) + result[swOffset + 1] + response = result[dataStart : dataLength + dataStart] + if self.debug: + print("<= %s%.2x" % (hexlify(response), sw)) + if sw != 0x9000: + raise BTChipException("Invalid status %04x" % sw, sw) + return response + + def waitFirstResponse(self, timeout): + start = time.time() + data = "" + while len(data) == 0: + data = self.device.read(65) + if not len(data): + if time.time() - start > timeout: + raise BTChipException("Timeout") + time.sleep(0.02) + return bytearray(data) + + def close(self): + if self.opened: + try: + self.device.close() + except Exception: + pass + self.opened = False + +class DongleServer(Dongle): + + def __init__(self, server, port, debug=False): + self.server = server + self.port = port + self.debug = debug + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + self.socket.connect((self.server, self.port)) + except Exception: + raise BTChipException("Proxy connection failed") + + def exchange(self, apdu, timeout=20000): + if self.debug: + print("=> %s" % hexlify(apdu)) + self.socket.send(struct.pack(">I", len(apdu))) + self.socket.send(apdu) + size = struct.unpack(">I", self.socket.recv(4))[0] + response = self.socket.recv(size) + sw = struct.unpack(">H", self.socket.recv(2))[0] + if self.debug: + print("<= %s%.2x" % (hexlify(response), sw)) + if sw != 0x9000: + raise BTChipException("Invalid status %04x" % sw, sw) + return bytearray(response) + + def close(self): + try: + self.socket.close() + except Exception: + pass diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchipException.py b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchipException.py new file mode 100644 index 0000000..ec57728 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchipException.py @@ -0,0 +1,28 @@ +""" +******************************************************************************* +* BTChip Bitcoin Hardware Wallet Python API +* (c) 2014 BTChip - 1BTChip7VfTnrPra5jqci7ejnMguuHogTn +* +* 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. +******************************************************************************** +""" + +class BTChipException(Exception): + + def __init__(self, message, sw=0x6f00): + self.message = message + self.sw = sw + + def __str__(self): + buf = "Exception : " + self.message + return buf diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchipHelpers.py b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchipHelpers.py new file mode 100644 index 0000000..ba5b66c --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchipHelpers.py @@ -0,0 +1,86 @@ +""" +******************************************************************************* +* BTChip Bitcoin Hardware Wallet Python API +* (c) 2014 BTChip - 1BTChip7VfTnrPra5jqci7ejnMguuHogTn +* +* 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. +******************************************************************************** +""" + +import decimal +import re + +# from pycoin +SATOSHI_PER_COIN = decimal.Decimal(1e8) +COIN_PER_SATOSHI = decimal.Decimal(1)/SATOSHI_PER_COIN + +def satoshi_to_btc(satoshi_count): + if satoshi_count == 0: + return decimal.Decimal(0) + r = satoshi_count * COIN_PER_SATOSHI + return r.normalize() + +def btc_to_satoshi(btc): + return int(decimal.Decimal(btc) * SATOSHI_PER_COIN) +# /from pycoin + +def writeUint32BE(value, buffer): + buffer.append((value >> 24) & 0xff) + buffer.append((value >> 16) & 0xff) + buffer.append((value >> 8) & 0xff) + buffer.append(value & 0xff) + return buffer + +def writeUint32LE(value, buffer): + buffer.append(value & 0xff) + buffer.append((value >> 8) & 0xff) + buffer.append((value >> 16) & 0xff) + buffer.append((value >> 24) & 0xff) + return buffer + +def writeHexAmount(value, buffer): + buffer.append(value & 0xff) + buffer.append((value >> 8) & 0xff) + buffer.append((value >> 16) & 0xff) + buffer.append((value >> 24) & 0xff) + buffer.append((value >> 32) & 0xff) + buffer.append((value >> 40) & 0xff) + buffer.append((value >> 48) & 0xff) + buffer.append((value >> 56) & 0xff) + return buffer + +def writeHexAmountBE(value, buffer): + buffer.append((value >> 56) & 0xff) + buffer.append((value >> 48) & 0xff) + buffer.append((value >> 40) & 0xff) + buffer.append((value >> 32) & 0xff) + buffer.append((value >> 24) & 0xff) + buffer.append((value >> 16) & 0xff) + buffer.append((value >> 8) & 0xff) + buffer.append(value & 0xff) + return buffer + +def parse_bip32_path(path): + if len(path) == 0: + return bytearray([ 0 ]) + result = [] + elements = path.split('/') + if len(elements) > 10: + raise BTChipException("Path too long") + for pathElement in elements: + element = re.split('\'|h|H', pathElement) + if len(element) == 1: + writeUint32BE(int(element[0]), result) + else: + writeUint32BE(0x80000000 | int(element[0]), result) + return bytearray([ len(elements) ] + result) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchipUtils.py b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchipUtils.py new file mode 100644 index 0000000..0bf2fa2 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/btchipUtils.py @@ -0,0 +1,105 @@ +""" +******************************************************************************* +* BTChip Bitcoin Hardware Wallet Python API +* (c) 2014 BTChip - 1BTChip7VfTnrPra5jqci7ejnMguuHogTn +* +* 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. +******************************************************************************** +""" + +from .btchipException import * +from .bitcoinTransaction import * +from .btchipHelpers import * + +def compress_public_key(publicKey): + if publicKey[0] == 0x04: + if (publicKey[64] & 1) != 0: + prefix = 0x03 + else: + prefix = 0x02 + result = [prefix] + result.extend(publicKey[1:33]) + return bytearray(result) + elif publicKey[0] == 0x03 or publicKey[0] == 0x02: + return publicKey + else: + raise BTChipException("Invalid public key format") + +def format_transaction(dongleOutputData, trustedInputsAndInputScripts, version=0x01, lockTime=0): + transaction = bitcoinTransaction() + transaction.version = [] + writeUint32LE(version, transaction.version) + for item in trustedInputsAndInputScripts: + newInput = bitcoinInput() + newInput.prevOut = item[0][4:4+36] + newInput.script = item[1] + if len(item) > 2: + newInput.sequence = bytearray(item[2].decode('hex')) + else: + newInput.sequence = bytearray([0xff, 0xff, 0xff, 0xff]) + transaction.inputs.append(newInput) + result = transaction.serialize(True) + result.extend(dongleOutputData) + writeUint32LE(lockTime, result) + return bytearray(result) + +def get_regular_input_script(sigHashtype, publicKey): + if len(sigHashtype) >= 0x4c: + raise BTChipException("Invalid sigHashtype") + if len(publicKey) >= 0x4c: + raise BTChipException("Invalid publicKey") + result = [ len(sigHashtype) ] + result.extend(sigHashtype) + result.append(len(publicKey)) + result.extend(publicKey) + return bytearray(result) + +def write_pushed_data_size(data, buffer): + if (len(data) > 0xffff): + raise BTChipException("unsupported encoding") + if (len(data) < 0x4c): + buffer.append(len(data)) + elif (len(data) > 255): + buffer.append(0x4d) + buffer.append(len(data) & 0xff) + buffer.append((len(data) >> 8) & 0xff) + else: + buffer.append(0x4c) + buffer.append(len(data)) + return buffer + + +def get_p2sh_input_script(redeemScript, sigHashtypeList): + result = [ 0x00 ] + for sigHashtype in sigHashtypeList: + write_pushed_data_size(sigHashtype, result) + result.extend(sigHashtype) + write_pushed_data_size(redeemScript, result) + result.extend(redeemScript) + return bytearray(result) + +def get_p2pk_input_script(sigHashtype): + if len(sigHashtype) >= 0x4c: + raise BTChipException("Invalid sigHashtype") + result = [ len(sigHashtype) ] + result.extend(sigHashtype) + return bytearray(result) + +def get_output_script(amountScriptArray): + result = [ len(amountScriptArray) ] + for amountScript in amountScriptArray: + writeHexAmount(btc_to_satoshi(str(amountScript[0])), result) + writeVarint(len(amountScript[1]), result) + result.extend(amountScript[1]) + return bytearray(result) + diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/ledgerWrapper.py b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/ledgerWrapper.py new file mode 100644 index 0000000..44fde1d --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/btchip/ledgerWrapper.py @@ -0,0 +1,92 @@ +""" +******************************************************************************* +* BTChip Bitcoin Hardware Wallet Python API +* (c) 2014 BTChip - 1BTChip7VfTnrPra5jqci7ejnMguuHogTn +* +* 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. +******************************************************************************** +""" + +import struct +from .btchipException import BTChipException + +def wrapCommandAPDU(channel, command, packetSize): + if packetSize < 3: + raise BTChipException("Can't handle Ledger framing with less than 3 bytes for the report") + sequenceIdx = 0 + offset = 0 + result = struct.pack(">HBHH", channel, 0x05, sequenceIdx, len(command)) + sequenceIdx = sequenceIdx + 1 + if len(command) > packetSize - 7: + blockSize = packetSize - 7 + else: + blockSize = len(command) + result += command[offset : offset + blockSize] + offset = offset + blockSize + while offset != len(command): + result += struct.pack(">HBH", channel, 0x05, sequenceIdx) + sequenceIdx = sequenceIdx + 1 + if (len(command) - offset) > packetSize - 5: + blockSize = packetSize - 5 + else: + blockSize = len(command) - offset + result += command[offset : offset + blockSize] + offset = offset + blockSize + while (len(result) % packetSize) != 0: + result += b"\x00" + return bytearray(result) + +def unwrapResponseAPDU(channel, data, packetSize): + sequenceIdx = 0 + offset = 0 + if ((data is None) or (len(data) < 7 + 5)): + return None + if struct.unpack(">H", data[offset : offset + 2])[0] != channel: + raise BTChipException("Invalid channel") + offset += 2 + if data[offset] != 0x05: + raise BTChipException("Invalid tag") + offset += 1 + if struct.unpack(">H", data[offset : offset + 2])[0] != sequenceIdx: + raise BTChipException("Invalid sequence") + offset += 2 + responseLength = struct.unpack(">H", data[offset : offset + 2])[0] + offset += 2 + if len(data) < 7 + responseLength: + return None + if responseLength > packetSize - 7: + blockSize = packetSize - 7 + else: + blockSize = responseLength + result = data[offset : offset + blockSize] + offset += blockSize + while (len(result) != responseLength): + sequenceIdx = sequenceIdx + 1 + if (offset == len(data)): + return None + if struct.unpack(">H", data[offset : offset + 2])[0] != channel: + raise BTChipException("Invalid channel") + offset += 2 + if data[offset] != 0x05: + raise BTChipException("Invalid tag") + offset += 1 + if struct.unpack(">H", data[offset : offset + 2])[0] != sequenceIdx: + raise BTChipException("Invalid sequence") + offset += 2 + if (responseLength - len(result)) > packetSize - 5: + blockSize = packetSize - 5 + else: + blockSize = responseLength - len(result) + result += data[offset : offset + blockSize] + offset += blockSize + return bytearray(result) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/client.py b/test/python/apps/bitcoin_client/ledger_bitcoin/client.py new file mode 100644 index 0000000..d8f4468 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/client.py @@ -0,0 +1,304 @@ +from packaging.version import parse as parse_version +from typing import Tuple, List, Mapping, Optional, Union +import base64 +from io import BytesIO, BufferedReader + +from .bip380.descriptors import Descriptor + +from .command_builder import BitcoinCommandBuilder, BitcoinInsType +from .common import Chain, read_uint, read_varint +from .client_command import ClientCommandInterpreter +from .client_base import Client, PartialSignature +from .client_legacy import LegacyClient +from .errors import UnknownDeviceError +from .merkle import get_merkleized_map_commitment +from .wallet import WalletPolicy, WalletType +from .psbt import PSBT, normalize_psbt +from . import segwit_addr +from ._serialize import deser_string +from ragger.backend import BackendInterface +from ragger.error import ExceptionRAPDU + + +def parse_stream_to_map(f: BufferedReader) -> Mapping[bytes, bytes]: + result = {} + while True: + try: + key = deser_string(f) + except Exception: + break + + # Check for separator + if len(key) == 0: + break + + value = deser_string(f) + + result[key] = value + return result + + +def _make_partial_signature(pubkey_augm: bytes, signature: bytes) -> PartialSignature: + if len(pubkey_augm) == 64: + # tapscript spend: pubkey_augm is the concatenation of: + # - a 32-byte x-only pubkey + # - the 32-byte tapleaf_hash + return PartialSignature(signature=signature, pubkey=pubkey_augm[0:32], tapleaf_hash=pubkey_augm[32:]) + + else: + # either legacy, segwit or taproot keypath spend + # pubkey must be 32 (taproot x-only pubkey) or 33 bytes (compressed pubkey) + + if len(pubkey_augm) not in [32, 33]: + raise UnknownDeviceError(f"Invalid pubkey length returned: {len(pubkey_augm)}") + + return PartialSignature(signature=signature, pubkey=pubkey_augm) + + +class NewClient(Client): + # internal use for testing: if set to True, sign_psbt will not clone the psbt before converting to psbt version 2 + _no_clone_psbt: bool = False + + def __init__(self, comm_client: BackendInterface, chain: Chain = Chain.MAIN, debug: bool = False) -> None: + super().__init__(comm_client, chain, debug) + self.builder = BitcoinCommandBuilder() + + # Modifies the behavior of the base method by taking care of SW_INTERRUPTED_EXECUTION responses + def _make_request( + self, apdu: dict, client_intepreter: ClientCommandInterpreter = None + ) -> Tuple[int, bytes]: + sw, response = self._apdu_exchange(apdu) + + while sw == 0xE000: + if not client_intepreter: + raise RuntimeError("Unexpected SW_INTERRUPTED_EXECUTION received.") + + command_response = client_intepreter.execute(response) + sw, response = self._apdu_exchange( + self.builder.continue_interrupted(command_response) + ) + + return sw, response + + def get_extended_pubkey(self, path: str, display: bool = False) -> str: + sw, response = self._make_request(self.builder.get_extended_pubkey(path, display)) + + if sw != 0x9000: + raise ExceptionRAPDU(sw, BitcoinInsType.GET_EXTENDED_PUBKEY) + + return response.decode() + + def register_wallet(self, wallet: WalletPolicy) -> Tuple[bytes, bytes]: + if wallet.version not in [WalletType.WALLET_POLICY_V1, WalletType.WALLET_POLICY_V2]: + raise ValueError("invalid wallet policy version") + + client_intepreter = ClientCommandInterpreter() + client_intepreter.add_known_preimage(wallet.serialize()) + client_intepreter.add_known_list([k.encode() for k in wallet.keys_info]) + + # necessary for version 1 of the protocol (introduced in version 2.1.0) + client_intepreter.add_known_preimage(wallet.descriptor_template.encode()) + + sw, response = self._make_request( + self.builder.register_wallet(wallet), client_intepreter + ) + + if sw != 0x9000: + raise ExceptionRAPDU(sw, BitcoinInsType.REGISTER_WALLET) + + if len(response) != 64: + raise RuntimeError(f"Invalid response length: {len(response)}") + + wallet_id = response[0:32] + wallet_hmac = response[32:64] + + if self._should_validate_address(wallet): + # sanity check: for miniscripts, derive the first address independently with python-bip380 + first_addr_device = self.get_wallet_address(wallet, wallet_hmac, 0, 0, False) + + if first_addr_device != self._derive_segwit_address_for_policy(wallet, False, 0): + raise RuntimeError("Invalid address. Please update your Bitcoin app. If the problem persists, report a bug at https://github.com/LedgerHQ/app-bitcoin-new") + + return wallet_id, wallet_hmac + + def get_wallet_address( + self, + wallet: WalletPolicy, + wallet_hmac: Optional[bytes], + change: int, + address_index: int, + display: bool, + ) -> str: + + if not isinstance(wallet, WalletPolicy) or wallet.version not in [WalletType.WALLET_POLICY_V1, WalletType.WALLET_POLICY_V2]: + raise ValueError("wallet type must be WalletPolicy, with version either WALLET_POLICY_V1 or WALLET_POLICY_V2") + + if change != 0 and change != 1: + raise ValueError("Invalid change") + + client_intepreter = ClientCommandInterpreter() + client_intepreter.add_known_list([k.encode() for k in wallet.keys_info]) + client_intepreter.add_known_preimage(wallet.serialize()) + + # necessary for version 1 of the protocol (introduced in version 2.1.0) + client_intepreter.add_known_preimage(wallet.descriptor_template.encode()) + + sw, response = self._make_request( + self.builder.get_wallet_address( + wallet, wallet_hmac, address_index, change, display + ), + client_intepreter, + ) + + if sw != 0x9000: + raise ExceptionRAPDU(sw, BitcoinInsType.GET_WALLET_ADDRESS) + + result = response.decode() + + if self._should_validate_address(wallet): + # sanity check: for miniscripts, derive the address independently with python-bip380 + + if result != self._derive_segwit_address_for_policy(wallet, change, address_index): + raise RuntimeError("Invalid address. Please update your Bitcoin app. If the problem persists, report a bug at https://github.com/LedgerHQ/app-bitcoin-new") + + return result + + def sign_psbt(self, psbt: Union[PSBT, bytes, str], wallet: WalletPolicy, wallet_hmac: Optional[bytes]) -> List[Tuple[int, PartialSignature]]: + + psbt = normalize_psbt(psbt) + + if psbt.version != 2: + if self._no_clone_psbt: + psbt.convert_to_v2() + psbt_v2 = psbt + else: + psbt_v2 = PSBT() + psbt_v2.deserialize(psbt.serialize()) # clone psbt + psbt_v2.convert_to_v2() + else: + psbt_v2 = psbt + + psbt_bytes = base64.b64decode(psbt_v2.serialize()) + f = BytesIO(psbt_bytes) + + # We parse the individual maps (global map, each input map, and each output map) from the psbt serialized as a + # sequence of bytes, in order to produce the serialized Merkleized map commitments. Moreover, we prepare the + # client interpreter to respond on queries on all the relevant Merkle trees and pre-images in the psbt. + + assert f.read(5) == b"psbt\xff" + + client_intepreter = ClientCommandInterpreter() + client_intepreter.add_known_list([k.encode() for k in wallet.keys_info]) + client_intepreter.add_known_preimage(wallet.serialize()) + + # necessary for version 1 of the protocol (introduced in version 2.1.0) + client_intepreter.add_known_preimage(wallet.descriptor_template.encode()) + + global_map: Mapping[bytes, bytes] = parse_stream_to_map(f) + client_intepreter.add_known_mapping(global_map) + + input_maps: List[Mapping[bytes, bytes]] = [] + for _ in range(len(psbt_v2.inputs)): + input_maps.append(parse_stream_to_map(f)) + for m in input_maps: + client_intepreter.add_known_mapping(m) + + output_maps: List[Mapping[bytes, bytes]] = [] + for _ in range(len(psbt_v2.outputs)): + output_maps.append(parse_stream_to_map(f)) + for m in output_maps: + client_intepreter.add_known_mapping(m) + + # We also add the Merkle tree of the input (resp. output) map commitments as a known tree + input_commitments = [get_merkleized_map_commitment(m_in) for m_in in input_maps] + output_commitments = [get_merkleized_map_commitment(m_out) for m_out in output_maps] + + client_intepreter.add_known_list(input_commitments) + client_intepreter.add_known_list(output_commitments) + + sw, _ = self._make_request( + self.builder.sign_psbt( + global_map, input_maps, output_maps, wallet, wallet_hmac + ), + client_intepreter, + ) + + if sw != 0x9000: + raise ExceptionRAPDU(sw, BitcoinInsType.SIGN_PSBT) + + # parse results and return a structured version instead + results = client_intepreter.yielded + + if any(len(x) <= 1 for x in results): + raise RuntimeError("Invalid response") + + results_list: List[Tuple[int, PartialSignature]] = [] + for res in results: + res_buffer = BytesIO(res) + input_index = read_varint(res_buffer) + + pubkey_augm_len = read_uint(res_buffer, 8) + pubkey_augm = res_buffer.read(pubkey_augm_len) + + signature = res_buffer.read() + + results_list.append((input_index, _make_partial_signature(pubkey_augm, signature))) + + return results_list + + def get_master_fingerprint(self) -> bytes: + sw, response = self._make_request(self.builder.get_master_fingerprint()) + + if sw != 0x9000: + raise ExceptionRAPDU(sw, BitcoinInsType.GET_EXTENDED_PUBKEY) + + return response + + def sign_message(self, message: Union[str, bytes], bip32_path: str) -> str: + if isinstance(message, str): + message_bytes = message.encode("utf-8") + else: + message_bytes = message + + chunks = [message_bytes[64 * i: 64 * i + 64] for i in range((len(message_bytes) + 63) // 64)] + + client_intepreter = ClientCommandInterpreter() + client_intepreter.add_known_list(chunks) + + sw, response = self._make_request(self.builder.sign_message(message_bytes, bip32_path), client_intepreter) + + if sw != 0x9000: + raise ExceptionRAPDU(sw, BitcoinInsType.SIGN_MESSAGE) + + return base64.b64encode(response).decode('utf-8') + + def _should_validate_address(self, wallet: WalletPolicy) -> bool: + # TODO: extend to taproot miniscripts once supported + return wallet.descriptor_template.startswith("wsh(") and not wallet.descriptor_template.startswith("wsh(sortedmulti(") + + def _derive_segwit_address_for_policy(self, wallet: WalletPolicy, change: bool, address_index: int) -> bool: + desc = Descriptor.from_str(wallet.get_descriptor(change)) + desc.derive(address_index) + spk = desc.script_pubkey + if spk[0:2] != b'\x00\x20' or len(spk) != 34: + raise RuntimeError("Invalid scriptPubKey") + hrp = "bc" if self.chain == Chain.MAIN else "tb" + return segwit_addr.encode(hrp, 0, spk[2:]) + + +def createClient(comm_client: BackendInterface, chain: Chain = Chain.MAIN, debug: bool = False) -> Union[LegacyClient, NewClient]: + + base_client = Client(comm_client, chain, debug) + app_name, app_version, _ = base_client.get_version() + + version = parse_version(app_version) + + # Use the legacy client if either: + # - the name of the app is "Bitcoin Legacy" or "Bitcoin Test Legacy" (regardless of the version) + # - the version is strictly less than 2.1 + use_legacy = app_name in ["Bitcoin Legacy", "Bitcoin Test Legacy"] or version.major < 2 or (version.major == 2 and version.minor == 0) + + if use_legacy: + return LegacyClient(comm_client, chain, debug) + else: + return NewClient(comm_client, chain, debug) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/client_base.py b/test/python/apps/bitcoin_client/ledger_bitcoin/client_base.py new file mode 100644 index 0000000..fcdbb45 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/client_base.py @@ -0,0 +1,246 @@ +from dataclasses import dataclass +from typing import List, Tuple, Optional, Union +from io import BytesIO + +from .common import Chain + +from .command_builder import DefaultInsType +from .exception import DeviceException + +from .wallet import WalletPolicy +from .psbt import PSBT +from ._serialize import deser_string + +from ragger.backend.interface import BackendInterface + +try: + from speculos.client import ApduException +except ImportError: + # Speculos package not available, we use our own class + class ApduException(Exception): + def __init__(self, sw: int, data: bytes) -> None: + super().__init__(f"Exception: invalid status 0x{sw:x}") + self.sw = sw + self.data = data + + +def print_apdu(apdu_dict: dict) -> None: + serialized_apdu = b''.join([ + apdu_dict["cla"].to_bytes(1, byteorder='big'), + apdu_dict["ins"].to_bytes(1, byteorder='big'), + apdu_dict["p1"].to_bytes(1, byteorder='big'), + apdu_dict["p2"].to_bytes(1, byteorder='big'), + len(apdu_dict["data"]).to_bytes(1, byteorder='big'), + apdu_dict["data"] + ]) + print(f"=> {serialized_apdu.hex()}") + + +def print_response(sw: int, data: bytes) -> None: + print(f"<= {data}{sw.to_bytes(2, byteorder='big')}") + + +@dataclass(frozen=True) +class PartialSignature: + """Represents a partial signature returned by sign_psbt. + + It always contains a pubkey and a signature. + The pubkey + + The tapleaf_hash is also filled if signing a for a tapscript. + """ + pubkey: bytes + signature: bytes + tapleaf_hash: Optional[bytes] = None + + +class Client: + def __init__(self, transport_client: BackendInterface , chain: Chain = Chain.MAIN, debug: bool = False) -> None: + self.transport_client = transport_client + self.chain = chain + self.debug = debug + + def _apdu_exchange(self, apdu: dict) -> Tuple[int, bytes]: + try: + if self.debug: + print_apdu(apdu) + + response = self.transport_client.exchange(**apdu) + if self.debug: + print_response(0x9000, response) + + return response.status, response.data + except ApduException as e: + if self.debug: + print_response(e.sw, e.data) + + return e.sw, e.data + + def _make_request(self, apdu: dict) -> Tuple[int, bytes]: + return self._apdu_exchange(apdu) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + yield() + + def stop(self) -> None: + """Stops the transport_client.""" + + self.transport_client.stop() + + def get_version(self) -> Tuple[str, str, bytes]: + """Queries the hardware wallet for the currently running app's name, version and state flags. + + Returns + ------- + Tuple[str, str, bytes] + The first element is the app's name, as a short string. + The second element is the app's version. + The third element is a binary string representing the platform's global state (pin lock etc). + """ + + sw, response = self._make_request( + {"cla": 0xB0, "ins": DefaultInsType.GET_VERSION, "p1": 0, "p2": 0, "data": b''}) + + if sw != 0x9000: + raise DeviceException( + error_code=sw, ins=DefaultInsType.GET_VERSION) + + r = BytesIO(response) + + format = r.read(1) + + app_name = deser_string(r) + app_version = deser_string(r) + app_flags = deser_string(r) + + if format != b'\1' or app_name == b'' or app_version == b'' or app_flags == b'': + raise DeviceException(error_code=sw, ins=DefaultInsType.GET_VERSION, + message="Invalid format returned by GET_VERSION") + + return app_name.decode(), app_version.decode(), app_flags + + def get_extended_pubkey(self, path: str, display: bool = False) -> str: + """Gets the serialized extended public key for certain BIP32 path. Optionally, validate with the user. + + Parameters + ---------- + path : str + BIP32 path of the public key you want. + display : bool + Whether you want to display address and ask confirmation on the device. + + Returns + ------- + str + The requested serialized extended public key. + """ + + raise NotImplementedError + + def register_wallet(self, wallet: WalletPolicy) -> Tuple[bytes, bytes]: + """Registers a wallet policy with the user. After approval returns the wallet id and hmac to be stored on the client. + + Parameters + ---------- + wallet : WalletPolicy + The Wallet policy to register on the device. + + Returns + ------- + Tuple[bytes, bytes] + The first element the tuple is the 32-bytes wallet id. + The second element is the hmac. + """ + + raise NotImplementedError + + def get_wallet_address( + self, + wallet: WalletPolicy, + wallet_hmac: Optional[bytes], + change: int, + address_index: int, + display: bool, + ) -> str: + """For a given wallet that was already registered on the device (or a standard wallet that does not need registration), + returns the address for a certain `change`/`address_index` combination. + + Parameters + ---------- + wallet : WalletPolicy + The registered wallet policy, or a standard wallet policy. + + wallet_hmac: Optional[bytes] + For a registered wallet, the hmac obtained at wallet registration. `None` for a standard wallet policy. + + change: int + 0 for a standard receive address, 1 for a change address. Other values are invalid. + + address_index: int + The address index in the last step of the BIP32 derivation. + + display: bool + Whether you want to display address and ask confirmation on the device. + + Returns + ------- + str + The requested address. + """ + + raise NotImplementedError + + def sign_psbt(self, psbt: Union[PSBT, bytes, str], wallet: WalletPolicy, wallet_hmac: Optional[bytes]) -> List[Tuple[int, PartialSignature]]: + """Signs a PSBT using a registered wallet (or a standard wallet that does not need registration). + + Signature requires explicit approval from the user. + + Parameters + ---------- + psbt : PSBT | bytes | str + A PSBT of version 0 or 2, with all the necessary information to sign the inputs already filled in; what the + required fields changes depending on the type of input. + The non-witness UTXO must be present for both legacy and SegWit inputs, or the hardware wallet will reject + signing (this will change for Taproot inputs). + The argument can be either a `PSBT` object, or `bytes`, or a base64-encoded `str`. + + wallet : WalletPolicy + The registered wallet policy, or a standard wallet policy. + + wallet_hmac: Optional[bytes] + For a registered wallet, the hmac obtained at wallet registration. `None` for a standard wallet policy. + + Returns + ------- + List[Tuple[int, PartialSignature]] + A list of tuples returned by the hardware wallets, where each element is a tuple of: + - an integer, the index of the input being signed; + - an instance of `PartialSignature`. + """ + + raise NotImplementedError + + def get_master_fingerprint(self) -> bytes: + """Gets the fingerprint of the master public key, as per BIP-32. + + Returns + ------- + bytes + The fingerprint of the master public key, as an array of 4 bytes. + """ + + raise NotImplementedError + + def sign_message(self, message: Union[str, bytes], bip32_path: str) -> str: + """ + Sign a message (bitcoin message signing). + Signs a message using the legacy Bitcoin Core signed message format. + The message is signed with the key at the given path. + :param message: The message to be signed. First encoded as bytes if not already. + :param bip32_path: The BIP 32 derivation for the key to sign the message with. + :return: The signature + """ + raise NotImplementedError diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/client_command.py b/test/python/apps/bitcoin_client/ledger_bitcoin/client_command.py new file mode 100644 index 0000000..9e32a56 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/client_command.py @@ -0,0 +1,334 @@ +from enum import IntEnum +from typing import List, Mapping +from collections import deque +from hashlib import sha256 + +from .common import ByteStreamParser, sha256, write_varint +from .merkle import MerkleTree, element_hash + + +class ClientCommandCode(IntEnum): + YIELD = 0x10 + GET_PREIMAGE = 0x40 + GET_MERKLE_LEAF_PROOF = 0x41 + GET_MERKLE_LEAF_INDEX = 0x42 + GET_MORE_ELEMENTS = 0xA0 + + +class ClientCommand: + def execute(self, request: bytes) -> bytes: + raise NotImplementedError("Subclasses should implement this method.") + + @property + def code(self) -> int: + raise NotImplementedError("Subclasses should implement this method.") + + +class YieldCommand(ClientCommand): + def __init__(self, results: List[bytes]): + self.results = results + + @property + def code(self) -> int: + return ClientCommandCode.YIELD + + def execute(self, request: bytes) -> bytes: + self.results.append(request[1:]) # only skip the first byte (command code) + return b"" + + +class GetPreimageCommand(ClientCommand): + def __init__(self, known_preimages: Mapping[bytes, bytes], queue: "deque[bytes]"): + self.queue = queue + self.known_preimages = known_preimages + + @property + def code(self) -> int: + return ClientCommandCode.GET_PREIMAGE + + def execute(self, request: bytes) -> bytes: + req = ByteStreamParser(request[1:]) + + if req.read_bytes(1) != b'\0': + raise RuntimeError(f"Unsupported request: the first byte should be 0") + + req_hash = req.read_bytes(32) + req.assert_empty() + + if req_hash in self.known_preimages: + known_preimage = self.known_preimages[req_hash] + + preimage_len_out = write_varint(len(known_preimage)) + + # We can send at most 255 - len(preimage_len_out) - 1 bytes in a single message; + # the rest will be stored for GET_MORE_ELEMENTS + + max_payload_size = 255 - len(preimage_len_out) - 1 + + payload_size = min(max_payload_size, len(known_preimage)) + + if payload_size < len(known_preimage): + # split into list of length-1 bytes elements + extra_elements = [ + known_preimage[i: i + 1] + for i in range(payload_size, len(known_preimage)) + ] + # add to the queue any remaining extra bytes + self.queue.extend(extra_elements) + + return ( + preimage_len_out + + payload_size.to_bytes(1, byteorder="big") + + known_preimage[:payload_size] + ) + + # not found + raise RuntimeError(f"Requested unknown preimage for: {req_hash.hex()}") + + +class GetMerkleLeafProofCommand(ClientCommand): + def __init__(self, known_trees: Mapping[bytes, MerkleTree], queue: "deque[bytes]"): + self.queue = queue + self.known_trees = known_trees + + @property + def code(self) -> int: + return ClientCommandCode.GET_MERKLE_LEAF_PROOF + + def execute(self, request: bytes) -> bytes: + req = ByteStreamParser(request[1:]) + + root = req.read_bytes(32) + tree_size = req.read_varint() + leaf_index = req.read_varint() + req.assert_empty() + + if not root in self.known_trees: + raise ValueError(f"Unknown Merkle root: {root.hex()}.") + + mt: MerkleTree = self.known_trees[root] + + if leaf_index >= tree_size or len(mt) != tree_size: + raise ValueError(f"Invalid index or tree size.") + + if len(self.queue) != 0: + raise RuntimeError( + "This command should not execute when the queue is not empty." + ) + + proof = mt.prove_leaf(leaf_index) + + # Compute how many elements we can fit in 255 - 32 - 1 - 1 = 221 bytes + n_response_elements = min((255 - 32 - 1 - 1) // 32, len(proof)) + n_leftover_elements = len(proof) - n_response_elements + + # Add to the queue any proof elements that do not fit the response + if (n_leftover_elements > 0): + self.queue.extend(proof[-n_leftover_elements:]) + + return b"".join( + [ + mt.get(leaf_index), + len(proof).to_bytes(1, byteorder="big"), + n_response_elements.to_bytes(1, byteorder="big"), + *proof[:n_response_elements], + ] + ) + + +class GetMerkleLeafIndexCommand(ClientCommand): + def __init__(self, known_trees: Mapping[bytes, MerkleTree]): + self.known_trees = known_trees + + @property + def code(self) -> int: + return ClientCommandCode.GET_MERKLE_LEAF_INDEX + + def execute(self, request: bytes) -> bytes: + req = ByteStreamParser(request[1:]) + + root = req.read_bytes(32) + leaf_hash = req.read_bytes(32) + req.assert_empty() + + if root not in self.known_trees: + raise ValueError(f"Unknown Merkle root: {root.hex()}.") + + try: + leaf_index = self.known_trees[root].leaf_index(leaf_hash) + found = 1 + except ValueError: + leaf_index = 0 + found = 0 + + return found.to_bytes(1, byteorder="big") + write_varint(leaf_index) + + +class GetMoreElementsCommand(ClientCommand): + def __init__(self, queue: "deque[bytes]"): + self.queue = queue + + @property + def code(self) -> int: + return ClientCommandCode.GET_MORE_ELEMENTS + + def execute(self, request: bytes) -> bytes: + if len(request) != 1: + raise ValueError("Wrong request length.") + + if len(self.queue) == 0: + raise ValueError("No elements to get.") + + element_len = len(self.queue[0]) + if any(len(el) != element_len for el in self.queue): + raise ValueError( + "The queue contains elements of different byte length, which is not expected." + ) + + # pop from the queue, keeping the total response length at most 255 + + response_elements = bytearray() + + n_added_elements = 0 + while len(self.queue) > 0 and len(response_elements) + element_len <= 253: + response_elements.extend(self.queue.popleft()) + n_added_elements += 1 + + return b"".join( + [ + n_added_elements.to_bytes(1, byteorder="big"), + element_len.to_bytes(1, byteorder="big"), + bytes(response_elements), + ] + ) + + +class ClientCommandInterpreter: + """Interpreter for the client-side commands. + + This class keeps has methods to keep track of: + - known preimages + - known Merkle trees from lists of elements + + Moreover, it containes the state that is relevant for the interpreted client side commands: + - a queue of bytes that contains any bytes that could not fit in a response from the + GET_PREIMAGE client command (when a preimage is too long to fit in a single message) or the + GET_MERKLE_LEAF_PROOF command (which returns a Merkle proof, which might be too long to fit + in a single message). The data in the queue is returned in one (or more) successive + GET_MORE_ELEMENTS commands from the hardware wallet. + + Finally, it keeps track of the yielded values (that is, the values sent from the hardware + wallet with a YIELD client command). + + Attributes + ---------- + yielded: list[bytes] + A list of all the value sent by the Hardware Wallet with a YIELD client command during thw + processing of an APDU. + """ + + def __init__(self): + self.known_preimages: Mapping[bytes, bytes] = {} + self.known_trees: Mapping[bytes, MerkleTree] = {} + + self.yielded: List[bytes] = [] + + queue = deque() + + commands = [ + YieldCommand(self.yielded), + GetPreimageCommand(self.known_preimages, queue), + GetMerkleLeafIndexCommand(self.known_trees), + GetMerkleLeafProofCommand(self.known_trees, queue), + GetMoreElementsCommand(queue), + ] + + self.commands = {cmd.code: cmd for cmd in commands} + + def execute(self, hw_response: bytes) -> bytes: + """Interprets the client command requested by the hardware wallet, returning the appropriate + response and updating the client interpreter's internal state if needed. + + Parameters + ---------- + hw_response : bytes + The data content of the SW_INTERRUPTED_EXECUTION sent by the hardware wallet. + + Returns + ------- + bytes + The result of the execution of the appropriate client side command, containing the response + to be sent via INS_CONTINUE. + """ + + if len(hw_response) == 0: + raise RuntimeError( + "Unexpected empty SW_INTERRUPTED_EXECUTION response from hardware wallet." + ) + + cmd_code = hw_response[0] + if cmd_code not in self.commands: + raise RuntimeError( + "Unexpected command code: 0x{:02X}".format(cmd_code) + ) + + return self.commands[cmd_code].execute(hw_response) + + def add_known_preimage(self, element: bytes) -> None: + """Adds a preimage to the list of known preimages. + + The client must respond with `element` when a GET_PREIMAGE command is sent with + `sha256(element)` in its request. + + Parameters + ---------- + element : bytes + An array of bytes whose preimage must be known to the client during an APDU execution. + """ + + self.known_preimages[sha256(element)] = element + + def add_known_list(self, elements: List[bytes]) -> None: + """Adds a known Merkleized list. + + Builds the Merkle tree of `elements`, and adds it to the Merkle trees known to the client + (mapped by Merkle root `mt_root`). + moreover, adds all the leafs (after adding the b'\0' prefix) to the list of known preimages. + + If `el` is one of `elements`, the client must respond with b'\0' + `el` when a GET_PREIMAGE + client command is sent with `sha256(b'\0' + el)`. + Moreover, the commands GET_MERKLE_LEAF_INDEX and GET_MERKLE_LEAF_PROOF must correctly answer + queries relative to the Merkle whose root is `mt_root`. + + Parameters + ---------- + elements : List[bytes] + A list of `bytes` corresponding to the leafs of the Merkle tree. + """ + + for el in elements: + self.add_known_preimage(b"\x00" + el) + + mt = MerkleTree(element_hash(el) for el in elements) + + self.known_trees[mt.root] = mt + + def add_known_mapping(self, mapping: Mapping[bytes, bytes]) -> None: + """Adds the Merkle trees of keys, and the Merkle tree of values (ordered by key) + of a mapping of bytes to bytes. + + Adds the Merkle tree of the list of keys, and the Merkle tree of the list of corresponding + values, with the same semantics as the `add_known_list` applied separately to the two lists. + + Parameters + ---------- + mapping : Mapping[bytes, bytes] + A mapping whose keys and values are `bytes`. + """ + + items_sorted = list(sorted(mapping.items())) + + keys = [i[0] for i in items_sorted] + values = [i[1] for i in items_sorted] + self.add_known_list(keys) + self.add_known_list(values) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/client_legacy.py b/test/python/apps/bitcoin_client/ledger_bitcoin/client_legacy.py new file mode 100644 index 0000000..d13816e --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/client_legacy.py @@ -0,0 +1,357 @@ +""" +This module provides a compatibility layer between the python client of the Ledger Nano Bitcoin app v2 and the v1.6.5, +by translating client requests to the API of the app v1.6.5. + +The bulk of the code is taken from bitcoin-core/HWI, with the necessary adaptations. +https://github.com/bitcoin-core/HWI/tree/a109bcd53d24a52e72f26af3ecbabb64b292ff0c, +""" + +import struct +import re +import base64 + +from .client_base import PartialSignature +from .client import Client + +from typing import List, Tuple, Optional, Union + +from .common import AddressType, Chain, hash160 +from .key import ExtendedKey, parse_path +from .psbt import PSBT, normalize_psbt +from .wallet import WalletPolicy + +from ._script import is_p2sh, is_witness, is_p2wpkh, is_p2wsh + +from .btchip.btchip import btchip +from .btchip.btchipUtils import compress_public_key +from .btchip.bitcoinTransaction import bitcoinTransaction +from ragger.backend import BackendInterface + + +def get_address_type_for_policy(policy: WalletPolicy) -> AddressType: + if policy.descriptor_template in ["pkh(@0/**)", "pkh(@0/<0;1>/*)"]: + return AddressType.LEGACY + elif policy.descriptor_template in ["wpkh(@0/**)", "wpkh(@0/<0:1>/*)"]: + return AddressType.WIT + elif policy.descriptor_template in ["sh(wpkh(@0/**))", "sh(wpkh(@0/<0;1>/*))"]: + return AddressType.SH_WIT + else: + raise ValueError("Invalid or unsupported policy") + + +# minimal checking of string keypath +# taken from HWI +def check_keypath(key_path: str) -> bool: + parts = re.split("/", key_path) + if parts[0] != "m": + return False + # strip hardening chars + for index in parts[1:]: + index_int = re.sub('[hH\']', '', index) + if not index_int.isdigit(): + return False + if int(index_int) > 0x80000000: + return False + return True + + +class DongleAdaptor: + # TODO: type for comm_client + def __init__(self, comm_client): + self.comm_client = comm_client + + def exchange(self, apdu: Union[bytes, bytearray]) -> bytearray: + cla = apdu[0] + ins = apdu[1] + p1 = apdu[2] + p2 = apdu[3] + lc = apdu[4] + data = apdu[5:] + assert len(data) == lc + return bytearray(self.comm_client.apdu_exchange(cla, ins, data, p1, p2)) + +class LegacyClient(Client): + """Wrapper for Ledger Bitcoin app before version 2.0.0.""" + + def __init__(self, comm_client: BackendInterface, chain: Chain = Chain.MAIN, debug: bool = False): + super().__init__(comm_client, chain, debug) + + self.app = btchip(DongleAdaptor(comm_client)) + + if self.app.getAppName() not in ["Bitcoin", "Bitcoin Legacy", "Bitcoin Test", "Bitcoin Test Legacy", "app"]: + raise ValueError("Ledger is not in either the Bitcoin or Bitcoin Testnet app") + + def get_extended_pubkey(self, path: str, display: bool = False) -> str: + # mostly taken from HWI + + path = path[2:] + path = path.replace('h', '\'') + path = path.replace('H', '\'') + + # This call returns raw uncompressed pubkey, chaincode + pubkey = self.app.getWalletPublicKey(path, display) + int_path = parse_path(path) + if len(path) > 0: + parent_path = "" + for ind in path.split("/")[:-1]: + parent_path += ind + "/" + parent_path = parent_path[:-1] + + # Get parent key fingerprint + parent = self.app.getWalletPublicKey(parent_path) + fpr = hash160(compress_public_key(parent["publicKey"]))[:4] + + child = int_path[-1] + # Special case for m + else: + child = 0 + fpr = b"\x00\x00\x00\x00" + + xpub = ExtendedKey( + version=ExtendedKey.MAINNET_PUBLIC if self.chain == Chain.MAIN else ExtendedKey.TESTNET_PUBLIC, + depth=len(path.split("/")) if len(path) > 0 else 0, + parent_fingerprint=fpr, + child_num=child, + chaincode=pubkey["chainCode"], + privkey=None, + pubkey=compress_public_key(pubkey["publicKey"]), + ) + return xpub.to_string() + + def register_wallet(self, wallet: WalletPolicy) -> Tuple[bytes, bytes]: + raise NotImplementedError # legacy app does not have this functionality + + def get_wallet_address( + self, + wallet: WalletPolicy, + wallet_hmac: Optional[bytes], + change: int, + address_index: int, + display: bool, + ) -> str: + # TODO: check keypath + + if wallet_hmac is not None or wallet.n_keys != 1: + raise NotImplementedError("Policy wallets are only supported from version 2.0.0. Please update your Ledger hardware wallet") + + if not isinstance(wallet, WalletPolicy): + raise ValueError("Invalid wallet policy type, it must be WalletPolicy") + + key_info = wallet.keys_info[0] + try: + first_slash_pos = key_info.index("/") + key_origin_end = key_info.index("]") + except ValueError: + raise ValueError("Could not extract key origin information") + + if key_info[0] != '[': + raise ValueError("Key must have key origin information") + + key_origin_path = key_info[first_slash_pos + 1: key_origin_end] + + addr_type = get_address_type_for_policy(wallet) + + p2sh_p2wpkh = addr_type == AddressType.SH_WIT + bech32 = addr_type == AddressType.WIT + output = self.app.getWalletPublicKey(f"{key_origin_path}/{change}/{address_index}", display, p2sh_p2wpkh or bech32, bech32) + assert isinstance(output["address"], str) + return output['address'][12:-2] # HACK: A bug in getWalletPublicKey results in the address being returned as the string "bytearray(b'
')". This extracts the actual address to work around this. + + def sign_psbt(self, psbt: Union[PSBT, bytes, str], wallet: WalletPolicy, wallet_hmac: Optional[bytes]) -> List[Tuple[int, PartialSignature]]: + if wallet_hmac is not None or wallet.n_keys != 1: + raise NotImplementedError("Policy wallets are only supported from version 2.0.0. Please update your Ledger hardware wallet") + + if not isinstance(wallet, WalletPolicy): + raise ValueError("Invalid wallet policy type, it must be WalletPolicy") + + if wallet.descriptor_template not in ["pkh(@0/**)", "pkh(@0/<0;1>/*)", "wpkh(@0/**)", "wpkh(@0/<0;1>/*)", "sh(wpkh(@0/**))", "sh(wpkh(@0/<0;1>/*))"]: + raise NotImplementedError("Unsupported policy") + + psbt = normalize_psbt(psbt) + + # the rest of the code is basically the HWI code, and it ignores wallet + + tx = psbt + + #c_tx = tx.get_unsigned_tx() + c_tx = tx.tx + tx_bytes = c_tx.serialize_with_witness() + + # Master key fingerprint + master_fpr = hash160(compress_public_key(self.app.getWalletPublicKey('')["publicKey"]))[:4] + # An entry per input, each with 0 to many keys to sign with + all_signature_attempts: List[List[Tuple[str, bytes]]] = [[]] * len(c_tx.vin) + + # Get the app version to determine whether to use Trusted Input for segwit + version = self.app.getFirmwareVersion() + use_trusted_segwit = (version['major_version'] == 1 and version['minor_version'] >= 4) or version['major_version'] > 1 + + # NOTE: We only support signing Segwit inputs, where we can skip over non-segwit + # inputs, or non-segwit inputs, where *all* inputs are non-segwit. This is due + # to Ledger's mutually exclusive signing steps for each type. + segwit_inputs = [] + # Legacy style inputs + legacy_inputs = [] + + has_segwit = False + has_legacy = False + + script_codes: List[bytes] = [b""] * len(c_tx.vin) + + # Detect changepath, (p2sh-)p2(w)pkh only + change_path = '' + for txout, i_num in zip(c_tx.vout, range(len(c_tx.vout))): + # Find which wallet key could be change based on hdsplit: m/.../1/k + # Wallets shouldn't be sending to change address as user action + # otherwise this will get confused + for pubkey, origin in tx.outputs[i_num].hd_keypaths.items(): + if origin.fingerprint == master_fpr and len(origin.path) > 1 and origin.path[-2] == 1: + # For possible matches, check if pubkey matches possible template + if hash160(pubkey) in txout.scriptPubKey or hash160(bytearray.fromhex("0014") + hash160(pubkey)) in txout.scriptPubKey: + change_path = '' + for index in origin.path: + change_path += str(index) + "/" + change_path = change_path[:-1] + + for txin, psbt_in, i_num in zip(c_tx.vin, tx.inputs, range(len(c_tx.vin))): + + seq_hex = txin.nSequence.to_bytes(4, byteorder="little").hex() + + scriptcode = b"" + utxo = None + if psbt_in.witness_utxo: + utxo = psbt_in.witness_utxo + if psbt_in.non_witness_utxo: + if txin.prevout.hash != psbt_in.non_witness_utxo.sha256: + raise ValueError('Input {} has a non_witness_utxo with the wrong hash'.format(i_num)) + utxo = psbt_in.non_witness_utxo.vout[txin.prevout.n] + if utxo is None: + raise Exception("PSBT is missing input utxo information, cannot sign") + scriptcode = utxo.scriptPubKey + + if is_p2sh(scriptcode): + if len(psbt_in.redeem_script) == 0: + continue + scriptcode = psbt_in.redeem_script + + is_wit, _, _ = is_witness(scriptcode) + + segwit_inputs.append({"value": txin.prevout.serialize() + struct.pack(" bytes: + master_pubkey = self.app.getWalletPublicKey("") + return hash160(compress_public_key(master_pubkey["publicKey"]))[:4] + + def sign_message(self, message: Union[str, bytes], keypath: str) -> str: + # copied verbatim from HWI + + if not check_keypath(keypath): + raise ValueError("Invalid keypath") + if isinstance(message, str): + message = bytearray(message, 'utf-8') + else: + message = bytearray(message) + keypath = keypath[2:] + # First display on screen what address you're signing for + self.app.getWalletPublicKey(keypath, True) + self.app.signMessagePrepare(keypath, message) + signature = self.app.signMessageSign() + + # Make signature into standard bitcoin format + rLength = signature[3] + r = int.from_bytes(signature[4: 4 + rLength], byteorder="big", signed=True) + s = int.from_bytes(signature[4 + rLength + 2:], byteorder="big", signed=True) + + sig = bytearray(chr(27 + 4 + (signature[0] & 0x01)), 'utf8') + r.to_bytes(32, byteorder="big", signed=False) + s.to_bytes(32, byteorder="big", signed=False) + + return base64.b64encode(sig).decode('utf-8') diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/command_builder.py b/test/python/apps/bitcoin_client/ledger_bitcoin/command_builder.py new file mode 100644 index 0000000..5819d44 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/command_builder.py @@ -0,0 +1,208 @@ +import enum +from typing import List, Tuple, Mapping, Union, Iterator, Optional + +from .common import bip32_path_from_string, write_varint +from .merkle import get_merkleized_map_commitment, MerkleTree, element_hash +from .wallet import WalletPolicy + +# p2 encodes the protocol version implemented +CURRENT_PROTOCOL_VERSION = 1 + +def chunkify(data: bytes, chunk_len: int) -> Iterator[Tuple[bool, bytes]]: + size: int = len(data) + + if size <= chunk_len: + yield True, data + return + + chunk: int = size // chunk_len + remaining: int = size % chunk_len + offset: int = 0 + + for i in range(chunk): + yield False, data[offset: offset + chunk_len] + offset += chunk_len + + if remaining: + yield True, data[offset:] + + +class DefaultInsType(enum.IntEnum): + GET_VERSION = 0x01 + +class BitcoinInsType(enum.IntEnum): + GET_EXTENDED_PUBKEY = 0x00 + REGISTER_WALLET = 0x02 + GET_WALLET_ADDRESS = 0x03 + SIGN_PSBT = 0x04 + GET_MASTER_FINGERPRINT = 0x05 + SIGN_MESSAGE = 0x10 + +class FrameworkInsType(enum.IntEnum): + CONTINUE_INTERRUPTED = 0x01 + + +class BitcoinCommandBuilder: + """APDU command builder for the Bitcoin application.""" + + CLA_DEFAULT: int = 0xB0 + CLA_BITCOIN: int = 0xE1 + CLA_FRAMEWORK: int = 0xF8 + + def serialize( + self, + cla: int, + ins: Union[int, enum.IntEnum], + p1: int = 0, + p2: int = CURRENT_PROTOCOL_VERSION, + cdata: bytes = b"", + ) -> dict: + """Serialize the whole APDU command (header + data). + + Parameters + ---------- + cla : int + Instruction class: CLA (1 byte) + ins : Union[int, IntEnum] + Instruction code: INS (1 byte) + p1 : int + Instruction parameter 1: P1 (1 byte). + p2 : int + Instruction parameter 2: P2 (1 byte). + cdata : bytes + Bytes of command data. + + Returns + ------- + dict + Dictionary representing the APDU message. + + """ + + return {"cla": cla, "ins": ins, "p1": p1, "p2": p2, "data": cdata} + + def get_extended_pubkey(self, bip32_path: str, display: bool = False): + bip32_path: List[bytes] = bip32_path_from_string(bip32_path) + + cdata: bytes = b"".join([ + b'\1' if display else b'\0', + len(bip32_path).to_bytes(1, byteorder="big"), + *bip32_path + ]) + + return self.serialize( + cla=self.CLA_BITCOIN, + ins=BitcoinInsType.GET_EXTENDED_PUBKEY, + cdata=cdata, + ) + + def register_wallet(self, wallet: WalletPolicy): + wallet_bytes = wallet.serialize() + + return self.serialize( + cla=self.CLA_BITCOIN, + ins=BitcoinInsType.REGISTER_WALLET, + cdata=write_varint(len(wallet_bytes)) + wallet_bytes, + ) + + def get_wallet_address( + self, + wallet: WalletPolicy, + wallet_hmac: Optional[bytes], + address_index: int, + change: bool, + display: bool, + ): + cdata: bytes = b"".join( + [ + b'\1' if display else b'\0', # 1 byte + wallet.id, # 32 bytes + wallet_hmac if wallet_hmac is not None else b'\0' * 32, # 32 bytes + b"\1" if change else b"\0", # 1 byte + address_index.to_bytes(4, byteorder="big"), # 4 bytes + ] + ) + + return self.serialize( + cla=self.CLA_BITCOIN, + ins=BitcoinInsType.GET_WALLET_ADDRESS, + cdata=cdata, + ) + + def sign_psbt( + self, + global_mapping: Mapping[bytes, bytes], + input_mappings: List[Mapping[bytes, bytes]], + output_mappings: List[Mapping[bytes, bytes]], + wallet: WalletPolicy, + wallet_hmac: Optional[bytes], + ): + + cdata = bytearray() + cdata += get_merkleized_map_commitment(global_mapping) + + cdata += write_varint(len(input_mappings)) + cdata += MerkleTree( + [ + element_hash(get_merkleized_map_commitment(m_in)) + for m_in in input_mappings + ] + ).root + + cdata += write_varint(len(output_mappings)) + cdata += MerkleTree( + [ + element_hash(get_merkleized_map_commitment(m_out)) + for m_out in output_mappings + ] + ).root + + cdata += wallet.id + cdata += wallet_hmac if wallet_hmac is not None else b'\0' * 32 + + return self.serialize( + cla=self.CLA_BITCOIN, ins=BitcoinInsType.SIGN_PSBT, cdata=bytes(cdata) + ) + + def get_master_fingerprint(self): + return self.serialize( + cla=self.CLA_BITCOIN, + ins=BitcoinInsType.GET_MASTER_FINGERPRINT + ) + + def sign_message(self, message: bytes, bip32_path: str): + cdata = bytearray() + + bip32_path: List[bytes] = bip32_path_from_string(bip32_path) + + # split message in 64-byte chunks (last chunk can be smaller) + n_chunks = (len(message) + 63) // 64 + chunks = [message[64 * i: 64 * i + 64] for i in range(n_chunks)] + + cdata += len(bip32_path).to_bytes(1, byteorder="big") + cdata += b''.join(bip32_path) + + cdata += write_varint(len(message)) + + cdata += MerkleTree(element_hash(c) for c in chunks).root + + return self.serialize( + cla=self.CLA_BITCOIN, + ins=BitcoinInsType.SIGN_MESSAGE, + cdata=bytes(cdata) + ) + + def continue_interrupted(self, cdata: bytes): + """Command builder for CONTINUE. + + Returns + ------- + bytes + APDU command for CONTINUE. + + """ + return self.serialize( + cla=self.CLA_FRAMEWORK, + ins=FrameworkInsType.CONTINUE_INTERRUPTED, + cdata=cdata, + ) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/common.py b/test/python/apps/bitcoin_client/ledger_bitcoin/common.py new file mode 100644 index 0000000..66ad38f --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/common.py @@ -0,0 +1,172 @@ +from io import BytesIO +from typing import List, Optional, Literal +from enum import Enum +from typing import Union + +import hashlib + +UINT64_MAX: int = 18446744073709551615 +UINT32_MAX: int = 4294967295 +UINT16_MAX: int = 65535 + + +# from bitcoin-core/HWI +class Chain(Enum): + """ + The blockchain network to use + """ + MAIN = 0 #: Bitcoin Main network + TEST = 1 #: Bitcoin Test network + REGTEST = 2 #: Bitcoin Core Regression Test network + SIGNET = 3 #: Bitcoin Signet + + def __str__(self) -> str: + return self.name.lower() + + def __repr__(self) -> str: + return str(self) + + @staticmethod + def argparse(s: str) -> Union['Chain', str]: + try: + return Chain[s.upper()] + except KeyError: + return s + +# from bitcoin-core/HWI +class AddressType(Enum): + """ + The type of address to use + """ + LEGACY = 1 #: Legacy address type. P2PKH for single sig, P2SH for scripts. + WIT = 2 #: Native segwit v0 address type. P2WPKH for single sig, P2WPSH for scripts. + SH_WIT = 3 #: Nested segwit v0 address type. P2SH-P2WPKH for single sig, P2SH-P2WPSH for scripts. + TAP = 4 #: Segwit v1 Taproot address type. P2TR always. + + def __str__(self) -> str: + return self.name.lower() + + def __repr__(self) -> str: + return str(self) + + @staticmethod + def argparse(s: str) -> Union['AddressType', str]: + try: + return AddressType[s.upper()] + except KeyError: + return s + +def bip32_path_from_string(path: str) -> List[bytes]: + splitted_path: List[str] = path.split("/") + + if not splitted_path: + raise Exception(f"BIP32 path format error: '{path}'") + + if "m" in splitted_path and splitted_path[0] == "m": + splitted_path = splitted_path[1:] + + return [int(p).to_bytes(4, byteorder="big") if "'" not in p + else (0x80000000 | int(p[:-1])).to_bytes(4, byteorder="big") + for p in splitted_path] + + +def write_varint(n: int) -> bytes: + if n <= 0xFC: + return n.to_bytes(1, byteorder="little") + + if n <= UINT16_MAX: + return b"\xFD" + n.to_bytes(2, byteorder="little") + + if n <= UINT32_MAX: + return b"\xFE" + n.to_bytes(4, byteorder="little") + + if n <= UINT64_MAX: + return b"\xFF" + n.to_bytes(8, byteorder="little") + + raise ValueError(f"Can't write to varint: '{n}'!") + + +def read_varint(buf: BytesIO, + prefix: Optional[bytes] = None) -> int: + b: bytes = prefix if prefix else buf.read(1) + + if not b: + raise ValueError(f"Can't read prefix: '{b}'!") + + n: int = {b"\xfd": 2, b"\xfe": 4, b"\xff": 8}.get(b, 1) # default to 1 + + b = buf.read(n) if n > 1 else b + + if len(b) != n: + raise ValueError("Can't read varint!") + + return int.from_bytes(b, byteorder="little") + + +def read_uint(buf: BytesIO, + bit_len: int, + byteorder: Literal['big', 'little'] = 'little') -> int: + size: int = bit_len // 8 + b: bytes = buf.read(size) + + if len(b) < size: + raise ValueError(f"Can't read u{bit_len} in buffer!") + + return int.from_bytes(b, byteorder) + + +def serialize_str(value: str) -> bytes: + return len(value.encode()).to_bytes(1, byteorder="big") + value.encode() + + +def ripemd160(x: bytes) -> bytes: + try: + h = hashlib.new("ripemd160") + h.update(x) + return h.digest() + except BaseException: + # ripemd160 is not always present in hashlib. + # Fallback to custom implementation if missing. + from . import ripemd + return ripemd.ripemd160(x) + +def sha256(s: bytes) -> bytes: + return hashlib.new('sha256', s).digest() + + +def hash160(s: bytes) -> bytes: + return ripemd160(sha256(s)) + + +def hash256(s: bytes) -> bytes: + return sha256(sha256(s)) + + +class ByteStreamParser: + def __init__(self, input: bytes): + self.stream = BytesIO(input) + + def assert_empty(self) -> bytes: + if self.stream.read(1) != b'': + raise ValueError("Byte stream was expected to be empty") + + def read_bytes(self, n: int) -> bytes: + result = self.stream.read(n) + if len(result) < n: + raise ValueError("Byte stream exhausted") + return result + + def read_uint(self, n: int, byteorder: Literal['big', 'little'] = "big") -> int: + return int.from_bytes(self.read_bytes(n), byteorder) + + def read_varint(self) -> int: + prefix = self.read_uint(1) + + if prefix == 253: + return self.read_uint(2, 'little') + elif prefix == 254: + return self.read_uint(4, 'little') + elif prefix == 255: + return self.read_uint(8, 'little') + else: + return prefix diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/errors.py b/test/python/apps/bitcoin_client/ledger_bitcoin/errors.py new file mode 100644 index 0000000..cd32c7c --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/errors.py @@ -0,0 +1,265 @@ +""" +Original version: https://github.com/bitcoin-core/HWI +Distributed under the MIT License. + + +Errors and Error Codes +********************** + +HWI has several possible Exceptions with corresponding error codes. + +:class:`~hwilib.hwwclient.HardwareWalletClient` functions and :mod:`~hwilib.commands` functions will generally raise an exception that is a subclass of :class:`HWWError`. +The HWI command line tool will convert these exceptions into a dictionary containing the error message and error code. +These look like ``{"error": "", "code": }``. +""" + +from typing import Any, Dict, Iterator, Optional +from contextlib import contextmanager + +# Error codes +NO_DEVICE_TYPE = -1 #: Device type was not specified +MISSING_ARGUMENTS = -2 #: Arguments are missing +DEVICE_CONN_ERROR = -3 #: Error connecting to the device +UNKNWON_DEVICE_TYPE = -4 #: Device type is unknown +INVALID_TX = -5 #: Transaction is invalid +NO_PASSWORD = -6 #: No password provided, but one is needed +BAD_ARGUMENT = -7 #: Bad, malformed, or conflicting argument was provided +NOT_IMPLEMENTED = -8 #: Function is not implemented +UNAVAILABLE_ACTION = -9 #: Function is not available for this device +DEVICE_ALREADY_INIT = -10 #: Device is already initialized +DEVICE_ALREADY_UNLOCKED = -11 #: Device is already unlocked +DEVICE_NOT_READY = -12 #: Device is not ready +UNKNOWN_ERROR = -13 #: An unknown error occurred +ACTION_CANCELED = -14 #: Action was canceled by the user +DEVICE_BUSY = -15 #: Device is busy +NEED_TO_BE_ROOT = -16 #: User needs to be root to perform action +HELP_TEXT = -17 #: Help text was requested by the user +DEVICE_NOT_INITIALIZED = -18 #: Device is not initialized + +# Exceptions +class HWWError(Exception): + """ + Generic exception type produced by HWI + Subclassed by specific Errors to have Exceptions that have specific error codes. + + Contains a message and error code. + """ + + def __init__(self, msg: str, code: int) -> None: + """ + Create an exception with the message and error code + + :param msg: The error message + :param code: The error code + """ + Exception.__init__(self) + self.code = code + self.msg = msg + + def get_code(self) -> int: + """ + Get the error code for this Error + + :return: The error code + """ + return self.code + + def get_msg(self) -> str: + """ + Get the error message for this Error + + :return: The error message + """ + return self.msg + + def __str__(self) -> str: + return self.msg + +class NoPasswordError(HWWError): + """ + :class:`HWWError` for :data:`NO_PASSWORD` + """ + + def __init__(self, msg: str): + """ + :param msg: The error message + """ + HWWError.__init__(self, msg, NO_PASSWORD) + +class UnavailableActionError(HWWError): + """ + :class:`HWWError` for :data:`UNAVAILABLE_ACTION` + """ + + def __init__(self, msg: str): + """ + :param msg: The error message + """ + HWWError.__init__(self, msg, UNAVAILABLE_ACTION) + +class DeviceAlreadyInitError(HWWError): + """ + :class:`HWWError` for :data:`DEVICE_ALREADY_INIT` + """ + + def __init__(self, msg: str): + """ + :param msg: The error message + """ + HWWError.__init__(self, msg, DEVICE_ALREADY_INIT) + +class DeviceNotReadyError(HWWError): + """ + :class:`HWWError` for :data:`DEVICE_NOT_READY` + """ + + def __init__(self, msg: str): + """ + :param msg: The error message + """ + HWWError.__init__(self, msg, DEVICE_NOT_READY) + +class DeviceAlreadyUnlockedError(HWWError): + """ + :class:`HWWError` for :data:`DEVICE_ALREADY_UNLOCKED` + """ + + def __init__(self, msg: str): + """ + :param msg: The error message + """ + HWWError.__init__(self, msg, DEVICE_ALREADY_UNLOCKED) + +class UnknownDeviceError(HWWError): + """ + :class:`HWWError` for :data:`DEVICE_TYPE` + """ + + def __init__(self, msg: str): + """ + :param msg: The error message + """ + HWWError.__init__(self, msg, UNKNWON_DEVICE_TYPE) + +class NotImplementedError(HWWError): + """ + :class:`HWWError` for :data:`NOT_IMPLEMENTED` + """ + + def __init__(self, msg: str): + """ + :param msg: The error message + """ + HWWError.__init__(self, msg, NOT_IMPLEMENTED) + +class PSBTSerializationError(HWWError): + """ + :class:`HWWError` for :data:`INVALID_TX` + """ + + def __init__(self, msg: str): + """ + :param msg: The error message + """ + HWWError.__init__(self, msg, INVALID_TX) + +class BadArgumentError(HWWError): + """ + :class:`HWWError` for :data:`BAD_ARGUMENT` + """ + + def __init__(self, msg: str): + """ + :param msg: The error message + """ + HWWError.__init__(self, msg, BAD_ARGUMENT) + +class DeviceFailureError(HWWError): + """ + :class:`HWWError` for :data:`UNKNOWN_ERROR` + """ + + def __init__(self, msg: str): + """ + :param msg: The error message + """ + HWWError.__init__(self, msg, UNKNOWN_ERROR) + +class ActionCanceledError(HWWError): + """ + :class:`HWWError` for :data:`ACTION_CANCELED` + """ + + def __init__(self, msg: str): + """ + :param msg: The error message + """ + HWWError.__init__(self, msg, ACTION_CANCELED) + +class DeviceConnectionError(HWWError): + """ + :class:`HWWError` for :data:`DEVICE_CONN_ERROR` + """ + + def __init__(self, msg: str): + """ + :param msg: The error message + """ + HWWError.__init__(self, msg, DEVICE_CONN_ERROR) + +class DeviceBusyError(HWWError): + """ + :class:`HWWError` for :data:`DEVICE_BUSY` + """ + + def __init__(self, msg: str): + """ + :param msg: The error message + """ + HWWError.__init__(self, msg, DEVICE_BUSY) + +class NeedsRootError(HWWError): + def __init__(self, msg: str): + HWWError.__init__(self, msg, NEED_TO_BE_ROOT) + +@contextmanager +def handle_errors( + msg: Optional[str] = None, + result: Optional[Dict[str, Any]] = None, + code: int = UNKNOWN_ERROR, + debug: bool = False, +) -> Iterator[None]: + """ + Context manager to catch all Exceptions and HWWErrors to return them as dictionaries containing the error message and code. + + :param msg: Error message prefix. Attached to the beginning of each error message + :param result: The dictionary to put the resulting error in + :param code: The default error code to use for Exceptions + :param debug: Whether to also print out the traceback for debugging purposes + """ + if result is None: + result = {} + + if msg is None: + msg = "" + else: + msg = msg + " " + + try: + yield + + except HWWError as e: + result['error'] = msg + e.get_msg() + result['code'] = e.get_code() + except Exception as e: + result['error'] = msg + str(e) + result['code'] = code + if debug: + import traceback + traceback.print_exc() + return result + + +common_err_msgs = { + "enumerate": "Could not open client or get fingerprint information:" +} diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/exception/__init__.py b/test/python/apps/bitcoin_client/ledger_bitcoin/exception/__init__.py new file mode 100644 index 0000000..7a0571c --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/exception/__init__.py @@ -0,0 +1,27 @@ +from .device_exception import DeviceException +from .errors import (UnknownDeviceError, + DenyError, + IncorrectDataError, + NotSupportedError, + WrongP1P2Error, + WrongDataLengthError, + InsNotSupportedError, + ClaNotSupportedError, + WrongResponseLengthError, + BadStateError, + SignatureFailError) + +__all__ = [ + "DeviceException", + "DenyError", + "IncorrectDataError", + "NotSupportedError", + "UnknownDeviceError", + "WrongP1P2Error", + "WrongDataLengthError", + "InsNotSupportedError", + "ClaNotSupportedError", + "WrongResponseLengthError", + "BadStateError", + "SignatureFailError" +] diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/exception/device_exception.py b/test/python/apps/bitcoin_client/ledger_bitcoin/exception/device_exception.py new file mode 100644 index 0000000..b20a57c --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/exception/device_exception.py @@ -0,0 +1,36 @@ +import enum +from typing import Dict, Any, Union + +from .errors import * + + +class DeviceException(Exception): # pylint: disable=too-few-public-methods + exc: Dict[int, Any] = { + 0x6985: DenyError, + 0x6982: SecurityStatusNotSatisfiedError, + 0x6A80: IncorrectDataError, + 0x6A82: NotSupportedError, + 0x6A86: WrongP1P2Error, + 0x6A87: WrongDataLengthError, + 0x6D00: InsNotSupportedError, + 0x6E00: ClaNotSupportedError, + 0xB000: WrongResponseLengthError, + 0xB007: BadStateError, + 0xB008: SignatureFailError, + 0xE000: InterruptedExecution, # not an error + } + + def __new__(cls, + error_code: int, + ins: Union[int, enum.IntEnum, None] = None, + message: str = "" + ) -> Any: + error_message: str = (f"Error in {ins!r} command" + if ins else "Error in command") + + if error_code in DeviceException.exc: + return DeviceException.exc[error_code](hex(error_code), + error_message, + message) + + return UnknownDeviceError(hex(error_code), error_message, message) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/exception/errors.py b/test/python/apps/bitcoin_client/ledger_bitcoin/exception/errors.py new file mode 100644 index 0000000..e875d08 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/exception/errors.py @@ -0,0 +1,51 @@ +class UnknownDeviceError(Exception): + pass + + +class SecurityStatusNotSatisfiedError(Exception): + pass + + +class DenyError(Exception): + pass + + +class IncorrectDataError(Exception): + pass + + +class NotSupportedError(Exception): + pass + + +class WrongP1P2Error(Exception): + pass + + +class WrongDataLengthError(Exception): + pass + + +class InsNotSupportedError(Exception): + pass + + +class ClaNotSupportedError(Exception): + pass + + +class WrongResponseLengthError(Exception): + pass + + +class BadStateError(Exception): + pass + + +class SignatureFailError(Exception): + pass + + +# Not really an error +class InterruptedExecution(Exception): + pass diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/key.py b/test/python/apps/bitcoin_client/ledger_bitcoin/key.py new file mode 100644 index 0000000..8e2a503 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/key.py @@ -0,0 +1,485 @@ +# Original version: https://github.com/bitcoin-core/HWI/blob/3fe369d0379212fae1c72729a179d133b0adc872/hwilib/key.py + +#!/usr/bin/env python3 +# Copyright (c) 2020 The HWI developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +""" +Key Classes and Utilities +************************* + +Classes and utilities for working with extended public keys, key origins, and other key related things. +""" + +from . import _base58 as base58 +from .common import ( + AddressType, + Chain, + hash256, + hash160, +) +from .errors import BadArgumentError + +import binascii +import hmac +import hashlib +import struct +from typing import ( + Dict, + List, + Optional, + Sequence, + Tuple, +) + + +HARDENED_FLAG = 1 << 31 + +p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F +n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 +G = (0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8) + +Point = Optional[Tuple[int, int]] + +def H_(x: int) -> int: + """ + Shortcut function that "hardens" a number in a BIP44 path. + """ + return x | HARDENED_FLAG + +def is_hardened(i: int) -> bool: + """ + Returns whether an index is hardened + """ + return i & HARDENED_FLAG != 0 + + +def point_add(p1: Point, p2: Point) -> Point: + if (p1 is None): + return p2 + if (p2 is None): + return p1 + if (p1[0] == p2[0] and p1[1] != p2[1]): + return None + if (p1 == p2): + lam = (3 * p1[0] * p1[0] * pow(2 * p1[1], p - 2, p)) % p + else: + lam = ((p2[1] - p1[1]) * pow(p2[0] - p1[0], p - 2, p)) % p + x3 = (lam * lam - p1[0] - p2[0]) % p + return (x3, (lam * (p1[0] - x3) - p1[1]) % p) + + +def point_mul(p: Point, n: int) -> Point: + r = None + for i in range(256): + if ((n >> i) & 1): + r = point_add(r, p) + p = point_add(p, p) + return r + + +def deserialize_point(b: bytes) -> Point: + x = int.from_bytes(b[1:], byteorder="big") + y = pow((x * x * x + 7) % p, (p + 1) // 4, p) + if (y & 1 != b[0] & 1): + y = p - y + return (x, y) + + +def bytes_to_point(point_bytes: bytes) -> Point: + header = point_bytes[0] + if header == 4: + x = point_bytes = point_bytes[1:33] + y = point_bytes = point_bytes[33:65] + return (int(binascii.hexlify(x), 16), int(binascii.hexlify(y), 16)) + return deserialize_point(point_bytes) + +def point_to_bytes(p: Point) -> bytes: + if p is None: + raise ValueError("Cannot convert None to bytes") + return (b'\x03' if p[1] & 1 else b'\x02') + p[0].to_bytes(32, byteorder="big") + +def int_from_bytes(b: bytes) -> int: + return int(binascii.hexlify(b), 16) + +def lift_x(x: int) -> 'Point': + c = (pow(x, 3, p) + 7) % p + y = pow(c, (p + 1) // 4, p) + + assert(c == y * y % p) + + return (x, p - y if y & 1 else y) + +def tagged_hash(tag: str, data: bytes) -> bytes: + hashtag = hashlib.sha256(tag.encode()).digest() + return hashlib.sha256(hashtag + hashtag + data).digest() + + +def taproot_tweak_pubkey(pubkey: bytes, h: bytes) -> Tuple[int, bytes]: + t = int_from_bytes(tagged_hash("TapTweak", pubkey + h)) + if t >= p: + raise ValueError + Q = point_add(lift_x(int_from_bytes(pubkey)), point_mul(G, t)) + return 0 if Q[1] & 1 == 0 else 1, Q[0].to_bytes(32, byteorder="big") + + +def get_taproot_output_key(derived_key: bytes) -> bytes: + assert(len(derived_key) == 33) + p = derived_key[1:] + _, key = taproot_tweak_pubkey(p, b'') + return key + + +# An extended public key (xpub) or private key (xprv). Just a data container for now. +# Only handles deserialization of extended keys into component data to be handled by something else +class ExtendedKey(object): + """ + A BIP 32 extended public key. + """ + + MAINNET_PUBLIC = b'\x04\x88\xB2\x1E' + MAINNET_PRIVATE = b'\x04\x88\xAD\xE4' + TESTNET_PUBLIC = b'\x04\x35\x87\xCF' + TESTNET_PRIVATE = b'\x04\x35\x83\x94' + + def __init__(self, version: bytes, depth: int, parent_fingerprint: bytes, child_num: int, chaincode: bytes, privkey: Optional[bytes], pubkey: bytes) -> None: + """ + :param version: The version bytes for this xpub + :param depth: The depth of this xpub as defined in BIP 32 + :param parent_fingerprint: The 4 byte fingerprint of the parent xpub as defined in BIP 32 + :param child_num: The number of this xpub as defined in BIP 32 + :param chaincode: The chaincode of this xpub as defined in BIP 32 + :param privkey: The private key for this xpub if available + :param pubkey: The public key for this xpub + """ + self.version: bytes = version + self.is_testnet: bool = version == ExtendedKey.TESTNET_PUBLIC or version == ExtendedKey.TESTNET_PRIVATE + self.is_private: bool = version == ExtendedKey.MAINNET_PRIVATE or version == ExtendedKey.TESTNET_PRIVATE + self.depth: int = depth + self.parent_fingerprint: bytes = parent_fingerprint + self.child_num: int = child_num + self.chaincode: bytes = chaincode + self.pubkey: bytes = pubkey + self.privkey: Optional[bytes] = privkey + + @classmethod + def deserialize(cls, xpub: str) -> 'ExtendedKey': + """ + Create an :class:`~ExtendedKey` from a Base58 check encoded xpub + + :param xpub: The Base58 check encoded xpub + """ + data = base58.decode(xpub)[:-4] # Decoded xpub without checksum + return cls.from_bytes(data) + + @classmethod + def from_bytes(cls, data: bytes) -> 'ExtendedKey': + """ + Create an :class:`~ExtendedKey` from a serialized xpub + + :param xpub: The serialized xpub + """ + + version = data[0:4] + if version not in [ExtendedKey.MAINNET_PRIVATE, ExtendedKey.MAINNET_PUBLIC, ExtendedKey.TESTNET_PRIVATE, ExtendedKey.TESTNET_PUBLIC]: + raise BadArgumentError(f"Extended key magic of {version.hex()} is invalid") + is_private = version == ExtendedKey.MAINNET_PRIVATE or version == ExtendedKey.TESTNET_PRIVATE + depth = data[4] + parent_fingerprint = data[5:9] + child_num = struct.unpack('>I', data[9:13])[0] + chaincode = data[13:45] + + if is_private: + privkey = data[46:] + pubkey = point_to_bytes(point_mul(G, int.from_bytes(privkey, byteorder="big"))) + return cls(version, depth, parent_fingerprint, child_num, chaincode, privkey, pubkey) + else: + pubkey = data[45:78] + return cls(version, depth, parent_fingerprint, child_num, chaincode, None, pubkey) + + def serialize(self) -> bytes: + """ + Serialize the ExtendedKey with the serialization format described in BIP 32. + Does not create an xpub string, but the bytes serialized here can be Base58 check encoded into one. + + :return: BIP 32 serialized extended key + """ + r = self.version + struct.pack('B', self.depth) + self.parent_fingerprint + struct.pack('>I', self.child_num) + self.chaincode + if self.is_private: + if self.privkey is None: + raise ValueError("Somehow we are private but don't have a privkey") + r += b"\x00" + self.privkey + else: + r += self.pubkey + return r + + def to_string(self) -> str: + """ + Serialize the ExtendedKey as a Base58 check encoded xpub string + + :return: Base58 check encoded xpub + """ + data = self.serialize() + checksum = hash256(data)[0:4] + return base58.encode(data + checksum) + + def get_printable_dict(self) -> Dict[str, object]: + """ + Get the attributes of this ExtendedKey as a dictionary that can be printed + + :return: Dictionary containing ExtendedKey information that can be printed + """ + d: Dict[str, object] = {} + d['testnet'] = self.is_testnet + d['private'] = self.is_private + d['depth'] = self.depth + d['parent_fingerprint'] = binascii.hexlify(self.parent_fingerprint).decode() + d['child_num'] = self.child_num + d['chaincode'] = binascii.hexlify(self.chaincode).decode() + if self.is_private and isinstance(self.privkey, bytes): + d['privkey'] = binascii.hexlify(self.privkey).decode() + d['pubkey'] = binascii.hexlify(self.pubkey).decode() + return d + + def derive_priv(self, i: int) -> 'ExtendedKey': + """ + Derive the private key at the given child index. + + :param i: The child index of the pubkey to derive + """ + if not self.privkey: + raise ValueError("Can only derive a private key from an extended private key") + + # Data to HMAC + if is_hardened(i): + data = b'\0' + self.privkey + struct.pack(">L", i) + else: + data = self.pubkey + struct.pack(">L", i) + + # Get HMAC of data + Ihmac = hmac.new(self.chaincode, data, hashlib.sha512).digest() + Il = Ihmac[:32] + Ir = Ihmac[32:] + + # Construct new key material from Il and current private key + Il_int = int.from_bytes(Il, byteorder="big") + if Il_int > n: + return None + + privkey_int = int.from_bytes(self.privkey, byteorder="big") + k_int = (Il_int + privkey_int) % n + if (k_int == 0): + return None + + privkey = k_int.to_bytes(32, byteorder="big") + pubkey = point_to_bytes(point_mul(G, k_int)) + + chaincode = Ir + fingerprint = hash160(self.pubkey)[0:4] + return ExtendedKey(ExtendedKey.TESTNET_PRIVATE if self.is_testnet else ExtendedKey.MAINNET_PRIVATE, self.depth + 1, fingerprint, i, chaincode, privkey, pubkey) + + def derive_pub(self, i: int) -> 'ExtendedKey': + """ + Derive the public key at the given child index. + + :param i: The child index of the pubkey to derive + """ + if is_hardened(i): + raise ValueError("Index cannot be larger than 2^31") + + # Data to HMAC. Same as CKDpriv() for public child key. + data = self.pubkey + struct.pack(">L", i) + + # Get HMAC of data + Ihmac = hmac.new(self.chaincode, data, hashlib.sha512).digest() + Il = Ihmac[:32] + Ir = Ihmac[32:] + + # Construct curve point Il*G+K + Il_int = int(binascii.hexlify(Il), 16) + child_pubkey = point_add(point_mul(G, Il_int), bytes_to_point(self.pubkey)) + + # Construct and return a new BIP32Key + pubkey = point_to_bytes(child_pubkey) + chaincode = Ir + fingerprint = hash160(self.pubkey)[0:4] + return ExtendedKey(ExtendedKey.TESTNET_PUBLIC if self.is_testnet else ExtendedKey.MAINNET_PUBLIC, self.depth + 1, fingerprint, i, chaincode, None, pubkey) + + def derive_priv_path(self, path: Sequence[int]) -> 'ExtendedKey': + """ + Derive the private key at the given path + + :param path: Sequence of integers for the path of the key to derive + """ + key = self + for i in path: + key = key.derive_priv(i) + return key + + def derive_pub_path(self, path: Sequence[int]) -> 'ExtendedKey': + """ + Derive the public key at the given path + + :param path: Sequence of integers for the path of the pubkey to derive + """ + key = self + for i in path: + key = key.derive_pub(i) + return key + + def neutered(self) -> 'ExtendedKey': + """ + Returns the public key corresponding to this private key. + """ + if not self.is_private: + raise ValueError("It is already a public key") + + return ExtendedKey(ExtendedKey.TESTNET_PUBLIC if self.is_testnet else ExtendedKey.MAINNET_PUBLIC, self.depth, self.parent_fingerprint, self.child_num, self.chaincode, None, self.pubkey) + + +class KeyOriginInfo(object): + """ + Object representing the origin of a key. + """ + + def __init__(self, fingerprint: bytes, path: Sequence[int]) -> None: + """ + :param fingerprint: The 4 byte BIP 32 fingerprint of a parent key from which this key is derived from + :param path: The derivation path to reach this key from the key at ``fingerprint`` + """ + self.fingerprint: bytes = fingerprint + self.path: Sequence[int] = path + + @classmethod + def deserialize(cls, s: bytes) -> 'KeyOriginInfo': + """ + Deserialize a serialized KeyOriginInfo. + They will be serialized in the same way that PSBTs serialize derivation paths + """ + fingerprint = s[0:4] + s = s[4:] + path = list(struct.unpack("<" + "I" * (len(s) // 4), s)) + return cls(fingerprint, path) + + def serialize(self) -> bytes: + """ + Serializes the KeyOriginInfo in the same way that derivation paths are stored in PSBTs + """ + r = self.fingerprint + r += struct.pack("<" + "I" * len(self.path), *self.path) + return r + + def _path_string(self) -> str: + s = "" + for i in self.path: + hardened = is_hardened(i) + i &= ~HARDENED_FLAG + s += "/" + str(i) + if hardened: + s += "h" + return s + + def to_string(self) -> str: + """ + Return the KeyOriginInfo as a string in the form ///... + This is the same way that KeyOriginInfo is shown in descriptors + """ + s = binascii.hexlify(self.fingerprint).decode() + s += self._path_string() + return s + + @classmethod + def from_string(cls, s: str) -> 'KeyOriginInfo': + """ + Create a KeyOriginInfo from the string + + :param s: The string to parse + """ + s = s.lower() + entries = s.split("/") + fingerprint = binascii.unhexlify(s[0:8]) + path: Sequence[int] = [] + if len(entries) > 1: + path = parse_path(s[9:]) + return cls(fingerprint, path) + + def get_derivation_path(self) -> str: + """ + Return the string for just the path + """ + return "m" + self._path_string() + + def get_full_int_list(self) -> List[int]: + """ + Return a list of ints representing this KeyOriginInfo. + The first int is the fingerprint, followed by the path + """ + xfp = [struct.unpack(" List[int]: + """ + Convert BIP32 path string to list of uint32 integers with hardened flags. + Several conventions are supported to set the hardened flag: -1, 1', 1h + + e.g.: "0/1h/1" -> [0, 0x80000001, 1] + + :param nstr: path string + :return: list of integers + """ + if not nstr: + return [] + + n = nstr.split("/") + + # m/a/b/c => a/b/c + if n[0] == "m": + n = n[1:] + + def str_to_harden(x: str) -> int: + if x.startswith("-"): + return H_(abs(int(x))) + elif x.endswith(("h", "'")): + return H_(int(x[:-1])) + else: + return int(x) + + try: + return [str_to_harden(x) for x in n] + except Exception: + raise ValueError("Invalid BIP32 path", nstr) + + +def get_bip44_purpose(addrtype: AddressType) -> int: + """ + Determine the BIP 44 purpose based on the given :class:`~hwilib.common.AddressType`. + + :param addrtype: The address type + """ + if addrtype == AddressType.LEGACY: + return 44 + elif addrtype == AddressType.SH_WIT: + return 49 + elif addrtype == AddressType.WIT: + return 84 + elif addrtype == AddressType.TAP: + return 86 + else: + raise ValueError("Unknown address type") + + +def get_bip44_chain(chain: Chain) -> int: + """ + Determine the BIP 44 coin type based on the Bitcoin chain type. + + For the Bitcoin mainnet chain, this returns 0. For the other chains, this returns 1. + + :param chain: The chain + """ + if chain == Chain.MAIN: + return 0 + else: + return 1 diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/merkle.py b/test/python/apps/bitcoin_client/ledger_bitcoin/merkle.py new file mode 100644 index 0000000..aa6e1ab --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/merkle.py @@ -0,0 +1,260 @@ +from typing import List, Iterable, Mapping + +from .common import write_varint, sha256 + +NIL = bytes([0] * 32) + + +def floor_lg(n: int) -> int: + """Return floor(log_2(n)) for a positive integer `n`""" + + assert n > 0 + + r = 0 + t = 1 + while 2 * t <= n: + t = 2 * t + r = r + 1 + return r + + +def ceil_lg(n: int) -> int: + """Return ceiling(log_2(n)) for a positive integer `n`.""" + + assert n > 0 + + r = 0 + t = 1 + while t < n: + t = 2 * t + r = r + 1 + return r + + +def is_power_of_2(n: int) -> bool: + """For a positive integer `n`, returns `True` is `n` is a perfect power of 2, `False` otherwise.""" + + assert n >= 1 + + return n & (n - 1) == 0 + + +def largest_power_of_2_less_than(n: int) -> int: + """For an integer `n` which is at least 2, returns the largest exact power of 2 that is strictly less than `n`.""" + + assert n > 1 + + if is_power_of_2(n): + return n // 2 + else: + return 1 << floor_lg(n) + + +def element_hash(element_preimage: bytes) -> bytes: + """Computes the hash of an element to be stored in the Merkle tree.""" + + return sha256(b'\x00' + element_preimage) + + +def combine_hashes(left: bytes, right: bytes) -> bytes: + if len(left) != 32 or len(right) != 32: + raise ValueError("The elements must be 32-bytes sha256 outputs.") + + return sha256(b'\x01' + left + right) + + +# root is the only node with parent == None +# leaves have left == right == None +class Node: + def __init__(self, left, right, parent, value: bytes): + self.left = left + self.right = right + self.parent = parent + self.value = value + + def recompute_value(self): + assert self.left is not None + assert self.right is not None + self.value = combine_hashes(self.left.value, self.right.value) + + def sibling(self): + if self.parent is None: + raise IndexError("The root does not have a sibling.") + + if self.parent.left == self: + return self.parent.right + elif self.parent.right == self: + return self.parent.left + else: + raise IndexError("Invalid state: not a child of his parent.") + + +def make_tree(leaves: List[Node], begin: int, size: int) -> Node: + """Given a list of nodes, builds the left-complete Merkle tree on top of it. + The nodes in `leaves` are modified by setting their `parent` field appropriately. + It returns the root of the newly built tree. + """ + + if size == 0: + return [] + if size == 1: + return leaves[begin] + + lchild_size = largest_power_of_2_less_than(size) + + lchild = make_tree(leaves, begin, lchild_size) + rchild = make_tree(leaves, begin + lchild_size, size - lchild_size) + root = Node(lchild, rchild, None, None) + root.recompute_value() + lchild.parent = rchild.parent = root + return root + + +class MerkleTree: + """ + Maintains a dynamic vector of values and the Merkle tree built on top of it. The elements of the vector are stored + as the leaves of a binary tree. It is possible to add a new element to the vector, or change an existing element; + the hashes in the Merkle tree will be recomputed after each operation in O(log n) time, for a vector with n + elements. + The value of each internal node is the hash of the concatenation of: + - a single byte 0x01; + - the values of the left child; + - the value of the right child. + + The binary tree has the following properties (assuming the vector contains n leaves): + - There are always n - 1 internal nodes; all the internal nodes have exactly two children. + - If a subtree has n > 1 leaves, then the left subchild is a complete subtree with p leaves, where p is the largest + power of 2 smaller than n. + """ + + def __init__(self, elements: Iterable[bytes] = []): + self.leaves = [Node(None, None, None, el) for el in elements] + n_elements = len(self.leaves) + if n_elements > 0: + self.root_node = make_tree(self.leaves, 0, n_elements) + self.depth = ceil_lg(n_elements) + else: + self.root_node = None + self.depth = None + + def __len__(self) -> int: + """Return the total number of leaves in the tree.""" + return len(self.leaves) + + @property + def root(self) -> bytes: + """Return the Merkle root, or None if the tree is empty.""" + return NIL if self.root_node is None else self.root_node.value + + def copy(self): + """Return an identical copy of this Merkle tree.""" + return MerkleTree([leaf.value for leaf in self.leaves]) + + def add(self, x: bytes) -> None: + """Add an element as new leaf, and recompute the tree accordingly. Cost O(log n).""" + + if len(x) != 32: + raise ValueError("Inserted elements must be exactly 32 bytes long") + + new_leaf = Node(None, None, None, x) + self.leaves.append(new_leaf) + if len(self.leaves) == 1: + self.root_node = new_leaf + self.depth = 0 + return + + # add a new leaf + if self.depth == 0: + ltree_size = 0 + else: + # number of leaves of the left subtree of cur_root + ltree_size = 1 << (self.depth - 1) + + cur_root = self.root_node + cur_root_size = len(self.leaves) - 1 + + while not is_power_of_2(cur_root_size): + cur_root = cur_root.right + cur_root_size -= ltree_size + ltree_size /= 2 + + # node value will be computed later + new_node = Node(cur_root, new_leaf, cur_root.parent, None) + if cur_root.parent is None: + # replacing the root + self.depth += 1 + self.root_node = new_node + else: + assert cur_root.parent.right == cur_root + cur_root.parent.right = new_node + cur_root.parent = new_node + new_leaf.parent = new_node + + self.fix_up(new_node) + + def set(self, index: int, x: bytes) -> None: + """ + Set the value of the leaf at position `index` to `x`, recomputing the tree accordingly. + If `index` equals the current number of leaves, then it is equivalent to `add(x)`. + + Cost: Worst case O(log n). + """ + assert 0 <= index <= len(self.leaves) + + if not (0 <= index <= len(self.leaves)): + raise ValueError( + "The index must be at least 0, and at most the current number of leaves.") + + if len(x) != 32: + raise ValueError("Inserted elements must be exactly 32 bytes long.") + + if index == len(self.leaves): + self.add(x) + else: + self.leaves[index].value = x + self.fix_up(self.leaves[index].parent) + + def fix_up(self, node: Node): + while node is not None: + node.recompute_value() + node = node.parent + + def get(self, i: int) -> bytes: + """Return the value of the leaf with index `i`, where 0 <= i < len(self).""" + return self.leaves[i].value + + def leaf_index(self, x: bytes) -> int: + """Return the index of the leaf with hash `x`. Raises `ValueError` if not found.""" + idx = 0 + while idx < len(self): + if self.leaves[idx].value == x: + return idx + idx += 1 + raise ValueError("Leaf not found") + + def prove_leaf(self, index: int) -> List[bytes]: + """Produce the Merkle proof of membership for the leaf with the given index where 0 <= index < len(self).""" + node = self.leaves[index] + proof = [] + while node.parent is not None: + sibling = node.sibling() + assert sibling is not None + + proof.append(sibling.value) + + node = node.parent + + return proof + + +def get_merkleized_map_commitment(mapping: Mapping[bytes, bytes]) -> bytes: + """Returns a serialized Merkleized map commitment, encoded as the concatenation of: + - the number of key/value pairs, as a Bitcoin-style varint; + - the root of the Merkle tree of the keys + - the root of the Merkle tree of the values. + """ + + items_sorted = list(sorted(mapping.items())) + keys_hashes = [element_hash(i[0]) for i in items_sorted] + values_hashes = [element_hash(i[1]) for i in items_sorted] + return write_varint(len(mapping)) + MerkleTree(keys_hashes).root + MerkleTree(values_hashes).root diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/psbt.py b/test/python/apps/bitcoin_client/ledger_bitcoin/psbt.py new file mode 100644 index 0000000..16de47d --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/psbt.py @@ -0,0 +1,1099 @@ +# Original version: https://github.com/bitcoin-core/HWI/blob/3fe369d0379212fae1c72729a179d133b0adc872/hwilib/key.py +# Distributed under the MIT License. + +""" +PSBT Classes and Utilities +************************** +""" + +import base64 +import struct + +from io import BytesIO, BufferedReader +from typing import ( + Dict, + List, + Mapping, + MutableMapping, + Optional, + Sequence, + Set, + Tuple, + Union, +) + +from .key import KeyOriginInfo +from .errors import PSBTSerializationError +from .tx import ( + COutPoint, + CTransaction, + CTxIn, + CTxInWitness, + CTxOut, +) +from ._serialize import ( + deser_compact_size, + deser_string, + Readable, + ser_compact_size, + ser_string, + ser_uint256, + uint256_from_str, +) + +def DeserializeHDKeypath( + f: Readable, + key: bytes, + hd_keypaths: MutableMapping[bytes, KeyOriginInfo], + expected_sizes: Sequence[int], +) -> None: + """ + :meta private: + + Deserialize a serialized PSBT public key and keypath key-value pair. + + :param f: The byte stream to read the value from. + :param key: The bytes of the key of the key-value pair. + :param hd_keypaths: Dictionary of public key bytes to their :class:`~hwilib.key.KeyOriginInfo`. + :param expected_sizes: List of key lengths expected for the keypair being deserialized. + """ + if len(key) not in expected_sizes: + raise PSBTSerializationError("Size of key was not the expected size for the type partial signature pubkey. Length: {}".format(len(key))) + pubkey = key[1:] + if pubkey in hd_keypaths: + raise PSBTSerializationError("Duplicate key, input partial signature for pubkey already provided") + + hd_keypaths[pubkey] = KeyOriginInfo.deserialize(deser_string(f)) + +def SerializeHDKeypath(hd_keypaths: Mapping[bytes, KeyOriginInfo], type: bytes) -> bytes: + """ + :meta private: + + Serialize a public key to :class:`~hwilib.key.KeyOriginInfo` mapping as a PSBT key-value pair. + + :param hd_keypaths: The mapping of public key to keypath + :param type: The PSBT type bytes to use + :returns: The serialized keypaths + """ + r = b"" + for pubkey, path in sorted(hd_keypaths.items()): + r += ser_string(type + pubkey) + packed = path.serialize() + r += ser_string(packed) + return r + +class PartiallySignedInput: + """ + An object for a PSBT input map. + """ + + PSBT_IN_NON_WITNESS_UTXO = 0x00 + PSBT_IN_WITNESS_UTXO = 0x01 + PSBT_IN_PARTIAL_SIG = 0x02 + PSBT_IN_SIGHASH_TYPE = 0x03 + PSBT_IN_REDEEM_SCRIPT = 0x04 + PSBT_IN_WITNESS_SCRIPT = 0x05 + PSBT_IN_BIP32_DERIVATION = 0x06 + PSBT_IN_FINAL_SCRIPTSIG = 0x07 + PSBT_IN_FINAL_SCRIPTWITNESS = 0x08 + PSBT_IN_PREVIOUS_TXID = 0x0e + PSBT_IN_OUTPUT_INDEX = 0x0f + PSBT_IN_SEQUENCE = 0x10 + PSBT_IN_REQUIRED_TIME_LOCKTIME = 0x11 + PSBT_IN_REQUIRED_HEIGHT_LOCKTIME = 0x12 + PSBT_IN_TAP_KEY_SIG = 0x13 + PSBT_IN_TAP_SCRIPT_SIG = 0x14 + PSBT_IN_TAP_LEAF_SCRIPT = 0x15 + PSBT_IN_TAP_BIP32_DERIVATION = 0x16 + PSBT_IN_TAP_INTERNAL_KEY = 0x17 + PSBT_IN_TAP_MERKLE_ROOT = 0x18 + + def __init__(self, version: int) -> None: + self.non_witness_utxo: Optional[CTransaction] = None + self.witness_utxo: Optional[CTxOut] = None + self.partial_sigs: Dict[bytes, bytes] = {} + self.sighash: Optional[int] = None + self.redeem_script = b"" + self.witness_script = b"" + self.hd_keypaths: Dict[bytes, KeyOriginInfo] = {} + self.final_script_sig = b"" + self.final_script_witness = CTxInWitness() + self.prev_txid = b"" + self.prev_out: Optional[int] = None + self.sequence: Optional[int] = None + self.time_locktime: Optional[int] = None + self.height_locktime: Optional[int] = None + self.tap_key_sig = b"" + self.tap_script_sigs: Dict[Tuple[bytes, bytes], bytes] = {} + self.tap_scripts: Dict[Tuple[bytes, int], Set[bytes]] = {} + self.tap_bip32_paths: Dict[bytes, Tuple[Set[bytes], KeyOriginInfo]] = {} + self.tap_internal_key = b"" + self.tap_merkle_root = b"" + self.unknown: Dict[bytes, bytes] = {} + + self.version: int = version + + def set_null(self) -> None: + """ + Clear all values in this PSBT input map. + """ + self.non_witness_utxo = None + self.witness_utxo = None + self.partial_sigs.clear() + self.sighash = None + self.redeem_script = b"" + self.witness_script = b"" + self.hd_keypaths.clear() + self.final_script_sig = b"" + self.final_script_witness = CTxInWitness() + self.tap_key_sig = b"" + self.tap_script_sigs.clear() + self.tap_scripts.clear() + self.tap_bip32_paths.clear() + self.tap_internal_key = b"" + self.tap_merkle_root = b"" + self.prev_txid = b"" + self.prev_out = None + self.sequence = None + self.time_locktime = None + self.height_locktime = None + self.unknown.clear() + + def deserialize(self, f: Readable) -> None: + """ + Deserialize a serialized PSBT input. + + :param f: A byte stream containing the serialized PSBT input + """ + key_lookup: Set[bytes] = set() + + while True: + # read the key + try: + key = deser_string(f) + except Exception: + break + + # Check for separator + if len(key) == 0: + break + + # First byte of key is the type + key_type = deser_compact_size(BytesIO(key)) + + if key_type == PartiallySignedInput.PSBT_IN_NON_WITNESS_UTXO: + if key in key_lookup: + raise PSBTSerializationError("Duplicate Key, input non witness utxo already provided") + elif len(key) != 1: + raise PSBTSerializationError("non witness utxo key is more than one byte type") + self.non_witness_utxo = CTransaction() + utxo_bytes = BufferedReader(BytesIO(deser_string(f))) # type: ignore + self.non_witness_utxo.deserialize(utxo_bytes) + self.non_witness_utxo.rehash() + elif key_type == PartiallySignedInput.PSBT_IN_WITNESS_UTXO: + if key in key_lookup: + raise PSBTSerializationError("Duplicate Key, input witness utxo already provided") + elif len(key) != 1: + raise PSBTSerializationError("witness utxo key is more than one byte type") + self.witness_utxo = CTxOut() + tx_out_bytes = BufferedReader(BytesIO(deser_string(f))) # type: ignore + self.witness_utxo.deserialize(tx_out_bytes) + elif key_type == PartiallySignedInput.PSBT_IN_PARTIAL_SIG: + if len(key) != 34 and len(key) != 66: + raise PSBTSerializationError("Size of key was not the expected size for the type partial signature pubkey") + pubkey = key[1:] + if pubkey in self.partial_sigs: + raise PSBTSerializationError("Duplicate key, input partial signature for pubkey already provided") + + sig = deser_string(f) + self.partial_sigs[pubkey] = sig + elif key_type == PartiallySignedInput.PSBT_IN_SIGHASH_TYPE: + if key in key_lookup: + raise PSBTSerializationError("Duplicate key, input sighash type already provided") + elif len(key) != 1: + raise PSBTSerializationError("sighash key is more than one byte type") + sighash_bytes = deser_string(f) + self.sighash = struct.unpack(" 65: + raise PSBTSerializationError("Input Taproot key path signature is longer than 65 bytes") + elif key_type == PartiallySignedInput.PSBT_IN_TAP_SCRIPT_SIG: + if key in key_lookup: + raise PSBTSerializationError("Duplicate key, input Taproot script signature already provided") + elif len(key) != 65: + raise PSBTSerializationError("Input Taproot script signature key is not 65 bytes") + xonly = key[1:33] + script_hash = key[33:65] + sig = deser_string(f) + if len(sig) < 64: + raise PSBTSerializationError("Input Taproot script path signature is shorter than 64 bytes") + elif len(sig) > 65: + raise PSBTSerializationError("Input Taproot script path signature is longer than 65 bytes") + self.tap_script_sigs[(xonly, script_hash)] = sig + elif key_type == PartiallySignedInput.PSBT_IN_TAP_LEAF_SCRIPT: + if key in key_lookup: + raise PSBTSerializationError("Duplicate key, input Taproot leaf script already provided") + elif len(key) < 34: + raise PSBTSerializationError("Input Taproot leaf script key is not at least 34 bytes") + elif (len(key) - 2) % 32 != 0: + raise PSBTSerializationError("Input Taproot leaf script key's control block is not valid") + script = deser_string(f) + if len(script) == 0: + raise PSBTSerializationError("Input Taproot leaf script cannot be empty") + leaf_script = (script[:-1], int(script[-1])) + if leaf_script not in self.tap_scripts: + self.tap_scripts[leaf_script] = set() + self.tap_scripts[(script[:-1], int(script[-1]))].add(key[1:]) + elif key_type == PartiallySignedInput.PSBT_IN_TAP_BIP32_DERIVATION: + if key in key_lookup: + raise PSBTSerializationError("Duplicate key, input Taproot BIP 32 keypath already provided") + elif len(key) != 33: + raise PSBTSerializationError("Input Taproot BIP 32 keypath key is not 33 bytes") + xonly = key[1:33] + value = deser_string(f) + vs = BytesIO(value) + num_hashes = deser_compact_size(vs) + leaf_hashes = set() + for i in range(0, num_hashes): + leaf_hashes.add(vs.read(32)) + self.tap_bip32_paths[xonly] = (leaf_hashes, KeyOriginInfo.deserialize(vs.read())) + elif key_type == PartiallySignedInput.PSBT_IN_TAP_INTERNAL_KEY: + if key in key_lookup: + raise PSBTSerializationError("Duplicate key, input Taproot internal key already provided") + elif len(key) != 1: + raise PSBTSerializationError("Input Taproot internal key key is more than one byte type") + self.tap_internal_key = deser_string(f) + if len(self.tap_internal_key) != 32: + raise PSBTSerializationError("Input Taproot internal key is not 32 bytes") + elif key_type == PartiallySignedInput.PSBT_IN_TAP_MERKLE_ROOT: + if key in key_lookup: + raise PSBTSerializationError("Duplicate key, input Taproot merkle root already provided") + elif len(key) != 1: + raise PSBTSerializationError("Input Taproot merkle root key is more than one byte type") + self.tap_merkle_root = deser_string(f) + if len(self.tap_merkle_root) != 32: + raise PSBTSerializationError("Input Taproot merkle root is not 32 bytes") + else: + if key in self.unknown: + raise PSBTSerializationError("Duplicate key, key for unknown value already provided") + unknown_bytes = deser_string(f) + self.unknown[key] = unknown_bytes + + key_lookup.add(key) + + # Make sure required PSBTv2 fields are present + if self.version >= 2: + if len(self.prev_txid) == 0: + raise PSBTSerializationError("Previous TXID is required in PSBTv2") + if self.prev_out is None: + raise PSBTSerializationError("Previous output's index is required in PSBTv2") + + def serialize(self) -> bytes: + """ + Serialize this PSBT input + + :returns: The serialized PSBT input + """ + r = b"" + + if self.non_witness_utxo: + r += ser_string(ser_compact_size(PartiallySignedInput.PSBT_IN_NON_WITNESS_UTXO)) + tx = self.non_witness_utxo.serialize_with_witness() + r += ser_string(tx) + + if self.witness_utxo: + r += ser_string(ser_compact_size(PartiallySignedInput.PSBT_IN_WITNESS_UTXO)) + tx = self.witness_utxo.serialize() + r += ser_string(tx) + + if len(self.final_script_sig) == 0 and self.final_script_witness.is_null(): + for pubkey, sig in sorted(self.partial_sigs.items()): + r += ser_string(ser_compact_size(PartiallySignedInput.PSBT_IN_PARTIAL_SIG) + pubkey) + r += ser_string(sig) + + if self.sighash is not None: + r += ser_string(ser_compact_size(PartiallySignedInput.PSBT_IN_SIGHASH_TYPE)) + r += ser_string(struct.pack("= 2: + if len(self.prev_txid) != 0: + r += ser_string(ser_compact_size(PartiallySignedInput.PSBT_IN_PREVIOUS_TXID)) + r += ser_string(self.prev_txid) + + if self.prev_out is not None: + r += ser_string(ser_compact_size(PartiallySignedInput.PSBT_IN_OUTPUT_INDEX)) + r += ser_string(struct.pack(" None: + self.redeem_script = b"" + self.witness_script = b"" + self.hd_keypaths: Dict[bytes, KeyOriginInfo] = {} + self.amount: Optional[int] = None + self.script = b"" + self.tap_internal_key = b"" + self.tap_tree = b"" + self.tap_bip32_paths: Dict[bytes, Tuple[Set[bytes], KeyOriginInfo]] = {} + self.unknown: Dict[bytes, bytes] = {} + + self.version: int = version + + def set_null(self) -> None: + """ + Clear this PSBT output map + """ + self.redeem_script = b"" + self.witness_script = b"" + self.hd_keypaths.clear() + self.tap_internal_key = b"" + self.tap_tree = b"" + self.tap_bip32_paths.clear() + self.amount = None + self.script = b"" + self.unknown.clear() + + def deserialize(self, f: Readable) -> None: + """ + Deserialize a serialized PSBT output map + + :param f: A byte stream containing the serialized PSBT output + """ + key_lookup: Set[bytes] = set() + + while True: + # read the key + try: + key = deser_string(f) + except Exception: + break + + # Check for separator + if len(key) == 0: + break + + # First byte of key is the type + key_type = deser_compact_size(BytesIO(key)) + + if key_type == PartiallySignedOutput.PSBT_OUT_REDEEM_SCRIPT: + if key in key_lookup: + raise PSBTSerializationError("Duplicate key, output redeemScript already provided") + elif len(key) != 1: + raise PSBTSerializationError("Output redeemScript key is more than one byte type") + self.redeem_script = deser_string(f) + elif key_type == PartiallySignedOutput.PSBT_OUT_WITNESS_SCRIPT: + if key in key_lookup: + raise PSBTSerializationError("Duplicate key, output witnessScript already provided") + elif len(key) != 1: + raise PSBTSerializationError("Output witnessScript key is more than one byte type") + self.witness_script = deser_string(f) + elif key_type == PartiallySignedOutput.PSBT_OUT_BIP32_DERIVATION: + DeserializeHDKeypath(f, key, self.hd_keypaths, [34, 66]) + elif key_type == PartiallySignedOutput.PSBT_OUT_AMOUNT: + if key in key_lookup: + raise PSBTSerializationError("Duplicate key, output amount already provided") + elif len(key) != 1: + raise PSBTSerializationError("Output amount key is more than one byte type") + v = deser_string(f) + if len(v) != 8: + raise PSBTSerializationError("Output amount is not 8 bytes") + self.amount = struct.unpack("= 2: + if self.amount is None: + raise PSBTSerializationError("PSBT_OUTPUT_AMOUNT is required in PSBTv2") + if len(self.script) == 0: + raise PSBTSerializationError("PSBT_OUTPUT_SCRIPT is required in PSBTv2") + + def serialize(self) -> bytes: + """ + Serialize this PSBT output + + :returns: The serialized PSBT output + """ + r = b"" + if len(self.redeem_script) != 0: + r += ser_string(ser_compact_size(PartiallySignedOutput.PSBT_OUT_REDEEM_SCRIPT)) + r += ser_string(self.redeem_script) + + if len(self.witness_script) != 0: + r += ser_string(ser_compact_size(PartiallySignedOutput.PSBT_OUT_WITNESS_SCRIPT)) + r += ser_string(self.witness_script) + + r += SerializeHDKeypath(self.hd_keypaths, ser_compact_size(PartiallySignedOutput.PSBT_OUT_BIP32_DERIVATION)) + + if self.version >= 2: + if self.amount is not None: + r += ser_string(ser_compact_size(PartiallySignedOutput.PSBT_OUT_AMOUNT)) + r += ser_string(struct.pack(" CTxOut: + """ + Creates a CTxOut for this output + + :returns: The CTxOut + """ + assert self.amount is not None + assert len(self.script) != 0 + return CTxOut(self.amount, self.script) + +class PSBT(object): + """ + A class representing a PSBT + """ + + PSBT_GLOBAL_UNSIGNED_TX = 0x00 + PSBT_GLOBAL_XPUB = 0x01 + PSBT_GLOBAL_TX_VERSION = 0x02 + PSBT_GLOBAL_FALLBACK_LOCKTIME = 0x03 + PSBT_GLOBAL_INPUT_COUNT = 0x04 + PSBT_GLOBAL_OUTPUT_COUNT = 0x05 + PSBT_GLOBAL_TX_MODIFIABLE = 0x06 + PSBT_GLOBAL_VERSION = 0xFB + + def __init__(self, tx: Optional[CTransaction] = None) -> None: + """ + :param tx: A Bitcoin transaction that specifies the inputs and outputs to use + """ + if tx: + self.tx = tx + else: + self.tx = CTransaction() + self.inputs: List[PartiallySignedInput] = [] + self.outputs: List[PartiallySignedOutput] = [] + self.unknown: Dict[bytes, bytes] = {} + self.xpub: Dict[bytes, KeyOriginInfo] = {} + self.tx_version: Optional[int] = None + self.fallback_locktime: Optional[int] = None + self.tx_modifiable: Optional[int] = None + + # Assume version 0 PSBT + self.version = 0 + self.explicit_version = False + + def deserialize(self, psbt: str) -> None: + """ + Deserialize a base 64 encoded PSBT. + + :param psbt: A base 64 PSBT. + """ + psbt_bytes = base64.b64decode(psbt.strip()) + f = BufferedReader(BytesIO(psbt_bytes)) # type: ignore + end = len(psbt_bytes) + + # Read the magic bytes + magic = f.read(5) + if magic != b"psbt\xff": + raise PSBTSerializationError("invalid magic") + + key_lookup: Set[bytes] = set() + + input_count = None + output_count = None + + # Read loop + while True: + # read the key + try: + key = deser_string(f) + except Exception: + break + + # Check for separator + if len(key) == 0: + break + + # First byte of key is the type + key_type = deser_compact_size(BytesIO(key)) + + # Do stuff based on type + if key_type == PSBT.PSBT_GLOBAL_UNSIGNED_TX: + # Checks for correctness + if key in key_lookup: + raise PSBTSerializationError("Duplicate key, unsigned tx already provided") + elif len(key) > 1: + raise PSBTSerializationError("Global unsigned tx key is more than one byte type") + + # read in value + tx_bytes = BufferedReader(BytesIO(deser_string(f))) # type: ignore + self.tx.deserialize(tx_bytes) + + # Make sure that all scriptSigs and scriptWitnesses are empty + for txin in self.tx.vin: + if len(txin.scriptSig) != 0 or not self.tx.wit.is_null(): + raise PSBTSerializationError("Unsigned tx does not have empty scriptSigs and scriptWitnesses") + elif key_type == PSBT.PSBT_GLOBAL_XPUB: + DeserializeHDKeypath(f, key, self.xpub, [79]) + elif key_type == PSBT.PSBT_GLOBAL_TX_VERSION: + if key in key_lookup: + raise PSBTSerializationError("Duplicate key, global transaction version is already provided") + elif len(key) > 1: + raise PSBTSerializationError("Global transaction version key is more than one byte type") + v = deser_string(f) + if len(v) != 4: + raise PSBTSerializationError("Global transaction version is not 4 bytes") + self.tx_version = struct.unpack(" 1: + raise PSBTSerializationError("Global fallback locktime key is more than one byte type") + v = deser_string(f) + if len(v) != 4: + raise PSBTSerializationError("Global fallback locktime is not 4 bytes") + self.fallback_locktime = struct.unpack(" 1: + raise PSBTSerializationError("Global input count key is more than one byte type") + _ = deser_compact_size(f) # Value length, we can ignore this + input_count = deser_compact_size(f) + elif key_type == PSBT.PSBT_GLOBAL_OUTPUT_COUNT: + if key in key_lookup: + raise PSBTSerializationError("Duplicate key, global output count is already provided") + elif len(key) > 1: + raise PSBTSerializationError("Global output count key is more than one byte type") + _ = deser_compact_size(f) # Value length, we can ignore this + output_count = deser_compact_size(f) + elif key_type == PSBT.PSBT_GLOBAL_TX_MODIFIABLE: + if key in key_lookup: + raise PSBTSerializationError("Duplicate key, global tx modifiable flags is already provided") + elif len(key) > 1: + raise PSBTSerializationError("Global tx modifiable flags key is more than one byte type") + v = deser_string(f) + if len(v) != 1: + raise PSBTSerializationError("Global tx modifiable flags is not 1 bytes") + self.tx_modifiable = struct.unpack(" 1: + raise PSBTSerializationError("Global PSBT version key is more than one byte type") + v = deser_string(f) + if len(v) != 4: + raise PSBTSerializationError("Global PSBT version is not 1 bytes") + self.version = struct.unpack("= 2: + # Tx version, input, and output counts are required + if self.tx_version is None: + raise PSBTSerializationError("PSBT_GLOBAL_TX_VERSION is required in PSBTv2") + if input_count is None: + raise PSBTSerializationError("PSBT_GLOBAL_INPUT_COUNT is required in PSBTv2") + if output_count is None: + raise PSBTSerializationError("PSBT_GLOBAL_OUTPUT_COUNT is required in PSBTv2") + # Unsigned tx is disallowed + if not self.tx.is_null(): + raise PSBTSerializationError("PSBT_GLOBAL_UNSIGNED_TX is not allowed in PSBTv2") + + # Read input data + if input_count is None: + input_count = len(self.tx.vin) + for i in range(input_count): + if f.tell() == end: + break + psbt_in = PartiallySignedInput(self.version) + psbt_in.deserialize(f) + self.inputs.append(psbt_in) + + if self.version >= 2: + prev_txid = psbt_in.prev_txid + else: + prev_txid = ser_uint256(self.tx.vin[i].prevout.hash) + + if psbt_in.non_witness_utxo: + psbt_in.non_witness_utxo.rehash() + if psbt_in.non_witness_utxo.hash != prev_txid: + raise PSBTSerializationError("Non-witness UTXO does not match outpoint hash") + + if (len(self.inputs) != input_count): + raise PSBTSerializationError("Inputs provided does not match the number of inputs in transaction") + + # Read output data + if output_count is None: + output_count = len(self.tx.vout) + for i in range(output_count): + if f.tell() == end: + break + output = PartiallySignedOutput(self.version) + output.deserialize(f) + self.outputs.append(output) + + if len(self.outputs) != output_count: + raise PSBTSerializationError("Outputs provided does not match the number of outputs in transaction") + + self.cache_unsigned_tx_pieces() + + def serialize(self) -> str: + """ + Serialize the PSBT as a base 64 encoded string. + + :returns: The base 64 encoded string. + """ + r = b"" + + # magic bytes + r += b"psbt\xff" + + if self.version == 0: + # unsigned tx flag + r += ser_string(ser_compact_size(PSBT.PSBT_GLOBAL_UNSIGNED_TX)) + + # write serialized tx + tx = self.tx.serialize_with_witness() + r += ser_compact_size(len(tx)) + r += tx + + # write xpubs + r += SerializeHDKeypath(self.xpub, ser_compact_size(PSBT.PSBT_GLOBAL_XPUB)) + + if self.version >= 2: + assert self.tx_version is not None + r += ser_string(ser_compact_size(PSBT.PSBT_GLOBAL_TX_VERSION)) + r += ser_string(struct.pack(" 0 or self.explicit_version: + r += ser_string(ser_compact_size(PSBT.PSBT_GLOBAL_VERSION)) + r += ser_string(struct.pack(" None: + """ + If this PSBT is v0, then the global unsigned transaction will be used to fill in the PSBTv2 + fields so that all users of the PSBT classes can use the same PSBTv2 interface regardless + of PSBT version. + + Does nothing if the PSBT is already v2. + """ + # To make things easier, we split up the global transaction + # and use the PSBTv2 fields for PSBTv0 + if self.tx is not None: + self.setup_from_tx(self.tx) + + def setup_from_tx(self, tx: CTransaction): + """ + Fills in the PSBTv2 fields for this PSBT given a transaction + + :param tx: The CTransaction to fill from + """ + self.tx_version = tx.nVersion + self.fallback_locktime = tx.nLockTime + + for i, txin in enumerate(tx.vin): + psbt_in = self.inputs[i] + + psbt_in.prev_txid = ser_uint256(txin.prevout.hash) + psbt_in.prev_out = txin.prevout.n + psbt_in.sequence = txin.nSequence + + for i, txout in enumerate(tx.vout): + psbt_out = self.outputs[i] + + psbt_out.amount = txout.nValue + psbt_out.script = txout.scriptPubKey + + def compute_lock_time(self) -> int: + """ + Computes the lock time for this transaction + + :returns: The lock time + """ + time_lock: Optional[int] = 0 + height_lock: Optional[int] = 0 + + for psbt_in in self.inputs: + if psbt_in.time_locktime is not None and psbt_in.height_locktime is None: + height_lock = None + if time_lock is None: + raise PSBTSerializationError("Cannot require both time and height locktimes") + elif psbt_in.time_locktime is None and psbt_in.height_locktime is not None: + time_lock = None + if height_lock is None: + raise PSBTSerializationError("Cannot require both time and height locktimes") + + if psbt_in.time_locktime is not None and time_lock is not None: + time_lock = max(time_lock, psbt_in.time_locktime) + if psbt_in.height_locktime is not None and height_lock is not None: + height_lock = max(height_lock, psbt_in.height_locktime) + + if height_lock is not None and height_lock > 0: + return height_lock + if time_lock is not None and time_lock > 0: + return time_lock + if self.fallback_locktime is not None: + return self.fallback_locktime + return 0 + + def get_unsigned_tx(self) -> CTransaction: + """ + Get the unsigned transaction represented by this PSBT + + :return: A CTransaction + """ + if not self.tx.is_null(): + return self.tx + + assert self.tx_version is not None + + tx = CTransaction() + tx.nVersion = self.tx_version + self.nLockTime = self.compute_lock_time() + + for psbt_in in self.inputs: + assert psbt_in.prev_txid is not None + assert psbt_in.prev_out is not None + assert psbt_in.sequence is not None + + txin = CTxIn(COutPoint(uint256_from_str(psbt_in.prev_txid), psbt_in.prev_out), b"", psbt_in.sequence) + tx.vin.append(txin) + + for psbt_out in self.outputs: + assert psbt_out.amount is not None + + txout = CTxOut(psbt_out.amount, psbt_out.script) + tx.vout.append(txout) + + tx.rehash() + return tx + + def _convert_version(self, version) -> None: + self.version = version + for psbt_in in self.inputs: + psbt_in.version = version + for psbt_out in self.outputs: + psbt_out.version = version + + def convert_to_v2(self) -> None: + """ + Sets this PSBT to version 2 + """ + + if self.version == 0: + # make sure fields that PSBT version 0 fields are not present + self.setup_from_tx(self.tx) + + self._convert_version(2) + + def convert_to_v0(self) -> None: + """ + Sets this PSBT to version 0 + """ + + if self.version == 2: + # strip PSBT version 2 fields + self.tx_version = None + self.fallback_locktime = None + self.tx_modifiable = None + + self._convert_version(0) + self.tx = self.get_unsigned_tx() + self.explicit_version = False + + +def normalize_psbt(psbt: Union[PSBT, bytes, str]) -> PSBT: + """ + Deserializes a psbt given as an argument from a string or a byte array, if necessary. + + :param psbt: Either an instance of PSBT, or binary-encoded psbt as `bytes`, or a base64-encoded psbt as a `str`. + :returns: the deserialized PSBT object. If `psbt` was already a `PSBT`, it is returned directly (without cloning). + """ + if isinstance(psbt, bytes): + psbt = base64.b64encode(psbt).decode() + + if isinstance(psbt, str): + psbt_obj = PSBT() + psbt_obj.deserialize(psbt) + psbt = psbt_obj + return psbt diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/py.typed b/test/python/apps/bitcoin_client/ledger_bitcoin/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/ripemd.py b/test/python/apps/bitcoin_client/ledger_bitcoin/ripemd.py new file mode 100644 index 0000000..ee08cc3 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/ripemd.py @@ -0,0 +1,115 @@ +# Copyright (c) 2021 Pieter Wuille +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# +# Taken from https://github.com/bitcoin/bitcoin/blob/124e75a41ea0f3f0e90b63b0c41813184ddce2ab/test/functional/test_framework/ripemd160.py + +""" +Pure Python RIPEMD160 implementation. + +WARNING: This implementation is NOT constant-time. +Do not use without understanding the implications. +""" + +# Message schedule indexes for the left path. +ML = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 +] + +# Message schedule indexes for the right path. +MR = [ + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 +] + +# Rotation counts for the left path. +RL = [ + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 +] + +# Rotation counts for the right path. +RR = [ + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 +] + +# K constants for the left path. +KL = [0, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e] + +# K constants for the right path. +KR = [0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0] + + +def fi(x, y, z, i): + """The f1, f2, f3, f4, and f5 functions from the specification.""" + if i == 0: + return x ^ y ^ z + elif i == 1: + return (x & y) | (~x & z) + elif i == 2: + return (x | ~y) ^ z + elif i == 3: + return (x & z) | (y & ~z) + elif i == 4: + return x ^ (y | ~z) + else: + assert False + + +def rol(x, i): + """Rotate the bottom 32 bits of x left by i bits.""" + return ((x << i) | ((x & 0xffffffff) >> (32 - i))) & 0xffffffff + + +def compress(h0, h1, h2, h3, h4, block): + """Compress state (h0, h1, h2, h3, h4) with block.""" + # Left path variables. + al, bl, cl, dl, el = h0, h1, h2, h3, h4 + # Right path variables. + ar, br, cr, dr, er = h0, h1, h2, h3, h4 + # Message variables. + x = [int.from_bytes(block[4*i:4*(i+1)], 'little') for i in range(16)] + + # Iterate over the 80 rounds of the compression. + for j in range(80): + rnd = j >> 4 + # Perform left side of the transformation. + al = rol(al + fi(bl, cl, dl, rnd) + x[ML[j]] + KL[rnd], RL[j]) + el + al, bl, cl, dl, el = el, al, bl, rol(cl, 10), dl + # Perform right side of the transformation. + ar = rol(ar + fi(br, cr, dr, 4 - rnd) + x[MR[j]] + KR[rnd], RR[j]) + er + ar, br, cr, dr, er = er, ar, br, rol(cr, 10), dr + + # Compose old state, left transform, and right transform into new state. + return h1 + cl + dr, h2 + dl + er, h3 + el + ar, h4 + al + br, h0 + bl + cr + + +def ripemd160(data): + """Compute the RIPEMD-160 hash of data.""" + # Initialize state. + state = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0) + # Process full 64-byte blocks in the input. + for b in range(len(data) >> 6): + state = compress(*state, data[64*b:64*(b+1)]) + # Construct final blocks (with padding and size). + pad = b"\x80" + b"\x00" * ((119 - len(data)) & 63) + fin = data[len(data) & ~63:] + pad + (8 * len(data)).to_bytes(8, 'little') + # Process final blocks. + for b in range(len(fin) >> 6): + state = compress(*state, fin[64*b:64*(b+1)]) + # Produce output. + return b"".join((h & 0xffffffff).to_bytes(4, 'little') for h in state) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/segwit_addr.py b/test/python/apps/bitcoin_client/ledger_bitcoin/segwit_addr.py new file mode 100644 index 0000000..ef41747 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/segwit_addr.py @@ -0,0 +1,137 @@ +# Copyright (c) 2017, 2020 Pieter Wuille +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +"""Reference implementation for Bech32/Bech32m and segwit addresses.""" + + +from enum import Enum + +class Encoding(Enum): + """Enumeration type to list the various supported encodings.""" + BECH32 = 1 + BECH32M = 2 + +CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" +BECH32M_CONST = 0x2bc830a3 + +def bech32_polymod(values): + """Internal function that computes the Bech32 checksum.""" + generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3] + chk = 1 + for value in values: + top = chk >> 25 + chk = (chk & 0x1ffffff) << 5 ^ value + for i in range(5): + chk ^= generator[i] if ((top >> i) & 1) else 0 + return chk + + +def bech32_hrp_expand(hrp): + """Expand the HRP into values for checksum computation.""" + return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp] + + +def bech32_verify_checksum(hrp, data): + """Verify a checksum given HRP and converted data characters.""" + const = bech32_polymod(bech32_hrp_expand(hrp) + data) + if const == 1: + return Encoding.BECH32 + if const == BECH32M_CONST: + return Encoding.BECH32M + return None + +def bech32_create_checksum(hrp, data, spec): + """Compute the checksum values given HRP and data.""" + values = bech32_hrp_expand(hrp) + data + const = BECH32M_CONST if spec == Encoding.BECH32M else 1 + polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ const + return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)] + + +def bech32_encode(hrp, data, spec): + """Compute a Bech32 string given HRP and data values.""" + combined = data + bech32_create_checksum(hrp, data, spec) + return hrp + '1' + ''.join([CHARSET[d] for d in combined]) + +def bech32_decode(bech): + """Validate a Bech32/Bech32m string, and determine HRP and data.""" + if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or + (bech.lower() != bech and bech.upper() != bech)): + return (None, None, None) + bech = bech.lower() + pos = bech.rfind('1') + if pos < 1 or pos + 7 > len(bech) or len(bech) > 90: + return (None, None, None) + if not all(x in CHARSET for x in bech[pos+1:]): + return (None, None, None) + hrp = bech[:pos] + data = [CHARSET.find(x) for x in bech[pos+1:]] + spec = bech32_verify_checksum(hrp, data) + if spec is None: + return (None, None, None) + return (hrp, data[:-6], spec) + +def convertbits(data, frombits, tobits, pad=True): + """General power-of-2 base conversion.""" + acc = 0 + bits = 0 + ret = [] + maxv = (1 << tobits) - 1 + max_acc = (1 << (frombits + tobits - 1)) - 1 + for value in data: + if value < 0 or (value >> frombits): + return None + acc = ((acc << frombits) | value) & max_acc + bits += frombits + while bits >= tobits: + bits -= tobits + ret.append((acc >> bits) & maxv) + if pad: + if bits: + ret.append((acc << (tobits - bits)) & maxv) + elif bits >= frombits or ((acc << (tobits - bits)) & maxv): + return None + return ret + + +def decode(hrp, addr): + """Decode a segwit address.""" + hrpgot, data, spec = bech32_decode(addr) + if hrpgot != hrp: + return (None, None) + decoded = convertbits(data[1:], 5, 8, False) + if decoded is None or len(decoded) < 2 or len(decoded) > 40: + return (None, None) + if data[0] > 16: + return (None, None) + if data[0] == 0 and len(decoded) != 20 and len(decoded) != 32: + return (None, None) + if data[0] == 0 and spec != Encoding.BECH32 or data[0] != 0 and spec != Encoding.BECH32M: + return (None, None) + return (data[0], decoded) + + +def encode(hrp, witver, witprog): + """Encode a segwit address.""" + spec = Encoding.BECH32 if witver == 0 else Encoding.BECH32M + ret = bech32_encode(hrp, [witver] + convertbits(witprog, 8, 5), spec) + if decode(hrp, ret) == (None, None): + return None + return ret \ No newline at end of file diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/tx.py b/test/python/apps/bitcoin_client/ledger_bitcoin/tx.py new file mode 100644 index 0000000..91b1215 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/tx.py @@ -0,0 +1,300 @@ +#!/usr/bin/env python3 +# Copyright (c) 2010 ArtForz -- public domain half-a-node +# Copyright (c) 2012 Jeff Garzik +# Copyright (c) 2010-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Bitcoin Object Python Serializations + +Modified from the test/test_framework/mininode.py file from the +Bitcoin repository + +CTransaction,CTxIn, CTxOut, etc....: + data structures that should map to corresponding structures in + bitcoin/primitives for transactions only +""" + +import copy +import struct + +from .common import ( + hash256, +) +from ._script import ( + is_opreturn, + is_p2sh, + is_p2pkh, + is_p2pk, + is_witness, + is_p2wsh, +) +from ._serialize import ( + deser_uint256, + deser_string, + deser_string_vector, + deser_vector, + Readable, + ser_uint256, + ser_string, + ser_string_vector, + ser_vector, + uint256_from_str, +) + +from typing import ( + List, + Optional, + Tuple, +) + +# Objects that map to bitcoind objects, which can be serialized/deserialized + +MSG_WITNESS_FLAG = 1 << 30 + +class COutPoint(object): + def __init__(self, hash: int = 0, n: int = 0xffffffff): + self.hash = hash + self.n = n + + def deserialize(self, f: Readable) -> None: + self.hash = deser_uint256(f) + self.n = struct.unpack(" bytes: + r = b"" + r += ser_uint256(self.hash) + r += struct.pack(" str: + return "COutPoint(hash=%064x n=%i)" % (self.hash, self.n) + + +class CTxIn(object): + def __init__( + self, + outpoint: Optional[COutPoint] = None, + scriptSig: bytes = b"", + nSequence: int = 0, + ): + if outpoint is None: + self.prevout = COutPoint() + else: + self.prevout = outpoint + self.scriptSig = scriptSig + self.nSequence = nSequence + + def deserialize(self, f: Readable) -> None: + self.prevout = COutPoint() + self.prevout.deserialize(f) + self.scriptSig = deser_string(f) + self.nSequence = struct.unpack(" bytes: + r = b"" + r += self.prevout.serialize() + r += ser_string(self.scriptSig) + r += struct.pack(" str: + return "CTxIn(prevout=%s scriptSig=%s nSequence=%i)" \ + % (repr(self.prevout), self.scriptSig.hex(), + self.nSequence) + + +class CTxOut(object): + def __init__(self, nValue: int = 0, scriptPubKey: bytes = b""): + self.nValue = nValue + self.scriptPubKey = scriptPubKey + + def deserialize(self, f: Readable) -> None: + self.nValue = struct.unpack(" bytes: + r = b"" + r += struct.pack(" bool: + return is_opreturn(self.scriptPubKey) + + def is_p2sh(self) -> bool: + return is_p2sh(self.scriptPubKey) + + def is_p2wsh(self) -> bool: + return is_p2wsh(self.scriptPubKey) + + def is_p2pkh(self) -> bool: + return is_p2pkh(self.scriptPubKey) + + def is_p2pk(self) -> bool: + return is_p2pk(self.scriptPubKey) + + def is_witness(self) -> Tuple[bool, int, bytes]: + return is_witness(self.scriptPubKey) + + def __repr__(self) -> str: + return "CTxOut(nValue=%i.%08i scriptPubKey=%s)" \ + % (self.nValue // 100_000_000, self.nValue % 100_000_000, self.scriptPubKey.hex()) + + +class CScriptWitness(object): + def __init__(self) -> None: + # stack is a vector of strings + self.stack: List[bytes] = [] + + def __repr__(self) -> str: + return "CScriptWitness(%s)" % \ + (",".join([x.hex() for x in self.stack])) + + def is_null(self) -> bool: + if self.stack: + return False + return True + + +class CTxInWitness(object): + def __init__(self) -> None: + self.scriptWitness = CScriptWitness() + + def deserialize(self, f: Readable) -> None: + self.scriptWitness.stack = deser_string_vector(f) + + def serialize(self) -> bytes: + return ser_string_vector(self.scriptWitness.stack) + + def __repr__(self) -> str: + return repr(self.scriptWitness) + + def is_null(self) -> bool: + return self.scriptWitness.is_null() + + +class CTxWitness(object): + def __init__(self) -> None: + self.vtxinwit: List[CTxInWitness] = [] + + def deserialize(self, f: Readable) -> None: + for i in range(len(self.vtxinwit)): + self.vtxinwit[i].deserialize(f) + + def serialize(self) -> bytes: + r = b"" + # This is different than the usual vector serialization -- + # we omit the length of the vector, which is required to be + # the same length as the transaction's vin vector. + for x in self.vtxinwit: + r += x.serialize() + return r + + def __repr__(self) -> str: + return "CTxWitness(%s)" % \ + (';'.join([repr(x) for x in self.vtxinwit])) + + def is_null(self) -> bool: + for x in self.vtxinwit: + if not x.is_null(): + return False + return True + + +class CTransaction(object): + def __init__(self, tx: Optional['CTransaction'] = None) -> None: + if tx is None: + self.nVersion = 1 + self.vin: List[CTxIn] = [] + self.vout: List[CTxOut] = [] + self.wit = CTxWitness() + self.nLockTime = 0 + self.sha256: Optional[int] = None + self.hash: Optional[bytes] = None + else: + self.nVersion = tx.nVersion + self.vin = copy.deepcopy(tx.vin) + self.vout = copy.deepcopy(tx.vout) + self.nLockTime = tx.nLockTime + self.sha256 = tx.sha256 + self.hash = tx.hash + self.wit = copy.deepcopy(tx.wit) + + def deserialize(self, f: Readable) -> None: + self.nVersion = struct.unpack(" bytes: + r = b"" + r += struct.pack(" bytes: + flags = 0 + if not self.wit.is_null(): + flags |= 1 + r = b"" + r += struct.pack(" bytes: + return self.serialize_without_witness() + + # Recalculate the txid (transaction hash without witness) + def rehash(self) -> None: + self.sha256 = None + self.calc_sha256() + + # We will only cache the serialization without witness in + # self.sha256 and self.hash -- those are expected to be the txid. + def calc_sha256(self, with_witness: bool = False) -> Optional[int]: + if with_witness: + # Don't cache the result, just return it + return uint256_from_str(hash256(self.serialize_with_witness())) + + if self.sha256 is None: + self.sha256 = uint256_from_str(hash256(self.serialize_without_witness())) + self.hash = hash256(self.serialize()) + return None + + def is_null(self) -> bool: + return len(self.vin) == 0 and len(self.vout) == 0 + + def __repr__(self) -> str: + return "CTransaction(nVersion=%i vin=%s vout=%s wit=%s nLockTime=%i)" \ + % (self.nVersion, repr(self.vin), repr(self.vout), repr(self.wit), self.nLockTime) diff --git a/test/python/apps/bitcoin_client/ledger_bitcoin/wallet.py b/test/python/apps/bitcoin_client/ledger_bitcoin/wallet.py new file mode 100644 index 0000000..d6ccf43 --- /dev/null +++ b/test/python/apps/bitcoin_client/ledger_bitcoin/wallet.py @@ -0,0 +1,121 @@ +import re + +from enum import IntEnum +from typing import List + +from hashlib import sha256 + +from .common import serialize_str, AddressType, write_varint +from .merkle import MerkleTree, element_hash + +class WalletType(IntEnum): + WALLET_POLICY_V1 = 1 + WALLET_POLICY_V2 = 2 + + +# should not be instantiated directly +class WalletPolicyBase: + def __init__(self, name: str, version: WalletType) -> None: + self.name = name + self.version = version + + if (version != WalletType.WALLET_POLICY_V1 and version != WalletType.WALLET_POLICY_V2): + raise ValueError("Invalid wallet policy version") + + def serialize(self) -> bytes: + return b"".join([ + self.version.value.to_bytes(1, byteorder="big"), + serialize_str(self.name) + ]) + + @property + def id(self) -> bytes: + return sha256(self.serialize()).digest() + + +class WalletPolicy(WalletPolicyBase): + """ + Represents a wallet stored with a wallet policy. + For version V2, the wallet is serialized as follows: + - 1 byte : wallet version + - 1 byte : length of the wallet name (max 64) + - (var) : wallet name (ASCII string) + - (varint) : length of the descriptor template + - 32-bytes : sha256 hash of the descriptor template + - (varint) : number of keys (not larger than 252) + - 32-bytes : root of the Merkle tree of all the keys information. + + The specific format of the keys is deferred to subclasses. + """ + + def __init__(self, name: str, descriptor_template: str, keys_info: List[str], version: WalletType = WalletType.WALLET_POLICY_V2): + super().__init__(name, version) + self.descriptor_template = descriptor_template + self.keys_info = keys_info + + @property + def n_keys(self) -> int: + return len(self.keys_info) + + def serialize(self) -> bytes: + keys_info_hashes = map(lambda k: element_hash(k.encode()), self.keys_info) + + descriptor_template_sha256 = sha256(self.descriptor_template.encode()).digest() + + return b"".join([ + super().serialize(), + write_varint(len(self.descriptor_template.encode())), + self.descriptor_template.encode() if self.version == WalletType.WALLET_POLICY_V1 else descriptor_template_sha256, + write_varint(len(self.keys_info)), + MerkleTree(keys_info_hashes).root + ]) + + def get_descriptor(self, change: bool) -> str: + desc = self.descriptor_template + for i in reversed(range(self.n_keys)): + key = self.keys_info[i] + desc = desc.replace(f"@{i}", key) + + # in V1, /** is part of the key; in V2, it's part of the policy map. This handles either + desc = desc.replace("/**", f"/{1 if change else 0}/*") + + if self.version == WalletType.WALLET_POLICY_V2: + # V2, the / syntax is supported. Replace with M if not change, or with N if change + regex = r"/<(\d+);(\d+)>" + desc = re.sub(regex, "/\\2" if change else "/\\1", desc) + + return desc + +class MultisigWallet(WalletPolicy): + def __init__(self, name: str, address_type: AddressType, threshold: int, keys_info: List[str], sorted: bool = True, version: WalletType = WalletType.WALLET_POLICY_V2) -> None: + n_keys = len(keys_info) + + if not (1 <= threshold <= n_keys <= 16): + raise ValueError("Invalid threshold or number of keys") + + multisig_op = "sortedmulti" if sorted else "multi" + + if (address_type == AddressType.LEGACY): + policy_prefix = f"sh({multisig_op}(" + policy_suffix = f"))" + elif address_type == AddressType.WIT: + policy_prefix = f"wsh({multisig_op}(" + policy_suffix = f"))" + elif address_type == AddressType.SH_WIT: + policy_prefix = f"sh(wsh({multisig_op}(" + policy_suffix = f")))" + else: + raise ValueError(f"Unexpected address type: {address_type}") + + key_placeholder_suffix = "/**" if version == WalletType.WALLET_POLICY_V2 else "" + + descriptor_template = "".join([ + policy_prefix, + str(threshold) + ",", + ",".join("@" + str(l) + key_placeholder_suffix for l in range(n_keys)), + policy_suffix + ]) + + super().__init__(name, descriptor_template, keys_info, version) + + self.threshold = threshold diff --git a/test/python/apps/bitcoin_client/pyproject.toml b/test/python/apps/bitcoin_client/pyproject.toml new file mode 100644 index 0000000..8945516 --- /dev/null +++ b/test/python/apps/bitcoin_client/pyproject.toml @@ -0,0 +1,10 @@ +[build-system] +requires = [ + "bip32~=3.0", + "coincurve~=18.0", + "typing-extensions>=3.7", + "ledgercomm>=1.1.0", + "setuptools>=42", + "wheel" +] +build-backend = "setuptools.build_meta" diff --git a/test/python/apps/bitcoin_client/setup.cfg b/test/python/apps/bitcoin_client/setup.cfg new file mode 100644 index 0000000..21656c8 --- /dev/null +++ b/test/python/apps/bitcoin_client/setup.cfg @@ -0,0 +1,36 @@ +[metadata] +name = ledger_bitcoin +version = attr: ledger_bitcoin.__version__ +author = Ledger +author_email = hello@ledger.fr +description = Client for Ledger Nano Bitcoin application +long_description = file: README.md +long_description_content_type = text/markdown +url = https://github.com/LedgerHQ/app-bitcoin-new +project_urls = + Bug Tracker = https://github.com/LedgerHQ/app-bitcoin-new/issues +classifiers = + Programming Language :: Python :: 3 + License :: OSI Approved :: Apache Software License + Operating System :: OS Independent + +[options] +packages = find: +python_requires = >=3.7 +install_requires= + bip32~=3.0, + coincurve~=18.0, + typing-extensions>=3.7 + ledgercomm>=1.1.0 + packaging>=21.3 + +[options.package_data] +* = py.typed + +[options.extras_require] +hid = hidapi>=0.9.0.post3 + +[options.packages.find] +exclude = + tests + tests.utils diff --git a/test/python/apps/bitcoin_client/txmaker.py b/test/python/apps/bitcoin_client/txmaker.py new file mode 100644 index 0000000..4be633b --- /dev/null +++ b/test/python/apps/bitcoin_client/txmaker.py @@ -0,0 +1,236 @@ +from random import randint + +from typing import List, Tuple, Optional +from ledger_bitcoin import WalletPolicy, WalletType +from ledger_bitcoin.key import KeyOriginInfo, parse_path, get_taproot_output_key +from ledger_bitcoin.psbt import PSBT, PartiallySignedInput, PartiallySignedOutput +from ledger_bitcoin.tx import CScriptWitness, CTransaction, CTxIn, CTxInWitness, CTxOut, COutPoint, CTxWitness, uint256_from_str + +from embit.descriptor import Descriptor +from embit.script import Script +from embit.bip32 import HDKey +from embit.bip39 import mnemonic_to_seed + + +SPECULOS_SEED = "glory promote mansion idle axis finger extra february uncover one trip resource lawn turtle enact monster seven myth punch hobby comfort wild raise skin" +master_key = HDKey.from_seed(mnemonic_to_seed(SPECULOS_SEED)) +master_key_fpr = master_key.derive("m/0'").fingerprint + + +def random_numbers_with_sum(n: int, s: int) -> List[int]: + """Returns a list of n random numbers with sum s.""" + assert n > 1 + + separators = list(sorted([randint(0, s) for _ in range(n - 1)])) + return [ + separators[0], + *[separators[i + 1] - separators[i] + for i in range(len(separators) - 1)], + s - separators[-1] + ] + + +def random_bytes(n: int) -> bytes: + """Returns n random bytes. Not cryptographically secure.""" + return bytes([randint(0, 255) for _ in range(n)]) + + +def random_txid() -> bytes: + """Returns 32 random bytes. Not cryptographically secure.""" + return random_bytes(32) + + +def getScriptPubkeyFromWallet(wallet: WalletPolicy, change: bool, address_index: int) -> Script: + descriptor_str = wallet.descriptor_template + + # Iterate in reverse order, as strings identifying a small-index key (like @1) can be a + # prefix of substrings identifying a large-index key (like @12), but not the other way around + # A more structural parsing would be more robust + for i, key_info_str in enumerate(reversed(wallet.keys_info)): + if wallet.version == WalletType.WALLET_POLICY_V1 and key_info_str[-3:] != "/**": + raise ValueError("All the keys must have wildcard (/**)") + + if f"@{i}" not in descriptor_str: + raise ValueError(f"Invalid policy: not using key @{i}") + + descriptor_str = descriptor_str.replace(f"@{i}", key_info_str) + + # by doing the text substitution of '/**' at the end, this works for either V1 or V2 + descriptor_str = descriptor_str.replace("/**", f"/{1 if change else 0}/*") + + return Descriptor.from_string(descriptor_str).derive(address_index).script_pubkey() + + +def createFakeWalletTransaction(n_inputs: int, n_outputs: int, output_amount: int, wallet: WalletPolicy) -> Tuple[CTransaction, int, int, int]: + """ + Creates a (fake) transaction that has n_inputs inputs and n_outputs outputs, with a random output equal to output_amount. + Each output of the transaction is a spend to wallet (possibly to a change address); the change/address_index of the + derivation of the selected output are also returned. + """ + assert n_inputs > 0 and n_outputs > 0 + + selected_output_index = randint(0, n_outputs - 1) + selected_output_change = randint(0, 1) + selected_output_address_index = randint(0, 10_000) + + vout: List[CTxOut] = [] + for i in range(n_outputs): + if i == selected_output_index: + scriptPubKey: bytes = getScriptPubkeyFromWallet( + wallet, selected_output_change, selected_output_address_index).data + vout.append(CTxOut(output_amount, scriptPubKey)) + else: + # could use any other script for the other outputs; doesn't really matter + scriptPubKey: bytes = getScriptPubkeyFromWallet( + wallet, randint(0, 1), randint(0, 10_000)).data + vout.append(CTxOut(randint(0, 100_000_000), scriptPubKey)) + + vin: List[CTxIn] = [] + for _ in range(n_inputs): + txIn = CTxIn() + txIn.prevout = COutPoint( + uint256_from_str(random_txid()), randint(0, 20)) + txIn.nSequence = 0 + txIn.scriptSig = random_bytes(80) # dummy + vin.append(txIn) + + tx = CTransaction() + tx.vin = vin + tx.vout = vout + tx.nVersion = 2 + tx.nLockTime = 0 + + tx.wit = CTxWitness() + + # if segwit, add witness_utxo + if Script(getScriptPubkeyFromWallet(wallet, 0, 0)).script_type in ["p2wpkh", "p2wsh", "p2tr"]: + for _ in range(n_inputs): + script_wit = CScriptWitness() + script_wit.stack = [random_bytes(64)] # dummy + in_wit = CTxInWitness() + in_wit.scriptWitness = script_wit + tx.wit.vtxinwit.append(in_wit) + + tx.rehash() + + return tx, selected_output_index, selected_output_change, selected_output_address_index + + +def createPsbt(wallet: WalletPolicy, input_amounts: List[int], output_amounts: List[int], output_is_change: List[bool], output_wallet: Optional[List[Optional[WalletPolicy]]] = None) -> PSBT: + if output_wallet is None: + output_wallet = [None] * len(output_amounts) + + assert len(output_amounts) == len(output_is_change) + assert len(output_amounts) == len(output_wallet) + assert sum(output_amounts) <= sum(input_amounts) + + # TODO: add support for wrapped segwit wallets + + if wallet.n_keys != 1: + raise NotImplementedError("Only 1-key wallets supported") + if wallet.version == WalletType.WALLET_POLICY_V1: + if wallet.descriptor_template not in ["pkh(@0)", "wpkh(@0)", "tr(@0)"]: + raise NotImplementedError("Unsupported policy type") + elif wallet.version == WalletType.WALLET_POLICY_V2: + if wallet.descriptor_template not in ["pkh(@0/**)", "wpkh(@0/**)", "tr(@0/**)"]: + raise NotImplementedError("Unsupported policy type") + else: + raise ValueError( + f"Unknown wallet policy version: {wallet.version}") + + vin: List[CTxIn] = [CTxIn() for _ in input_amounts] + vout: List[CTxOut] = [CTxOut() for _ in output_amounts] + + # create some credible prevout transactions + prevouts: List[CTransaction] = [] + prevout_ns: List[int] = [] + prevout_path_change: List[int] = [] + prevout_path_addr_idx: List[int] = [] + for i, prevout_amount in enumerate(input_amounts): + n_inputs = randint(1, 10) + n_outputs = randint(1, 10) + prevout, idx, is_change, addr_idx = createFakeWalletTransaction( + n_inputs, n_outputs, prevout_amount, wallet) + prevouts.append(prevout) + prevout_ns.append(idx) + prevout_path_change.append(is_change) + prevout_path_addr_idx.append(addr_idx) + + vin[i].prevout = COutPoint(prevout.sha256, idx) + vin[i].scriptSig = b'' + vin[i].nSequence = 0 + + psbt = PSBT() + psbt.version = 0 + + tx = CTransaction() + tx.vin = vin + tx.vout = vout + tx.wit = CTxWitness() + + psbt.inputs = [PartiallySignedInput(0) for _ in input_amounts] + psbt.outputs = [PartiallySignedOutput(0) for _ in output_amounts] + + # simplification; good enough for the scripts we support now, but will need more work + is_legacy = wallet.descriptor_template.startswith("pkh(") + is_segwitv0 = wallet.descriptor_template.startswith( + "wpkh(") or wallet.descriptor_template.startswith("sh(wpkh(") + is_taproot = wallet.descriptor_template.startswith("tr(") + + key_origin = wallet.keys_info[0][1:wallet.keys_info[0].index("]")] + + for i in range(len(input_amounts)): + if is_legacy or is_segwitv0: + # add non-witness UTXO + psbt.inputs[i].non_witness_utxo = prevouts[i] + if is_segwitv0 or is_taproot: + # add witness UTXO + psbt.inputs[i].witness_utxo = prevouts[i].vout[prevout_ns[i]] + + path_str = f"m{key_origin[8:]}/{prevout_path_change[i]}/{prevout_path_addr_idx[i]}" + path = parse_path(path_str) + input_key: bytes = master_key.derive(path_str).key.sec() + + assert len(input_key) == 33 + + # add key and path info + if is_legacy or is_segwitv0: + psbt.inputs[i].hd_keypaths[input_key] = KeyOriginInfo( + master_key_fpr, path) + elif is_taproot: + tweaked_key = get_taproot_output_key(input_key) + psbt.inputs[i].tap_bip32_paths[tweaked_key] = ( + list(), KeyOriginInfo(master_key_fpr, path)) + else: + raise RuntimeError("Unexpected state: unknown transaction type") + + for i, output_amount in enumerate(output_amounts): + wallet_i = output_wallet[i] + if output_is_change[i] or wallet_i is None: + script = getScriptPubkeyFromWallet(wallet, output_is_change[i], i) + else: + script = getScriptPubkeyFromWallet(wallet_i, 0, i) + + tx.vout[i].scriptPubKey = script.data + tx.vout[i].nValue = output_amount + + if output_is_change[i]: + path_str = f"m{key_origin[8:]}/1/{i}" + path = parse_path(path_str) + output_key: bytes = master_key.derive(path_str).key.sec() + + # add key and path information for change output + if is_legacy or is_segwitv0: + psbt.outputs[i].hd_keypaths[output_key] = KeyOriginInfo( + master_key_fpr, path) + elif is_taproot: + tweaked_key = get_taproot_output_key(output_key) + psbt.outputs[i].tap_bip32_paths[tweaked_key] = ( + list(), KeyOriginInfo(master_key_fpr, path)) + + psbt.outputs[i].tap_bip32_paths[tweaked_key] = ( + list(), KeyOriginInfo(master_key_fpr, path)) + + psbt.tx = tx + + return psbt diff --git a/test/python/apps/cal.py b/test/python/apps/cal.py index 7c05762..eccacf1 100644 --- a/test/python/apps/cal.py +++ b/test/python/apps/cal.py @@ -14,6 +14,9 @@ from .tezos_legacy import XTZ_PACKED_DERIVATION_PATH, XTZ_CONF from .tezos_new import NTZ_PACKED_DERIVATION_PATH, NTZ_CONF from .bsc import BSC_PACKED_DERIVATION_PATH, BSC_CONF +from .polkadot import DOT_PACKED_DERIVATION_PATH, DOT_CONF +from .tron import TRX_PACKED_DERIVATION_PATH, TRX_CONF +from .tron import TRX_USDT_CONF, TRX_USDC_CONF, TRX_TUSD_CONF, TRX_USDD_CONF TICKER_ID_TO_CONF = { "ETC": ETC_CONF, @@ -26,6 +29,12 @@ "XTZ": XTZ_CONF, "NTZ": NTZ_CONF, "BSC": BSC_CONF, + "DOT": DOT_CONF, + "TRX": TRX_CONF, + "USDT": TRX_USDT_CONF, + "USDC": TRX_USDC_CONF, + "TUSD": TRX_TUSD_CONF, + "USDD": TRX_USDD_CONF, } TICKER_ID_TO_PACKED_DERIVATION_PATH = { @@ -39,19 +48,12 @@ "XTZ": XTZ_PACKED_DERIVATION_PATH, "NTZ": NTZ_PACKED_DERIVATION_PATH, "BSC": BSC_PACKED_DERIVATION_PATH, -} - -TICKER_ID_TO_PACKED_DERIVATION_PATH = { - "ETC": ETC_PACKED_DERIVATION_PATH, - "ETH": ETH_PACKED_DERIVATION_PATH, - "BTC": BTC_PACKED_DERIVATION_PATH, - "LTC": LTC_PACKED_DERIVATION_PATH, - "XLM": XLM_PACKED_DERIVATION_PATH, - "SOL": SOL_PACKED_DERIVATION_PATH, - "XRP": XRP_PACKED_DERIVATION_PATH, - "XTZ": XTZ_PACKED_DERIVATION_PATH, - "NTZ": NTZ_PACKED_DERIVATION_PATH, - "BSC": BSC_PACKED_DERIVATION_PATH, + "DOT": DOT_PACKED_DERIVATION_PATH, + "TRX": TRX_PACKED_DERIVATION_PATH, + "USDT": TRX_PACKED_DERIVATION_PATH, + "USDC": TRX_PACKED_DERIVATION_PATH, + "TUSD": TRX_PACKED_DERIVATION_PATH, + "USDD": TRX_PACKED_DERIVATION_PATH, } # Helper that can be called from outside if we want to generate errors easily diff --git a/test/python/apps/exchange.py b/test/python/apps/exchange.py index ba12824..12f3545 100644 --- a/test/python/apps/exchange.py +++ b/test/python/apps/exchange.py @@ -5,7 +5,7 @@ from ragger.backend.interface import BackendInterface, RAPDU from ..utils import handle_lib_call_start_or_stop, int_to_minimally_sized_bytes, prefix_with_len_custom -from .exchange_transaction_builder import SubCommand, craft_transaction_proposal +from .exchange_transaction_builder import SubCommand MAX_CHUNK_SIZE = 255 @@ -102,14 +102,12 @@ def set_partner_key(self, credentials: bytes) -> RAPDU: def check_partner_key(self, signed_credentials: bytes) -> RAPDU: return self._exchange(Command.CHECK_PARTNER, signed_credentials) - def process_transaction(self, transaction: bytes, fees: int) -> RAPDU: - payload = craft_transaction_proposal(self.subcommand, transaction, fees) - + def process_transaction(self, transaction: bytes) -> RAPDU: if self.subcommand == SubCommand.SWAP or self.subcommand == SubCommand.FUND or self.subcommand == SubCommand.SELL: - return self._exchange(Command.PROCESS_TRANSACTION_RESPONSE, payload=payload) + return self._exchange(Command.PROCESS_TRANSACTION_RESPONSE, payload=transaction) else: - payload_split = [payload[x:x + MAX_CHUNK_SIZE] for x in range(0, len(payload), MAX_CHUNK_SIZE)] + payload_split = [transaction[x:x + MAX_CHUNK_SIZE] for x in range(0, len(transaction), MAX_CHUNK_SIZE)] for i, p in enumerate(payload_split): p2 = self.subcommand # Send all chunks with P2_MORE except for the last chunk diff --git a/test/python/apps/exchange_test_runner.py b/test/python/apps/exchange_test_runner.py index 91640c5..417438e 100644 --- a/test/python/apps/exchange_test_runner.py +++ b/test/python/apps/exchange_test_runner.py @@ -6,7 +6,7 @@ from ragger.error import ExceptionRAPDU from .exchange import ExchangeClient, Rate, SubCommand, Errors -from .exchange_transaction_builder import get_partner_curve, craft_tx, encode_tx, extract_payout_ticker, extract_refund_ticker +from .exchange_transaction_builder import get_partner_curve, extract_payout_ticker, extract_refund_ticker, get_credentials, craft_and_sign_tx from . import cal as cal from .signing_authority import SigningAuthority, LEDGER_SIGNER @@ -36,9 +36,17 @@ class ExchangeTestRunner: # fake_refund_memo: str # fake_payout: str # fake_payout_memo: str + # # signature_refusal_error_code: int - - # You can optionnaly overwrite the following default values if you want + # + # you can override signature_refusal_error_code with specific values + # wrong_method_error_code: int + # wrong_fees_error_code: int + # wrong_memo_error_code: int + # wrong_destination_error_code: int + # wrong_amount_error_code: int + + # You can optionally overwrite the following default values if you want partner_name = "Default name" fund_user_id = "Jon Wick" fund_account_name = "My account 00" @@ -46,10 +54,28 @@ class ExchangeTestRunner: sell_out_currency = "USD" sell_out_amount = {"coefficient": b"\x01", "exponent": 3} + signature_refusal_error_code = None + wrong_method_error_code = None + wrong_fees_error_code = None + wrong_memo_error_code = None + wrong_destination_error_code = None + wrong_amount_error_code = None + def __init__(self, backend, exchange_navigation_helper): self.backend = backend self.exchange_navigation_helper = exchange_navigation_helper + if self.wrong_method_error_code is None: + self.wrong_method_error_code = self.signature_refusal_error_code + if self.wrong_fees_error_code is None: + self.wrong_fees_error_code = self.signature_refusal_error_code + if self.wrong_memo_error_code is None: + self.wrong_memo_error_code = self.signature_refusal_error_code + if self.wrong_destination_error_code is None: + self.wrong_destination_error_code = self.signature_refusal_error_code + if self.wrong_amount_error_code is None: + self.wrong_amount_error_code = self.signature_refusal_error_code + def run_test(self, function_to_test: str): # Remove the flow suffix as the function is the same and the snapshot path is the same too if function_to_test.endswith(TEST_LEGACY_SUFFIX): @@ -72,16 +98,16 @@ def _perform_valid_exchange(self, subcommand, tx_infos, fees, ui_validation): transaction_id = ex.init_transaction().data # Enroll the partner - ex.set_partner_key(partner.credentials) - ex.check_partner_key(LEDGER_SIGNER.sign(partner.credentials)) + credentials = get_credentials(subcommand, partner) + ex.set_partner_key(credentials) + ex.check_partner_key(LEDGER_SIGNER.sign(credentials)) # Craft the exchange transaction proposal and have it signed by the enrolled partner - tx = craft_tx(subcommand, tx_infos, transaction_id) - signed_tx = encode_tx(subcommand, partner, tx) + tx, tx_signature = craft_and_sign_tx(subcommand, tx_infos, transaction_id, fees, partner) # Send the exchange transaction proposal and its signature - ex.process_transaction(tx, fees) - ex.check_transaction_signature(signed_tx) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) # Ask our fake CAL the coin configuration for both payout and refund tickers (None for refund in case of FUND or SELL) payout_ticker = extract_payout_ticker(subcommand, tx_infos) @@ -236,16 +262,17 @@ def perform_test_swap_wrong_fees(self, legacy): self.perform_valid_swap_from_custom(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, self.valid_destination_memo_1, legacy=legacy) with pytest.raises(ExceptionRAPDU) as e: self.perform_coin_specific_final_tx(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_2, self.valid_destination_memo_1) - assert e.value.status == self.signature_refusal_error_code + assert e.value.status == self.wrong_fees_error_code self.assert_exchange_is_started() # Test swap with a malicious TX with tampered memo def perform_test_swap_wrong_memo(self, legacy): - assert self.valid_destination_memo_1 != self.valid_destination_memo_2, "This test won't work if the values are the same" + if self.valid_destination_memo_1 == self.valid_destination_memo_2: + pytest.skip("This test won't work if the values are the same") self.perform_valid_swap_from_custom(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, self.valid_destination_memo_1, legacy=legacy) with pytest.raises(ExceptionRAPDU) as e: self.perform_coin_specific_final_tx(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, self.valid_destination_memo_2) - assert e.value.status == self.signature_refusal_error_code + assert e.value.status == self.wrong_memo_error_code self.assert_exchange_is_started() # Test swap with a malicious TX with tampered destination @@ -254,7 +281,7 @@ def perform_test_swap_wrong_destination(self, legacy): self.perform_valid_swap_from_custom(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, self.valid_destination_memo_1, legacy=legacy) with pytest.raises(ExceptionRAPDU) as e: self.perform_coin_specific_final_tx(self.valid_destination_2, self.valid_send_amount_1, self.valid_fees_1, self.valid_destination_memo_1) - assert e.value.status == self.signature_refusal_error_code + assert e.value.status == self.wrong_destination_error_code self.assert_exchange_is_started() # Test swap with a malicious TX with tampered amount @@ -263,7 +290,7 @@ def perform_test_swap_wrong_amount(self, legacy): self.perform_valid_swap_from_custom(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, self.valid_destination_memo_1, legacy=legacy) with pytest.raises(ExceptionRAPDU) as e: self.perform_coin_specific_final_tx(self.valid_destination_1, self.valid_send_amount_2, self.valid_fees_1, self.valid_destination_memo_1) - assert e.value.status == self.signature_refusal_error_code + assert e.value.status == self.wrong_amount_error_code self.assert_exchange_is_started() ######################################################### @@ -288,7 +315,7 @@ def perform_test_fund_wrong_fees(self, legacy): self.perform_valid_fund_from_custom(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, legacy=legacy) with pytest.raises(ExceptionRAPDU) as e: self.perform_coin_specific_final_tx(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_2, "") - assert e.value.status == self.signature_refusal_error_code + assert e.value.status == self.wrong_fees_error_code self.assert_exchange_is_started() # Test fund with a malicious TX with tampered memo @@ -296,7 +323,7 @@ def perform_test_fund_wrong_memo(self, legacy): self.perform_valid_fund_from_custom(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, legacy=legacy) with pytest.raises(ExceptionRAPDU) as e: self.perform_coin_specific_final_tx(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, "no memo expected") - assert e.value.status == self.signature_refusal_error_code + assert e.value.status == self.wrong_memo_error_code self.assert_exchange_is_started() # Test fund with a malicious TX with tampered destination @@ -305,7 +332,7 @@ def perform_test_fund_wrong_destination(self, legacy): self.perform_valid_fund_from_custom(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, legacy=legacy) with pytest.raises(ExceptionRAPDU) as e: self.perform_coin_specific_final_tx(self.valid_destination_2, self.valid_send_amount_1, self.valid_fees_1, "") - assert e.value.status == self.signature_refusal_error_code + assert e.value.status == self.wrong_destination_error_code self.assert_exchange_is_started() # Test fund with a malicious TX with tampered amount @@ -314,7 +341,7 @@ def perform_test_fund_wrong_amount(self, legacy): self.perform_valid_fund_from_custom(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, legacy=legacy) with pytest.raises(ExceptionRAPDU) as e: self.perform_coin_specific_final_tx(self.valid_destination_1, self.valid_send_amount_2, self.valid_fees_1, "") - assert e.value.status == self.signature_refusal_error_code + assert e.value.status == self.wrong_amount_error_code self.assert_exchange_is_started() ######################################################### @@ -339,7 +366,7 @@ def perform_test_sell_wrong_fees(self, legacy): self.perform_valid_sell_from_custom(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, legacy=legacy) with pytest.raises(ExceptionRAPDU) as e: self.perform_coin_specific_final_tx(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_2, "") - assert e.value.status == self.signature_refusal_error_code + assert e.value.status == self.wrong_fees_error_code self.assert_exchange_is_started() # Test sell with a malicious TX with tampered memo @@ -347,7 +374,7 @@ def perform_test_sell_wrong_memo(self, legacy): self.perform_valid_sell_from_custom(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, legacy=legacy) with pytest.raises(ExceptionRAPDU) as e: self.perform_coin_specific_final_tx(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, "no memo expected") - assert e.value.status == self.signature_refusal_error_code + assert e.value.status == self.wrong_memo_error_code self.assert_exchange_is_started() # Test sell with a malicious TX with tampered destination @@ -356,7 +383,7 @@ def perform_test_sell_wrong_destination(self, legacy): self.perform_valid_sell_from_custom(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, legacy=legacy) with pytest.raises(ExceptionRAPDU) as e: self.perform_coin_specific_final_tx(self.valid_destination_2, self.valid_send_amount_1, self.valid_fees_1, "") - assert e.value.status == self.signature_refusal_error_code + assert e.value.status == self.wrong_destination_error_code self.assert_exchange_is_started() # Test sell with a malicious TX with tampered amount @@ -365,7 +392,7 @@ def perform_test_sell_wrong_amount(self, legacy): self.perform_valid_sell_from_custom(self.valid_destination_1, self.valid_send_amount_1, self.valid_fees_1, legacy=legacy) with pytest.raises(ExceptionRAPDU) as e: self.perform_coin_specific_final_tx(self.valid_destination_1, self.valid_send_amount_2, self.valid_fees_1, "") - assert e.value.status == self.signature_refusal_error_code + assert e.value.status == self.wrong_amount_error_code self.assert_exchange_is_started() # Automatically collect all tests functions and export their name in ready-to-be-parametrized lists @@ -377,7 +404,9 @@ def perform_test_sell_wrong_amount(self, legacy): ALL_TESTS = [x + suffix for x in ALL_TESTS_NAME for suffix in (TEST_LEGACY_SUFFIX, TEST_UNIFIED_SUFFIX)] ALL_TESTS_EXCEPT_MEMO = [test for test in ALL_TESTS if not "memo" in test] +ALL_TESTS_EXCEPT_FEES = [test for test in ALL_TESTS if not "fees" in test] ALL_TESTS_EXCEPT_MEMO_AND_FEES = [test for test in ALL_TESTS if (not "memo" in test and not "fees" in test)] SWAP_TESTS = [test for test in ALL_TESTS if "swap" in test] FUND_TESTS = [test for test in ALL_TESTS if "fund" in test] SELL_TESTS = [test for test in ALL_TESTS if "sell" in test] +VALID_TESTS = [test for test in ALL_TESTS if "valid" in test] diff --git a/test/python/apps/exchange_transaction_builder.py b/test/python/apps/exchange_transaction_builder.py index 2bc5938..eee09d2 100644 --- a/test/python/apps/exchange_transaction_builder.py +++ b/test/python/apps/exchange_transaction_builder.py @@ -1,5 +1,5 @@ from base64 import urlsafe_b64encode -from typing import Optional, Dict, Callable, Iterable +from typing import Optional, Dict, Callable, Iterable, Union from enum import Enum, auto, IntEnum from dataclasses import dataclass from cryptography.hazmat.primitives.asymmetric import ec @@ -44,8 +44,9 @@ class SubCommand(IntEnum): NEW_SUBCOMMANDS = [SubCommand.SWAP_NG, SubCommand.SELL_NG, SubCommand.FUND_NG] ALL_SUBCOMMANDS = [SubCommand.SWAP, SubCommand.SELL, SubCommand.FUND, SubCommand.SWAP_NG, SubCommand.SELL_NG, SubCommand.FUND_NG] -@dataclass(frozen=True) +@dataclass() class SubCommandSpecs: + subcommand_id: SubCommand partner_curve: ec.EllipticCurve signature_computation: SignatureComputation signature_encoding: SignatureEncoding @@ -56,6 +57,22 @@ class SubCommandSpecs: payout_field: str refund_field: Optional[str] + @property + def dot_prefix(self): + return int.to_bytes(1 if (self.signature_computation == SignatureComputation.DOT_PREFIXED_BASE_64_URL) else 0, 1, byteorder='big') + @property + def signature_encoding_prefix(self): + return int.to_bytes(1 if (self.signature_encoding == SignatureEncoding.PLAIN_R_S) else 0, 1, byteorder='big') + @property + def payload_encoding_prefix(self): + return int.to_bytes(1 if (self.payload_encoding == PayloadEncoding.BASE_64_URL) else 0, 1, byteorder='big') + @property + def is_ng(self): + return (self.subcommand_id == SubCommand.SWAP_NG or self.subcommand_id == SubCommand.SELL_NG or self.subcommand_id == SubCommand.FUND_NG) + @property + def size_of_transaction_length(self): + return (2 if self.is_ng else 1) + def check_conf(self, conf: Dict) -> bool: return (all(i in conf for i in self.required_fields) and (len(conf) == len(self.required_fields))) @@ -75,6 +92,10 @@ def encode_signature(self, signature_to_encode: bytes) -> bytes: if self.signature_encoding == SignatureEncoding.PLAIN_R_S: r, s = decode_dss_signature(signature_to_encode) signature_to_encode = r.to_bytes(32, "big") + s.to_bytes(32, "big") + + if self.is_ng: + signature_to_encode = self.dot_prefix + self.signature_encoding_prefix + signature_to_encode + return signature_to_encode def create_transaction(self, conf: Dict, transaction_id: bytes) -> bytes: @@ -84,8 +105,25 @@ def create_transaction(self, conf: Dict, transaction_id: bytes) -> bytes: raw_transaction = self.transaction_type(**c).SerializeToString() return self.encode_payload(raw_transaction) - -SWAP_NG_SPECS: SubCommandSpecs = SubCommandSpecs( + def craft_pb(self, tx_infos: Dict, transaction_id: bytes) -> bytes: + assert self.check_conf(tx_infos) + return self.create_transaction(tx_infos, transaction_id) + + def craft_transaction(self, transaction: bytes, fees: int) -> bytes: + fees_bytes = int_to_minimally_sized_bytes(fees) + payload = prefix_with_len_custom(transaction, self.size_of_transaction_length) + prefix_with_len(fees_bytes) + if self.is_ng: + payload = self.payload_encoding_prefix + payload + return payload + + def encode_transaction_signature(self, signer: SigningAuthority, tx: bytes) -> bytes: + formated_transaction = self.format_transaction(tx) + signed_transaction = signer.sign(formated_transaction) + encoded_signature = self.encode_signature(signed_transaction) + return encoded_signature + +SWAP_NG_SPECS = SubCommandSpecs( + subcommand_id = SubCommand.SWAP_NG, partner_curve = ec.SECP256R1(), signature_computation = SignatureComputation.DOT_PREFIXED_BASE_64_URL, signature_encoding = SignatureEncoding.PLAIN_R_S, @@ -99,7 +137,8 @@ def create_transaction(self, conf: Dict, transaction_id: bytes) -> bytes: refund_field = "currency_from", ) -SWAP_SPECS: SubCommandSpecs = SubCommandSpecs( +SWAP_SPECS = SubCommandSpecs( + subcommand_id = SubCommand.SWAP, partner_curve = ec.SECP256K1(), signature_computation = SignatureComputation.BINARY_ENCODED_PAYLOAD, signature_encoding = SignatureEncoding.DER, @@ -113,7 +152,8 @@ def create_transaction(self, conf: Dict, transaction_id: bytes) -> bytes: refund_field = "currency_from", ) -SELL_NG_SPECS: SubCommandSpecs = SubCommandSpecs( +SELL_NG_SPECS = SubCommandSpecs( + subcommand_id = SubCommand.SELL_NG, partner_curve = ec.SECP256R1(), signature_computation = SignatureComputation.DOT_PREFIXED_BASE_64_URL, signature_encoding = SignatureEncoding.PLAIN_R_S, @@ -125,10 +165,21 @@ def create_transaction(self, conf: Dict, transaction_id: bytes) -> bytes: refund_field = None, ) -# Legacy SELL specs happen to be the same as the unified specs -SELL_SPECS: SubCommandSpecs = SELL_NG_SPECS +SELL_SPECS = SubCommandSpecs( + subcommand_id = SubCommand.SELL, + partner_curve = ec.SECP256R1(), + signature_computation = SignatureComputation.DOT_PREFIXED_BASE_64_URL, + signature_encoding = SignatureEncoding.PLAIN_R_S, + payload_encoding = PayloadEncoding.BASE_64_URL, + transaction_type = NewSellResponse, + transaction_id_field = "device_transaction_id", + required_fields = ["trader_email", "in_currency", "in_amount", "in_address", "out_currency", "out_amount"], + payout_field = "in_currency", + refund_field = None, +) -FUND_NG_SPECS: SubCommandSpecs = SubCommandSpecs( +FUND_NG_SPECS = SubCommandSpecs( + subcommand_id = SubCommand.FUND_NG, partner_curve = ec.SECP256R1(), signature_computation = SignatureComputation.DOT_PREFIXED_BASE_64_URL, signature_encoding = SignatureEncoding.PLAIN_R_S, @@ -140,7 +191,8 @@ def create_transaction(self, conf: Dict, transaction_id: bytes) -> bytes: refund_field = None, ) -FUND_SPECS: SubCommandSpecs = SubCommandSpecs( +FUND_SPECS = SubCommandSpecs( + subcommand_id = SubCommand.FUND, partner_curve = ec.SECP256R1(), signature_computation = SignatureComputation.DOT_PREFIXED_BASE_64_URL, signature_encoding = SignatureEncoding.DER, @@ -161,16 +213,15 @@ def create_transaction(self, conf: Dict, transaction_id: bytes) -> bytes: SubCommand.FUND_NG: FUND_NG_SPECS, } -def craft_tx(subcommand: SubCommand, conf: Dict, transaction_id: bytes) -> bytes: - subcommand_specs = SUBCOMMAND_TO_SPECS[subcommand] - assert subcommand_specs.check_conf(conf) - return subcommand_specs.create_transaction(conf, transaction_id) - -def encode_tx(subcommand: SubCommand, signer: SigningAuthority, tx: bytes) -> bytes: - subcommand_specs = SUBCOMMAND_TO_SPECS[subcommand] - formated_transaction = subcommand_specs.format_transaction(tx) - signed_transaction = signer.sign(formated_transaction) - return subcommand_specs.encode_signature(signed_transaction) +def craft_and_sign_tx(subcommand: Union[SubCommand, SubCommandSpecs], tx_infos: Dict, transaction_id: bytes, fees: int, signer: SigningAuthority): + if isinstance(subcommand, SubCommand): + subcommand_specs = SUBCOMMAND_TO_SPECS[subcommand] + else: + subcommand_specs = subcommand + pb = subcommand_specs.craft_pb(tx_infos, transaction_id) + tx = subcommand_specs.craft_transaction(pb, fees) + signed_tx = subcommand_specs.encode_transaction_signature(signer, pb) + return tx, signed_tx def extract_payout_ticker(subcommand: SubCommand, tx_infos: Dict) -> str: subcommand_specs = SUBCOMMAND_TO_SPECS[subcommand] @@ -186,8 +237,8 @@ def extract_refund_ticker(subcommand: SubCommand, tx_infos: Dict) -> Optional[st def get_partner_curve(subcommand: SubCommand) -> ec.EllipticCurve: return SUBCOMMAND_TO_SPECS[subcommand].partner_curve -def craft_transaction_proposal(subcommand: SubCommand, transaction: bytes, fees: int) -> bytes: - fees_bytes = int_to_minimally_sized_bytes(fees) - prefix_length = 2 if (subcommand == SubCommand.SWAP_NG or subcommand == SubCommand.FUND_NG or subcommand == SubCommand.SELL_NG) else 1 - payload = prefix_with_len_custom(transaction, prefix_length) + prefix_with_len(fees_bytes) - return payload +def get_credentials(subcommand: SubCommand, partner: SigningAuthority) -> bytes: + if subcommand == SubCommand.SWAP_NG or subcommand == SubCommand.SELL_NG or subcommand == SubCommand.FUND_NG: + return partner.credentials_ng + else: + return partner.credentials diff --git a/test/python/apps/polkadot.py b/test/python/apps/polkadot.py new file mode 100644 index 0000000..7ea74f7 --- /dev/null +++ b/test/python/apps/polkadot.py @@ -0,0 +1,151 @@ +import traceback +from enum import IntEnum + +from nacl.encoding import HexEncoder +from nacl.signing import VerifyKey,SigningKey +from nacl.exceptions import BadSignatureError + +from ragger.utils import create_currency_config +from ragger.bip import bitcoin_pack_derivation_path, BtcDerivationPathFormat +from ragger.error import ExceptionRAPDU +from scalecodec.base import RuntimeConfiguration +from scalecodec.type_registry import load_type_registry_preset +from scalecodec.utils.ss58 import ss58_decode + +class Method(IntEnum): + BALANCE_TRANSFER = 0x0500 + BALANCE_FORCE_TRANSFER = 0x0502 + +class AccountIdLookupType(IntEnum): + ID = 0 + INDEX = 1 + RAW = 2 + ADDRESS32 = 3 + ADDRESS20 = 4 + +def _polkadot_address_to_pk(address: str) -> bytes: + return bytes.fromhex(ss58_decode(address)) + +def _format_amount(amount: int) -> bytes: + RuntimeConfiguration().update_type_registry(load_type_registry_preset("legacy")) + obj = RuntimeConfiguration().create_scale_object('Compact') + scale_data = obj.encode(amount) + return bytes(scale_data.get_remaining_bytes()) + +# Not sure what this exactly is but we don't actually care +UNKNOWN = bytes([0x85, 0x02, 0x00, 0x00]) + +SPEC_VERSION = 9360 +TX_VERSION = 24 + +# We don't care about the block hash content +BLOCK_HASH = bytes([0x00] * 32) + +GENESIS_HASH = bytes([ + 0x91, 0xb1, 0x71, 0xbb, 0x15, 0x8e, 0x2d, 0x38, 0x48, 0xfa, + 0x23, 0xa9, 0xf1, 0xc2, 0x51, 0x82, 0xfb, 0x8e, 0x20, 0x31, + 0x3b, 0x2c, 0x1e, 0xb4, 0x92, 0x19, 0xda, 0x7a, 0x70, 0xce, + 0x90, 0xc3, +]) + +ERR_SWAP_CHECK_WRONG_METHOD = 0x6984 +ERR_SWAP_CHECK_WRONG_METHOD_ARGS_CNT = 0x6984 +ERR_SWAP_CHECK_WRONG_DEST_ADDR = 0x6984 +ERR_SWAP_CHECK_WRONG_AMOUNT = 0x6984 + +class Command: + GET_VERSION = 0x00 + GET_ADDRESS = 0x01 + SIGN_TX = 0x02 + +class GetAddrP1: + NO_CONFIRM = 0x00 + CONFIRM = 0x01 + +class SignP1: + INIT = 0x00 + ADD = 0x01 + LAST = 0x02 + +class SignP2Last: + ED25519 = 0x00 + SR25119 = 0x01 + +DOT_CONF = create_currency_config("DOT", "Polkadot", ("DOT", 18)) + +DOT_PACKED_DERIVATION_PATH = bitcoin_pack_derivation_path(BtcDerivationPathFormat.LEGACY, "m/44'/354'/0'/0'/0'") + +DOT_PACKED_DERIVATION_PATH_SIGN_INIT = bytes([0x2c, 0x00, 0x00, 0x80, + 0x62, 0x01, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x80]) + + +class PolkadotClient: + CLA = 0x90 + def __init__(self, client): + self._client = client + + @property + def client(self): + return self._client + + def get_pubkey(self): + msg = self.client.exchange(self.CLA, ins=Command.GET_ADDRESS, p1=0, p2=0, data=DOT_PACKED_DERIVATION_PATH_SIGN_INIT) + return msg.data[:32].hex().encode() + + def sign_init(self): + return self.client.exchange(self.CLA, ins=Command.SIGN_TX, p1=SignP1.INIT, data=DOT_PACKED_DERIVATION_PATH_SIGN_INIT) + + def sign_add(self,tx_chunk): + return self.client.exchange(self.CLA, ins=Command.SIGN_TX, p1=SignP1.ADD,data=tx_chunk) + + def sign_last(self,tx_chunk): + return self.client.exchange(self.CLA, ins=Command.SIGN_TX, p1=SignP1.LAST, p2=SignP2Last.ED25519, data=tx_chunk) + + def verify_signature(self,hex_key:bytes,signature:bytes,message:bytes) -> bool : + # Create a VerifyKey object from a hex serialized public key + verify_key = VerifyKey(hex_key, encoder=HexEncoder) + # Check the validity of a message's signature + try: + verify_key.verify(message, signature, encoder=HexEncoder) + except BadSignatureError: + print("Wrong signature.") + return False + except Exception as e : + print("Something went wrong.") + print(e) + print(traceback.format_exc()) + return False + else: + print("Signature is ok.") + return True + + def craft_valid_polkadot_transaction(address, send_amount, fees, memo) -> bytes: + return Method.BALANCE_TRANSFER.to_bytes(2, "big") \ + + AccountIdLookupType.ID.to_bytes(1, "big") \ + + _polkadot_address_to_pk(address) \ + + _format_amount(send_amount) \ + + UNKNOWN \ + + SPEC_VERSION.to_bytes(4, "little") \ + + TX_VERSION.to_bytes(4, "little") \ + + GENESIS_HASH \ + + BLOCK_HASH + + def craft_invalid_polkadot_transaction(address, send_amount, fees, memo) -> bytes: + force_transfer = Method.BALANCE_FORCE_TRANSFER.to_bytes(2, "big") \ + + bytes([0x00, 0xdc, 0x5a, 0xda, 0x10, 0xee, 0xdd, 0x89, 0x81, 0x92, + 0x78, 0xb0, 0x92, 0x35, 0x87, 0x80, 0x3d, 0x7d, 0xb2, 0x07, + 0xe1, 0xdc, 0x7e, 0x1c, 0x18, 0x42, 0x4f, 0xa4, 0xad, 0x59, + 0xb4, 0x00, 0x19, 0x00, 0xb0, 0x0b, 0x9f, 0x27, 0xc2, 0xd1, + 0xd2, 0x16, 0x01, 0x58, 0x51, 0xdc, 0x3a, 0x69, 0xc8, 0xab, + 0x52, 0xb2, 0x86, 0x62, 0xe7, 0xfa, 0x31, 0x7c, 0x07, 0xad, + 0x1f, 0x34, 0xa4, 0xdf, 0xcd, 0x62, 0x07, 0x70, 0xf9, 0xdb, + 0xdf, 0x02, 0x55, 0x02, 0x00, 0x00]) + + return force_transfer \ + + SPEC_VERSION.to_bytes(4, "little") \ + + TX_VERSION.to_bytes(4, "little") \ + + GENESIS_HASH \ + + BLOCK_HASH diff --git a/test/python/apps/signing_authority.py b/test/python/apps/signing_authority.py index 3f1675e..6b7526d 100644 --- a/test/python/apps/signing_authority.py +++ b/test/python/apps/signing_authority.py @@ -13,6 +13,7 @@ class SigningAuthority: _public_key: dh.DHPublicKey _name: str _credentials: bytes + _credentials_ng: bytes def __init__(self, curve: ec.EllipticCurve, name: str, existing_key: Optional[int] = None): """ @@ -44,19 +45,35 @@ def __init__(self, curve: ec.EllipticCurve, name: str, existing_key: Optional[in ) self._credentials = prefixed_encoded_name + public_bytes + if isinstance(curve, ec.SECP256K1): + curve_id = int.to_bytes(0x00, length=1, byteorder='big') + elif isinstance(curve, ec.SECP256R1): + curve_id = int.to_bytes(0x01, length=1, byteorder='big') + else: + raise ValueError + self._credentials_ng = prefixed_encoded_name + curve_id + public_bytes + @property def credentials(self) -> bytes: """ - :return: The partner credentials correctly formated. + :return: The partner credentials correctly formatted for legacy flows :rtype: bytes """ return self._credentials + @property + def credentials_ng(self) -> bytes: + """ + :return: The partner credentials correctly formatted for ng flows + :rtype: bytes + """ + return self._credentials_ng + def sign(self, payload_to_sign: bytes) -> bytes: """ Sign the requested data - :param payload_to_sign: The payload the parnter needs to sign + :param payload_to_sign: The payload the partner needs to sign :type payload_to_sign: bytes :return: The payload signed diff --git a/test/python/apps/tron.py b/test/python/apps/tron.py new file mode 100644 index 0000000..aef7f9e --- /dev/null +++ b/test/python/apps/tron.py @@ -0,0 +1,184 @@ +import sys +import base58 +from pathlib import Path + +from enum import IntEnum + +from ragger.backend.interface import BackendInterface, RAPDU +from ragger.bip import pack_derivation_path +from ragger.utils import create_currency_config +from ragger.error import ExceptionRAPDU + +sys.path.append(f"{Path(__file__).parent.resolve()}/tron_proto") +''' +Tron Protobuf +''' +from core import Tron_pb2 as tron +from core import Contract_pb2 as Contract +from google.protobuf.any_pb2 import Any + +TRX_CONF = create_currency_config("TRX", "Tron") +TRX_USDT_CONF = create_currency_config("USDT", "Tron", ("USDT", 6)) +TRX_USDC_CONF = create_currency_config("USDC", "Tron", ("USDC", 6)) +TRX_TUSD_CONF = create_currency_config("TUSD", "Tron", ("TUSD", 18)) +TRX_USDD_CONF = create_currency_config("USDD", "Tron", ("USDD", 18)) + +TRX_PACKED_DERIVATION_PATH = pack_derivation_path("m/44'/195'/0'") + +MAX_APDU_LEN: int = 255 +CLA = 0xE0 + + +class InsType(IntEnum): + GET_PUBLIC_KEY = 0x02 + SIGN = 0x04 + SIGN_TXN_HASH = 0x05 # Unsafe + GET_APP_CONFIGURATION = 0x06 # Version and settings + SIGN_PERSONAL_MESSAGE = 0x08 + GET_ECDH_SECRET = 0x0A + + +class P1(): + # GET_PUBLIC_KEY P1 values + CONFIRM = 0x01 + NON_CONFIRM = 0x00 + # SIGN P1 values + SIGN = 0x10 + FIRST = 0x00 + MORE = 0x80 + LAST = 0x90 + TRC10_NAME = 0xA0 + + +class P2(): + # GET_PUBLIC_KEY P2 values + NO_CHAINCODE = 0x00 + CHAINCODE = 0x01 + + +class TronErrors(IntEnum): + SW_DENY = 0x6985 + E_MISSING_SETTING_DATA_ALLOWED = 0x6a8b + SW_SWAP_CHECKING_FAIL = 0x6a8e + + +class TronClient: + def __init__(self, backend: BackendInterface): + if not isinstance(backend, BackendInterface): + raise TypeError("backend must be an instance of BackendInterface") + self._backend = backend + self.owner_address = None + + def _address_hex(self, address): + return base58.b58decode_check(address).hex().upper() + + def parse_get_public_key_response( + self, response: bytes) -> (bytes, str): + # response = public_key_len (1) || + # public_key (var) || + # address_len (1) || + # address (var) + offset: int = 0 + + public_key_len: int = response[offset] + offset += 1 + public_key: bytes = response[offset:offset + public_key_len] + offset += public_key_len + address_len: int = response[offset] + offset += 1 + address: str = response[offset:offset + address_len].decode("ascii") + offset += address_len + + assert len(response) == offset + assert len(public_key) == 65 + + return public_key, address + + def send_get_public_key_non_confirm(self, derivation_path: str) -> RAPDU: + p1 = P1.NON_CONFIRM + p2 = P2.NO_CHAINCODE + payload = pack_derivation_path(derivation_path) + return self._backend.exchange(CLA, InsType.GET_PUBLIC_KEY, p1, p2, + payload) + + def _packContract(self, + contractType, + contract, + data=None, + permission_id=None): + tx = tron.Transaction() + tx.raw_data.timestamp = 1575712492061 + tx.raw_data.expiration = 1575712551000 + tx.raw_data.ref_block_hash = bytes.fromhex("95DA42177DB00507") + tx.raw_data.ref_block_bytes = bytes.fromhex("3DCE") + if data: + tx.raw_data.custom_data = data.encode() + + c = tx.raw_data.contract.add() + c.type = contractType + param = Any() + param.Pack(contract, deterministic=True) + + c.parameter.CopyFrom(param) + + if permission_id: + c.Permission_id = permission_id + return tx.raw_data.SerializeToString() + + def _craft_trx_send_tx(self, memo: str, owner_address: bytes, to_address: bytes, send_amount: int) -> bytes: + contract = Contract.TransferContract(owner_address=owner_address, + to_address=to_address, + amount=send_amount) + + return self._packContract(tron.Transaction.Contract.TransferContract, + contract, + memo) + + def _craft_trc20_send_tx(self, memo: str, owner_address: bytes, to_address: bytes, send_amount: int, token: str) -> bytes: + if token == "USDT": + contract_address = bytes.fromhex("41a614f803b6fd780986a42c78ec9c7f77e6ded13c") + elif token == "USDC": + contract_address = bytes.fromhex("413487b63d30b5b2c87fb7ffa8bcfade38eaac1abe") + elif token == "TUSD": + contract_address = bytes.fromhex("41cebde71077b830b958c8da17bcddeeb85d0bcf25") + elif token == "USDD": + contract_address = bytes.fromhex("4194f24e992ca04b49c6f2a2753076ef8938ed4daa") + else: + assert ValueError("Unsupported token") + + data = bytes.fromhex("a9059cbb") # transfer + data += bytes.fromhex("00" * 11) + data += to_address + data += send_amount.to_bytes(32, "big") + + contract = Contract.TriggerSmartContract(owner_address=owner_address, + contract_address=contract_address, + data=data) + + return self._packContract(tron.Transaction.Contract.TriggerSmartContract, + contract, + memo) + + def send_tx(self, + path: str, + memo: str, + destination: str, + send_amount: int, + token: str) -> RAPDU: + + if not self.owner_address: + rapdu = self.send_get_public_key_non_confirm(path) + _, address = self.parse_get_public_key_response(rapdu.data) + self.owner_address = bytes.fromhex(self._address_hex(address)) + + to_address = bytes.fromhex(self._address_hex(destination)) + + data = pack_derivation_path(path) + + if token == "TRX": + data += self._craft_trx_send_tx(memo, self.owner_address, to_address, send_amount) + else: + data += self._craft_trc20_send_tx(memo, self.owner_address, to_address, send_amount, token) + assert len(data) < MAX_APDU_LEN + + return self._backend.exchange(CLA, InsType.SIGN, P1.SIGN, 0x00, data) diff --git a/test/python/apps/tron_proto/Makefile b/test/python/apps/tron_proto/Makefile new file mode 100644 index 0000000..13e39f2 --- /dev/null +++ b/test/python/apps/tron_proto/Makefile @@ -0,0 +1,19 @@ +include ../nanopb/extra/nanopb.mk + +DEFINES += PB_NO_ERRMSG=1 + +C_TARGETS = core/Tron.pb.c core/Tron.pb.h \ + core/Contract.pb.c core/Contract.pb.h \ + misc/TronApp.pb.c misc/TronApp.pb.h \ + google/protobuf/any.pb.c google/protobuf/any.pb.h + +PY_TARGETS = core/Tron_pb2.py \ + core/Contract_pb2.py \ + misc/TronApp_pb2.py \ + google/protobuf/any_pb2.py + +default: ${C_TARGETS} + python3 -m grpc_tools.protoc -I. --python_out=. ./google/protobuf/*.proto ./core/*.proto + +clean: + rm -f ${C_TARGETS} ${PY_TARGETS} diff --git a/test/python/apps/tron_proto/core/Contract.options b/test/python/apps/tron_proto/core/Contract.options new file mode 100644 index 0000000..ac82d0c --- /dev/null +++ b/test/python/apps/tron_proto/core/Contract.options @@ -0,0 +1,63 @@ +# Address size is 21 + +protocol.AccountUpdateContract.owner_address max_size: 21, fixed_length: true + +protocol.TransferContract.owner_address max_size: 21, fixed_length: true +protocol.TransferContract.to_address max_size: 21, fixed_length: true + +protocol.TransferAssetContract.asset_name max_size: 16 +protocol.TransferAssetContract.owner_address max_size: 21, fixed_length: true +protocol.TransferAssetContract.to_address max_size: 21, fixed_length: true + +protocol.VoteWitnessContract.owner_address max_size: 21, fixed_length: true +protocol.VoteWitnessContract.votes max_count: 5 # Assume 5 votes max +protocol.VoteWitnessContract.Vote.vote_address max_size: 21, fixed_length: true +protocol.VoteWitnessContract.support type: FT_IGNORE + +protocol.FreezeBalanceContract.owner_address max_size: 21, fixed_length: true +protocol.FreezeBalanceContract.receiver_address max_size: 21, fixed_length: true + +protocol.UnfreezeBalanceContract.owner_address max_size: 21, fixed_length: true +protocol.UnfreezeBalanceContract.receiver_address max_size: 21, fixed_length: true + +protocol.FreezeBalanceV2Contract.owner_address max_size: 21, fixed_length: true +protocol.UnfreezeBalanceV2Contract.owner_address max_size: 21, fixed_length: true + +protocol.WithdrawExpireUnfreezeContract.owner_address max_size: 21, fixed_length: true + +protocol.DelegateResourceContract.owner_address max_size: 21, fixed_length: true +protocol.DelegateResourceContract.receiver_address max_size: 21, fixed_length: true + +protocol.UnDelegateResourceContract.owner_address max_size: 21, fixed_length: true +protocol.UnDelegateResourceContract.receiver_address max_size: 21, fixed_length: true + +protocol.WithdrawBalanceContract.owner_address max_size: 21, fixed_length: true + +protocol.ProposalCreateContract.owner_address max_size: 21, fixed_length: true +protocol.ProposalCreateContract.parameters max_count: 10 + +protocol.ProposalApproveContract.owner_address max_size: 21, fixed_length: true + +protocol.ProposalDeleteContract.owner_address max_size: 21, fixed_length: true + +protocol.TriggerSmartContract.owner_address max_size: 21, fixed_length: true +protocol.TriggerSmartContract.contract_address max_size: 21, fixed_length: true +protocol.TriggerSmartContract.data type: FT_CALLBACK + +protocol.ExchangeCreateContract.owner_address max_size: 21, fixed_length: true +protocol.ExchangeCreateContract.first_token_id max_size: 8 +protocol.ExchangeCreateContract.second_token_id max_size: 8 + +protocol.ExchangeInjectContract.owner_address max_size: 21, fixed_length: true +protocol.ExchangeInjectContract.token_id max_size: 8 + +protocol.ExchangeWithdrawContract.owner_address max_size: 21, fixed_length: true +protocol.ExchangeWithdrawContract.token_id max_size: 8 + +protocol.ExchangeTransactionContract.owner_address max_size: 21, fixed_length: true +protocol.ExchangeTransactionContract.token_id max_size: 8 + +protocol.AccountPermissionUpdateContract.owner_address max_size: 21, fixed_length: true +protocol.AccountPermissionUpdateContract.owner type: FT_IGNORE +protocol.AccountPermissionUpdateContract.witness type: FT_IGNORE +protocol.AccountPermissionUpdateContract.actives type: FT_IGNORE diff --git a/test/python/apps/tron_proto/core/Contract.pb.c b/test/python/apps/tron_proto/core/Contract.pb.c new file mode 100644 index 0000000..bd57fe0 --- /dev/null +++ b/test/python/apps/tron_proto/core/Contract.pb.c @@ -0,0 +1,109 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.5 */ + +#include "core/Contract.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(protocol_AccountCreateContract, protocol_AccountCreateContract, AUTO) + + +PB_BIND(protocol_AccountUpdateContract, protocol_AccountUpdateContract, AUTO) + + +PB_BIND(protocol_TransferContract, protocol_TransferContract, AUTO) + + +PB_BIND(protocol_TransferAssetContract, protocol_TransferAssetContract, AUTO) + + +PB_BIND(protocol_VoteAssetContract, protocol_VoteAssetContract, AUTO) + + +PB_BIND(protocol_VoteWitnessContract, protocol_VoteWitnessContract, AUTO) + + +PB_BIND(protocol_VoteWitnessContract_Vote, protocol_VoteWitnessContract_Vote, AUTO) + + +PB_BIND(protocol_WitnessCreateContract, protocol_WitnessCreateContract, AUTO) + + +PB_BIND(protocol_WitnessUpdateContract, protocol_WitnessUpdateContract, AUTO) + + +PB_BIND(protocol_AssetIssueContract, protocol_AssetIssueContract, AUTO) + + +PB_BIND(protocol_AssetIssueContract_FrozenSupply, protocol_AssetIssueContract_FrozenSupply, AUTO) + + +PB_BIND(protocol_ParticipateAssetIssueContract, protocol_ParticipateAssetIssueContract, AUTO) + + +PB_BIND(protocol_DeployContract, protocol_DeployContract, AUTO) + + +PB_BIND(protocol_FreezeBalanceContract, protocol_FreezeBalanceContract, AUTO) + + +PB_BIND(protocol_UnfreezeBalanceContract, protocol_UnfreezeBalanceContract, AUTO) + + +PB_BIND(protocol_FreezeBalanceV2Contract, protocol_FreezeBalanceV2Contract, AUTO) + + +PB_BIND(protocol_UnfreezeBalanceV2Contract, protocol_UnfreezeBalanceV2Contract, AUTO) + + +PB_BIND(protocol_WithdrawExpireUnfreezeContract, protocol_WithdrawExpireUnfreezeContract, AUTO) + + +PB_BIND(protocol_DelegateResourceContract, protocol_DelegateResourceContract, AUTO) + + +PB_BIND(protocol_UnDelegateResourceContract, protocol_UnDelegateResourceContract, AUTO) + + +PB_BIND(protocol_UnfreezeAssetContract, protocol_UnfreezeAssetContract, AUTO) + + +PB_BIND(protocol_WithdrawBalanceContract, protocol_WithdrawBalanceContract, AUTO) + + +PB_BIND(protocol_UpdateAssetContract, protocol_UpdateAssetContract, AUTO) + + +PB_BIND(protocol_ProposalCreateContract, protocol_ProposalCreateContract, AUTO) + + +PB_BIND(protocol_ProposalCreateContract_ParametersEntry, protocol_ProposalCreateContract_ParametersEntry, AUTO) + + +PB_BIND(protocol_ProposalApproveContract, protocol_ProposalApproveContract, AUTO) + + +PB_BIND(protocol_ProposalDeleteContract, protocol_ProposalDeleteContract, AUTO) + + +PB_BIND(protocol_TriggerSmartContract, protocol_TriggerSmartContract, AUTO) + + +PB_BIND(protocol_ExchangeCreateContract, protocol_ExchangeCreateContract, AUTO) + + +PB_BIND(protocol_ExchangeInjectContract, protocol_ExchangeInjectContract, AUTO) + + +PB_BIND(protocol_ExchangeWithdrawContract, protocol_ExchangeWithdrawContract, AUTO) + + +PB_BIND(protocol_ExchangeTransactionContract, protocol_ExchangeTransactionContract, AUTO) + + +PB_BIND(protocol_AccountPermissionUpdateContract, protocol_AccountPermissionUpdateContract, AUTO) + + + + diff --git a/test/python/apps/tron_proto/core/Contract.pb.h b/test/python/apps/tron_proto/core/Contract.pb.h new file mode 100644 index 0000000..c80b38e --- /dev/null +++ b/test/python/apps/tron_proto/core/Contract.pb.h @@ -0,0 +1,792 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.5 */ + +#ifndef PB_PROTOCOL_CORE_CONTRACT_PB_H_INCLUDED +#define PB_PROTOCOL_CORE_CONTRACT_PB_H_INCLUDED +#include +#include "core/Tron.pb.h" + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +typedef enum _protocol_ResourceCode { + protocol_ResourceCode_BANDWIDTH = 0, + protocol_ResourceCode_ENERGY = 1 +} protocol_ResourceCode; + +/* Struct definitions */ +typedef struct _protocol_DeployContract { + pb_callback_t owner_address; + pb_callback_t script; +} protocol_DeployContract; + +typedef struct _protocol_UnfreezeAssetContract { + pb_callback_t owner_address; +} protocol_UnfreezeAssetContract; + +typedef struct _protocol_WitnessCreateContract { + pb_callback_t owner_address; + pb_callback_t url; +} protocol_WitnessCreateContract; + +typedef struct _protocol_WitnessUpdateContract { + pb_callback_t owner_address; + pb_callback_t update_url; +} protocol_WitnessUpdateContract; + +typedef struct _protocol_AccountCreateContract { + pb_callback_t owner_address; + pb_callback_t account_address; + protocol_AccountType type; +} protocol_AccountCreateContract; + +typedef struct _protocol_AccountPermissionUpdateContract { + pb_byte_t owner_address[21]; +} protocol_AccountPermissionUpdateContract; + +/* Update account name. Account name is not unique now. */ +typedef struct _protocol_AccountUpdateContract { + pb_callback_t account_name; + pb_byte_t owner_address[21]; +} protocol_AccountUpdateContract; + +typedef struct _protocol_AssetIssueContract { + pb_callback_t owner_address; + pb_callback_t name; + pb_callback_t abbr; /* the name of target asset */ + int64_t total_supply; /* the amount of drops */ + pb_callback_t frozen_supply; + int32_t trx_num; + int32_t num; + int64_t start_time; + int64_t end_time; + int32_t vote_score; + pb_callback_t description; + pb_callback_t url; + int64_t free_asset_net_limit; + int64_t public_free_asset_net_limit; + int64_t public_free_asset_net_usage; + int64_t public_latest_free_net_time; +} protocol_AssetIssueContract; + +typedef struct _protocol_AssetIssueContract_FrozenSupply { + int64_t frozen_amount; + int64_t frozen_days; +} protocol_AssetIssueContract_FrozenSupply; + +typedef struct _protocol_DelegateResourceContract { + pb_byte_t owner_address[21]; + protocol_ResourceCode resource; + int64_t balance; + pb_byte_t receiver_address[21]; + bool lock; +} protocol_DelegateResourceContract; + +typedef PB_BYTES_ARRAY_T(8) protocol_ExchangeCreateContract_first_token_id_t; +typedef PB_BYTES_ARRAY_T(8) protocol_ExchangeCreateContract_second_token_id_t; +typedef struct _protocol_ExchangeCreateContract { + pb_byte_t owner_address[21]; + protocol_ExchangeCreateContract_first_token_id_t first_token_id; + int64_t first_token_balance; + protocol_ExchangeCreateContract_second_token_id_t second_token_id; + int64_t second_token_balance; +} protocol_ExchangeCreateContract; + +typedef PB_BYTES_ARRAY_T(8) protocol_ExchangeInjectContract_token_id_t; +typedef struct _protocol_ExchangeInjectContract { + pb_byte_t owner_address[21]; + int64_t exchange_id; /* Empty is invalidate */ + protocol_ExchangeInjectContract_token_id_t token_id; /* Can be empty */ + int64_t quant; /* Empty is invalidate */ +} protocol_ExchangeInjectContract; + +typedef PB_BYTES_ARRAY_T(8) protocol_ExchangeTransactionContract_token_id_t; +typedef struct _protocol_ExchangeTransactionContract { + pb_byte_t owner_address[21]; + int64_t exchange_id; + protocol_ExchangeTransactionContract_token_id_t token_id; + int64_t quant; + int64_t expected; +} protocol_ExchangeTransactionContract; + +typedef PB_BYTES_ARRAY_T(8) protocol_ExchangeWithdrawContract_token_id_t; +typedef struct _protocol_ExchangeWithdrawContract { + pb_byte_t owner_address[21]; + int64_t exchange_id; + protocol_ExchangeWithdrawContract_token_id_t token_id; + int64_t quant; +} protocol_ExchangeWithdrawContract; + +typedef struct _protocol_FreezeBalanceContract { + pb_byte_t owner_address[21]; + int64_t frozen_balance; + int64_t frozen_duration; + protocol_ResourceCode resource; + pb_byte_t receiver_address[21]; +} protocol_FreezeBalanceContract; + +typedef struct _protocol_FreezeBalanceV2Contract { + pb_byte_t owner_address[21]; + int64_t frozen_balance; + protocol_ResourceCode resource; +} protocol_FreezeBalanceV2Contract; + +typedef struct _protocol_ParticipateAssetIssueContract { + pb_callback_t owner_address; + pb_callback_t to_address; + pb_callback_t asset_name; + int64_t amount; +} protocol_ParticipateAssetIssueContract; + +typedef struct _protocol_ProposalApproveContract { + pb_byte_t owner_address[21]; + int64_t proposal_id; + bool is_add_approval; +} protocol_ProposalApproveContract; + +typedef struct _protocol_ProposalCreateContract_ParametersEntry { + int64_t key; + int64_t value; +} protocol_ProposalCreateContract_ParametersEntry; + +typedef struct _protocol_ProposalDeleteContract { + pb_byte_t owner_address[21]; + int64_t proposal_id; +} protocol_ProposalDeleteContract; + +typedef PB_BYTES_ARRAY_T(16) protocol_TransferAssetContract_asset_name_t; +typedef struct _protocol_TransferAssetContract { + protocol_TransferAssetContract_asset_name_t asset_name; + pb_byte_t owner_address[21]; + pb_byte_t to_address[21]; + int64_t amount; +} protocol_TransferAssetContract; + +typedef struct _protocol_TransferContract { + pb_byte_t owner_address[21]; + pb_byte_t to_address[21]; + int64_t amount; +} protocol_TransferContract; + +typedef struct _protocol_TriggerSmartContract { + pb_byte_t owner_address[21]; + pb_byte_t contract_address[21]; + int64_t call_value; + pb_callback_t data; + int64_t call_token_value; + int64_t token_id; +} protocol_TriggerSmartContract; + +typedef struct _protocol_UnDelegateResourceContract { + pb_byte_t owner_address[21]; + protocol_ResourceCode resource; + int64_t balance; + pb_byte_t receiver_address[21]; +} protocol_UnDelegateResourceContract; + +typedef struct _protocol_UnfreezeBalanceContract { + pb_byte_t owner_address[21]; + protocol_ResourceCode resource; + pb_byte_t receiver_address[21]; +} protocol_UnfreezeBalanceContract; + +typedef struct _protocol_UnfreezeBalanceV2Contract { + pb_byte_t owner_address[21]; + int64_t unfreeze_balance; + protocol_ResourceCode resource; +} protocol_UnfreezeBalanceV2Contract; + +typedef struct _protocol_UpdateAssetContract { + pb_callback_t owner_address; + pb_callback_t description; + pb_callback_t url; /* add or remove approval */ + int64_t new_limit; + int64_t new_public_limit; +} protocol_UpdateAssetContract; + +typedef struct _protocol_VoteAssetContract { + pb_callback_t owner_address; + pb_callback_t vote_address; + bool support; + int32_t count; +} protocol_VoteAssetContract; + +typedef struct _protocol_VoteWitnessContract_Vote { + pb_byte_t vote_address[21]; + int64_t vote_count; +} protocol_VoteWitnessContract_Vote; + +typedef struct _protocol_WithdrawBalanceContract { + pb_byte_t owner_address[21]; +} protocol_WithdrawBalanceContract; + +typedef struct _protocol_WithdrawExpireUnfreezeContract { + pb_byte_t owner_address[21]; +} protocol_WithdrawExpireUnfreezeContract; + +typedef struct _protocol_ProposalCreateContract { + pb_byte_t owner_address[21]; + pb_size_t parameters_count; + protocol_ProposalCreateContract_ParametersEntry parameters[10]; +} protocol_ProposalCreateContract; + +typedef struct _protocol_VoteWitnessContract { + pb_byte_t owner_address[21]; + pb_size_t votes_count; + protocol_VoteWitnessContract_Vote votes[5]; +} protocol_VoteWitnessContract; + + +/* Helper constants for enums */ +#define _protocol_ResourceCode_MIN protocol_ResourceCode_BANDWIDTH +#define _protocol_ResourceCode_MAX protocol_ResourceCode_ENERGY +#define _protocol_ResourceCode_ARRAYSIZE ((protocol_ResourceCode)(protocol_ResourceCode_ENERGY+1)) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define protocol_AccountCreateContract_init_default {{{NULL}, NULL}, {{NULL}, NULL}, _protocol_AccountType_MIN} +#define protocol_AccountUpdateContract_init_default {{{NULL}, NULL}, {0}} +#define protocol_TransferContract_init_default {{0}, {0}, 0} +#define protocol_TransferAssetContract_init_default {{0, {0}}, {0}, {0}, 0} +#define protocol_VoteAssetContract_init_default {{{NULL}, NULL}, {{NULL}, NULL}, 0, 0} +#define protocol_VoteWitnessContract_init_default {{0}, 0, {protocol_VoteWitnessContract_Vote_init_default, protocol_VoteWitnessContract_Vote_init_default, protocol_VoteWitnessContract_Vote_init_default, protocol_VoteWitnessContract_Vote_init_default, protocol_VoteWitnessContract_Vote_init_default}} +#define protocol_VoteWitnessContract_Vote_init_default {{0}, 0} +#define protocol_WitnessCreateContract_init_default {{{NULL}, NULL}, {{NULL}, NULL}} +#define protocol_WitnessUpdateContract_init_default {{{NULL}, NULL}, {{NULL}, NULL}} +#define protocol_AssetIssueContract_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, 0, {{NULL}, NULL}, 0, 0, 0, 0, 0, {{NULL}, NULL}, {{NULL}, NULL}, 0, 0, 0, 0} +#define protocol_AssetIssueContract_FrozenSupply_init_default {0, 0} +#define protocol_ParticipateAssetIssueContract_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, 0} +#define protocol_DeployContract_init_default {{{NULL}, NULL}, {{NULL}, NULL}} +#define protocol_FreezeBalanceContract_init_default {{0}, 0, 0, _protocol_ResourceCode_MIN, {0}} +#define protocol_UnfreezeBalanceContract_init_default {{0}, _protocol_ResourceCode_MIN, {0}} +#define protocol_FreezeBalanceV2Contract_init_default {{0}, 0, _protocol_ResourceCode_MIN} +#define protocol_UnfreezeBalanceV2Contract_init_default {{0}, 0, _protocol_ResourceCode_MIN} +#define protocol_WithdrawExpireUnfreezeContract_init_default {{0}} +#define protocol_DelegateResourceContract_init_default {{0}, _protocol_ResourceCode_MIN, 0, {0}, 0} +#define protocol_UnDelegateResourceContract_init_default {{0}, _protocol_ResourceCode_MIN, 0, {0}} +#define protocol_UnfreezeAssetContract_init_default {{{NULL}, NULL}} +#define protocol_WithdrawBalanceContract_init_default {{0}} +#define protocol_UpdateAssetContract_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, 0, 0} +#define protocol_ProposalCreateContract_init_default {{0}, 0, {protocol_ProposalCreateContract_ParametersEntry_init_default, protocol_ProposalCreateContract_ParametersEntry_init_default, protocol_ProposalCreateContract_ParametersEntry_init_default, protocol_ProposalCreateContract_ParametersEntry_init_default, protocol_ProposalCreateContract_ParametersEntry_init_default, protocol_ProposalCreateContract_ParametersEntry_init_default, protocol_ProposalCreateContract_ParametersEntry_init_default, protocol_ProposalCreateContract_ParametersEntry_init_default, protocol_ProposalCreateContract_ParametersEntry_init_default, protocol_ProposalCreateContract_ParametersEntry_init_default}} +#define protocol_ProposalCreateContract_ParametersEntry_init_default {0, 0} +#define protocol_ProposalApproveContract_init_default {{0}, 0, 0} +#define protocol_ProposalDeleteContract_init_default {{0}, 0} +#define protocol_TriggerSmartContract_init_default {{0}, {0}, 0, {{NULL}, NULL}, 0, 0} +#define protocol_ExchangeCreateContract_init_default {{0}, {0, {0}}, 0, {0, {0}}, 0} +#define protocol_ExchangeInjectContract_init_default {{0}, 0, {0, {0}}, 0} +#define protocol_ExchangeWithdrawContract_init_default {{0}, 0, {0, {0}}, 0} +#define protocol_ExchangeTransactionContract_init_default {{0}, 0, {0, {0}}, 0, 0} +#define protocol_AccountPermissionUpdateContract_init_default {{0}} +#define protocol_AccountCreateContract_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, _protocol_AccountType_MIN} +#define protocol_AccountUpdateContract_init_zero {{{NULL}, NULL}, {0}} +#define protocol_TransferContract_init_zero {{0}, {0}, 0} +#define protocol_TransferAssetContract_init_zero {{0, {0}}, {0}, {0}, 0} +#define protocol_VoteAssetContract_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, 0, 0} +#define protocol_VoteWitnessContract_init_zero {{0}, 0, {protocol_VoteWitnessContract_Vote_init_zero, protocol_VoteWitnessContract_Vote_init_zero, protocol_VoteWitnessContract_Vote_init_zero, protocol_VoteWitnessContract_Vote_init_zero, protocol_VoteWitnessContract_Vote_init_zero}} +#define protocol_VoteWitnessContract_Vote_init_zero {{0}, 0} +#define protocol_WitnessCreateContract_init_zero {{{NULL}, NULL}, {{NULL}, NULL}} +#define protocol_WitnessUpdateContract_init_zero {{{NULL}, NULL}, {{NULL}, NULL}} +#define protocol_AssetIssueContract_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, 0, {{NULL}, NULL}, 0, 0, 0, 0, 0, {{NULL}, NULL}, {{NULL}, NULL}, 0, 0, 0, 0} +#define protocol_AssetIssueContract_FrozenSupply_init_zero {0, 0} +#define protocol_ParticipateAssetIssueContract_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, 0} +#define protocol_DeployContract_init_zero {{{NULL}, NULL}, {{NULL}, NULL}} +#define protocol_FreezeBalanceContract_init_zero {{0}, 0, 0, _protocol_ResourceCode_MIN, {0}} +#define protocol_UnfreezeBalanceContract_init_zero {{0}, _protocol_ResourceCode_MIN, {0}} +#define protocol_FreezeBalanceV2Contract_init_zero {{0}, 0, _protocol_ResourceCode_MIN} +#define protocol_UnfreezeBalanceV2Contract_init_zero {{0}, 0, _protocol_ResourceCode_MIN} +#define protocol_WithdrawExpireUnfreezeContract_init_zero {{0}} +#define protocol_DelegateResourceContract_init_zero {{0}, _protocol_ResourceCode_MIN, 0, {0}, 0} +#define protocol_UnDelegateResourceContract_init_zero {{0}, _protocol_ResourceCode_MIN, 0, {0}} +#define protocol_UnfreezeAssetContract_init_zero {{{NULL}, NULL}} +#define protocol_WithdrawBalanceContract_init_zero {{0}} +#define protocol_UpdateAssetContract_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, 0, 0} +#define protocol_ProposalCreateContract_init_zero {{0}, 0, {protocol_ProposalCreateContract_ParametersEntry_init_zero, protocol_ProposalCreateContract_ParametersEntry_init_zero, protocol_ProposalCreateContract_ParametersEntry_init_zero, protocol_ProposalCreateContract_ParametersEntry_init_zero, protocol_ProposalCreateContract_ParametersEntry_init_zero, protocol_ProposalCreateContract_ParametersEntry_init_zero, protocol_ProposalCreateContract_ParametersEntry_init_zero, protocol_ProposalCreateContract_ParametersEntry_init_zero, protocol_ProposalCreateContract_ParametersEntry_init_zero, protocol_ProposalCreateContract_ParametersEntry_init_zero}} +#define protocol_ProposalCreateContract_ParametersEntry_init_zero {0, 0} +#define protocol_ProposalApproveContract_init_zero {{0}, 0, 0} +#define protocol_ProposalDeleteContract_init_zero {{0}, 0} +#define protocol_TriggerSmartContract_init_zero {{0}, {0}, 0, {{NULL}, NULL}, 0, 0} +#define protocol_ExchangeCreateContract_init_zero {{0}, {0, {0}}, 0, {0, {0}}, 0} +#define protocol_ExchangeInjectContract_init_zero {{0}, 0, {0, {0}}, 0} +#define protocol_ExchangeWithdrawContract_init_zero {{0}, 0, {0, {0}}, 0} +#define protocol_ExchangeTransactionContract_init_zero {{0}, 0, {0, {0}}, 0, 0} +#define protocol_AccountPermissionUpdateContract_init_zero {{0}} + +/* Field tags (for use in manual encoding/decoding) */ +#define protocol_DeployContract_owner_address_tag 1 +#define protocol_DeployContract_script_tag 2 +#define protocol_UnfreezeAssetContract_owner_address_tag 1 +#define protocol_WitnessCreateContract_owner_address_tag 1 +#define protocol_WitnessCreateContract_url_tag 2 +#define protocol_WitnessUpdateContract_owner_address_tag 1 +#define protocol_WitnessUpdateContract_update_url_tag 12 +#define protocol_AccountCreateContract_owner_address_tag 1 +#define protocol_AccountCreateContract_account_address_tag 2 +#define protocol_AccountCreateContract_type_tag 3 +#define protocol_AccountPermissionUpdateContract_owner_address_tag 1 +#define protocol_AccountUpdateContract_account_name_tag 1 +#define protocol_AccountUpdateContract_owner_address_tag 2 +#define protocol_AssetIssueContract_owner_address_tag 1 +#define protocol_AssetIssueContract_name_tag 2 +#define protocol_AssetIssueContract_abbr_tag 3 +#define protocol_AssetIssueContract_total_supply_tag 4 +#define protocol_AssetIssueContract_frozen_supply_tag 5 +#define protocol_AssetIssueContract_trx_num_tag 6 +#define protocol_AssetIssueContract_num_tag 8 +#define protocol_AssetIssueContract_start_time_tag 9 +#define protocol_AssetIssueContract_end_time_tag 10 +#define protocol_AssetIssueContract_vote_score_tag 16 +#define protocol_AssetIssueContract_description_tag 20 +#define protocol_AssetIssueContract_url_tag 21 +#define protocol_AssetIssueContract_free_asset_net_limit_tag 22 +#define protocol_AssetIssueContract_public_free_asset_net_limit_tag 23 +#define protocol_AssetIssueContract_public_free_asset_net_usage_tag 24 +#define protocol_AssetIssueContract_public_latest_free_net_time_tag 25 +#define protocol_AssetIssueContract_FrozenSupply_frozen_amount_tag 1 +#define protocol_AssetIssueContract_FrozenSupply_frozen_days_tag 2 +#define protocol_DelegateResourceContract_owner_address_tag 1 +#define protocol_DelegateResourceContract_resource_tag 2 +#define protocol_DelegateResourceContract_balance_tag 3 +#define protocol_DelegateResourceContract_receiver_address_tag 4 +#define protocol_DelegateResourceContract_lock_tag 5 +#define protocol_ExchangeCreateContract_owner_address_tag 1 +#define protocol_ExchangeCreateContract_first_token_id_tag 2 +#define protocol_ExchangeCreateContract_first_token_balance_tag 3 +#define protocol_ExchangeCreateContract_second_token_id_tag 4 +#define protocol_ExchangeCreateContract_second_token_balance_tag 5 +#define protocol_ExchangeInjectContract_owner_address_tag 1 +#define protocol_ExchangeInjectContract_exchange_id_tag 2 +#define protocol_ExchangeInjectContract_token_id_tag 3 +#define protocol_ExchangeInjectContract_quant_tag 4 +#define protocol_ExchangeTransactionContract_owner_address_tag 1 +#define protocol_ExchangeTransactionContract_exchange_id_tag 2 +#define protocol_ExchangeTransactionContract_token_id_tag 3 +#define protocol_ExchangeTransactionContract_quant_tag 4 +#define protocol_ExchangeTransactionContract_expected_tag 5 +#define protocol_ExchangeWithdrawContract_owner_address_tag 1 +#define protocol_ExchangeWithdrawContract_exchange_id_tag 2 +#define protocol_ExchangeWithdrawContract_token_id_tag 3 +#define protocol_ExchangeWithdrawContract_quant_tag 4 +#define protocol_FreezeBalanceContract_owner_address_tag 1 +#define protocol_FreezeBalanceContract_frozen_balance_tag 2 +#define protocol_FreezeBalanceContract_frozen_duration_tag 3 +#define protocol_FreezeBalanceContract_resource_tag 10 +#define protocol_FreezeBalanceContract_receiver_address_tag 15 +#define protocol_FreezeBalanceV2Contract_owner_address_tag 1 +#define protocol_FreezeBalanceV2Contract_frozen_balance_tag 2 +#define protocol_FreezeBalanceV2Contract_resource_tag 3 +#define protocol_ParticipateAssetIssueContract_owner_address_tag 1 +#define protocol_ParticipateAssetIssueContract_to_address_tag 2 +#define protocol_ParticipateAssetIssueContract_asset_name_tag 3 +#define protocol_ParticipateAssetIssueContract_amount_tag 4 +#define protocol_ProposalApproveContract_owner_address_tag 1 +#define protocol_ProposalApproveContract_proposal_id_tag 2 +#define protocol_ProposalApproveContract_is_add_approval_tag 3 +#define protocol_ProposalCreateContract_ParametersEntry_key_tag 1 +#define protocol_ProposalCreateContract_ParametersEntry_value_tag 2 +#define protocol_ProposalDeleteContract_owner_address_tag 1 +#define protocol_ProposalDeleteContract_proposal_id_tag 2 +#define protocol_TransferAssetContract_asset_name_tag 1 +#define protocol_TransferAssetContract_owner_address_tag 2 +#define protocol_TransferAssetContract_to_address_tag 3 +#define protocol_TransferAssetContract_amount_tag 4 +#define protocol_TransferContract_owner_address_tag 1 +#define protocol_TransferContract_to_address_tag 2 +#define protocol_TransferContract_amount_tag 3 +#define protocol_TriggerSmartContract_owner_address_tag 1 +#define protocol_TriggerSmartContract_contract_address_tag 2 +#define protocol_TriggerSmartContract_call_value_tag 3 +#define protocol_TriggerSmartContract_data_tag 4 +#define protocol_TriggerSmartContract_call_token_value_tag 5 +#define protocol_TriggerSmartContract_token_id_tag 6 +#define protocol_UnDelegateResourceContract_owner_address_tag 1 +#define protocol_UnDelegateResourceContract_resource_tag 2 +#define protocol_UnDelegateResourceContract_balance_tag 3 +#define protocol_UnDelegateResourceContract_receiver_address_tag 4 +#define protocol_UnfreezeBalanceContract_owner_address_tag 1 +#define protocol_UnfreezeBalanceContract_resource_tag 10 +#define protocol_UnfreezeBalanceContract_receiver_address_tag 15 +#define protocol_UnfreezeBalanceV2Contract_owner_address_tag 1 +#define protocol_UnfreezeBalanceV2Contract_unfreeze_balance_tag 2 +#define protocol_UnfreezeBalanceV2Contract_resource_tag 3 +#define protocol_UpdateAssetContract_owner_address_tag 1 +#define protocol_UpdateAssetContract_description_tag 2 +#define protocol_UpdateAssetContract_url_tag 3 +#define protocol_UpdateAssetContract_new_limit_tag 4 +#define protocol_UpdateAssetContract_new_public_limit_tag 5 +#define protocol_VoteAssetContract_owner_address_tag 1 +#define protocol_VoteAssetContract_vote_address_tag 2 +#define protocol_VoteAssetContract_support_tag 3 +#define protocol_VoteAssetContract_count_tag 5 +#define protocol_VoteWitnessContract_Vote_vote_address_tag 1 +#define protocol_VoteWitnessContract_Vote_vote_count_tag 2 +#define protocol_WithdrawBalanceContract_owner_address_tag 1 +#define protocol_WithdrawExpireUnfreezeContract_owner_address_tag 1 +#define protocol_ProposalCreateContract_owner_address_tag 1 +#define protocol_ProposalCreateContract_parameters_tag 2 +#define protocol_VoteWitnessContract_owner_address_tag 1 +#define protocol_VoteWitnessContract_votes_tag 2 + +/* Struct field encoding specification for nanopb */ +#define protocol_AccountCreateContract_FIELDLIST(X, a) \ +X(a, CALLBACK, SINGULAR, BYTES, owner_address, 1) \ +X(a, CALLBACK, SINGULAR, BYTES, account_address, 2) \ +X(a, STATIC, SINGULAR, UENUM, type, 3) +#define protocol_AccountCreateContract_CALLBACK pb_default_field_callback +#define protocol_AccountCreateContract_DEFAULT NULL + +#define protocol_AccountUpdateContract_FIELDLIST(X, a) \ +X(a, CALLBACK, SINGULAR, BYTES, account_name, 1) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 2) +#define protocol_AccountUpdateContract_CALLBACK pb_default_field_callback +#define protocol_AccountUpdateContract_DEFAULT NULL + +#define protocol_TransferContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, to_address, 2) \ +X(a, STATIC, SINGULAR, INT64, amount, 3) +#define protocol_TransferContract_CALLBACK NULL +#define protocol_TransferContract_DEFAULT NULL + +#define protocol_TransferAssetContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, BYTES, asset_name, 1) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 2) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, to_address, 3) \ +X(a, STATIC, SINGULAR, INT64, amount, 4) +#define protocol_TransferAssetContract_CALLBACK NULL +#define protocol_TransferAssetContract_DEFAULT NULL + +#define protocol_VoteAssetContract_FIELDLIST(X, a) \ +X(a, CALLBACK, SINGULAR, BYTES, owner_address, 1) \ +X(a, CALLBACK, REPEATED, BYTES, vote_address, 2) \ +X(a, STATIC, SINGULAR, BOOL, support, 3) \ +X(a, STATIC, SINGULAR, INT32, count, 5) +#define protocol_VoteAssetContract_CALLBACK pb_default_field_callback +#define protocol_VoteAssetContract_DEFAULT NULL + +#define protocol_VoteWitnessContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, REPEATED, MESSAGE, votes, 2) +#define protocol_VoteWitnessContract_CALLBACK NULL +#define protocol_VoteWitnessContract_DEFAULT NULL +#define protocol_VoteWitnessContract_votes_MSGTYPE protocol_VoteWitnessContract_Vote + +#define protocol_VoteWitnessContract_Vote_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, vote_address, 1) \ +X(a, STATIC, SINGULAR, INT64, vote_count, 2) +#define protocol_VoteWitnessContract_Vote_CALLBACK NULL +#define protocol_VoteWitnessContract_Vote_DEFAULT NULL + +#define protocol_WitnessCreateContract_FIELDLIST(X, a) \ +X(a, CALLBACK, SINGULAR, BYTES, owner_address, 1) \ +X(a, CALLBACK, SINGULAR, BYTES, url, 2) +#define protocol_WitnessCreateContract_CALLBACK pb_default_field_callback +#define protocol_WitnessCreateContract_DEFAULT NULL + +#define protocol_WitnessUpdateContract_FIELDLIST(X, a) \ +X(a, CALLBACK, SINGULAR, BYTES, owner_address, 1) \ +X(a, CALLBACK, SINGULAR, BYTES, update_url, 12) +#define protocol_WitnessUpdateContract_CALLBACK pb_default_field_callback +#define protocol_WitnessUpdateContract_DEFAULT NULL + +#define protocol_AssetIssueContract_FIELDLIST(X, a) \ +X(a, CALLBACK, SINGULAR, BYTES, owner_address, 1) \ +X(a, CALLBACK, SINGULAR, BYTES, name, 2) \ +X(a, CALLBACK, SINGULAR, BYTES, abbr, 3) \ +X(a, STATIC, SINGULAR, INT64, total_supply, 4) \ +X(a, CALLBACK, REPEATED, MESSAGE, frozen_supply, 5) \ +X(a, STATIC, SINGULAR, INT32, trx_num, 6) \ +X(a, STATIC, SINGULAR, INT32, num, 8) \ +X(a, STATIC, SINGULAR, INT64, start_time, 9) \ +X(a, STATIC, SINGULAR, INT64, end_time, 10) \ +X(a, STATIC, SINGULAR, INT32, vote_score, 16) \ +X(a, CALLBACK, SINGULAR, BYTES, description, 20) \ +X(a, CALLBACK, SINGULAR, BYTES, url, 21) \ +X(a, STATIC, SINGULAR, INT64, free_asset_net_limit, 22) \ +X(a, STATIC, SINGULAR, INT64, public_free_asset_net_limit, 23) \ +X(a, STATIC, SINGULAR, INT64, public_free_asset_net_usage, 24) \ +X(a, STATIC, SINGULAR, INT64, public_latest_free_net_time, 25) +#define protocol_AssetIssueContract_CALLBACK pb_default_field_callback +#define protocol_AssetIssueContract_DEFAULT NULL +#define protocol_AssetIssueContract_frozen_supply_MSGTYPE protocol_AssetIssueContract_FrozenSupply + +#define protocol_AssetIssueContract_FrozenSupply_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, INT64, frozen_amount, 1) \ +X(a, STATIC, SINGULAR, INT64, frozen_days, 2) +#define protocol_AssetIssueContract_FrozenSupply_CALLBACK NULL +#define protocol_AssetIssueContract_FrozenSupply_DEFAULT NULL + +#define protocol_ParticipateAssetIssueContract_FIELDLIST(X, a) \ +X(a, CALLBACK, SINGULAR, BYTES, owner_address, 1) \ +X(a, CALLBACK, SINGULAR, BYTES, to_address, 2) \ +X(a, CALLBACK, SINGULAR, BYTES, asset_name, 3) \ +X(a, STATIC, SINGULAR, INT64, amount, 4) +#define protocol_ParticipateAssetIssueContract_CALLBACK pb_default_field_callback +#define protocol_ParticipateAssetIssueContract_DEFAULT NULL + +#define protocol_DeployContract_FIELDLIST(X, a) \ +X(a, CALLBACK, SINGULAR, BYTES, owner_address, 1) \ +X(a, CALLBACK, SINGULAR, BYTES, script, 2) +#define protocol_DeployContract_CALLBACK pb_default_field_callback +#define protocol_DeployContract_DEFAULT NULL + +#define protocol_FreezeBalanceContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, SINGULAR, INT64, frozen_balance, 2) \ +X(a, STATIC, SINGULAR, INT64, frozen_duration, 3) \ +X(a, STATIC, SINGULAR, UENUM, resource, 10) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, receiver_address, 15) +#define protocol_FreezeBalanceContract_CALLBACK NULL +#define protocol_FreezeBalanceContract_DEFAULT NULL + +#define protocol_UnfreezeBalanceContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, SINGULAR, UENUM, resource, 10) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, receiver_address, 15) +#define protocol_UnfreezeBalanceContract_CALLBACK NULL +#define protocol_UnfreezeBalanceContract_DEFAULT NULL + +#define protocol_FreezeBalanceV2Contract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, SINGULAR, INT64, frozen_balance, 2) \ +X(a, STATIC, SINGULAR, UENUM, resource, 3) +#define protocol_FreezeBalanceV2Contract_CALLBACK NULL +#define protocol_FreezeBalanceV2Contract_DEFAULT NULL + +#define protocol_UnfreezeBalanceV2Contract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, SINGULAR, INT64, unfreeze_balance, 2) \ +X(a, STATIC, SINGULAR, UENUM, resource, 3) +#define protocol_UnfreezeBalanceV2Contract_CALLBACK NULL +#define protocol_UnfreezeBalanceV2Contract_DEFAULT NULL + +#define protocol_WithdrawExpireUnfreezeContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) +#define protocol_WithdrawExpireUnfreezeContract_CALLBACK NULL +#define protocol_WithdrawExpireUnfreezeContract_DEFAULT NULL + +#define protocol_DelegateResourceContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, SINGULAR, UENUM, resource, 2) \ +X(a, STATIC, SINGULAR, INT64, balance, 3) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, receiver_address, 4) \ +X(a, STATIC, SINGULAR, BOOL, lock, 5) +#define protocol_DelegateResourceContract_CALLBACK NULL +#define protocol_DelegateResourceContract_DEFAULT NULL + +#define protocol_UnDelegateResourceContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, SINGULAR, UENUM, resource, 2) \ +X(a, STATIC, SINGULAR, INT64, balance, 3) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, receiver_address, 4) +#define protocol_UnDelegateResourceContract_CALLBACK NULL +#define protocol_UnDelegateResourceContract_DEFAULT NULL + +#define protocol_UnfreezeAssetContract_FIELDLIST(X, a) \ +X(a, CALLBACK, SINGULAR, BYTES, owner_address, 1) +#define protocol_UnfreezeAssetContract_CALLBACK pb_default_field_callback +#define protocol_UnfreezeAssetContract_DEFAULT NULL + +#define protocol_WithdrawBalanceContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) +#define protocol_WithdrawBalanceContract_CALLBACK NULL +#define protocol_WithdrawBalanceContract_DEFAULT NULL + +#define protocol_UpdateAssetContract_FIELDLIST(X, a) \ +X(a, CALLBACK, SINGULAR, BYTES, owner_address, 1) \ +X(a, CALLBACK, SINGULAR, BYTES, description, 2) \ +X(a, CALLBACK, SINGULAR, BYTES, url, 3) \ +X(a, STATIC, SINGULAR, INT64, new_limit, 4) \ +X(a, STATIC, SINGULAR, INT64, new_public_limit, 5) +#define protocol_UpdateAssetContract_CALLBACK pb_default_field_callback +#define protocol_UpdateAssetContract_DEFAULT NULL + +#define protocol_ProposalCreateContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, REPEATED, MESSAGE, parameters, 2) +#define protocol_ProposalCreateContract_CALLBACK NULL +#define protocol_ProposalCreateContract_DEFAULT NULL +#define protocol_ProposalCreateContract_parameters_MSGTYPE protocol_ProposalCreateContract_ParametersEntry + +#define protocol_ProposalCreateContract_ParametersEntry_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, INT64, key, 1) \ +X(a, STATIC, SINGULAR, INT64, value, 2) +#define protocol_ProposalCreateContract_ParametersEntry_CALLBACK NULL +#define protocol_ProposalCreateContract_ParametersEntry_DEFAULT NULL + +#define protocol_ProposalApproveContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, SINGULAR, INT64, proposal_id, 2) \ +X(a, STATIC, SINGULAR, BOOL, is_add_approval, 3) +#define protocol_ProposalApproveContract_CALLBACK NULL +#define protocol_ProposalApproveContract_DEFAULT NULL + +#define protocol_ProposalDeleteContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, SINGULAR, INT64, proposal_id, 2) +#define protocol_ProposalDeleteContract_CALLBACK NULL +#define protocol_ProposalDeleteContract_DEFAULT NULL + +#define protocol_TriggerSmartContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, contract_address, 2) \ +X(a, STATIC, SINGULAR, INT64, call_value, 3) \ +X(a, CALLBACK, SINGULAR, BYTES, data, 4) \ +X(a, STATIC, SINGULAR, INT64, call_token_value, 5) \ +X(a, STATIC, SINGULAR, INT64, token_id, 6) +#define protocol_TriggerSmartContract_CALLBACK pb_default_field_callback +#define protocol_TriggerSmartContract_DEFAULT NULL + +#define protocol_ExchangeCreateContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, SINGULAR, BYTES, first_token_id, 2) \ +X(a, STATIC, SINGULAR, INT64, first_token_balance, 3) \ +X(a, STATIC, SINGULAR, BYTES, second_token_id, 4) \ +X(a, STATIC, SINGULAR, INT64, second_token_balance, 5) +#define protocol_ExchangeCreateContract_CALLBACK NULL +#define protocol_ExchangeCreateContract_DEFAULT NULL + +#define protocol_ExchangeInjectContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, SINGULAR, INT64, exchange_id, 2) \ +X(a, STATIC, SINGULAR, BYTES, token_id, 3) \ +X(a, STATIC, SINGULAR, INT64, quant, 4) +#define protocol_ExchangeInjectContract_CALLBACK NULL +#define protocol_ExchangeInjectContract_DEFAULT NULL + +#define protocol_ExchangeWithdrawContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, SINGULAR, INT64, exchange_id, 2) \ +X(a, STATIC, SINGULAR, BYTES, token_id, 3) \ +X(a, STATIC, SINGULAR, INT64, quant, 4) +#define protocol_ExchangeWithdrawContract_CALLBACK NULL +#define protocol_ExchangeWithdrawContract_DEFAULT NULL + +#define protocol_ExchangeTransactionContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) \ +X(a, STATIC, SINGULAR, INT64, exchange_id, 2) \ +X(a, STATIC, SINGULAR, BYTES, token_id, 3) \ +X(a, STATIC, SINGULAR, INT64, quant, 4) \ +X(a, STATIC, SINGULAR, INT64, expected, 5) +#define protocol_ExchangeTransactionContract_CALLBACK NULL +#define protocol_ExchangeTransactionContract_DEFAULT NULL + +#define protocol_AccountPermissionUpdateContract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, owner_address, 1) +#define protocol_AccountPermissionUpdateContract_CALLBACK NULL +#define protocol_AccountPermissionUpdateContract_DEFAULT NULL + +extern const pb_msgdesc_t protocol_AccountCreateContract_msg; +extern const pb_msgdesc_t protocol_AccountUpdateContract_msg; +extern const pb_msgdesc_t protocol_TransferContract_msg; +extern const pb_msgdesc_t protocol_TransferAssetContract_msg; +extern const pb_msgdesc_t protocol_VoteAssetContract_msg; +extern const pb_msgdesc_t protocol_VoteWitnessContract_msg; +extern const pb_msgdesc_t protocol_VoteWitnessContract_Vote_msg; +extern const pb_msgdesc_t protocol_WitnessCreateContract_msg; +extern const pb_msgdesc_t protocol_WitnessUpdateContract_msg; +extern const pb_msgdesc_t protocol_AssetIssueContract_msg; +extern const pb_msgdesc_t protocol_AssetIssueContract_FrozenSupply_msg; +extern const pb_msgdesc_t protocol_ParticipateAssetIssueContract_msg; +extern const pb_msgdesc_t protocol_DeployContract_msg; +extern const pb_msgdesc_t protocol_FreezeBalanceContract_msg; +extern const pb_msgdesc_t protocol_UnfreezeBalanceContract_msg; +extern const pb_msgdesc_t protocol_FreezeBalanceV2Contract_msg; +extern const pb_msgdesc_t protocol_UnfreezeBalanceV2Contract_msg; +extern const pb_msgdesc_t protocol_WithdrawExpireUnfreezeContract_msg; +extern const pb_msgdesc_t protocol_DelegateResourceContract_msg; +extern const pb_msgdesc_t protocol_UnDelegateResourceContract_msg; +extern const pb_msgdesc_t protocol_UnfreezeAssetContract_msg; +extern const pb_msgdesc_t protocol_WithdrawBalanceContract_msg; +extern const pb_msgdesc_t protocol_UpdateAssetContract_msg; +extern const pb_msgdesc_t protocol_ProposalCreateContract_msg; +extern const pb_msgdesc_t protocol_ProposalCreateContract_ParametersEntry_msg; +extern const pb_msgdesc_t protocol_ProposalApproveContract_msg; +extern const pb_msgdesc_t protocol_ProposalDeleteContract_msg; +extern const pb_msgdesc_t protocol_TriggerSmartContract_msg; +extern const pb_msgdesc_t protocol_ExchangeCreateContract_msg; +extern const pb_msgdesc_t protocol_ExchangeInjectContract_msg; +extern const pb_msgdesc_t protocol_ExchangeWithdrawContract_msg; +extern const pb_msgdesc_t protocol_ExchangeTransactionContract_msg; +extern const pb_msgdesc_t protocol_AccountPermissionUpdateContract_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define protocol_AccountCreateContract_fields &protocol_AccountCreateContract_msg +#define protocol_AccountUpdateContract_fields &protocol_AccountUpdateContract_msg +#define protocol_TransferContract_fields &protocol_TransferContract_msg +#define protocol_TransferAssetContract_fields &protocol_TransferAssetContract_msg +#define protocol_VoteAssetContract_fields &protocol_VoteAssetContract_msg +#define protocol_VoteWitnessContract_fields &protocol_VoteWitnessContract_msg +#define protocol_VoteWitnessContract_Vote_fields &protocol_VoteWitnessContract_Vote_msg +#define protocol_WitnessCreateContract_fields &protocol_WitnessCreateContract_msg +#define protocol_WitnessUpdateContract_fields &protocol_WitnessUpdateContract_msg +#define protocol_AssetIssueContract_fields &protocol_AssetIssueContract_msg +#define protocol_AssetIssueContract_FrozenSupply_fields &protocol_AssetIssueContract_FrozenSupply_msg +#define protocol_ParticipateAssetIssueContract_fields &protocol_ParticipateAssetIssueContract_msg +#define protocol_DeployContract_fields &protocol_DeployContract_msg +#define protocol_FreezeBalanceContract_fields &protocol_FreezeBalanceContract_msg +#define protocol_UnfreezeBalanceContract_fields &protocol_UnfreezeBalanceContract_msg +#define protocol_FreezeBalanceV2Contract_fields &protocol_FreezeBalanceV2Contract_msg +#define protocol_UnfreezeBalanceV2Contract_fields &protocol_UnfreezeBalanceV2Contract_msg +#define protocol_WithdrawExpireUnfreezeContract_fields &protocol_WithdrawExpireUnfreezeContract_msg +#define protocol_DelegateResourceContract_fields &protocol_DelegateResourceContract_msg +#define protocol_UnDelegateResourceContract_fields &protocol_UnDelegateResourceContract_msg +#define protocol_UnfreezeAssetContract_fields &protocol_UnfreezeAssetContract_msg +#define protocol_WithdrawBalanceContract_fields &protocol_WithdrawBalanceContract_msg +#define protocol_UpdateAssetContract_fields &protocol_UpdateAssetContract_msg +#define protocol_ProposalCreateContract_fields &protocol_ProposalCreateContract_msg +#define protocol_ProposalCreateContract_ParametersEntry_fields &protocol_ProposalCreateContract_ParametersEntry_msg +#define protocol_ProposalApproveContract_fields &protocol_ProposalApproveContract_msg +#define protocol_ProposalDeleteContract_fields &protocol_ProposalDeleteContract_msg +#define protocol_TriggerSmartContract_fields &protocol_TriggerSmartContract_msg +#define protocol_ExchangeCreateContract_fields &protocol_ExchangeCreateContract_msg +#define protocol_ExchangeInjectContract_fields &protocol_ExchangeInjectContract_msg +#define protocol_ExchangeWithdrawContract_fields &protocol_ExchangeWithdrawContract_msg +#define protocol_ExchangeTransactionContract_fields &protocol_ExchangeTransactionContract_msg +#define protocol_AccountPermissionUpdateContract_fields &protocol_AccountPermissionUpdateContract_msg + +/* Maximum encoded size of messages (where known) */ +/* protocol_AccountCreateContract_size depends on runtime parameters */ +/* protocol_AccountUpdateContract_size depends on runtime parameters */ +/* protocol_VoteAssetContract_size depends on runtime parameters */ +/* protocol_WitnessCreateContract_size depends on runtime parameters */ +/* protocol_WitnessUpdateContract_size depends on runtime parameters */ +/* protocol_AssetIssueContract_size depends on runtime parameters */ +/* protocol_ParticipateAssetIssueContract_size depends on runtime parameters */ +/* protocol_DeployContract_size depends on runtime parameters */ +/* protocol_UnfreezeAssetContract_size depends on runtime parameters */ +/* protocol_UpdateAssetContract_size depends on runtime parameters */ +/* protocol_TriggerSmartContract_size depends on runtime parameters */ +#define protocol_AccountPermissionUpdateContract_size 23 +#define protocol_AssetIssueContract_FrozenSupply_size 22 +#define protocol_DelegateResourceContract_size 61 +#define protocol_ExchangeCreateContract_size 65 +#define protocol_ExchangeInjectContract_size 55 +#define protocol_ExchangeTransactionContract_size 66 +#define protocol_ExchangeWithdrawContract_size 55 +#define protocol_FreezeBalanceContract_size 70 +#define protocol_FreezeBalanceV2Contract_size 36 +#define protocol_ProposalApproveContract_size 36 +#define protocol_ProposalCreateContract_ParametersEntry_size 22 +#define protocol_ProposalCreateContract_size 263 +#define protocol_ProposalDeleteContract_size 34 +#define protocol_TransferAssetContract_size 75 +#define protocol_TransferContract_size 57 +#define protocol_UnDelegateResourceContract_size 59 +#define protocol_UnfreezeBalanceContract_size 48 +#define protocol_UnfreezeBalanceV2Contract_size 36 +#define protocol_VoteWitnessContract_Vote_size 34 +#define protocol_VoteWitnessContract_size 203 +#define protocol_WithdrawBalanceContract_size 23 +#define protocol_WithdrawExpireUnfreezeContract_size 23 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/test/python/apps/tron_proto/core/Contract.proto b/test/python/apps/tron_proto/core/Contract.proto new file mode 100644 index 0000000..4f550dc --- /dev/null +++ b/test/python/apps/tron_proto/core/Contract.proto @@ -0,0 +1,242 @@ +/* + * java-tron is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * java-tron is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +syntax = "proto3"; + +package protocol; + +option java_package = "org.tron.protos"; //Specify the name of the package that generated the Java file +option java_outer_classname = "Contract"; //Specify the class name of the generated Java file +option go_package = "github.com/tronprotocol/grpc-gateway/core"; + +import "core/Tron.proto"; + +message AccountCreateContract { + bytes owner_address = 1; + bytes account_address = 2; + AccountType type = 3; +} + +// Update account name. Account name is not unique now. +message AccountUpdateContract { + bytes account_name = 1; + bytes owner_address = 2; +} + +message TransferContract { + bytes owner_address = 1; + bytes to_address = 2; + int64 amount = 3; +} + +message TransferAssetContract { + bytes asset_name = 1; + bytes owner_address = 2; + bytes to_address = 3; + int64 amount = 4; +} + + +message VoteAssetContract { + bytes owner_address = 1; + repeated bytes vote_address = 2; + bool support = 3; + int32 count = 5; +} + +message VoteWitnessContract { + message Vote { + bytes vote_address = 1; + int64 vote_count = 2; + } + bytes owner_address = 1; + repeated Vote votes = 2; + bool support = 3; +} + +message WitnessCreateContract { + bytes owner_address = 1; + bytes url = 2; +} + +message WitnessUpdateContract { + bytes owner_address = 1; + bytes update_url = 12; +} + +message AssetIssueContract { + message FrozenSupply { + int64 frozen_amount = 1; + int64 frozen_days = 2; + } + bytes owner_address = 1; + bytes name = 2; + bytes abbr = 3; + int64 total_supply = 4; + repeated FrozenSupply frozen_supply = 5; + int32 trx_num = 6; + int32 num = 8; + int64 start_time = 9; + int64 end_time = 10; + int32 vote_score = 16; + bytes description = 20; + bytes url = 21; + int64 free_asset_net_limit = 22; + int64 public_free_asset_net_limit = 23; + int64 public_free_asset_net_usage = 24; + int64 public_latest_free_net_time = 25; +} + +message ParticipateAssetIssueContract { + bytes owner_address = 1; + bytes to_address = 2; + bytes asset_name = 3; // the name of target asset + int64 amount = 4; // the amount of drops +} + +message DeployContract { + bytes owner_address = 1; + bytes script = 2; +} + +enum ResourceCode { + BANDWIDTH = 0x00; + ENERGY = 0x01; +} + +message FreezeBalanceContract { + bytes owner_address = 1; + int64 frozen_balance = 2; + int64 frozen_duration = 3; + + ResourceCode resource = 10; + bytes receiver_address = 15; +} + +message UnfreezeBalanceContract { + bytes owner_address = 1; + + ResourceCode resource = 10; + bytes receiver_address = 15; +} + +message FreezeBalanceV2Contract { + bytes owner_address = 1; + int64 frozen_balance = 2; + ResourceCode resource = 3; +} + +message UnfreezeBalanceV2Contract { + bytes owner_address = 1; + int64 unfreeze_balance = 2; + ResourceCode resource = 3; +} + +message WithdrawExpireUnfreezeContract { + bytes owner_address = 1; +} + +message DelegateResourceContract { + bytes owner_address = 1; + ResourceCode resource = 2; + int64 balance = 3; + bytes receiver_address = 4; + bool lock = 5; +} + +message UnDelegateResourceContract { + bytes owner_address = 1; + ResourceCode resource = 2; + int64 balance = 3; + bytes receiver_address = 4; +} + +message UnfreezeAssetContract { + bytes owner_address = 1; +} + +message WithdrawBalanceContract { + bytes owner_address = 1; +} + +message UpdateAssetContract { + bytes owner_address = 1; + bytes description = 2; + bytes url = 3; + int64 new_limit = 4; + int64 new_public_limit = 5; +} + +message ProposalCreateContract { + bytes owner_address = 1; + map parameters = 2; +} + +message ProposalApproveContract { + bytes owner_address = 1; + int64 proposal_id = 2; + bool is_add_approval = 3; // add or remove approval +} + +message ProposalDeleteContract { + bytes owner_address = 1; + int64 proposal_id = 2; +} + +message TriggerSmartContract { + bytes owner_address = 1; + bytes contract_address = 2; + int64 call_value = 3; + bytes data = 4; + int64 call_token_value = 5; + int64 token_id = 6; +} + +message ExchangeCreateContract { + bytes owner_address = 1; + bytes first_token_id = 2; + int64 first_token_balance = 3; + bytes second_token_id = 4; + int64 second_token_balance = 5; +} + +message ExchangeInjectContract { + bytes owner_address = 1; + int64 exchange_id = 2; + bytes token_id = 3; + int64 quant = 4; +} + +message ExchangeWithdrawContract { + bytes owner_address = 1; + int64 exchange_id = 2; + bytes token_id = 3; + int64 quant = 4; +} + +message ExchangeTransactionContract { + bytes owner_address = 1; + int64 exchange_id = 2; + bytes token_id = 3; + int64 quant = 4; + int64 expected = 5; +} + +message AccountPermissionUpdateContract { + bytes owner_address = 1; + Permission owner = 2; // Empty is invalidate + Permission witness = 3; // Can be empty + repeated Permission actives = 4; // Empty is invalidate + } \ No newline at end of file diff --git a/test/python/apps/tron_proto/core/Contract_pb2.py b/test/python/apps/tron_proto/core/Contract_pb2.py new file mode 100644 index 0000000..c7ae6a7 --- /dev/null +++ b/test/python/apps/tron_proto/core/Contract_pb2.py @@ -0,0 +1,368 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: core/Contract.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from core import Tron_pb2 as core_dot_Tron__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13\x63ore/Contract.proto\x12\x08protocol\x1a\x0f\x63ore/Tron.proto\"l\n\x15\x41\x63\x63ountCreateContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x17\n\x0f\x61\x63\x63ount_address\x18\x02 \x01(\x0c\x12#\n\x04type\x18\x03 \x01(\x0e\x32\x15.protocol.AccountType\"D\n\x15\x41\x63\x63ountUpdateContract\x12\x14\n\x0c\x61\x63\x63ount_name\x18\x01 \x01(\x0c\x12\x15\n\rowner_address\x18\x02 \x01(\x0c\"M\n\x10TransferContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x12\n\nto_address\x18\x02 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x03 \x01(\x03\"f\n\x15TransferAssetContract\x12\x12\n\nasset_name\x18\x01 \x01(\x0c\x12\x15\n\rowner_address\x18\x02 \x01(\x0c\x12\x12\n\nto_address\x18\x03 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x04 \x01(\x03\"`\n\x11VoteAssetContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x14\n\x0cvote_address\x18\x02 \x03(\x0c\x12\x0f\n\x07support\x18\x03 \x01(\x08\x12\r\n\x05\x63ount\x18\x05 \x01(\x05\"\xa2\x01\n\x13VoteWitnessContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x31\n\x05votes\x18\x02 \x03(\x0b\x32\".protocol.VoteWitnessContract.Vote\x12\x0f\n\x07support\x18\x03 \x01(\x08\x1a\x30\n\x04Vote\x12\x14\n\x0cvote_address\x18\x01 \x01(\x0c\x12\x12\n\nvote_count\x18\x02 \x01(\x03\";\n\x15WitnessCreateContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x0b\n\x03url\x18\x02 \x01(\x0c\"B\n\x15WitnessUpdateContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x12\n\nupdate_url\x18\x0c \x01(\x0c\"\xe2\x03\n\x12\x41ssetIssueContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x02 \x01(\x0c\x12\x0c\n\x04\x61\x62\x62r\x18\x03 \x01(\x0c\x12\x14\n\x0ctotal_supply\x18\x04 \x01(\x03\x12@\n\rfrozen_supply\x18\x05 \x03(\x0b\x32).protocol.AssetIssueContract.FrozenSupply\x12\x0f\n\x07trx_num\x18\x06 \x01(\x05\x12\x0b\n\x03num\x18\x08 \x01(\x05\x12\x12\n\nstart_time\x18\t \x01(\x03\x12\x10\n\x08\x65nd_time\x18\n \x01(\x03\x12\x12\n\nvote_score\x18\x10 \x01(\x05\x12\x13\n\x0b\x64\x65scription\x18\x14 \x01(\x0c\x12\x0b\n\x03url\x18\x15 \x01(\x0c\x12\x1c\n\x14\x66ree_asset_net_limit\x18\x16 \x01(\x03\x12#\n\x1bpublic_free_asset_net_limit\x18\x17 \x01(\x03\x12#\n\x1bpublic_free_asset_net_usage\x18\x18 \x01(\x03\x12#\n\x1bpublic_latest_free_net_time\x18\x19 \x01(\x03\x1a:\n\x0c\x46rozenSupply\x12\x15\n\rfrozen_amount\x18\x01 \x01(\x03\x12\x13\n\x0b\x66rozen_days\x18\x02 \x01(\x03\"n\n\x1dParticipateAssetIssueContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x12\n\nto_address\x18\x02 \x01(\x0c\x12\x12\n\nasset_name\x18\x03 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x04 \x01(\x03\"7\n\x0e\x44\x65ployContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x0e\n\x06script\x18\x02 \x01(\x0c\"\xa3\x01\n\x15\x46reezeBalanceContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x16\n\x0e\x66rozen_balance\x18\x02 \x01(\x03\x12\x17\n\x0f\x66rozen_duration\x18\x03 \x01(\x03\x12(\n\x08resource\x18\n \x01(\x0e\x32\x16.protocol.ResourceCode\x12\x18\n\x10receiver_address\x18\x0f \x01(\x0c\"t\n\x17UnfreezeBalanceContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12(\n\x08resource\x18\n \x01(\x0e\x32\x16.protocol.ResourceCode\x12\x18\n\x10receiver_address\x18\x0f \x01(\x0c\"r\n\x17\x46reezeBalanceV2Contract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x16\n\x0e\x66rozen_balance\x18\x02 \x01(\x03\x12(\n\x08resource\x18\x03 \x01(\x0e\x32\x16.protocol.ResourceCode\"v\n\x19UnfreezeBalanceV2Contract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x18\n\x10unfreeze_balance\x18\x02 \x01(\x03\x12(\n\x08resource\x18\x03 \x01(\x0e\x32\x16.protocol.ResourceCode\"7\n\x1eWithdrawExpireUnfreezeContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\"\x94\x01\n\x18\x44\x65legateResourceContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12(\n\x08resource\x18\x02 \x01(\x0e\x32\x16.protocol.ResourceCode\x12\x0f\n\x07\x62\x61lance\x18\x03 \x01(\x03\x12\x18\n\x10receiver_address\x18\x04 \x01(\x0c\x12\x0c\n\x04lock\x18\x05 \x01(\x08\"\x88\x01\n\x1aUnDelegateResourceContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12(\n\x08resource\x18\x02 \x01(\x0e\x32\x16.protocol.ResourceCode\x12\x0f\n\x07\x62\x61lance\x18\x03 \x01(\x03\x12\x18\n\x10receiver_address\x18\x04 \x01(\x0c\".\n\x15UnfreezeAssetContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\"0\n\x17WithdrawBalanceContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\"{\n\x13UpdateAssetContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\x0c\x12\x0b\n\x03url\x18\x03 \x01(\x0c\x12\x11\n\tnew_limit\x18\x04 \x01(\x03\x12\x18\n\x10new_public_limit\x18\x05 \x01(\x03\"\xa8\x01\n\x16ProposalCreateContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x44\n\nparameters\x18\x02 \x03(\x0b\x32\x30.protocol.ProposalCreateContract.ParametersEntry\x1a\x31\n\x0fParametersEntry\x12\x0b\n\x03key\x18\x01 \x01(\x03\x12\r\n\x05value\x18\x02 \x01(\x03:\x02\x38\x01\"^\n\x17ProposalApproveContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x13\n\x0bproposal_id\x18\x02 \x01(\x03\x12\x17\n\x0fis_add_approval\x18\x03 \x01(\x08\"D\n\x16ProposalDeleteContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x13\n\x0bproposal_id\x18\x02 \x01(\x03\"\x95\x01\n\x14TriggerSmartContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x18\n\x10\x63ontract_address\x18\x02 \x01(\x0c\x12\x12\n\ncall_value\x18\x03 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12\x18\n\x10\x63\x61ll_token_value\x18\x05 \x01(\x03\x12\x10\n\x08token_id\x18\x06 \x01(\x03\"\x9b\x01\n\x16\x45xchangeCreateContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x16\n\x0e\x66irst_token_id\x18\x02 \x01(\x0c\x12\x1b\n\x13\x66irst_token_balance\x18\x03 \x01(\x03\x12\x17\n\x0fsecond_token_id\x18\x04 \x01(\x0c\x12\x1c\n\x14second_token_balance\x18\x05 \x01(\x03\"e\n\x16\x45xchangeInjectContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x13\n\x0b\x65xchange_id\x18\x02 \x01(\x03\x12\x10\n\x08token_id\x18\x03 \x01(\x0c\x12\r\n\x05quant\x18\x04 \x01(\x03\"g\n\x18\x45xchangeWithdrawContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x13\n\x0b\x65xchange_id\x18\x02 \x01(\x03\x12\x10\n\x08token_id\x18\x03 \x01(\x0c\x12\r\n\x05quant\x18\x04 \x01(\x03\"|\n\x1b\x45xchangeTransactionContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12\x13\n\x0b\x65xchange_id\x18\x02 \x01(\x03\x12\x10\n\x08token_id\x18\x03 \x01(\x0c\x12\r\n\x05quant\x18\x04 \x01(\x03\x12\x10\n\x08\x65xpected\x18\x05 \x01(\x03\"\xab\x01\n\x1f\x41\x63\x63ountPermissionUpdateContract\x12\x15\n\rowner_address\x18\x01 \x01(\x0c\x12#\n\x05owner\x18\x02 \x01(\x0b\x32\x14.protocol.Permission\x12%\n\x07witness\x18\x03 \x01(\x0b\x32\x14.protocol.Permission\x12%\n\x07\x61\x63tives\x18\x04 \x03(\x0b\x32\x14.protocol.Permission*)\n\x0cResourceCode\x12\r\n\tBANDWIDTH\x10\x00\x12\n\n\x06\x45NERGY\x10\x01\x42\x46\n\x0forg.tron.protosB\x08\x43ontractZ)github.com/tronprotocol/grpc-gateway/coreb\x06proto3') + +_RESOURCECODE = DESCRIPTOR.enum_types_by_name['ResourceCode'] +ResourceCode = enum_type_wrapper.EnumTypeWrapper(_RESOURCECODE) +BANDWIDTH = 0 +ENERGY = 1 + + +_ACCOUNTCREATECONTRACT = DESCRIPTOR.message_types_by_name['AccountCreateContract'] +_ACCOUNTUPDATECONTRACT = DESCRIPTOR.message_types_by_name['AccountUpdateContract'] +_TRANSFERCONTRACT = DESCRIPTOR.message_types_by_name['TransferContract'] +_TRANSFERASSETCONTRACT = DESCRIPTOR.message_types_by_name['TransferAssetContract'] +_VOTEASSETCONTRACT = DESCRIPTOR.message_types_by_name['VoteAssetContract'] +_VOTEWITNESSCONTRACT = DESCRIPTOR.message_types_by_name['VoteWitnessContract'] +_VOTEWITNESSCONTRACT_VOTE = _VOTEWITNESSCONTRACT.nested_types_by_name['Vote'] +_WITNESSCREATECONTRACT = DESCRIPTOR.message_types_by_name['WitnessCreateContract'] +_WITNESSUPDATECONTRACT = DESCRIPTOR.message_types_by_name['WitnessUpdateContract'] +_ASSETISSUECONTRACT = DESCRIPTOR.message_types_by_name['AssetIssueContract'] +_ASSETISSUECONTRACT_FROZENSUPPLY = _ASSETISSUECONTRACT.nested_types_by_name['FrozenSupply'] +_PARTICIPATEASSETISSUECONTRACT = DESCRIPTOR.message_types_by_name['ParticipateAssetIssueContract'] +_DEPLOYCONTRACT = DESCRIPTOR.message_types_by_name['DeployContract'] +_FREEZEBALANCECONTRACT = DESCRIPTOR.message_types_by_name['FreezeBalanceContract'] +_UNFREEZEBALANCECONTRACT = DESCRIPTOR.message_types_by_name['UnfreezeBalanceContract'] +_FREEZEBALANCEV2CONTRACT = DESCRIPTOR.message_types_by_name['FreezeBalanceV2Contract'] +_UNFREEZEBALANCEV2CONTRACT = DESCRIPTOR.message_types_by_name['UnfreezeBalanceV2Contract'] +_WITHDRAWEXPIREUNFREEZECONTRACT = DESCRIPTOR.message_types_by_name['WithdrawExpireUnfreezeContract'] +_DELEGATERESOURCECONTRACT = DESCRIPTOR.message_types_by_name['DelegateResourceContract'] +_UNDELEGATERESOURCECONTRACT = DESCRIPTOR.message_types_by_name['UnDelegateResourceContract'] +_UNFREEZEASSETCONTRACT = DESCRIPTOR.message_types_by_name['UnfreezeAssetContract'] +_WITHDRAWBALANCECONTRACT = DESCRIPTOR.message_types_by_name['WithdrawBalanceContract'] +_UPDATEASSETCONTRACT = DESCRIPTOR.message_types_by_name['UpdateAssetContract'] +_PROPOSALCREATECONTRACT = DESCRIPTOR.message_types_by_name['ProposalCreateContract'] +_PROPOSALCREATECONTRACT_PARAMETERSENTRY = _PROPOSALCREATECONTRACT.nested_types_by_name['ParametersEntry'] +_PROPOSALAPPROVECONTRACT = DESCRIPTOR.message_types_by_name['ProposalApproveContract'] +_PROPOSALDELETECONTRACT = DESCRIPTOR.message_types_by_name['ProposalDeleteContract'] +_TRIGGERSMARTCONTRACT = DESCRIPTOR.message_types_by_name['TriggerSmartContract'] +_EXCHANGECREATECONTRACT = DESCRIPTOR.message_types_by_name['ExchangeCreateContract'] +_EXCHANGEINJECTCONTRACT = DESCRIPTOR.message_types_by_name['ExchangeInjectContract'] +_EXCHANGEWITHDRAWCONTRACT = DESCRIPTOR.message_types_by_name['ExchangeWithdrawContract'] +_EXCHANGETRANSACTIONCONTRACT = DESCRIPTOR.message_types_by_name['ExchangeTransactionContract'] +_ACCOUNTPERMISSIONUPDATECONTRACT = DESCRIPTOR.message_types_by_name['AccountPermissionUpdateContract'] +AccountCreateContract = _reflection.GeneratedProtocolMessageType('AccountCreateContract', (_message.Message,), { + 'DESCRIPTOR' : _ACCOUNTCREATECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.AccountCreateContract) + }) +_sym_db.RegisterMessage(AccountCreateContract) + +AccountUpdateContract = _reflection.GeneratedProtocolMessageType('AccountUpdateContract', (_message.Message,), { + 'DESCRIPTOR' : _ACCOUNTUPDATECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.AccountUpdateContract) + }) +_sym_db.RegisterMessage(AccountUpdateContract) + +TransferContract = _reflection.GeneratedProtocolMessageType('TransferContract', (_message.Message,), { + 'DESCRIPTOR' : _TRANSFERCONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.TransferContract) + }) +_sym_db.RegisterMessage(TransferContract) + +TransferAssetContract = _reflection.GeneratedProtocolMessageType('TransferAssetContract', (_message.Message,), { + 'DESCRIPTOR' : _TRANSFERASSETCONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.TransferAssetContract) + }) +_sym_db.RegisterMessage(TransferAssetContract) + +VoteAssetContract = _reflection.GeneratedProtocolMessageType('VoteAssetContract', (_message.Message,), { + 'DESCRIPTOR' : _VOTEASSETCONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.VoteAssetContract) + }) +_sym_db.RegisterMessage(VoteAssetContract) + +VoteWitnessContract = _reflection.GeneratedProtocolMessageType('VoteWitnessContract', (_message.Message,), { + + 'Vote' : _reflection.GeneratedProtocolMessageType('Vote', (_message.Message,), { + 'DESCRIPTOR' : _VOTEWITNESSCONTRACT_VOTE, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.VoteWitnessContract.Vote) + }) + , + 'DESCRIPTOR' : _VOTEWITNESSCONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.VoteWitnessContract) + }) +_sym_db.RegisterMessage(VoteWitnessContract) +_sym_db.RegisterMessage(VoteWitnessContract.Vote) + +WitnessCreateContract = _reflection.GeneratedProtocolMessageType('WitnessCreateContract', (_message.Message,), { + 'DESCRIPTOR' : _WITNESSCREATECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.WitnessCreateContract) + }) +_sym_db.RegisterMessage(WitnessCreateContract) + +WitnessUpdateContract = _reflection.GeneratedProtocolMessageType('WitnessUpdateContract', (_message.Message,), { + 'DESCRIPTOR' : _WITNESSUPDATECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.WitnessUpdateContract) + }) +_sym_db.RegisterMessage(WitnessUpdateContract) + +AssetIssueContract = _reflection.GeneratedProtocolMessageType('AssetIssueContract', (_message.Message,), { + + 'FrozenSupply' : _reflection.GeneratedProtocolMessageType('FrozenSupply', (_message.Message,), { + 'DESCRIPTOR' : _ASSETISSUECONTRACT_FROZENSUPPLY, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.AssetIssueContract.FrozenSupply) + }) + , + 'DESCRIPTOR' : _ASSETISSUECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.AssetIssueContract) + }) +_sym_db.RegisterMessage(AssetIssueContract) +_sym_db.RegisterMessage(AssetIssueContract.FrozenSupply) + +ParticipateAssetIssueContract = _reflection.GeneratedProtocolMessageType('ParticipateAssetIssueContract', (_message.Message,), { + 'DESCRIPTOR' : _PARTICIPATEASSETISSUECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.ParticipateAssetIssueContract) + }) +_sym_db.RegisterMessage(ParticipateAssetIssueContract) + +DeployContract = _reflection.GeneratedProtocolMessageType('DeployContract', (_message.Message,), { + 'DESCRIPTOR' : _DEPLOYCONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.DeployContract) + }) +_sym_db.RegisterMessage(DeployContract) + +FreezeBalanceContract = _reflection.GeneratedProtocolMessageType('FreezeBalanceContract', (_message.Message,), { + 'DESCRIPTOR' : _FREEZEBALANCECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.FreezeBalanceContract) + }) +_sym_db.RegisterMessage(FreezeBalanceContract) + +UnfreezeBalanceContract = _reflection.GeneratedProtocolMessageType('UnfreezeBalanceContract', (_message.Message,), { + 'DESCRIPTOR' : _UNFREEZEBALANCECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.UnfreezeBalanceContract) + }) +_sym_db.RegisterMessage(UnfreezeBalanceContract) + +FreezeBalanceV2Contract = _reflection.GeneratedProtocolMessageType('FreezeBalanceV2Contract', (_message.Message,), { + 'DESCRIPTOR' : _FREEZEBALANCEV2CONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.FreezeBalanceV2Contract) + }) +_sym_db.RegisterMessage(FreezeBalanceV2Contract) + +UnfreezeBalanceV2Contract = _reflection.GeneratedProtocolMessageType('UnfreezeBalanceV2Contract', (_message.Message,), { + 'DESCRIPTOR' : _UNFREEZEBALANCEV2CONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.UnfreezeBalanceV2Contract) + }) +_sym_db.RegisterMessage(UnfreezeBalanceV2Contract) + +WithdrawExpireUnfreezeContract = _reflection.GeneratedProtocolMessageType('WithdrawExpireUnfreezeContract', (_message.Message,), { + 'DESCRIPTOR' : _WITHDRAWEXPIREUNFREEZECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.WithdrawExpireUnfreezeContract) + }) +_sym_db.RegisterMessage(WithdrawExpireUnfreezeContract) + +DelegateResourceContract = _reflection.GeneratedProtocolMessageType('DelegateResourceContract', (_message.Message,), { + 'DESCRIPTOR' : _DELEGATERESOURCECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.DelegateResourceContract) + }) +_sym_db.RegisterMessage(DelegateResourceContract) + +UnDelegateResourceContract = _reflection.GeneratedProtocolMessageType('UnDelegateResourceContract', (_message.Message,), { + 'DESCRIPTOR' : _UNDELEGATERESOURCECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.UnDelegateResourceContract) + }) +_sym_db.RegisterMessage(UnDelegateResourceContract) + +UnfreezeAssetContract = _reflection.GeneratedProtocolMessageType('UnfreezeAssetContract', (_message.Message,), { + 'DESCRIPTOR' : _UNFREEZEASSETCONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.UnfreezeAssetContract) + }) +_sym_db.RegisterMessage(UnfreezeAssetContract) + +WithdrawBalanceContract = _reflection.GeneratedProtocolMessageType('WithdrawBalanceContract', (_message.Message,), { + 'DESCRIPTOR' : _WITHDRAWBALANCECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.WithdrawBalanceContract) + }) +_sym_db.RegisterMessage(WithdrawBalanceContract) + +UpdateAssetContract = _reflection.GeneratedProtocolMessageType('UpdateAssetContract', (_message.Message,), { + 'DESCRIPTOR' : _UPDATEASSETCONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.UpdateAssetContract) + }) +_sym_db.RegisterMessage(UpdateAssetContract) + +ProposalCreateContract = _reflection.GeneratedProtocolMessageType('ProposalCreateContract', (_message.Message,), { + + 'ParametersEntry' : _reflection.GeneratedProtocolMessageType('ParametersEntry', (_message.Message,), { + 'DESCRIPTOR' : _PROPOSALCREATECONTRACT_PARAMETERSENTRY, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.ProposalCreateContract.ParametersEntry) + }) + , + 'DESCRIPTOR' : _PROPOSALCREATECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.ProposalCreateContract) + }) +_sym_db.RegisterMessage(ProposalCreateContract) +_sym_db.RegisterMessage(ProposalCreateContract.ParametersEntry) + +ProposalApproveContract = _reflection.GeneratedProtocolMessageType('ProposalApproveContract', (_message.Message,), { + 'DESCRIPTOR' : _PROPOSALAPPROVECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.ProposalApproveContract) + }) +_sym_db.RegisterMessage(ProposalApproveContract) + +ProposalDeleteContract = _reflection.GeneratedProtocolMessageType('ProposalDeleteContract', (_message.Message,), { + 'DESCRIPTOR' : _PROPOSALDELETECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.ProposalDeleteContract) + }) +_sym_db.RegisterMessage(ProposalDeleteContract) + +TriggerSmartContract = _reflection.GeneratedProtocolMessageType('TriggerSmartContract', (_message.Message,), { + 'DESCRIPTOR' : _TRIGGERSMARTCONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.TriggerSmartContract) + }) +_sym_db.RegisterMessage(TriggerSmartContract) + +ExchangeCreateContract = _reflection.GeneratedProtocolMessageType('ExchangeCreateContract', (_message.Message,), { + 'DESCRIPTOR' : _EXCHANGECREATECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.ExchangeCreateContract) + }) +_sym_db.RegisterMessage(ExchangeCreateContract) + +ExchangeInjectContract = _reflection.GeneratedProtocolMessageType('ExchangeInjectContract', (_message.Message,), { + 'DESCRIPTOR' : _EXCHANGEINJECTCONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.ExchangeInjectContract) + }) +_sym_db.RegisterMessage(ExchangeInjectContract) + +ExchangeWithdrawContract = _reflection.GeneratedProtocolMessageType('ExchangeWithdrawContract', (_message.Message,), { + 'DESCRIPTOR' : _EXCHANGEWITHDRAWCONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.ExchangeWithdrawContract) + }) +_sym_db.RegisterMessage(ExchangeWithdrawContract) + +ExchangeTransactionContract = _reflection.GeneratedProtocolMessageType('ExchangeTransactionContract', (_message.Message,), { + 'DESCRIPTOR' : _EXCHANGETRANSACTIONCONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.ExchangeTransactionContract) + }) +_sym_db.RegisterMessage(ExchangeTransactionContract) + +AccountPermissionUpdateContract = _reflection.GeneratedProtocolMessageType('AccountPermissionUpdateContract', (_message.Message,), { + 'DESCRIPTOR' : _ACCOUNTPERMISSIONUPDATECONTRACT, + '__module__' : 'core.Contract_pb2' + # @@protoc_insertion_point(class_scope:protocol.AccountPermissionUpdateContract) + }) +_sym_db.RegisterMessage(AccountPermissionUpdateContract) + +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + DESCRIPTOR._serialized_options = b'\n\017org.tron.protosB\010ContractZ)github.com/tronprotocol/grpc-gateway/core' + _PROPOSALCREATECONTRACT_PARAMETERSENTRY._options = None + _PROPOSALCREATECONTRACT_PARAMETERSENTRY._serialized_options = b'8\001' + _RESOURCECODE._serialized_start=3704 + _RESOURCECODE._serialized_end=3745 + _ACCOUNTCREATECONTRACT._serialized_start=50 + _ACCOUNTCREATECONTRACT._serialized_end=158 + _ACCOUNTUPDATECONTRACT._serialized_start=160 + _ACCOUNTUPDATECONTRACT._serialized_end=228 + _TRANSFERCONTRACT._serialized_start=230 + _TRANSFERCONTRACT._serialized_end=307 + _TRANSFERASSETCONTRACT._serialized_start=309 + _TRANSFERASSETCONTRACT._serialized_end=411 + _VOTEASSETCONTRACT._serialized_start=413 + _VOTEASSETCONTRACT._serialized_end=509 + _VOTEWITNESSCONTRACT._serialized_start=512 + _VOTEWITNESSCONTRACT._serialized_end=674 + _VOTEWITNESSCONTRACT_VOTE._serialized_start=626 + _VOTEWITNESSCONTRACT_VOTE._serialized_end=674 + _WITNESSCREATECONTRACT._serialized_start=676 + _WITNESSCREATECONTRACT._serialized_end=735 + _WITNESSUPDATECONTRACT._serialized_start=737 + _WITNESSUPDATECONTRACT._serialized_end=803 + _ASSETISSUECONTRACT._serialized_start=806 + _ASSETISSUECONTRACT._serialized_end=1288 + _ASSETISSUECONTRACT_FROZENSUPPLY._serialized_start=1230 + _ASSETISSUECONTRACT_FROZENSUPPLY._serialized_end=1288 + _PARTICIPATEASSETISSUECONTRACT._serialized_start=1290 + _PARTICIPATEASSETISSUECONTRACT._serialized_end=1400 + _DEPLOYCONTRACT._serialized_start=1402 + _DEPLOYCONTRACT._serialized_end=1457 + _FREEZEBALANCECONTRACT._serialized_start=1460 + _FREEZEBALANCECONTRACT._serialized_end=1623 + _UNFREEZEBALANCECONTRACT._serialized_start=1625 + _UNFREEZEBALANCECONTRACT._serialized_end=1741 + _FREEZEBALANCEV2CONTRACT._serialized_start=1743 + _FREEZEBALANCEV2CONTRACT._serialized_end=1857 + _UNFREEZEBALANCEV2CONTRACT._serialized_start=1859 + _UNFREEZEBALANCEV2CONTRACT._serialized_end=1977 + _WITHDRAWEXPIREUNFREEZECONTRACT._serialized_start=1979 + _WITHDRAWEXPIREUNFREEZECONTRACT._serialized_end=2034 + _DELEGATERESOURCECONTRACT._serialized_start=2037 + _DELEGATERESOURCECONTRACT._serialized_end=2185 + _UNDELEGATERESOURCECONTRACT._serialized_start=2188 + _UNDELEGATERESOURCECONTRACT._serialized_end=2324 + _UNFREEZEASSETCONTRACT._serialized_start=2326 + _UNFREEZEASSETCONTRACT._serialized_end=2372 + _WITHDRAWBALANCECONTRACT._serialized_start=2374 + _WITHDRAWBALANCECONTRACT._serialized_end=2422 + _UPDATEASSETCONTRACT._serialized_start=2424 + _UPDATEASSETCONTRACT._serialized_end=2547 + _PROPOSALCREATECONTRACT._serialized_start=2550 + _PROPOSALCREATECONTRACT._serialized_end=2718 + _PROPOSALCREATECONTRACT_PARAMETERSENTRY._serialized_start=2669 + _PROPOSALCREATECONTRACT_PARAMETERSENTRY._serialized_end=2718 + _PROPOSALAPPROVECONTRACT._serialized_start=2720 + _PROPOSALAPPROVECONTRACT._serialized_end=2814 + _PROPOSALDELETECONTRACT._serialized_start=2816 + _PROPOSALDELETECONTRACT._serialized_end=2884 + _TRIGGERSMARTCONTRACT._serialized_start=2887 + _TRIGGERSMARTCONTRACT._serialized_end=3036 + _EXCHANGECREATECONTRACT._serialized_start=3039 + _EXCHANGECREATECONTRACT._serialized_end=3194 + _EXCHANGEINJECTCONTRACT._serialized_start=3196 + _EXCHANGEINJECTCONTRACT._serialized_end=3297 + _EXCHANGEWITHDRAWCONTRACT._serialized_start=3299 + _EXCHANGEWITHDRAWCONTRACT._serialized_end=3402 + _EXCHANGETRANSACTIONCONTRACT._serialized_start=3404 + _EXCHANGETRANSACTIONCONTRACT._serialized_end=3528 + _ACCOUNTPERMISSIONUPDATECONTRACT._serialized_start=3531 + _ACCOUNTPERMISSIONUPDATECONTRACT._serialized_end=3702 +# @@protoc_insertion_point(module_scope) diff --git a/test/python/apps/tron_proto/core/Tron.options b/test/python/apps/tron_proto/core/Tron.options new file mode 100644 index 0000000..ed7e832 --- /dev/null +++ b/test/python/apps/tron_proto/core/Tron.options @@ -0,0 +1,13 @@ +protocol.Transaction.raw.contract max_count: 1 +protocol.Transaction.raw.ref_block_bytes type: FT_IGNORE +protocol.Transaction.raw.ref_block_num type: FT_IGNORE +protocol.Transaction.raw.ref_block_hash type: FT_IGNORE +protocol.Transaction.raw.expiration type: FT_IGNORE +protocol.Transaction.raw.auths type: FT_IGNORE +protocol.Transaction.raw.scripts type: FT_IGNORE +protocol.Transaction.raw.timestamp type: FT_IGNORE + +protocol.Key.address max_size: 21, fixed_length: true + +protocol.Permission.keys max_count: 3 # Assume 3 max keys +protocol.Permission.operations max_size: 32, fixed_length: true diff --git a/test/python/apps/tron_proto/core/Tron.pb.c b/test/python/apps/tron_proto/core/Tron.pb.c new file mode 100644 index 0000000..d786937 --- /dev/null +++ b/test/python/apps/tron_proto/core/Tron.pb.c @@ -0,0 +1,41 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.5 */ + +#include "core/Tron.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(protocol_Exchange, protocol_Exchange, AUTO) + + +PB_BIND(protocol_AccountId, protocol_AccountId, AUTO) + + +PB_BIND(protocol_authority, protocol_authority, AUTO) + + +PB_BIND(protocol_Transaction, protocol_Transaction, AUTO) + + +PB_BIND(protocol_Transaction_Contract, protocol_Transaction_Contract, AUTO) + + +PB_BIND(protocol_Transaction_Result, protocol_Transaction_Result, AUTO) + + +PB_BIND(protocol_Transaction_raw, protocol_Transaction_raw, AUTO) + + +PB_BIND(protocol_Key, protocol_Key, AUTO) + + +PB_BIND(protocol_Permission, protocol_Permission, AUTO) + + + + + + + + diff --git a/test/python/apps/tron_proto/core/Tron.pb.h b/test/python/apps/tron_proto/core/Tron.pb.h new file mode 100644 index 0000000..d6edada --- /dev/null +++ b/test/python/apps/tron_proto/core/Tron.pb.h @@ -0,0 +1,376 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.5 */ + +#ifndef PB_PROTOCOL_CORE_TRON_PB_H_INCLUDED +#define PB_PROTOCOL_CORE_TRON_PB_H_INCLUDED +#include +#include "google/protobuf/any.pb.h" + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +typedef enum _protocol_AccountType { + protocol_AccountType_Normal = 0, + protocol_AccountType_AssetIssue = 1, + protocol_AccountType_Contract = 2 +} protocol_AccountType; + +typedef enum _protocol_Transaction_Contract_ContractType { + protocol_Transaction_Contract_ContractType_AccountCreateContract = 0, + protocol_Transaction_Contract_ContractType_TransferContract = 1, + protocol_Transaction_Contract_ContractType_TransferAssetContract = 2, + protocol_Transaction_Contract_ContractType_VoteAssetContract = 3, + protocol_Transaction_Contract_ContractType_VoteWitnessContract = 4, + protocol_Transaction_Contract_ContractType_WitnessCreateContract = 5, + protocol_Transaction_Contract_ContractType_AssetIssueContract = 6, + protocol_Transaction_Contract_ContractType_WitnessUpdateContract = 8, + protocol_Transaction_Contract_ContractType_ParticipateAssetIssueContract = 9, + protocol_Transaction_Contract_ContractType_AccountUpdateContract = 10, + protocol_Transaction_Contract_ContractType_FreezeBalanceContract = 11, + protocol_Transaction_Contract_ContractType_UnfreezeBalanceContract = 12, + protocol_Transaction_Contract_ContractType_WithdrawBalanceContract = 13, + protocol_Transaction_Contract_ContractType_UnfreezeAssetContract = 14, + protocol_Transaction_Contract_ContractType_UpdateAssetContract = 15, + protocol_Transaction_Contract_ContractType_ProposalCreateContract = 16, + protocol_Transaction_Contract_ContractType_ProposalApproveContract = 17, + protocol_Transaction_Contract_ContractType_ProposalDeleteContract = 18, + protocol_Transaction_Contract_ContractType_SetAccountIdContract = 19, + protocol_Transaction_Contract_ContractType_CustomContract = 20, + protocol_Transaction_Contract_ContractType_CreateSmartContract = 30, + protocol_Transaction_Contract_ContractType_TriggerSmartContract = 31, + protocol_Transaction_Contract_ContractType_GetContract = 32, + protocol_Transaction_Contract_ContractType_UpdateSettingContract = 33, + protocol_Transaction_Contract_ContractType_ExchangeCreateContract = 41, + protocol_Transaction_Contract_ContractType_ExchangeInjectContract = 42, + protocol_Transaction_Contract_ContractType_ExchangeWithdrawContract = 43, + protocol_Transaction_Contract_ContractType_ExchangeTransactionContract = 44, + protocol_Transaction_Contract_ContractType_UpdateEnergyLimitContract = 45, + protocol_Transaction_Contract_ContractType_AccountPermissionUpdateContract = 46, + protocol_Transaction_Contract_ContractType_ClearABIContract = 48, + protocol_Transaction_Contract_ContractType_UpdateBrokerageContract = 49, + protocol_Transaction_Contract_ContractType_FreezeBalanceV2Contract = 54, + protocol_Transaction_Contract_ContractType_UnfreezeBalanceV2Contract = 55, + protocol_Transaction_Contract_ContractType_WithdrawExpireUnfreezeContract = 56, + protocol_Transaction_Contract_ContractType_DelegateResourceContract = 57, + protocol_Transaction_Contract_ContractType_UnDelegateResourceContract = 58 +} protocol_Transaction_Contract_ContractType; + +typedef enum _protocol_Transaction_Result_code { + protocol_Transaction_Result_code_SUCESS = 0, + protocol_Transaction_Result_code_FAILED = 1 +} protocol_Transaction_Result_code; + +typedef enum _protocol_Transaction_Result_contractResult { + protocol_Transaction_Result_contractResult_DEFAULT = 0, + protocol_Transaction_Result_contractResult_SUCCESS = 1, + protocol_Transaction_Result_contractResult_REVERT = 2, + protocol_Transaction_Result_contractResult_BAD_JUMP_DESTINATION = 3, + protocol_Transaction_Result_contractResult_OUT_OF_MEMORY = 4, + protocol_Transaction_Result_contractResult_PRECOMPILED_CONTRACT = 5, + protocol_Transaction_Result_contractResult_STACK_TOO_SMALL = 6, + protocol_Transaction_Result_contractResult_STACK_TOO_LARGE = 7, + protocol_Transaction_Result_contractResult_ILLEGAL_OPERATION = 8, + protocol_Transaction_Result_contractResult_STACK_OVERFLOW = 9, + protocol_Transaction_Result_contractResult_OUT_OF_ENERGY = 10, + protocol_Transaction_Result_contractResult_OUT_OF_TIME = 11, + protocol_Transaction_Result_contractResult_JVM_STACK_OVER_FLOW = 12, + protocol_Transaction_Result_contractResult_UNKNOWN = 13, + protocol_Transaction_Result_contractResult_TRANSFER_FAILED = 14 +} protocol_Transaction_Result_contractResult; + +typedef enum _protocol_Permission_PermissionType { + protocol_Permission_PermissionType_Owner = 0, + protocol_Permission_PermissionType_Witness = 1, + protocol_Permission_PermissionType_Active = 2 +} protocol_Permission_PermissionType; + +/* Struct definitions */ +/* AccountId, (name, address) use name, (null, address) use address, (name, null) use name, */ +typedef struct _protocol_AccountId { + pb_callback_t name; + pb_callback_t address; +} protocol_AccountId; + +/* Exchange */ +typedef struct _protocol_Exchange { + int64_t exchange_id; + pb_callback_t creator_address; + int64_t create_time; + pb_callback_t first_token_id; + int64_t first_token_balance; + pb_callback_t second_token_id; + int64_t second_token_balance; +} protocol_Exchange; + +typedef struct _protocol_Key { + pb_byte_t address[21]; + int64_t weight; +} protocol_Key; + +typedef struct _protocol_Transaction_Contract { + protocol_Transaction_Contract_ContractType type; + bool has_parameter; + google_protobuf_Any parameter; + pb_callback_t provider; + pb_callback_t ContractName; + int32_t Permission_id; +} protocol_Transaction_Contract; + +typedef struct _protocol_Transaction_Result { + int64_t fee; + protocol_Transaction_Result_code ret; /* Owner id=0, Witness id=1, Active id start by 2 */ + protocol_Transaction_Result_contractResult contractRet; + pb_callback_t assetIssueID; + int64_t withdraw_amount; + int64_t unfreeze_amount; /* 1 bit 1 contract */ + int64_t exchange_received_amount; + int64_t exchange_inject_another_amount; + int64_t exchange_withdraw_another_amount; + int64_t exchange_id; +} protocol_Transaction_Result; + +typedef struct _protocol_authority { + bool has_account; + protocol_AccountId account; + pb_callback_t permission_name; +} protocol_authority; + +typedef struct _protocol_Permission { + protocol_Permission_PermissionType type; + int32_t id; + pb_callback_t permission_name; + int64_t threshold; + int32_t parent_id; + pb_byte_t operations[32]; + pb_size_t keys_count; + protocol_Key keys[3]; +} protocol_Permission; + +typedef struct _protocol_Transaction_raw { + pb_callback_t custom_data; + pb_size_t contract_count; + protocol_Transaction_Contract contract[1]; + int64_t fee_limit; +} protocol_Transaction_raw; + +typedef struct _protocol_Transaction { + bool has_raw_data; + protocol_Transaction_raw raw_data; + /* only support size = 1, repeated list here for muti-sig extension */ + pb_callback_t signature; + pb_callback_t ret; +} protocol_Transaction; + + +/* Helper constants for enums */ +#define _protocol_AccountType_MIN protocol_AccountType_Normal +#define _protocol_AccountType_MAX protocol_AccountType_Contract +#define _protocol_AccountType_ARRAYSIZE ((protocol_AccountType)(protocol_AccountType_Contract+1)) + +#define _protocol_Transaction_Contract_ContractType_MIN protocol_Transaction_Contract_ContractType_AccountCreateContract +#define _protocol_Transaction_Contract_ContractType_MAX protocol_Transaction_Contract_ContractType_UnDelegateResourceContract +#define _protocol_Transaction_Contract_ContractType_ARRAYSIZE ((protocol_Transaction_Contract_ContractType)(protocol_Transaction_Contract_ContractType_UnDelegateResourceContract+1)) + +#define _protocol_Transaction_Result_code_MIN protocol_Transaction_Result_code_SUCESS +#define _protocol_Transaction_Result_code_MAX protocol_Transaction_Result_code_FAILED +#define _protocol_Transaction_Result_code_ARRAYSIZE ((protocol_Transaction_Result_code)(protocol_Transaction_Result_code_FAILED+1)) + +#define _protocol_Transaction_Result_contractResult_MIN protocol_Transaction_Result_contractResult_DEFAULT +#define _protocol_Transaction_Result_contractResult_MAX protocol_Transaction_Result_contractResult_TRANSFER_FAILED +#define _protocol_Transaction_Result_contractResult_ARRAYSIZE ((protocol_Transaction_Result_contractResult)(protocol_Transaction_Result_contractResult_TRANSFER_FAILED+1)) + +#define _protocol_Permission_PermissionType_MIN protocol_Permission_PermissionType_Owner +#define _protocol_Permission_PermissionType_MAX protocol_Permission_PermissionType_Active +#define _protocol_Permission_PermissionType_ARRAYSIZE ((protocol_Permission_PermissionType)(protocol_Permission_PermissionType_Active+1)) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define protocol_Exchange_init_default {0, {{NULL}, NULL}, 0, {{NULL}, NULL}, 0, {{NULL}, NULL}, 0} +#define protocol_AccountId_init_default {{{NULL}, NULL}, {{NULL}, NULL}} +#define protocol_authority_init_default {false, protocol_AccountId_init_default, {{NULL}, NULL}} +#define protocol_Transaction_init_default {false, protocol_Transaction_raw_init_default, {{NULL}, NULL}, {{NULL}, NULL}} +#define protocol_Transaction_Contract_init_default {_protocol_Transaction_Contract_ContractType_MIN, false, google_protobuf_Any_init_default, {{NULL}, NULL}, {{NULL}, NULL}, 0} +#define protocol_Transaction_Result_init_default {0, _protocol_Transaction_Result_code_MIN, _protocol_Transaction_Result_contractResult_MIN, {{NULL}, NULL}, 0, 0, 0, 0, 0, 0} +#define protocol_Transaction_raw_init_default {{{NULL}, NULL}, 0, {protocol_Transaction_Contract_init_default}, 0} +#define protocol_Key_init_default {{0}, 0} +#define protocol_Permission_init_default {_protocol_Permission_PermissionType_MIN, 0, {{NULL}, NULL}, 0, 0, {0}, 0, {protocol_Key_init_default, protocol_Key_init_default, protocol_Key_init_default}} +#define protocol_Exchange_init_zero {0, {{NULL}, NULL}, 0, {{NULL}, NULL}, 0, {{NULL}, NULL}, 0} +#define protocol_AccountId_init_zero {{{NULL}, NULL}, {{NULL}, NULL}} +#define protocol_authority_init_zero {false, protocol_AccountId_init_zero, {{NULL}, NULL}} +#define protocol_Transaction_init_zero {false, protocol_Transaction_raw_init_zero, {{NULL}, NULL}, {{NULL}, NULL}} +#define protocol_Transaction_Contract_init_zero {_protocol_Transaction_Contract_ContractType_MIN, false, google_protobuf_Any_init_zero, {{NULL}, NULL}, {{NULL}, NULL}, 0} +#define protocol_Transaction_Result_init_zero {0, _protocol_Transaction_Result_code_MIN, _protocol_Transaction_Result_contractResult_MIN, {{NULL}, NULL}, 0, 0, 0, 0, 0, 0} +#define protocol_Transaction_raw_init_zero {{{NULL}, NULL}, 0, {protocol_Transaction_Contract_init_zero}, 0} +#define protocol_Key_init_zero {{0}, 0} +#define protocol_Permission_init_zero {_protocol_Permission_PermissionType_MIN, 0, {{NULL}, NULL}, 0, 0, {0}, 0, {protocol_Key_init_zero, protocol_Key_init_zero, protocol_Key_init_zero}} + +/* Field tags (for use in manual encoding/decoding) */ +#define protocol_AccountId_name_tag 1 +#define protocol_AccountId_address_tag 2 +#define protocol_Exchange_exchange_id_tag 1 +#define protocol_Exchange_creator_address_tag 2 +#define protocol_Exchange_create_time_tag 3 +#define protocol_Exchange_first_token_id_tag 6 +#define protocol_Exchange_first_token_balance_tag 7 +#define protocol_Exchange_second_token_id_tag 8 +#define protocol_Exchange_second_token_balance_tag 9 +#define protocol_Key_address_tag 1 +#define protocol_Key_weight_tag 2 +#define protocol_Transaction_Contract_type_tag 1 +#define protocol_Transaction_Contract_parameter_tag 2 +#define protocol_Transaction_Contract_provider_tag 3 +#define protocol_Transaction_Contract_ContractName_tag 4 +#define protocol_Transaction_Contract_Permission_id_tag 5 +#define protocol_Transaction_Result_fee_tag 1 +#define protocol_Transaction_Result_ret_tag 2 +#define protocol_Transaction_Result_contractRet_tag 3 +#define protocol_Transaction_Result_assetIssueID_tag 14 +#define protocol_Transaction_Result_withdraw_amount_tag 15 +#define protocol_Transaction_Result_unfreeze_amount_tag 16 +#define protocol_Transaction_Result_exchange_received_amount_tag 18 +#define protocol_Transaction_Result_exchange_inject_another_amount_tag 19 +#define protocol_Transaction_Result_exchange_withdraw_another_amount_tag 20 +#define protocol_Transaction_Result_exchange_id_tag 21 +#define protocol_authority_account_tag 1 +#define protocol_authority_permission_name_tag 2 +#define protocol_Permission_type_tag 1 +#define protocol_Permission_id_tag 2 +#define protocol_Permission_permission_name_tag 3 +#define protocol_Permission_threshold_tag 4 +#define protocol_Permission_parent_id_tag 5 +#define protocol_Permission_operations_tag 6 +#define protocol_Permission_keys_tag 7 +#define protocol_Transaction_raw_custom_data_tag 10 +#define protocol_Transaction_raw_contract_tag 11 +#define protocol_Transaction_raw_fee_limit_tag 18 +#define protocol_Transaction_raw_data_tag 1 +#define protocol_Transaction_signature_tag 2 +#define protocol_Transaction_ret_tag 5 + +/* Struct field encoding specification for nanopb */ +#define protocol_Exchange_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, INT64, exchange_id, 1) \ +X(a, CALLBACK, SINGULAR, BYTES, creator_address, 2) \ +X(a, STATIC, SINGULAR, INT64, create_time, 3) \ +X(a, CALLBACK, SINGULAR, BYTES, first_token_id, 6) \ +X(a, STATIC, SINGULAR, INT64, first_token_balance, 7) \ +X(a, CALLBACK, SINGULAR, BYTES, second_token_id, 8) \ +X(a, STATIC, SINGULAR, INT64, second_token_balance, 9) +#define protocol_Exchange_CALLBACK pb_default_field_callback +#define protocol_Exchange_DEFAULT NULL + +#define protocol_AccountId_FIELDLIST(X, a) \ +X(a, CALLBACK, SINGULAR, BYTES, name, 1) \ +X(a, CALLBACK, SINGULAR, BYTES, address, 2) +#define protocol_AccountId_CALLBACK pb_default_field_callback +#define protocol_AccountId_DEFAULT NULL + +#define protocol_authority_FIELDLIST(X, a) \ +X(a, STATIC, OPTIONAL, MESSAGE, account, 1) \ +X(a, CALLBACK, SINGULAR, BYTES, permission_name, 2) +#define protocol_authority_CALLBACK pb_default_field_callback +#define protocol_authority_DEFAULT NULL +#define protocol_authority_account_MSGTYPE protocol_AccountId + +#define protocol_Transaction_FIELDLIST(X, a) \ +X(a, STATIC, OPTIONAL, MESSAGE, raw_data, 1) \ +X(a, CALLBACK, REPEATED, BYTES, signature, 2) \ +X(a, CALLBACK, REPEATED, MESSAGE, ret, 5) +#define protocol_Transaction_CALLBACK pb_default_field_callback +#define protocol_Transaction_DEFAULT NULL +#define protocol_Transaction_raw_data_MSGTYPE protocol_Transaction_raw +#define protocol_Transaction_ret_MSGTYPE protocol_Transaction_Result + +#define protocol_Transaction_Contract_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, type, 1) \ +X(a, STATIC, OPTIONAL, MESSAGE, parameter, 2) \ +X(a, CALLBACK, SINGULAR, BYTES, provider, 3) \ +X(a, CALLBACK, SINGULAR, BYTES, ContractName, 4) \ +X(a, STATIC, SINGULAR, INT32, Permission_id, 5) +#define protocol_Transaction_Contract_CALLBACK pb_default_field_callback +#define protocol_Transaction_Contract_DEFAULT NULL +#define protocol_Transaction_Contract_parameter_MSGTYPE google_protobuf_Any + +#define protocol_Transaction_Result_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, INT64, fee, 1) \ +X(a, STATIC, SINGULAR, UENUM, ret, 2) \ +X(a, STATIC, SINGULAR, UENUM, contractRet, 3) \ +X(a, CALLBACK, SINGULAR, STRING, assetIssueID, 14) \ +X(a, STATIC, SINGULAR, INT64, withdraw_amount, 15) \ +X(a, STATIC, SINGULAR, INT64, unfreeze_amount, 16) \ +X(a, STATIC, SINGULAR, INT64, exchange_received_amount, 18) \ +X(a, STATIC, SINGULAR, INT64, exchange_inject_another_amount, 19) \ +X(a, STATIC, SINGULAR, INT64, exchange_withdraw_another_amount, 20) \ +X(a, STATIC, SINGULAR, INT64, exchange_id, 21) +#define protocol_Transaction_Result_CALLBACK pb_default_field_callback +#define protocol_Transaction_Result_DEFAULT NULL + +#define protocol_Transaction_raw_FIELDLIST(X, a) \ +X(a, CALLBACK, SINGULAR, BYTES, custom_data, 10) \ +X(a, STATIC, REPEATED, MESSAGE, contract, 11) \ +X(a, STATIC, SINGULAR, INT64, fee_limit, 18) +#define protocol_Transaction_raw_CALLBACK pb_default_field_callback +#define protocol_Transaction_raw_DEFAULT NULL +#define protocol_Transaction_raw_contract_MSGTYPE protocol_Transaction_Contract + +#define protocol_Key_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, address, 1) \ +X(a, STATIC, SINGULAR, INT64, weight, 2) +#define protocol_Key_CALLBACK NULL +#define protocol_Key_DEFAULT NULL + +#define protocol_Permission_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, type, 1) \ +X(a, STATIC, SINGULAR, INT32, id, 2) \ +X(a, CALLBACK, SINGULAR, STRING, permission_name, 3) \ +X(a, STATIC, SINGULAR, INT64, threshold, 4) \ +X(a, STATIC, SINGULAR, INT32, parent_id, 5) \ +X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, operations, 6) \ +X(a, STATIC, REPEATED, MESSAGE, keys, 7) +#define protocol_Permission_CALLBACK pb_default_field_callback +#define protocol_Permission_DEFAULT NULL +#define protocol_Permission_keys_MSGTYPE protocol_Key + +extern const pb_msgdesc_t protocol_Exchange_msg; +extern const pb_msgdesc_t protocol_AccountId_msg; +extern const pb_msgdesc_t protocol_authority_msg; +extern const pb_msgdesc_t protocol_Transaction_msg; +extern const pb_msgdesc_t protocol_Transaction_Contract_msg; +extern const pb_msgdesc_t protocol_Transaction_Result_msg; +extern const pb_msgdesc_t protocol_Transaction_raw_msg; +extern const pb_msgdesc_t protocol_Key_msg; +extern const pb_msgdesc_t protocol_Permission_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define protocol_Exchange_fields &protocol_Exchange_msg +#define protocol_AccountId_fields &protocol_AccountId_msg +#define protocol_authority_fields &protocol_authority_msg +#define protocol_Transaction_fields &protocol_Transaction_msg +#define protocol_Transaction_Contract_fields &protocol_Transaction_Contract_msg +#define protocol_Transaction_Result_fields &protocol_Transaction_Result_msg +#define protocol_Transaction_raw_fields &protocol_Transaction_raw_msg +#define protocol_Key_fields &protocol_Key_msg +#define protocol_Permission_fields &protocol_Permission_msg + +/* Maximum encoded size of messages (where known) */ +/* protocol_Exchange_size depends on runtime parameters */ +/* protocol_AccountId_size depends on runtime parameters */ +/* protocol_authority_size depends on runtime parameters */ +/* protocol_Transaction_size depends on runtime parameters */ +/* protocol_Transaction_Contract_size depends on runtime parameters */ +/* protocol_Transaction_Result_size depends on runtime parameters */ +/* protocol_Transaction_raw_size depends on runtime parameters */ +/* protocol_Permission_size depends on runtime parameters */ +#define protocol_Key_size 34 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/test/python/apps/tron_proto/core/Tron.proto b/test/python/apps/tron_proto/core/Tron.proto new file mode 100644 index 0000000..63da792 --- /dev/null +++ b/test/python/apps/tron_proto/core/Tron.proto @@ -0,0 +1,162 @@ +syntax = "proto3"; + +import "google/protobuf/any.proto"; +// import "core/Discover.proto"; + +package protocol; + +enum AccountType { + Normal = 0; + AssetIssue = 1; + Contract = 2; +} + +// Exchange +message Exchange { + int64 exchange_id = 1; + bytes creator_address = 2; + int64 create_time = 3; + bytes first_token_id = 6; + int64 first_token_balance = 7; + bytes second_token_id = 8; + int64 second_token_balance = 9; +} + +// AccountId, (name, address) use name, (null, address) use address, (name, null) use name, +message AccountId { + bytes name = 1; + bytes address = 2; +} + +message authority { + AccountId account = 1; + bytes permission_name = 2; +} + +message Transaction { + message Contract { + enum ContractType { + AccountCreateContract = 0; + TransferContract = 1; + TransferAssetContract = 2; + VoteAssetContract = 3; + VoteWitnessContract = 4; + WitnessCreateContract = 5; + AssetIssueContract = 6; + WitnessUpdateContract = 8; + ParticipateAssetIssueContract = 9; + AccountUpdateContract = 10; + FreezeBalanceContract = 11; + UnfreezeBalanceContract = 12; + WithdrawBalanceContract = 13; + UnfreezeAssetContract = 14; + UpdateAssetContract = 15; + ProposalCreateContract = 16; + ProposalApproveContract = 17; + ProposalDeleteContract = 18; + SetAccountIdContract = 19; + CustomContract = 20; + // BuyStorageContract = 21; + // BuyStorageBytesContract = 22; + // SellStorageContract = 23; + CreateSmartContract = 30; + TriggerSmartContract = 31; + GetContract = 32; + UpdateSettingContract = 33; + ExchangeCreateContract = 41; + ExchangeInjectContract = 42; + ExchangeWithdrawContract = 43; + ExchangeTransactionContract = 44; + UpdateEnergyLimitContract = 45; + AccountPermissionUpdateContract = 46; + ClearABIContract = 48; + UpdateBrokerageContract = 49; + FreezeBalanceV2Contract = 54; + UnfreezeBalanceV2Contract = 55; + WithdrawExpireUnfreezeContract = 56; + DelegateResourceContract = 57; + UnDelegateResourceContract = 58; + } + ContractType type = 1; + google.protobuf.Any parameter = 2; + bytes provider = 3; + bytes ContractName = 4; + int32 Permission_id = 5; + } + + message Result { + enum code { + SUCESS = 0; + FAILED = 1; + } + enum contractResult { + DEFAULT = 0; + SUCCESS = 1; + REVERT = 2; + BAD_JUMP_DESTINATION = 3; + OUT_OF_MEMORY = 4; + PRECOMPILED_CONTRACT = 5; + STACK_TOO_SMALL = 6; + STACK_TOO_LARGE = 7; + ILLEGAL_OPERATION = 8; + STACK_OVERFLOW = 9; + OUT_OF_ENERGY = 10; + OUT_OF_TIME = 11; + JVM_STACK_OVER_FLOW = 12; + UNKNOWN = 13; + TRANSFER_FAILED = 14; + } + int64 fee = 1; + code ret = 2; + contractResult contractRet = 3; + + string assetIssueID = 14; + int64 withdraw_amount = 15; + int64 unfreeze_amount = 16; + int64 exchange_received_amount = 18; + int64 exchange_inject_another_amount = 19; + int64 exchange_withdraw_another_amount = 20; + int64 exchange_id = 21; + } + + message raw { + bytes ref_block_bytes = 1; + int64 ref_block_num = 3; + bytes ref_block_hash = 4; + int64 expiration = 8; + repeated authority auths = 9; + // data not used + bytes custom_data = 10; + //only support size = 1, repeated list here for extension + repeated Contract contract = 11; + // scripts not used + bytes scripts = 12; + int64 timestamp = 14; + int64 fee_limit = 18; + } + + raw raw_data = 1; + // only support size = 1, repeated list here for muti-sig extension + repeated bytes signature = 2; + repeated Result ret = 5; +} + +message Key { + bytes address = 1; + int64 weight = 2; +} + +message Permission { + enum PermissionType { + Owner = 0; + Witness = 1; + Active = 2; + } + PermissionType type = 1; + int32 id = 2; //Owner id=0, Witness id=1, Active id start by 2 + string permission_name = 3; + int64 threshold = 4; + int32 parent_id = 5; + bytes operations = 6; //1 bit 1 contract + repeated Key keys = 7; +} diff --git a/test/python/apps/tron_proto/core/Tron_pb2.py b/test/python/apps/tron_proto/core/Tron_pb2.py new file mode 100644 index 0000000..0142b3d --- /dev/null +++ b/test/python/apps/tron_proto/core/Tron_pb2.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: core/Tron.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0f\x63ore/Tron.proto\x12\x08protocol\x1a\x19google/protobuf/any.proto\"\xb9\x01\n\x08\x45xchange\x12\x13\n\x0b\x65xchange_id\x18\x01 \x01(\x03\x12\x17\n\x0f\x63reator_address\x18\x02 \x01(\x0c\x12\x13\n\x0b\x63reate_time\x18\x03 \x01(\x03\x12\x16\n\x0e\x66irst_token_id\x18\x06 \x01(\x0c\x12\x1b\n\x13\x66irst_token_balance\x18\x07 \x01(\x03\x12\x17\n\x0fsecond_token_id\x18\x08 \x01(\x0c\x12\x1c\n\x14second_token_balance\x18\t \x01(\x03\"*\n\tAccountId\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x01(\x0c\"J\n\tauthority\x12$\n\x07\x61\x63\x63ount\x18\x01 \x01(\x0b\x32\x13.protocol.AccountId\x12\x17\n\x0fpermission_name\x18\x02 \x01(\x0c\"\xed\x11\n\x0bTransaction\x12+\n\x08raw_data\x18\x01 \x01(\x0b\x32\x19.protocol.Transaction.raw\x12\x11\n\tsignature\x18\x02 \x03(\x0c\x12)\n\x03ret\x18\x05 \x03(\x0b\x32\x1c.protocol.Transaction.Result\x1a\xbd\t\n\x08\x43ontract\x12\x39\n\x04type\x18\x01 \x01(\x0e\x32+.protocol.Transaction.Contract.ContractType\x12\'\n\tparameter\x18\x02 \x01(\x0b\x32\x14.google.protobuf.Any\x12\x10\n\x08provider\x18\x03 \x01(\x0c\x12\x14\n\x0c\x43ontractName\x18\x04 \x01(\x0c\x12\x15\n\rPermission_id\x18\x05 \x01(\x05\"\x8d\x08\n\x0c\x43ontractType\x12\x19\n\x15\x41\x63\x63ountCreateContract\x10\x00\x12\x14\n\x10TransferContract\x10\x01\x12\x19\n\x15TransferAssetContract\x10\x02\x12\x15\n\x11VoteAssetContract\x10\x03\x12\x17\n\x13VoteWitnessContract\x10\x04\x12\x19\n\x15WitnessCreateContract\x10\x05\x12\x16\n\x12\x41ssetIssueContract\x10\x06\x12\x19\n\x15WitnessUpdateContract\x10\x08\x12!\n\x1dParticipateAssetIssueContract\x10\t\x12\x19\n\x15\x41\x63\x63ountUpdateContract\x10\n\x12\x19\n\x15\x46reezeBalanceContract\x10\x0b\x12\x1b\n\x17UnfreezeBalanceContract\x10\x0c\x12\x1b\n\x17WithdrawBalanceContract\x10\r\x12\x19\n\x15UnfreezeAssetContract\x10\x0e\x12\x17\n\x13UpdateAssetContract\x10\x0f\x12\x1a\n\x16ProposalCreateContract\x10\x10\x12\x1b\n\x17ProposalApproveContract\x10\x11\x12\x1a\n\x16ProposalDeleteContract\x10\x12\x12\x18\n\x14SetAccountIdContract\x10\x13\x12\x12\n\x0e\x43ustomContract\x10\x14\x12\x17\n\x13\x43reateSmartContract\x10\x1e\x12\x18\n\x14TriggerSmartContract\x10\x1f\x12\x0f\n\x0bGetContract\x10 \x12\x19\n\x15UpdateSettingContract\x10!\x12\x1a\n\x16\x45xchangeCreateContract\x10)\x12\x1a\n\x16\x45xchangeInjectContract\x10*\x12\x1c\n\x18\x45xchangeWithdrawContract\x10+\x12\x1f\n\x1b\x45xchangeTransactionContract\x10,\x12\x1d\n\x19UpdateEnergyLimitContract\x10-\x12#\n\x1f\x41\x63\x63ountPermissionUpdateContract\x10.\x12\x14\n\x10\x43learABIContract\x10\x30\x12\x1b\n\x17UpdateBrokerageContract\x10\x31\x12\x1b\n\x17\x46reezeBalanceV2Contract\x10\x36\x12\x1d\n\x19UnfreezeBalanceV2Contract\x10\x37\x12\"\n\x1eWithdrawExpireUnfreezeContract\x10\x38\x12\x1c\n\x18\x44\x65legateResourceContract\x10\x39\x12\x1e\n\x1aUnDelegateResourceContract\x10:\x1a\xac\x05\n\x06Result\x12\x0b\n\x03\x66\x65\x65\x18\x01 \x01(\x03\x12.\n\x03ret\x18\x02 \x01(\x0e\x32!.protocol.Transaction.Result.code\x12@\n\x0b\x63ontractRet\x18\x03 \x01(\x0e\x32+.protocol.Transaction.Result.contractResult\x12\x14\n\x0c\x61ssetIssueID\x18\x0e \x01(\t\x12\x17\n\x0fwithdraw_amount\x18\x0f \x01(\x03\x12\x17\n\x0funfreeze_amount\x18\x10 \x01(\x03\x12 \n\x18\x65xchange_received_amount\x18\x12 \x01(\x03\x12&\n\x1e\x65xchange_inject_another_amount\x18\x13 \x01(\x03\x12(\n exchange_withdraw_another_amount\x18\x14 \x01(\x03\x12\x13\n\x0b\x65xchange_id\x18\x15 \x01(\x03\"\x1e\n\x04\x63ode\x12\n\n\x06SUCESS\x10\x00\x12\n\n\x06\x46\x41ILED\x10\x01\"\xb1\x02\n\x0e\x63ontractResult\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x00\x12\x0b\n\x07SUCCESS\x10\x01\x12\n\n\x06REVERT\x10\x02\x12\x18\n\x14\x42\x41\x44_JUMP_DESTINATION\x10\x03\x12\x11\n\rOUT_OF_MEMORY\x10\x04\x12\x18\n\x14PRECOMPILED_CONTRACT\x10\x05\x12\x13\n\x0fSTACK_TOO_SMALL\x10\x06\x12\x13\n\x0fSTACK_TOO_LARGE\x10\x07\x12\x15\n\x11ILLEGAL_OPERATION\x10\x08\x12\x12\n\x0eSTACK_OVERFLOW\x10\t\x12\x11\n\rOUT_OF_ENERGY\x10\n\x12\x0f\n\x0bOUT_OF_TIME\x10\x0b\x12\x17\n\x13JVM_STACK_OVER_FLOW\x10\x0c\x12\x0b\n\x07UNKNOWN\x10\r\x12\x13\n\x0fTRANSFER_FAILED\x10\x0e\x1a\x83\x02\n\x03raw\x12\x17\n\x0fref_block_bytes\x18\x01 \x01(\x0c\x12\x15\n\rref_block_num\x18\x03 \x01(\x03\x12\x16\n\x0eref_block_hash\x18\x04 \x01(\x0c\x12\x12\n\nexpiration\x18\x08 \x01(\x03\x12\"\n\x05\x61uths\x18\t \x03(\x0b\x32\x13.protocol.authority\x12\x13\n\x0b\x63ustom_data\x18\n \x01(\x0c\x12\x30\n\x08\x63ontract\x18\x0b \x03(\x0b\x32\x1e.protocol.Transaction.Contract\x12\x0f\n\x07scripts\x18\x0c \x01(\x0c\x12\x11\n\ttimestamp\x18\x0e \x01(\x03\x12\x11\n\tfee_limit\x18\x12 \x01(\x03\"&\n\x03Key\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x0e\n\x06weight\x18\x02 \x01(\x03\"\xf1\x01\n\nPermission\x12\x31\n\x04type\x18\x01 \x01(\x0e\x32#.protocol.Permission.PermissionType\x12\n\n\x02id\x18\x02 \x01(\x05\x12\x17\n\x0fpermission_name\x18\x03 \x01(\t\x12\x11\n\tthreshold\x18\x04 \x01(\x03\x12\x11\n\tparent_id\x18\x05 \x01(\x05\x12\x12\n\noperations\x18\x06 \x01(\x0c\x12\x1b\n\x04keys\x18\x07 \x03(\x0b\x32\r.protocol.Key\"4\n\x0ePermissionType\x12\t\n\x05Owner\x10\x00\x12\x0b\n\x07Witness\x10\x01\x12\n\n\x06\x41\x63tive\x10\x02*7\n\x0b\x41\x63\x63ountType\x12\n\n\x06Normal\x10\x00\x12\x0e\n\nAssetIssue\x10\x01\x12\x0c\n\x08\x43ontract\x10\x02\x62\x06proto3') + +_ACCOUNTTYPE = DESCRIPTOR.enum_types_by_name['AccountType'] +AccountType = enum_type_wrapper.EnumTypeWrapper(_ACCOUNTTYPE) +Normal = 0 +AssetIssue = 1 +Contract = 2 + + +_EXCHANGE = DESCRIPTOR.message_types_by_name['Exchange'] +_ACCOUNTID = DESCRIPTOR.message_types_by_name['AccountId'] +_AUTHORITY = DESCRIPTOR.message_types_by_name['authority'] +_TRANSACTION = DESCRIPTOR.message_types_by_name['Transaction'] +_TRANSACTION_CONTRACT = _TRANSACTION.nested_types_by_name['Contract'] +_TRANSACTION_RESULT = _TRANSACTION.nested_types_by_name['Result'] +_TRANSACTION_RAW = _TRANSACTION.nested_types_by_name['raw'] +_KEY = DESCRIPTOR.message_types_by_name['Key'] +_PERMISSION = DESCRIPTOR.message_types_by_name['Permission'] +_TRANSACTION_CONTRACT_CONTRACTTYPE = _TRANSACTION_CONTRACT.enum_types_by_name['ContractType'] +_TRANSACTION_RESULT_CODE = _TRANSACTION_RESULT.enum_types_by_name['code'] +_TRANSACTION_RESULT_CONTRACTRESULT = _TRANSACTION_RESULT.enum_types_by_name['contractResult'] +_PERMISSION_PERMISSIONTYPE = _PERMISSION.enum_types_by_name['PermissionType'] +Exchange = _reflection.GeneratedProtocolMessageType('Exchange', (_message.Message,), { + 'DESCRIPTOR' : _EXCHANGE, + '__module__' : 'core.Tron_pb2' + # @@protoc_insertion_point(class_scope:protocol.Exchange) + }) +_sym_db.RegisterMessage(Exchange) + +AccountId = _reflection.GeneratedProtocolMessageType('AccountId', (_message.Message,), { + 'DESCRIPTOR' : _ACCOUNTID, + '__module__' : 'core.Tron_pb2' + # @@protoc_insertion_point(class_scope:protocol.AccountId) + }) +_sym_db.RegisterMessage(AccountId) + +authority = _reflection.GeneratedProtocolMessageType('authority', (_message.Message,), { + 'DESCRIPTOR' : _AUTHORITY, + '__module__' : 'core.Tron_pb2' + # @@protoc_insertion_point(class_scope:protocol.authority) + }) +_sym_db.RegisterMessage(authority) + +Transaction = _reflection.GeneratedProtocolMessageType('Transaction', (_message.Message,), { + + 'Contract' : _reflection.GeneratedProtocolMessageType('Contract', (_message.Message,), { + 'DESCRIPTOR' : _TRANSACTION_CONTRACT, + '__module__' : 'core.Tron_pb2' + # @@protoc_insertion_point(class_scope:protocol.Transaction.Contract) + }) + , + + 'Result' : _reflection.GeneratedProtocolMessageType('Result', (_message.Message,), { + 'DESCRIPTOR' : _TRANSACTION_RESULT, + '__module__' : 'core.Tron_pb2' + # @@protoc_insertion_point(class_scope:protocol.Transaction.Result) + }) + , + + 'raw' : _reflection.GeneratedProtocolMessageType('raw', (_message.Message,), { + 'DESCRIPTOR' : _TRANSACTION_RAW, + '__module__' : 'core.Tron_pb2' + # @@protoc_insertion_point(class_scope:protocol.Transaction.raw) + }) + , + 'DESCRIPTOR' : _TRANSACTION, + '__module__' : 'core.Tron_pb2' + # @@protoc_insertion_point(class_scope:protocol.Transaction) + }) +_sym_db.RegisterMessage(Transaction) +_sym_db.RegisterMessage(Transaction.Contract) +_sym_db.RegisterMessage(Transaction.Result) +_sym_db.RegisterMessage(Transaction.raw) + +Key = _reflection.GeneratedProtocolMessageType('Key', (_message.Message,), { + 'DESCRIPTOR' : _KEY, + '__module__' : 'core.Tron_pb2' + # @@protoc_insertion_point(class_scope:protocol.Key) + }) +_sym_db.RegisterMessage(Key) + +Permission = _reflection.GeneratedProtocolMessageType('Permission', (_message.Message,), { + 'DESCRIPTOR' : _PERMISSION, + '__module__' : 'core.Tron_pb2' + # @@protoc_insertion_point(class_scope:protocol.Permission) + }) +_sym_db.RegisterMessage(Permission) + +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _ACCOUNTTYPE._serialized_start=2936 + _ACCOUNTTYPE._serialized_end=2991 + _EXCHANGE._serialized_start=57 + _EXCHANGE._serialized_end=242 + _ACCOUNTID._serialized_start=244 + _ACCOUNTID._serialized_end=286 + _AUTHORITY._serialized_start=288 + _AUTHORITY._serialized_end=362 + _TRANSACTION._serialized_start=365 + _TRANSACTION._serialized_end=2650 + _TRANSACTION_CONTRACT._serialized_start=488 + _TRANSACTION_CONTRACT._serialized_end=1701 + _TRANSACTION_CONTRACT_CONTRACTTYPE._serialized_start=664 + _TRANSACTION_CONTRACT_CONTRACTTYPE._serialized_end=1701 + _TRANSACTION_RESULT._serialized_start=1704 + _TRANSACTION_RESULT._serialized_end=2388 + _TRANSACTION_RESULT_CODE._serialized_start=2050 + _TRANSACTION_RESULT_CODE._serialized_end=2080 + _TRANSACTION_RESULT_CONTRACTRESULT._serialized_start=2083 + _TRANSACTION_RESULT_CONTRACTRESULT._serialized_end=2388 + _TRANSACTION_RAW._serialized_start=2391 + _TRANSACTION_RAW._serialized_end=2650 + _KEY._serialized_start=2652 + _KEY._serialized_end=2690 + _PERMISSION._serialized_start=2693 + _PERMISSION._serialized_end=2934 + _PERMISSION_PERMISSIONTYPE._serialized_start=2882 + _PERMISSION_PERMISSIONTYPE._serialized_end=2934 +# @@protoc_insertion_point(module_scope) diff --git a/test/python/apps/tron_proto/google/protobuf/any.options b/test/python/apps/tron_proto/google/protobuf/any.options new file mode 100644 index 0000000..e69de29 diff --git a/test/python/apps/tron_proto/google/protobuf/any.pb.c b/test/python/apps/tron_proto/google/protobuf/any.pb.c new file mode 100644 index 0000000..a7d2155 --- /dev/null +++ b/test/python/apps/tron_proto/google/protobuf/any.pb.c @@ -0,0 +1,12 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.5 */ + +#include "google/protobuf/any.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(google_protobuf_Any, google_protobuf_Any, AUTO) + + + diff --git a/test/python/apps/tron_proto/google/protobuf/any.pb.h b/test/python/apps/tron_proto/google/protobuf/any.pb.h new file mode 100644 index 0000000..6284fd0 --- /dev/null +++ b/test/python/apps/tron_proto/google/protobuf/any.pb.h @@ -0,0 +1,157 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.5 */ + +#ifndef PB_GOOGLE_PROTOBUF_GOOGLE_PROTOBUF_ANY_PB_H_INCLUDED +#define PB_GOOGLE_PROTOBUF_GOOGLE_PROTOBUF_ANY_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Struct definitions */ +/* `Any` contains an arbitrary serialized protocol buffer message along with a + URL that describes the type of the serialized message. + + Protobuf library provides support to pack/unpack Any values in the form + of utility functions or additional generated methods of the Any type. + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + 'type.googleapis.com/full.type.name' as the type URL and the unpack + methods only use the fully qualified type name after the last '/' + in the type URL, for example "foo.bar.com/x/y.z" will yield type + name "y.z". + + + JSON + ==== + The JSON representation of an `Any` value uses the regular + representation of the deserialized, embedded message, with an + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + representation, that representation will be embedded adding a field + `value` which holds the custom JSON in addition to the `@type` + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } */ +typedef struct _google_protobuf_Any { + /* A URL/resource name that uniquely identifies the type of the serialized + protocol buffer message. This string must contain at least + one "/" character. The last segment of the URL's path must represent + the fully qualified name of the type (as in + `path/google.protobuf.Duration`). The name should be in a canonical form + (e.g., leading "." is not accepted). + + In practice, teams usually precompile into the binary all types that they + expect it to use in the context of Any. However, for URLs which use the + scheme `http`, `https`, or no scheme, one can optionally set up a type + server that maps type URLs to message definitions as follows: + + * If no scheme is provided, `https` is assumed. + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the official + protobuf release, and it is not used for type URLs beginning with + type.googleapis.com. + + Schemes other than `http`, `https` (or the empty scheme) might be + used with implementation specific semantics. */ + pb_callback_t type_url; + /* Must be a valid serialized protocol buffer of the above specified type. */ + pb_callback_t value; +} google_protobuf_Any; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define google_protobuf_Any_init_default {{{NULL}, NULL}, {{NULL}, NULL}} +#define google_protobuf_Any_init_zero {{{NULL}, NULL}, {{NULL}, NULL}} + +/* Field tags (for use in manual encoding/decoding) */ +#define google_protobuf_Any_type_url_tag 1 +#define google_protobuf_Any_value_tag 2 + +/* Struct field encoding specification for nanopb */ +#define google_protobuf_Any_FIELDLIST(X, a) \ +X(a, CALLBACK, SINGULAR, STRING, type_url, 1) \ +X(a, CALLBACK, SINGULAR, BYTES, value, 2) +#define google_protobuf_Any_CALLBACK pb_default_field_callback +#define google_protobuf_Any_DEFAULT NULL + +extern const pb_msgdesc_t google_protobuf_Any_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define google_protobuf_Any_fields &google_protobuf_Any_msg + +/* Maximum encoded size of messages (where known) */ +/* google_protobuf_Any_size depends on runtime parameters */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/test/python/apps/tron_proto/google/protobuf/any.proto b/test/python/apps/tron_proto/google/protobuf/any.proto new file mode 100644 index 0000000..2919070 --- /dev/null +++ b/test/python/apps/tron_proto/google/protobuf/any.proto @@ -0,0 +1,155 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "github.com/golang/protobuf/ptypes/any"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "AnyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := ptypes.MarshalAny(foo) +// ... +// foo := &pb.Foo{} +// if err := ptypes.UnmarshalAny(any, foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +message Any { + // A URL/resource name that uniquely identifies the type of the serialized + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent + // the fully qualified name of the type (as in + // `path/google.protobuf.Duration`). The name should be in a canonical form + // (e.g., leading "." is not accepted). + // + // In practice, teams usually precompile into the binary all types that they + // expect it to use in the context of Any. However, for URLs which use the + // scheme `http`, `https`, or no scheme, one can optionally set up a type + // server that maps type URLs to message definitions as follows: + // + // * If no scheme is provided, `https` is assumed. + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Note: this functionality is not currently available in the official + // protobuf release, and it is not used for type URLs beginning with + // type.googleapis.com. + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + string type_url = 1; + + // Must be a valid serialized protocol buffer of the above specified type. + bytes value = 2; +} \ No newline at end of file diff --git a/test/python/apps/tron_proto/google/protobuf/any_pb2.py b/test/python/apps/tron_proto/google/protobuf/any_pb2.py new file mode 100644 index 0000000..2cf457a --- /dev/null +++ b/test/python/apps/tron_proto/google/protobuf/any_pb2.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/any.proto +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19google/protobuf/any.proto\x12\x0fgoogle.protobuf\"&\n\x03\x41ny\x12\x10\n\x08type_url\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c\x42o\n\x13\x63om.google.protobufB\x08\x41nyProtoP\x01Z%github.com/golang/protobuf/ptypes/any\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3') + + + +_ANY = DESCRIPTOR.message_types_by_name['Any'] +Any = _reflection.GeneratedProtocolMessageType('Any', (_message.Message,), { + 'DESCRIPTOR' : _ANY, + '__module__' : 'google.protobuf.any_pb2' + # @@protoc_insertion_point(class_scope:google.protobuf.Any) + }) +_sym_db.RegisterMessage(Any) + +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + DESCRIPTOR._serialized_options = b'\n\023com.google.protobufB\010AnyProtoP\001Z%github.com/golang/protobuf/ptypes/any\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes' + _ANY._serialized_start=46 + _ANY._serialized_end=84 +# @@protoc_insertion_point(module_scope) diff --git a/test/python/apps/tron_proto/misc/TronApp.options b/test/python/apps/tron_proto/misc/TronApp.options new file mode 100644 index 0000000..fd9dc83 --- /dev/null +++ b/test/python/apps/tron_proto/misc/TronApp.options @@ -0,0 +1,8 @@ +ExchangeDetails.token1Id max_size: 8 /* Must be or 1 */ +ExchangeDetails.token1Name max_size: 32 +ExchangeDetails.token2Id max_size: 8 /* Must be or 1 */ +ExchangeDetails.token2Name max_size: 32 +ExchangeDetails.signature max_size: 72 + +TokenDetails.name max_size: 32 +TokenDetails.signature max_size: 72 diff --git a/test/python/apps/tron_proto/misc/TronApp.pb.c b/test/python/apps/tron_proto/misc/TronApp.pb.c new file mode 100644 index 0000000..0b19acd --- /dev/null +++ b/test/python/apps/tron_proto/misc/TronApp.pb.c @@ -0,0 +1,15 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.5 */ + +#include "misc/TronApp.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(ExchangeDetails, ExchangeDetails, AUTO) + + +PB_BIND(TokenDetails, TokenDetails, AUTO) + + + diff --git a/test/python/apps/tron_proto/misc/TronApp.pb.h b/test/python/apps/tron_proto/misc/TronApp.pb.h new file mode 100644 index 0000000..66f4f96 --- /dev/null +++ b/test/python/apps/tron_proto/misc/TronApp.pb.h @@ -0,0 +1,91 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.5 */ + +#ifndef PB_MISC_TRONAPP_PB_H_INCLUDED +#define PB_MISC_TRONAPP_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Struct definitions */ +typedef PB_BYTES_ARRAY_T(72) ExchangeDetails_signature_t; +typedef struct _ExchangeDetails { + uint64_t exchangeId; + char token1Id[8]; + char token1Name[32]; + uint32_t token1Precision; + char token2Id[8]; + char token2Name[32]; + uint32_t token2Precision; + ExchangeDetails_signature_t signature; +} ExchangeDetails; + +typedef PB_BYTES_ARRAY_T(72) TokenDetails_signature_t; +typedef struct _TokenDetails { + char name[32]; + uint32_t precision; + TokenDetails_signature_t signature; +} TokenDetails; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define ExchangeDetails_init_default {0, "", "", 0, "", "", 0, {0, {0}}} +#define TokenDetails_init_default {"", 0, {0, {0}}} +#define ExchangeDetails_init_zero {0, "", "", 0, "", "", 0, {0, {0}}} +#define TokenDetails_init_zero {"", 0, {0, {0}}} + +/* Field tags (for use in manual encoding/decoding) */ +#define ExchangeDetails_exchangeId_tag 1 +#define ExchangeDetails_token1Id_tag 2 +#define ExchangeDetails_token1Name_tag 3 +#define ExchangeDetails_token1Precision_tag 4 +#define ExchangeDetails_token2Id_tag 5 +#define ExchangeDetails_token2Name_tag 6 +#define ExchangeDetails_token2Precision_tag 7 +#define ExchangeDetails_signature_tag 8 +#define TokenDetails_name_tag 1 +#define TokenDetails_precision_tag 2 +#define TokenDetails_signature_tag 3 + +/* Struct field encoding specification for nanopb */ +#define ExchangeDetails_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT64, exchangeId, 1) \ +X(a, STATIC, SINGULAR, STRING, token1Id, 2) \ +X(a, STATIC, SINGULAR, STRING, token1Name, 3) \ +X(a, STATIC, SINGULAR, UINT32, token1Precision, 4) \ +X(a, STATIC, SINGULAR, STRING, token2Id, 5) \ +X(a, STATIC, SINGULAR, STRING, token2Name, 6) \ +X(a, STATIC, SINGULAR, UINT32, token2Precision, 7) \ +X(a, STATIC, SINGULAR, BYTES, signature, 8) +#define ExchangeDetails_CALLBACK NULL +#define ExchangeDetails_DEFAULT NULL + +#define TokenDetails_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, STRING, name, 1) \ +X(a, STATIC, SINGULAR, UINT32, precision, 2) \ +X(a, STATIC, SINGULAR, BYTES, signature, 3) +#define TokenDetails_CALLBACK NULL +#define TokenDetails_DEFAULT NULL + +extern const pb_msgdesc_t ExchangeDetails_msg; +extern const pb_msgdesc_t TokenDetails_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define ExchangeDetails_fields &ExchangeDetails_msg +#define TokenDetails_fields &TokenDetails_msg + +/* Maximum encoded size of messages (where known) */ +#define ExchangeDetails_size 181 +#define TokenDetails_size 113 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/test/python/apps/tron_proto/misc/TronApp.proto b/test/python/apps/tron_proto/misc/TronApp.proto new file mode 100644 index 0000000..c40ab57 --- /dev/null +++ b/test/python/apps/tron_proto/misc/TronApp.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +message ExchangeDetails { + uint64 exchangeId = 1; + + string token1Id = 2; + string token1Name = 3; + uint32 token1Precision = 4; + + string token2Id = 5; + string token2Name = 6; + uint32 token2Precision = 7; + + bytes signature = 8; +} + +message TokenDetails { + string name = 1; + uint32 precision = 2; + bytes signature = 3; +} \ No newline at end of file diff --git a/test/python/requirements.txt b/test/python/requirements.txt index 87edd2c..431daea 100644 --- a/test/python/requirements.txt +++ b/test/python/requirements.txt @@ -1,6 +1,8 @@ -ledger-bitcoin>=0.0.3 ragger[tests,speculos] >= 1.9.2 protobuf==3.20.0 stellar_sdk base58 xrpl-py +scalecodec +bip32 +embit diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00000.png b/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00001.png b/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00002.png b/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00002.png new file mode 100644 index 0000000..c52e174 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00003.png b/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00004.png b/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00004.png new file mode 100644 index 0000000..37f904f Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00005.png b/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00006.png b/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00000.png b/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00001.png b/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00002.png b/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00002.png new file mode 100644 index 0000000..cba45bc Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00003.png b/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00004.png b/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00004.png new file mode 100644 index 0000000..b637189 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00005.png b/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00006.png b/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00000.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00001.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00002.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00002.png new file mode 100644 index 0000000..c52e174 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00003.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00004.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00004.png new file mode 100644 index 0000000..37f904f Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00005.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00006.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00000.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00001.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00002.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00002.png new file mode 100644 index 0000000..c52e174 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00003.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00004.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00004.png new file mode 100644 index 0000000..37f904f Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00005.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00006.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00000.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00001.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00002.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00002.png new file mode 100644 index 0000000..c52e174 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00003.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00004.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00004.png new file mode 100644 index 0000000..37f904f Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00005.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00005.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00006.png b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_fund_wrong_fees/00006.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00000.png b/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00001.png b/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00002.png b/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00002.png new file mode 100644 index 0000000..c52e174 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00003.png b/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00004.png b/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00004.png new file mode 100644 index 0000000..37f904f Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00005.png b/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00006.png b/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00000.png b/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00001.png b/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00002.png b/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00002.png new file mode 100644 index 0000000..cba45bc Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00003.png b/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00004.png b/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00004.png new file mode 100644 index 0000000..b637189 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00005.png b/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00006.png b/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00000.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00001.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00002.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00002.png new file mode 100644 index 0000000..c52e174 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00003.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00004.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00004.png new file mode 100644 index 0000000..37f904f Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00005.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00006.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00000.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00001.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00002.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00002.png new file mode 100644 index 0000000..c52e174 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00003.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00004.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00004.png new file mode 100644 index 0000000..37f904f Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00005.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00006.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00000.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00001.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00002.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00002.png new file mode 100644 index 0000000..c52e174 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00003.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00004.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00004.png new file mode 100644 index 0000000..37f904f Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00005.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00005.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00006.png b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_sell_wrong_fees/00006.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00000.png b/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00001.png b/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00001.png new file mode 100644 index 0000000..c52e174 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00002.png b/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00003.png b/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00003.png new file mode 100644 index 0000000..37f904f Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00004.png b/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00005.png b/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00000.png b/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00001.png b/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00001.png new file mode 100644 index 0000000..cba45bc Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00002.png b/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00003.png b/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00003.png new file mode 100644 index 0000000..b637189 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00004.png b/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00005.png b/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00000.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00001.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00001.png new file mode 100644 index 0000000..c52e174 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00002.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00003.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00003.png new file mode 100644 index 0000000..37f904f Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00004.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00005.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00000.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00001.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00001.png new file mode 100644 index 0000000..c52e174 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00002.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00003.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00003.png new file mode 100644 index 0000000..37f904f Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00004.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00005.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00000.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00000.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00001.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00001.png new file mode 100644 index 0000000..c52e174 Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00001.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00002.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00002.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00003.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00003.png new file mode 100644 index 0000000..37f904f Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00003.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00004.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00004.png differ diff --git a/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00005.png b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_bitcoin_swap_wrong_fees/00005.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00000.png b/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00001.png b/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00002.png b/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00002.png new file mode 100644 index 0000000..c693eec Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00003.png b/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00004.png b/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00004.png new file mode 100644 index 0000000..cd5a1cb Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00005.png b/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00006.png b/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00000.png b/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00001.png b/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00002.png b/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00002.png new file mode 100644 index 0000000..08e9a8f Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00003.png b/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00004.png b/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00004.png new file mode 100644 index 0000000..67aab3c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00005.png b/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00006.png b/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00000.png b/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00001.png b/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00002.png b/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00002.png new file mode 100644 index 0000000..c693eec Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00003.png b/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00004.png b/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00004.png new file mode 100644 index 0000000..cd5a1cb Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00005.png b/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00006.png b/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00000.png b/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00001.png b/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00002.png b/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00002.png new file mode 100644 index 0000000..c693eec Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00003.png b/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00004.png b/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00004.png new file mode 100644 index 0000000..cd5a1cb Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00005.png b/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00006.png b/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00000.png b/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00001.png b/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00002.png b/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00002.png new file mode 100644 index 0000000..c693eec Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00003.png b/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00004.png b/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00004.png new file mode 100644 index 0000000..cd5a1cb Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00005.png b/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00006.png b/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00000.png b/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00001.png b/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00002.png b/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00002.png new file mode 100644 index 0000000..08e9a8f Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00003.png b/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00004.png b/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00004.png new file mode 100644 index 0000000..67aab3c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00005.png b/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00006.png b/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00000.png b/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00001.png b/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00002.png b/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00002.png new file mode 100644 index 0000000..c693eec Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00003.png b/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00004.png b/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00004.png new file mode 100644 index 0000000..cd5a1cb Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00005.png b/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00006.png b/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00000.png b/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00001.png b/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00002.png b/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00002.png new file mode 100644 index 0000000..c693eec Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00003.png b/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00004.png b/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00004.png new file mode 100644 index 0000000..cd5a1cb Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00005.png b/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00006.png b/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00000.png b/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00001.png b/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00001.png new file mode 100644 index 0000000..c693eec Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00002.png b/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00003.png b/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00003.png new file mode 100644 index 0000000..cd5a1cb Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00004.png b/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00005.png b/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00000.png b/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00001.png b/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00001.png new file mode 100644 index 0000000..08e9a8f Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00002.png b/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00003.png b/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00003.png new file mode 100644 index 0000000..67aab3c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00004.png b/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00005.png b/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00000.png b/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00001.png b/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00001.png new file mode 100644 index 0000000..c693eec Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00002.png b/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00003.png b/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00003.png new file mode 100644 index 0000000..cd5a1cb Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00004.png b/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00005.png b/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00000.png b/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00001.png b/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00001.png new file mode 100644 index 0000000..c693eec Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00002.png b/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00003.png b/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00003.png new file mode 100644 index 0000000..cd5a1cb Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00004.png b/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00005.png b/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_polkadot_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00000.png b/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00000.png differ diff --git a/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00001.png b/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00001.png new file mode 100644 index 0000000..c693eec Binary files /dev/null and b/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00001.png differ diff --git a/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00002.png b/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00002.png new file mode 100644 index 0000000..83b2a69 Binary files /dev/null and b/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00002.png differ diff --git a/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00003.png b/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00003.png new file mode 100644 index 0000000..cd5a1cb Binary files /dev/null and b/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00003.png differ diff --git a/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00004.png b/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00004.png differ diff --git a/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00005.png b/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_swap_flow_dot_nominal/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00002.png new file mode 100644 index 0000000..da8f01d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00006.png b/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00002.png new file mode 100644 index 0000000..d2053bb Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00004.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00006.png b/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00000.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00001.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00002.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00002.png new file mode 100644 index 0000000..da8f01d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00003.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00004.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00005.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00006.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00000.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00001.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00002.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00002.png new file mode 100644 index 0000000..da8f01d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00003.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00004.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00005.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00006.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00000.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00001.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00002.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00002.png new file mode 100644 index 0000000..da8f01d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00003.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00004.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00005.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00006.png b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_fund_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00002.png new file mode 100644 index 0000000..da8f01d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00006.png b/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00002.png new file mode 100644 index 0000000..d2053bb Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00004.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00006.png b/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00000.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00001.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00002.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00002.png new file mode 100644 index 0000000..da8f01d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00003.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00004.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00005.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00006.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00000.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00001.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00002.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00002.png new file mode 100644 index 0000000..da8f01d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00003.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00004.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00005.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00006.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00000.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00001.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00002.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00002.png new file mode 100644 index 0000000..da8f01d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00003.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00004.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00005.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00006.png b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_sell_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00001.png new file mode 100644 index 0000000..da8f01d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00003.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00001.png new file mode 100644 index 0000000..d2053bb Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00003.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00000.png b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00001.png b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00001.png new file mode 100644 index 0000000..da8f01d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00002.png b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00003.png b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00003.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00004.png b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00005.png b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00000.png b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00001.png b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00001.png new file mode 100644 index 0000000..da8f01d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00002.png b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00003.png b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00003.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00004.png b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00005.png b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00002.png new file mode 100644 index 0000000..da8f01d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00006.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00002.png new file mode 100644 index 0000000..d2053bb Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00004.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00006.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00002.png new file mode 100644 index 0000000..da8f01d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00006.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00002.png new file mode 100644 index 0000000..d2053bb Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00004.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00006.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00001.png new file mode 100644 index 0000000..da8f01d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00003.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00001.png new file mode 100644 index 0000000..d2053bb Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00003.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_trx_to_usdt_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00002.png new file mode 100644 index 0000000..cbac8e9 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00006.png b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00002.png new file mode 100644 index 0000000..dbaa0a9 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00004.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00006.png b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00000.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00001.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00002.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00002.png new file mode 100644 index 0000000..cbac8e9 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00003.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00004.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00005.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00006.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00000.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00001.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00002.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00002.png new file mode 100644 index 0000000..cbac8e9 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00003.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00004.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00005.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00006.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00000.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00001.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00002.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00002.png new file mode 100644 index 0000000..cbac8e9 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00003.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00004.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00005.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00006.png b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_fund_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00002.png new file mode 100644 index 0000000..cbac8e9 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00006.png b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00002.png new file mode 100644 index 0000000..dbaa0a9 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00004.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00006.png b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00000.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00001.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00002.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00002.png new file mode 100644 index 0000000..cbac8e9 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00003.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00004.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00005.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00006.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00000.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00001.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00002.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00002.png new file mode 100644 index 0000000..cbac8e9 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00003.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00004.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00005.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00006.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00000.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00001.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00002.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00002.png new file mode 100644 index 0000000..cbac8e9 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00003.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00004.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00005.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00006.png b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_sell_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00001.png new file mode 100644 index 0000000..cbac8e9 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00003.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00001.png new file mode 100644 index 0000000..dbaa0a9 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00003.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00000.png b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00001.png b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00001.png new file mode 100644 index 0000000..cbac8e9 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00002.png b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00003.png b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00003.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00004.png b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00005.png b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00000.png b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00001.png b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00001.png new file mode 100644 index 0000000..cbac8e9 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00002.png b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00003.png b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00003.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00004.png b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00005.png b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdc_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00002.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00006.png b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00002.png new file mode 100644 index 0000000..c09f37b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00004.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00006.png b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00000.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00001.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00002.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00002.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00003.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00004.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00005.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00006.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00000.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00001.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00002.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00002.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00003.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00004.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00005.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00006.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00000.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00001.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00002.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00002.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00003.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00004.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00005.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00006.png b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_fund_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00002.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00006.png b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00002.png new file mode 100644 index 0000000..c09f37b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00004.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00006.png b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00000.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00001.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00002.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00002.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00003.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00004.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00005.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00006.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00000.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00001.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00002.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00002.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00003.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00004.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00005.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00006.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00000.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00001.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00002.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00002.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00003.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00004.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00005.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00006.png b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_sell_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00001.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00003.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00001.png new file mode 100644 index 0000000..c09f37b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00003.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00000.png b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00001.png b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00001.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00002.png b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00003.png b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00003.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00004.png b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00005.png b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00000.png b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00001.png b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00001.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00002.png b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00003.png b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00003.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00004.png b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00005.png b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00002.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00006.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00002.png new file mode 100644 index 0000000..c09f37b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00004.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00006.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00002.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00006.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00002.png new file mode 100644 index 0000000..c09f37b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00004.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00006.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00001.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00003.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00001.png new file mode 100644 index 0000000..c09f37b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00003.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_trx_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00002.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00006.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00001.png new file mode 100644 index 0000000..f68ce8a Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00002.png new file mode 100644 index 0000000..c09f37b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00003.png new file mode 100644 index 0000000..68d0d6b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00004.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00006.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00002.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00004.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00006.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00001.png new file mode 100644 index 0000000..ae0a294 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00002.png new file mode 100644 index 0000000..c09f37b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00003.png new file mode 100644 index 0000000..01f7f18 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00004.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00005.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00006.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00006.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00000.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00001.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00001.png new file mode 100644 index 0000000..f199288 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00002.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00003.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00003.png new file mode 100644 index 0000000..bc35682 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00004.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00005.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00000.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00000.png new file mode 100644 index 0000000..8d84cc7 Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00001.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00001.png new file mode 100644 index 0000000..c09f37b Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00002.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00002.png new file mode 100644 index 0000000..b744ccf Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00003.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00003.png new file mode 100644 index 0000000..f87f7ac Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00004.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00004.png new file mode 100644 index 0000000..1c9156c Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00005.png b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00005.png new file mode 100644 index 0000000..a0aef4d Binary files /dev/null and b/test/python/snapshots/nanos/test_tron_usdt_to_usdc_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00000.png b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00001.png b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00002.png b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00002.png new file mode 100644 index 0000000..0af1a76 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00003.png b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00004.png b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00005.png b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00006.png b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00000.png b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00001.png b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00002.png b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00002.png new file mode 100644 index 0000000..8c278a5 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00003.png b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00004.png b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00004.png new file mode 100644 index 0000000..408304d Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00005.png b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00006.png b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00002.png new file mode 100644 index 0000000..0af1a76 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00006.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00002.png new file mode 100644 index 0000000..0af1a76 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00006.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00000.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00001.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00002.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00002.png new file mode 100644 index 0000000..0af1a76 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00003.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00004.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00005.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00006.png b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_fund_wrong_fees/00006.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00000.png b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00001.png b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00002.png b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00002.png new file mode 100644 index 0000000..0af1a76 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00003.png b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00004.png b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00005.png b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00006.png b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00000.png b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00001.png b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00002.png b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00002.png new file mode 100644 index 0000000..8c278a5 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00003.png b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00004.png b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00004.png new file mode 100644 index 0000000..408304d Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00005.png b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00006.png b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00002.png new file mode 100644 index 0000000..0af1a76 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00006.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00002.png new file mode 100644 index 0000000..0af1a76 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00006.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00000.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00001.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00002.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00002.png new file mode 100644 index 0000000..0af1a76 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00003.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00004.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00005.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00006.png b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_sell_wrong_fees/00006.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00000.png b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00001.png b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00001.png new file mode 100644 index 0000000..0af1a76 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00002.png b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00003.png b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00003.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00004.png b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00005.png b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00000.png b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00001.png b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00001.png new file mode 100644 index 0000000..8c278a5 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00002.png b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00003.png b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00003.png new file mode 100644 index 0000000..408304d Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00004.png b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00005.png b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00001.png new file mode 100644 index 0000000..0af1a76 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00003.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00001.png new file mode 100644 index 0000000..0af1a76 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00003.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00000.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00000.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00001.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00001.png new file mode 100644 index 0000000..0af1a76 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00001.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00002.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00002.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00003.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00003.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00003.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00004.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00004.png differ diff --git a/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00005.png b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_bitcoin_swap_wrong_fees/00005.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00000.png b/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00001.png b/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00002.png b/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00002.png new file mode 100644 index 0000000..943f8a9 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00003.png b/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00004.png b/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00004.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00005.png b/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00006.png b/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00000.png b/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00001.png b/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00002.png b/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00002.png new file mode 100644 index 0000000..91a9389 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00003.png b/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00004.png b/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00004.png new file mode 100644 index 0000000..b964cc8 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00005.png b/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00006.png b/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00002.png new file mode 100644 index 0000000..943f8a9 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00004.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00006.png b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00002.png new file mode 100644 index 0000000..943f8a9 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00004.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00006.png b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00000.png b/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00001.png b/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00002.png b/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00002.png new file mode 100644 index 0000000..943f8a9 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00003.png b/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00004.png b/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00004.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00005.png b/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00006.png b/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00000.png b/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00001.png b/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00002.png b/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00002.png new file mode 100644 index 0000000..91a9389 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00003.png b/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00004.png b/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00004.png new file mode 100644 index 0000000..b964cc8 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00005.png b/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00006.png b/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00002.png new file mode 100644 index 0000000..943f8a9 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00004.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00006.png b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00002.png new file mode 100644 index 0000000..943f8a9 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00004.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00006.png b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00000.png b/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00001.png b/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00001.png new file mode 100644 index 0000000..943f8a9 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00002.png b/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00003.png b/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00003.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00004.png b/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00005.png b/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00000.png b/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00001.png b/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00001.png new file mode 100644 index 0000000..91a9389 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00002.png b/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00003.png b/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00003.png new file mode 100644 index 0000000..b964cc8 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00004.png b/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00005.png b/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00001.png new file mode 100644 index 0000000..943f8a9 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00003.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00001.png new file mode 100644 index 0000000..943f8a9 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00003.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_polkadot_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00002.png new file mode 100644 index 0000000..c0c115d Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00006.png b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00002.png new file mode 100644 index 0000000..1f3ce54 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00006.png b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00002.png new file mode 100644 index 0000000..c0c115d Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00006.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00002.png new file mode 100644 index 0000000..c0c115d Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00006.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00000.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00001.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00002.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00002.png new file mode 100644 index 0000000..c0c115d Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00003.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00004.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00005.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00006.png b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_fund_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00002.png new file mode 100644 index 0000000..c0c115d Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00006.png b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00002.png new file mode 100644 index 0000000..1f3ce54 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00006.png b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00002.png new file mode 100644 index 0000000..c0c115d Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00006.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00002.png new file mode 100644 index 0000000..c0c115d Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00006.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00000.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00001.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00002.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00002.png new file mode 100644 index 0000000..c0c115d Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00003.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00004.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00005.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00006.png b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_sell_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00001.png new file mode 100644 index 0000000..c0c115d Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00001.png new file mode 100644 index 0000000..1f3ce54 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00003.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00001.png new file mode 100644 index 0000000..c0c115d Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00001.png new file mode 100644 index 0000000..c0c115d Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00002.png new file mode 100644 index 0000000..c0c115d Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00006.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00002.png new file mode 100644 index 0000000..1f3ce54 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00006.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00002.png new file mode 100644 index 0000000..c0c115d Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00006.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00002.png new file mode 100644 index 0000000..1f3ce54 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00006.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00001.png new file mode 100644 index 0000000..c0c115d Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00001.png new file mode 100644 index 0000000..1f3ce54 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00003.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_trx_to_usdt_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00002.png new file mode 100644 index 0000000..2eeeecc Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00006.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00002.png new file mode 100644 index 0000000..208be5e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00006.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00002.png new file mode 100644 index 0000000..2eeeecc Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00006.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00002.png new file mode 100644 index 0000000..2eeeecc Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00006.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00000.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00001.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00002.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00002.png new file mode 100644 index 0000000..2eeeecc Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00003.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00004.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00005.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00006.png b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_fund_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00002.png new file mode 100644 index 0000000..2eeeecc Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00006.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00002.png new file mode 100644 index 0000000..208be5e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00006.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00002.png new file mode 100644 index 0000000..2eeeecc Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00006.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00002.png new file mode 100644 index 0000000..2eeeecc Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00006.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00000.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00001.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00002.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00002.png new file mode 100644 index 0000000..2eeeecc Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00003.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00004.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00005.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00006.png b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_sell_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00001.png new file mode 100644 index 0000000..2eeeecc Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00001.png new file mode 100644 index 0000000..208be5e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00003.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00001.png new file mode 100644 index 0000000..2eeeecc Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00001.png new file mode 100644 index 0000000..2eeeecc Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdc_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00002.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00002.png new file mode 100644 index 0000000..0be51c4 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00002.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00002.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00002.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_fund_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00002.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00002.png new file mode 100644 index 0000000..0be51c4 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00002.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00002.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00002.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_sell_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00001.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00001.png new file mode 100644 index 0000000..0be51c4 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00003.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00001.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00001.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00002.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00002.png new file mode 100644 index 0000000..0be51c4 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00002.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00002.png new file mode 100644 index 0000000..0be51c4 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00001.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00001.png new file mode 100644 index 0000000..0be51c4 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00003.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_trx_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00002.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00001.png new file mode 100644 index 0000000..fcfe2eb Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00002.png new file mode 100644 index 0000000..0be51c4 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00003.png new file mode 100644 index 0000000..ce6b87a Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00002.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00001.png new file mode 100644 index 0000000..a7dec8e Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00002.png new file mode 100644 index 0000000..0be51c4 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00006.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00006.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00001.png new file mode 100644 index 0000000..6aad096 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00000.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00001.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00001.png new file mode 100644 index 0000000..0be51c4 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00002.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00003.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00003.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00004.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00005.png b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00005.png new file mode 100644 index 0000000..7713012 Binary files /dev/null and b/test/python/snapshots/nanosp/test_tron_usdt_to_usdc_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00000.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00001.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00002.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00002.png new file mode 100644 index 0000000..ec236cf Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00003.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00004.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00005.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00006.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00007.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00007.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00007.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00008.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00008.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_1/00008.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00000.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00001.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00002.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00002.png new file mode 100644 index 0000000..047edb7 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00003.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00004.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00004.png new file mode 100644 index 0000000..408304d Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00005.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00006.png b/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00000.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00001.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00002.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00002.png new file mode 100644 index 0000000..ec236cf Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00003.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00004.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00005.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00006.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00000.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00001.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00002.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00002.png new file mode 100644 index 0000000..ec236cf Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00003.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00004.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00005.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00006.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00000.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00001.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00002.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00002.png new file mode 100644 index 0000000..ec236cf Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00003.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00004.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00005.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00006.png b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_fund_wrong_fees/00006.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00000.png b/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00001.png b/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00002.png b/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00002.png new file mode 100644 index 0000000..ec236cf Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00003.png b/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00004.png b/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00005.png b/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00006.png b/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00000.png b/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00001.png b/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00002.png b/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00002.png new file mode 100644 index 0000000..047edb7 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00003.png b/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00004.png b/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00004.png new file mode 100644 index 0000000..408304d Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00005.png b/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00006.png b/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00000.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00001.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00002.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00002.png new file mode 100644 index 0000000..ec236cf Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00003.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00004.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00005.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00006.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00000.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00001.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00002.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00002.png new file mode 100644 index 0000000..ec236cf Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00003.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00004.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00005.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00006.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00000.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00001.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00002.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00002.png new file mode 100644 index 0000000..ec236cf Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00003.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00004.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00004.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00005.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00006.png b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_sell_wrong_fees/00006.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00000.png b/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00001.png b/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00001.png new file mode 100644 index 0000000..ec236cf Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00002.png b/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00003.png b/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00003.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00004.png b/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00005.png b/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00000.png b/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00001.png b/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00001.png new file mode 100644 index 0000000..047edb7 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00002.png b/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00003.png b/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00003.png new file mode 100644 index 0000000..408304d Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00004.png b/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00005.png b/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00000.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00001.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00001.png new file mode 100644 index 0000000..ec236cf Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00002.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00003.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00003.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00004.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00005.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00000.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00001.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00001.png new file mode 100644 index 0000000..ec236cf Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00002.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00003.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00003.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00004.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00005.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00000.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00000.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00001.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00001.png new file mode 100644 index 0000000..ec236cf Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00001.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00002.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00002.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00003.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00003.png new file mode 100644 index 0000000..6a47016 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00003.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00004.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00004.png differ diff --git a/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00005.png b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_bitcoin_swap_wrong_fees/00005.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00000.png b/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00001.png b/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00002.png b/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00002.png new file mode 100644 index 0000000..d14fc86 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00003.png b/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00004.png b/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00004.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00005.png b/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00006.png b/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00000.png b/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00001.png b/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00002.png b/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00002.png new file mode 100644 index 0000000..b5070ff Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00003.png b/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00004.png b/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00004.png new file mode 100644 index 0000000..b964cc8 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00005.png b/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00006.png b/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00000.png b/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00001.png b/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00002.png b/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00002.png new file mode 100644 index 0000000..d14fc86 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00003.png b/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00004.png b/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00004.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00005.png b/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00006.png b/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00000.png b/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00001.png b/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00002.png b/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00002.png new file mode 100644 index 0000000..d14fc86 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00003.png b/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00004.png b/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00004.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00005.png b/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00006.png b/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00000.png b/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00001.png b/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00002.png b/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00002.png new file mode 100644 index 0000000..d14fc86 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00003.png b/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00004.png b/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00004.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00005.png b/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00006.png b/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00000.png b/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00001.png b/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00002.png b/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00002.png new file mode 100644 index 0000000..b5070ff Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00003.png b/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00004.png b/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00004.png new file mode 100644 index 0000000..b964cc8 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00005.png b/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00006.png b/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00000.png b/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00001.png b/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00002.png b/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00002.png new file mode 100644 index 0000000..d14fc86 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00003.png b/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00004.png b/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00004.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00005.png b/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00006.png b/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00000.png b/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00001.png b/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00002.png b/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00002.png new file mode 100644 index 0000000..d14fc86 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00003.png b/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00004.png b/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00004.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00005.png b/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00006.png b/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00000.png b/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00001.png b/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00001.png new file mode 100644 index 0000000..d14fc86 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00002.png b/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00003.png b/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00003.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00004.png b/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00005.png b/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00000.png b/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00001.png b/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00001.png new file mode 100644 index 0000000..b5070ff Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00002.png b/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00003.png b/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00003.png new file mode 100644 index 0000000..b964cc8 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00004.png b/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00005.png b/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00000.png b/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00001.png b/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00001.png new file mode 100644 index 0000000..d14fc86 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00002.png b/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00003.png b/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00003.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00004.png b/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00005.png b/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00000.png b/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00001.png b/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00001.png new file mode 100644 index 0000000..d14fc86 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00002.png b/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00003.png b/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00003.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00004.png b/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00005.png b/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_polkadot_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00000.png b/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00000.png differ diff --git a/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00001.png b/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00001.png new file mode 100644 index 0000000..d14fc86 Binary files /dev/null and b/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00001.png differ diff --git a/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00002.png b/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00002.png new file mode 100644 index 0000000..1bf0ca9 Binary files /dev/null and b/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00002.png differ diff --git a/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00003.png b/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00003.png new file mode 100644 index 0000000..85d2ff8 Binary files /dev/null and b/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00003.png differ diff --git a/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00004.png b/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00004.png differ diff --git a/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00005.png b/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_swap_flow_dot_nominal/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00002.png new file mode 100644 index 0000000..85e221f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00006.png b/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00002.png new file mode 100644 index 0000000..d5e62d1 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00006.png b/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00000.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00001.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00002.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00002.png new file mode 100644 index 0000000..85e221f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00003.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00004.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00005.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00006.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00000.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00001.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00002.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00002.png new file mode 100644 index 0000000..85e221f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00003.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00004.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00005.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00006.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00000.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00001.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00002.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00002.png new file mode 100644 index 0000000..85e221f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00003.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00004.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00005.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00006.png b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_fund_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00002.png new file mode 100644 index 0000000..85e221f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00006.png b/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00002.png new file mode 100644 index 0000000..d5e62d1 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00006.png b/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00000.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00001.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00002.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00002.png new file mode 100644 index 0000000..85e221f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00003.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00004.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00005.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00006.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00000.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00001.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00002.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00002.png new file mode 100644 index 0000000..85e221f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00003.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00004.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00005.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00006.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00000.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00001.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00002.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00002.png new file mode 100644 index 0000000..85e221f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00003.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00004.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00005.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00006.png b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_sell_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00001.png new file mode 100644 index 0000000..85e221f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00001.png new file mode 100644 index 0000000..d5e62d1 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00003.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00000.png b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00001.png b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00001.png new file mode 100644 index 0000000..85e221f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00002.png b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00003.png b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00004.png b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00005.png b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00000.png b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00001.png b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00001.png new file mode 100644 index 0000000..85e221f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00002.png b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00003.png b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00004.png b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00005.png b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00002.png new file mode 100644 index 0000000..85e221f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00006.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00002.png new file mode 100644 index 0000000..d5e62d1 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00006.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00002.png new file mode 100644 index 0000000..85e221f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00006.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00002.png new file mode 100644 index 0000000..d5e62d1 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00006.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00001.png new file mode 100644 index 0000000..85e221f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00001.png new file mode 100644 index 0000000..d5e62d1 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00003.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_trx_to_usdt_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00002.png new file mode 100644 index 0000000..d6c198f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00006.png b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00002.png new file mode 100644 index 0000000..aa7b59e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00006.png b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00000.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00001.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00002.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00002.png new file mode 100644 index 0000000..d6c198f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00003.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00004.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00005.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00006.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00000.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00001.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00002.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00002.png new file mode 100644 index 0000000..d6c198f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00003.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00004.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00005.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00006.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00000.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00001.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00002.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00002.png new file mode 100644 index 0000000..d6c198f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00003.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00004.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00005.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00006.png b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_fund_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00002.png new file mode 100644 index 0000000..d6c198f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00006.png b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00002.png new file mode 100644 index 0000000..aa7b59e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00006.png b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00000.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00001.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00002.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00002.png new file mode 100644 index 0000000..d6c198f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00003.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00004.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00005.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00006.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00000.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00001.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00002.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00002.png new file mode 100644 index 0000000..d6c198f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00003.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00004.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00005.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00006.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00000.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00001.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00002.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00002.png new file mode 100644 index 0000000..d6c198f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00003.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00004.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00005.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00006.png b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_sell_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00001.png new file mode 100644 index 0000000..d6c198f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00001.png new file mode 100644 index 0000000..aa7b59e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00003.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00000.png b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00001.png b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00001.png new file mode 100644 index 0000000..d6c198f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00002.png b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00003.png b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00004.png b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00005.png b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00000.png b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00001.png b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00001.png new file mode 100644 index 0000000..d6c198f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00002.png b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00003.png b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00004.png b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00005.png b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdc_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00002.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00006.png b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00002.png new file mode 100644 index 0000000..a2d261f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00006.png b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00000.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00001.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00002.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00002.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00003.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00004.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00005.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00006.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00000.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00001.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00002.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00002.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00003.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00004.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00005.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00006.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00000.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00001.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00002.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00002.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00003.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00004.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00005.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00006.png b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_fund_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00002.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00006.png b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00002.png new file mode 100644 index 0000000..a2d261f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00006.png b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00000.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00001.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00002.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00002.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00003.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00004.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00005.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00006.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_amount/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00000.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00001.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00002.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00002.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00003.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00004.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00005.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00006.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_destination/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00000.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00001.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00002.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00002.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00003.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00004.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00005.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00006.png b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_sell_wrong_memo/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00001.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00001.png new file mode 100644 index 0000000..a2d261f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00003.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00000.png b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00001.png b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00001.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00002.png b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00003.png b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00004.png b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00005.png b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_amount/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00000.png b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00001.png b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00001.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00002.png b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00003.png b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00004.png b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00005.png b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_swap_wrong_destination/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00002.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00006.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00002.png new file mode 100644 index 0000000..a2d261f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00006.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00002.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00006.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00002.png new file mode 100644 index 0000000..a2d261f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00006.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00001.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00001.png new file mode 100644 index 0000000..a2d261f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00003.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_trx_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00002.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00006.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00001.png new file mode 100644 index 0000000..28a5f8e Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00002.png new file mode 100644 index 0000000..a2d261f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00003.png new file mode 100644 index 0000000..66adf0b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00006.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_fund_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00002.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00004.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00006.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_1/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00001.png new file mode 100644 index 0000000..60ee769 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00002.png new file mode 100644 index 0000000..a2d261f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00003.png new file mode 100644 index 0000000..6749f27 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00004.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00005.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00006.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00006.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_sell_valid_2/00006.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00000.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00001.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00001.png new file mode 100644 index 0000000..0cc9fc4 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00002.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00003.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00003.png new file mode 100644 index 0000000..9880135 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00004.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00005.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_1/00005.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00000.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00000.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00001.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00001.png new file mode 100644 index 0000000..a2d261f Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00001.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00002.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00002.png new file mode 100644 index 0000000..2d2fc70 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00002.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00003.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00003.png new file mode 100644 index 0000000..d6876a6 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00003.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00004.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00004.png new file mode 100644 index 0000000..570ce28 Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00004.png differ diff --git a/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00005.png b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00005.png new file mode 100644 index 0000000..6c4d06b Binary files /dev/null and b/test/python/snapshots/nanox/test_tron_usdt_to_usdc_swap_valid_2/00005.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_fund_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_fund_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_valid_1/review/00000.png b/test/python/snapshots/stax/test_bitcoin_fund_valid_1/review/00000.png new file mode 100644 index 0000000..701b8f5 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_valid_1/review/00001.png b/test/python/snapshots/stax/test_bitcoin_fund_valid_1/review/00001.png new file mode 100644 index 0000000..1fdf257 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_valid_1/review/00002.png b/test/python/snapshots/stax/test_bitcoin_fund_valid_1/review/00002.png new file mode 100644 index 0000000..18b7010 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_valid_1/review/00003.png b/test/python/snapshots/stax/test_bitcoin_fund_valid_1/review/00003.png new file mode 100644 index 0000000..18b7010 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_valid_1/review/00003.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_fund_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_fund_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_valid_2/review/00000.png b/test/python/snapshots/stax/test_bitcoin_fund_valid_2/review/00000.png new file mode 100644 index 0000000..701b8f5 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_valid_2/review/00001.png b/test/python/snapshots/stax/test_bitcoin_fund_valid_2/review/00001.png new file mode 100644 index 0000000..bc74a6f Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_valid_2/review/00002.png b/test/python/snapshots/stax/test_bitcoin_fund_valid_2/review/00002.png new file mode 100644 index 0000000..18b7010 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_valid_2/review/00003.png b/test/python/snapshots/stax/test_bitcoin_fund_valid_2/review/00003.png new file mode 100644 index 0000000..18b7010 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_valid_2/review/00003.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..0228e5e Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/review/00000.png new file mode 100644 index 0000000..701b8f5 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/review/00001.png new file mode 100644 index 0000000..1fdf257 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/review/00002.png new file mode 100644 index 0000000..18b7010 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/review/00003.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/review/00003.png new file mode 100644 index 0000000..18b7010 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_amount/review/00003.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..0228e5e Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/review/00000.png new file mode 100644 index 0000000..701b8f5 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/review/00001.png new file mode 100644 index 0000000..1fdf257 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/review/00002.png new file mode 100644 index 0000000..18b7010 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/review/00003.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/review/00003.png new file mode 100644 index 0000000..18b7010 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_destination/review/00003.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/post_sign/00000.png new file mode 100644 index 0000000..0228e5e Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/review/00000.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/review/00000.png new file mode 100644 index 0000000..701b8f5 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/review/00001.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/review/00001.png new file mode 100644 index 0000000..1fdf257 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/review/00002.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/review/00002.png new file mode 100644 index 0000000..18b7010 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/review/00003.png b/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/review/00003.png new file mode 100644 index 0000000..18b7010 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_fund_wrong_fees/review/00003.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_sell_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_sell_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_valid_1/review/00000.png b/test/python/snapshots/stax/test_bitcoin_sell_valid_1/review/00000.png new file mode 100644 index 0000000..782238a Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_valid_1/review/00001.png b/test/python/snapshots/stax/test_bitcoin_sell_valid_1/review/00001.png new file mode 100644 index 0000000..84b8294 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_valid_1/review/00002.png b/test/python/snapshots/stax/test_bitcoin_sell_valid_1/review/00002.png new file mode 100644 index 0000000..4bc4a49 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_valid_1/review/00003.png b/test/python/snapshots/stax/test_bitcoin_sell_valid_1/review/00003.png new file mode 100644 index 0000000..4bc4a49 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_valid_1/review/00003.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_sell_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_sell_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_valid_2/review/00000.png b/test/python/snapshots/stax/test_bitcoin_sell_valid_2/review/00000.png new file mode 100644 index 0000000..782238a Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_valid_2/review/00001.png b/test/python/snapshots/stax/test_bitcoin_sell_valid_2/review/00001.png new file mode 100644 index 0000000..f6cf400 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_valid_2/review/00002.png b/test/python/snapshots/stax/test_bitcoin_sell_valid_2/review/00002.png new file mode 100644 index 0000000..4bc4a49 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_valid_2/review/00003.png b/test/python/snapshots/stax/test_bitcoin_sell_valid_2/review/00003.png new file mode 100644 index 0000000..4bc4a49 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_valid_2/review/00003.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..0228e5e Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/review/00000.png new file mode 100644 index 0000000..782238a Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/review/00001.png new file mode 100644 index 0000000..84b8294 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/review/00002.png new file mode 100644 index 0000000..4bc4a49 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/review/00003.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/review/00003.png new file mode 100644 index 0000000..4bc4a49 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_amount/review/00003.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..0228e5e Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/review/00000.png new file mode 100644 index 0000000..782238a Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/review/00001.png new file mode 100644 index 0000000..84b8294 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/review/00002.png new file mode 100644 index 0000000..4bc4a49 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/review/00003.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/review/00003.png new file mode 100644 index 0000000..4bc4a49 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_destination/review/00003.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/post_sign/00000.png new file mode 100644 index 0000000..0228e5e Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/review/00000.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/review/00000.png new file mode 100644 index 0000000..782238a Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/review/00001.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/review/00001.png new file mode 100644 index 0000000..84b8294 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/review/00002.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/review/00002.png new file mode 100644 index 0000000..4bc4a49 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/review/00003.png b/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/review/00003.png new file mode 100644 index 0000000..4bc4a49 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_sell_wrong_fees/review/00003.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_swap_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_swap_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_valid_1/review/00000.png b/test/python/snapshots/stax/test_bitcoin_swap_valid_1/review/00000.png new file mode 100644 index 0000000..3a1e6e2 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_valid_1/review/00001.png b/test/python/snapshots/stax/test_bitcoin_swap_valid_1/review/00001.png new file mode 100644 index 0000000..f7e0b71 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_valid_1/review/00002.png b/test/python/snapshots/stax/test_bitcoin_swap_valid_1/review/00002.png new file mode 100644 index 0000000..c4fd23d Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_valid_1/review/00003.png b/test/python/snapshots/stax/test_bitcoin_swap_valid_1/review/00003.png new file mode 100644 index 0000000..c4fd23d Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_valid_1/review/00003.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_swap_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_swap_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_valid_2/review/00000.png b/test/python/snapshots/stax/test_bitcoin_swap_valid_2/review/00000.png new file mode 100644 index 0000000..3a1e6e2 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_valid_2/review/00001.png b/test/python/snapshots/stax/test_bitcoin_swap_valid_2/review/00001.png new file mode 100644 index 0000000..5a6121c Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_valid_2/review/00002.png b/test/python/snapshots/stax/test_bitcoin_swap_valid_2/review/00002.png new file mode 100644 index 0000000..c4fd23d Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_valid_2/review/00003.png b/test/python/snapshots/stax/test_bitcoin_swap_valid_2/review/00003.png new file mode 100644 index 0000000..c4fd23d Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_valid_2/review/00003.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..0228e5e Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/review/00000.png new file mode 100644 index 0000000..3a1e6e2 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/review/00001.png new file mode 100644 index 0000000..f7e0b71 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/review/00002.png new file mode 100644 index 0000000..c4fd23d Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/review/00003.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/review/00003.png new file mode 100644 index 0000000..c4fd23d Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_amount/review/00003.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..0228e5e Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/review/00000.png new file mode 100644 index 0000000..3a1e6e2 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/review/00001.png new file mode 100644 index 0000000..f7e0b71 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/review/00002.png new file mode 100644 index 0000000..c4fd23d Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/review/00003.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/review/00003.png new file mode 100644 index 0000000..c4fd23d Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_destination/review/00003.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/post_sign/00000.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/post_sign/00000.png new file mode 100644 index 0000000..0228e5e Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/post_sign/00001.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/review/00000.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/review/00000.png new file mode 100644 index 0000000..3a1e6e2 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/review/00000.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/review/00001.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/review/00001.png new file mode 100644 index 0000000..f7e0b71 Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/review/00001.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/review/00002.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/review/00002.png new file mode 100644 index 0000000..c4fd23d Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/review/00002.png differ diff --git a/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/review/00003.png b/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/review/00003.png new file mode 100644 index 0000000..c4fd23d Binary files /dev/null and b/test/python/snapshots/stax/test_bitcoin_swap_wrong_fees/review/00003.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_polkadot_fund_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_polkadot_fund_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_valid_1/review/00000.png b/test/python/snapshots/stax/test_polkadot_fund_valid_1/review/00000.png new file mode 100644 index 0000000..ed60469 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_valid_1/review/00001.png b/test/python/snapshots/stax/test_polkadot_fund_valid_1/review/00001.png new file mode 100644 index 0000000..b351bd1 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_valid_1/review/00002.png b/test/python/snapshots/stax/test_polkadot_fund_valid_1/review/00002.png new file mode 100644 index 0000000..de00298 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_polkadot_fund_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_polkadot_fund_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_valid_2/review/00000.png b/test/python/snapshots/stax/test_polkadot_fund_valid_2/review/00000.png new file mode 100644 index 0000000..ed60469 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_valid_2/review/00001.png b/test/python/snapshots/stax/test_polkadot_fund_valid_2/review/00001.png new file mode 100644 index 0000000..03ea823 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_valid_2/review/00002.png b/test/python/snapshots/stax/test_polkadot_fund_valid_2/review/00002.png new file mode 100644 index 0000000..de00298 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..fb52f54 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/review/00000.png new file mode 100644 index 0000000..ed60469 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/review/00001.png new file mode 100644 index 0000000..b351bd1 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/review/00002.png new file mode 100644 index 0000000..de00298 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..fb52f54 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/review/00000.png new file mode 100644 index 0000000..ed60469 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/review/00001.png new file mode 100644 index 0000000..b351bd1 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/review/00002.png new file mode 100644 index 0000000..de00298 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_fund_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_polkadot_sell_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_polkadot_sell_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_valid_1/review/00000.png b/test/python/snapshots/stax/test_polkadot_sell_valid_1/review/00000.png new file mode 100644 index 0000000..c483e88 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_valid_1/review/00001.png b/test/python/snapshots/stax/test_polkadot_sell_valid_1/review/00001.png new file mode 100644 index 0000000..e7fb2d7 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_valid_1/review/00002.png b/test/python/snapshots/stax/test_polkadot_sell_valid_1/review/00002.png new file mode 100644 index 0000000..cdb07a6 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_polkadot_sell_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_polkadot_sell_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_valid_2/review/00000.png b/test/python/snapshots/stax/test_polkadot_sell_valid_2/review/00000.png new file mode 100644 index 0000000..c483e88 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_valid_2/review/00001.png b/test/python/snapshots/stax/test_polkadot_sell_valid_2/review/00001.png new file mode 100644 index 0000000..a5a7a34 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_valid_2/review/00002.png b/test/python/snapshots/stax/test_polkadot_sell_valid_2/review/00002.png new file mode 100644 index 0000000..cdb07a6 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..fb52f54 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/review/00000.png new file mode 100644 index 0000000..c483e88 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/review/00001.png new file mode 100644 index 0000000..e7fb2d7 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/review/00002.png new file mode 100644 index 0000000..cdb07a6 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..fb52f54 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/review/00000.png new file mode 100644 index 0000000..c483e88 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/review/00001.png new file mode 100644 index 0000000..e7fb2d7 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/review/00002.png new file mode 100644 index 0000000..cdb07a6 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_sell_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_polkadot_swap_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_polkadot_swap_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_valid_1/review/00000.png b/test/python/snapshots/stax/test_polkadot_swap_valid_1/review/00000.png new file mode 100644 index 0000000..4e2a994 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_valid_1/review/00001.png b/test/python/snapshots/stax/test_polkadot_swap_valid_1/review/00001.png new file mode 100644 index 0000000..9709cf3 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_valid_1/review/00002.png b/test/python/snapshots/stax/test_polkadot_swap_valid_1/review/00002.png new file mode 100644 index 0000000..5f8d978 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_polkadot_swap_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_polkadot_swap_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_valid_2/review/00000.png b/test/python/snapshots/stax/test_polkadot_swap_valid_2/review/00000.png new file mode 100644 index 0000000..4e2a994 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_valid_2/review/00001.png b/test/python/snapshots/stax/test_polkadot_swap_valid_2/review/00001.png new file mode 100644 index 0000000..fa732c6 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_valid_2/review/00002.png b/test/python/snapshots/stax/test_polkadot_swap_valid_2/review/00002.png new file mode 100644 index 0000000..5f8d978 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..fb52f54 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/review/00000.png new file mode 100644 index 0000000..4e2a994 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/review/00001.png new file mode 100644 index 0000000..9709cf3 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/review/00002.png new file mode 100644 index 0000000..5f8d978 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..fb52f54 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/review/00000.png new file mode 100644 index 0000000..4e2a994 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/review/00001.png new file mode 100644 index 0000000..9709cf3 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/review/00002.png new file mode 100644 index 0000000..5f8d978 Binary files /dev/null and b/test/python/snapshots/stax/test_polkadot_swap_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_fund_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_fund_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_trx_fund_valid_1/review/00000.png new file mode 100644 index 0000000..381a51f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_trx_fund_valid_1/review/00001.png new file mode 100644 index 0000000..4884b59 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_trx_fund_valid_1/review/00002.png new file mode 100644 index 0000000..4d18316 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_fund_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_fund_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_trx_fund_valid_2/review/00000.png new file mode 100644 index 0000000..381a51f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_trx_fund_valid_2/review/00001.png new file mode 100644 index 0000000..935de6a Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_trx_fund_valid_2/review/00002.png new file mode 100644 index 0000000..4d18316 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/review/00000.png new file mode 100644 index 0000000..381a51f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/review/00001.png new file mode 100644 index 0000000..4884b59 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/review/00002.png new file mode 100644 index 0000000..4d18316 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/review/00000.png new file mode 100644 index 0000000..381a51f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/review/00001.png new file mode 100644 index 0000000..4884b59 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/review/00002.png new file mode 100644 index 0000000..4d18316 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/review/00000.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/review/00000.png new file mode 100644 index 0000000..381a51f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/review/00001.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/review/00001.png new file mode 100644 index 0000000..4884b59 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/review/00002.png b/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/review/00002.png new file mode 100644 index 0000000..4d18316 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_fund_wrong_memo/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_sell_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_sell_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_trx_sell_valid_1/review/00000.png new file mode 100644 index 0000000..7254d57 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_trx_sell_valid_1/review/00001.png new file mode 100644 index 0000000..489fdbb Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_trx_sell_valid_1/review/00002.png new file mode 100644 index 0000000..292dfaf Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_sell_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_sell_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_trx_sell_valid_2/review/00000.png new file mode 100644 index 0000000..7254d57 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_trx_sell_valid_2/review/00001.png new file mode 100644 index 0000000..ae9f464 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_trx_sell_valid_2/review/00002.png new file mode 100644 index 0000000..292dfaf Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/review/00000.png new file mode 100644 index 0000000..7254d57 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/review/00001.png new file mode 100644 index 0000000..489fdbb Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/review/00002.png new file mode 100644 index 0000000..292dfaf Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/review/00000.png new file mode 100644 index 0000000..7254d57 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/review/00001.png new file mode 100644 index 0000000..489fdbb Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/review/00002.png new file mode 100644 index 0000000..292dfaf Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/review/00000.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/review/00000.png new file mode 100644 index 0000000..7254d57 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/review/00001.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/review/00001.png new file mode 100644 index 0000000..489fdbb Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/review/00002.png b/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/review/00002.png new file mode 100644 index 0000000..292dfaf Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_sell_wrong_memo/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_swap_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_swap_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_trx_swap_valid_1/review/00000.png new file mode 100644 index 0000000..f269524 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_trx_swap_valid_1/review/00001.png new file mode 100644 index 0000000..21c484e Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_trx_swap_valid_1/review/00002.png new file mode 100644 index 0000000..9a7df44 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_swap_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_swap_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_trx_swap_valid_2/review/00000.png new file mode 100644 index 0000000..f269524 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_trx_swap_valid_2/review/00001.png new file mode 100644 index 0000000..939c4e2 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_trx_swap_valid_2/review/00002.png new file mode 100644 index 0000000..9a7df44 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/review/00000.png new file mode 100644 index 0000000..f269524 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/review/00001.png new file mode 100644 index 0000000..21c484e Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/review/00002.png new file mode 100644 index 0000000..9a7df44 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/review/00000.png new file mode 100644 index 0000000..f269524 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/review/00001.png new file mode 100644 index 0000000..21c484e Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/review/00002.png new file mode 100644 index 0000000..9a7df44 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_swap_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/review/00000.png new file mode 100644 index 0000000..381a51f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/review/00001.png new file mode 100644 index 0000000..4884b59 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/review/00002.png new file mode 100644 index 0000000..4d18316 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/review/00000.png new file mode 100644 index 0000000..381a51f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/review/00001.png new file mode 100644 index 0000000..935de6a Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/review/00002.png new file mode 100644 index 0000000..4d18316 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_fund_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/review/00000.png new file mode 100644 index 0000000..7254d57 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/review/00001.png new file mode 100644 index 0000000..489fdbb Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/review/00002.png new file mode 100644 index 0000000..292dfaf Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/review/00000.png new file mode 100644 index 0000000..7254d57 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/review/00001.png new file mode 100644 index 0000000..ae9f464 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/review/00002.png new file mode 100644 index 0000000..292dfaf Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_sell_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/review/00000.png new file mode 100644 index 0000000..f269524 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/review/00001.png new file mode 100644 index 0000000..21c484e Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/review/00002.png new file mode 100644 index 0000000..9a7df44 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/review/00000.png new file mode 100644 index 0000000..f269524 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/review/00001.png new file mode 100644 index 0000000..939c4e2 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/review/00002.png new file mode 100644 index 0000000..9a7df44 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_trx_to_usdt_swap_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/review/00000.png new file mode 100644 index 0000000..be8c338 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/review/00001.png new file mode 100644 index 0000000..d5f8e9b Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/review/00002.png new file mode 100644 index 0000000..af9beb9 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/review/00000.png new file mode 100644 index 0000000..be8c338 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/review/00001.png new file mode 100644 index 0000000..20cd0f9 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/review/00002.png new file mode 100644 index 0000000..af9beb9 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/review/00000.png new file mode 100644 index 0000000..be8c338 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/review/00001.png new file mode 100644 index 0000000..d5f8e9b Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/review/00002.png new file mode 100644 index 0000000..af9beb9 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/review/00000.png new file mode 100644 index 0000000..be8c338 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/review/00001.png new file mode 100644 index 0000000..d5f8e9b Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/review/00002.png new file mode 100644 index 0000000..af9beb9 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/review/00000.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/review/00000.png new file mode 100644 index 0000000..be8c338 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/review/00001.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/review/00001.png new file mode 100644 index 0000000..d5f8e9b Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/review/00002.png b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/review/00002.png new file mode 100644 index 0000000..af9beb9 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_fund_wrong_memo/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/review/00000.png new file mode 100644 index 0000000..249dd37 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/review/00001.png new file mode 100644 index 0000000..7742088 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/review/00002.png new file mode 100644 index 0000000..4560425 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/review/00000.png new file mode 100644 index 0000000..249dd37 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/review/00001.png new file mode 100644 index 0000000..e443703 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/review/00002.png new file mode 100644 index 0000000..4560425 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/review/00000.png new file mode 100644 index 0000000..249dd37 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/review/00001.png new file mode 100644 index 0000000..7742088 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/review/00002.png new file mode 100644 index 0000000..4560425 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/review/00000.png new file mode 100644 index 0000000..249dd37 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/review/00001.png new file mode 100644 index 0000000..7742088 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/review/00002.png new file mode 100644 index 0000000..4560425 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/review/00000.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/review/00000.png new file mode 100644 index 0000000..249dd37 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/review/00001.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/review/00001.png new file mode 100644 index 0000000..7742088 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/review/00002.png b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/review/00002.png new file mode 100644 index 0000000..4560425 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_sell_wrong_memo/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/review/00000.png new file mode 100644 index 0000000..852435c Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/review/00001.png new file mode 100644 index 0000000..35e074d Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/review/00002.png new file mode 100644 index 0000000..37a55c5 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/review/00000.png new file mode 100644 index 0000000..852435c Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/review/00001.png new file mode 100644 index 0000000..9f0a869 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/review/00002.png new file mode 100644 index 0000000..37a55c5 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/review/00000.png new file mode 100644 index 0000000..852435c Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/review/00001.png new file mode 100644 index 0000000..35e074d Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/review/00002.png new file mode 100644 index 0000000..37a55c5 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/review/00000.png new file mode 100644 index 0000000..852435c Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/review/00001.png new file mode 100644 index 0000000..35e074d Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/review/00002.png new file mode 100644 index 0000000..37a55c5 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdc_swap_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/review/00000.png new file mode 100644 index 0000000..af2bfc7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/review/00001.png new file mode 100644 index 0000000..f37b14b Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/review/00002.png new file mode 100644 index 0000000..d871260 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/review/00000.png new file mode 100644 index 0000000..af2bfc7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/review/00001.png new file mode 100644 index 0000000..1362a93 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/review/00002.png new file mode 100644 index 0000000..d871260 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/review/00000.png new file mode 100644 index 0000000..af2bfc7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/review/00001.png new file mode 100644 index 0000000..f37b14b Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/review/00002.png new file mode 100644 index 0000000..d871260 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/review/00000.png new file mode 100644 index 0000000..af2bfc7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/review/00001.png new file mode 100644 index 0000000..f37b14b Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/review/00002.png new file mode 100644 index 0000000..d871260 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/review/00000.png new file mode 100644 index 0000000..af2bfc7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/review/00001.png new file mode 100644 index 0000000..f37b14b Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/review/00002.png new file mode 100644 index 0000000..d871260 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_fund_wrong_memo/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/review/00000.png new file mode 100644 index 0000000..ddd6f4a Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/review/00001.png new file mode 100644 index 0000000..2127f8e Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/review/00002.png new file mode 100644 index 0000000..9f27ef7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/review/00000.png new file mode 100644 index 0000000..ddd6f4a Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/review/00001.png new file mode 100644 index 0000000..fdac24e Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/review/00002.png new file mode 100644 index 0000000..9f27ef7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/review/00000.png new file mode 100644 index 0000000..ddd6f4a Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/review/00001.png new file mode 100644 index 0000000..2127f8e Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/review/00002.png new file mode 100644 index 0000000..9f27ef7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/review/00000.png new file mode 100644 index 0000000..ddd6f4a Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/review/00001.png new file mode 100644 index 0000000..2127f8e Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/review/00002.png new file mode 100644 index 0000000..9f27ef7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/review/00000.png new file mode 100644 index 0000000..ddd6f4a Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/review/00001.png new file mode 100644 index 0000000..2127f8e Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/review/00002.png new file mode 100644 index 0000000..9f27ef7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_sell_wrong_memo/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/review/00000.png new file mode 100644 index 0000000..ee70d75 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/review/00001.png new file mode 100644 index 0000000..8827138 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/review/00002.png new file mode 100644 index 0000000..c4dbc0f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/post_sign/00000.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/review/00000.png new file mode 100644 index 0000000..ee70d75 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/review/00001.png new file mode 100644 index 0000000..3417a95 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/review/00002.png new file mode 100644 index 0000000..c4dbc0f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/review/00000.png new file mode 100644 index 0000000..ee70d75 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/review/00001.png new file mode 100644 index 0000000..8827138 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/review/00002.png new file mode 100644 index 0000000..c4dbc0f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_amount/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/review/00000.png new file mode 100644 index 0000000..ee70d75 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/review/00001.png new file mode 100644 index 0000000..8827138 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/review/00002.png new file mode 100644 index 0000000..c4dbc0f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_swap_wrong_destination/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/review/00000.png new file mode 100644 index 0000000..af2bfc7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/review/00001.png new file mode 100644 index 0000000..f37b14b Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/review/00002.png new file mode 100644 index 0000000..d871260 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/review/00000.png new file mode 100644 index 0000000..af2bfc7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/review/00001.png new file mode 100644 index 0000000..1362a93 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/review/00002.png new file mode 100644 index 0000000..d871260 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_fund_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/review/00000.png new file mode 100644 index 0000000..ddd6f4a Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/review/00001.png new file mode 100644 index 0000000..2127f8e Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/review/00002.png new file mode 100644 index 0000000..9f27ef7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/review/00000.png new file mode 100644 index 0000000..ddd6f4a Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/review/00001.png new file mode 100644 index 0000000..fdac24e Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/review/00002.png new file mode 100644 index 0000000..9f27ef7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_sell_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/review/00000.png new file mode 100644 index 0000000..ee70d75 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/review/00001.png new file mode 100644 index 0000000..8827138 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/review/00002.png new file mode 100644 index 0000000..c4dbc0f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/review/00000.png new file mode 100644 index 0000000..ee70d75 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/review/00001.png new file mode 100644 index 0000000..3417a95 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/review/00002.png new file mode 100644 index 0000000..c4dbc0f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_trx_swap_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/review/00000.png new file mode 100644 index 0000000..af2bfc7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/review/00001.png new file mode 100644 index 0000000..f37b14b Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/review/00002.png new file mode 100644 index 0000000..d871260 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/review/00000.png new file mode 100644 index 0000000..af2bfc7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/review/00001.png new file mode 100644 index 0000000..1362a93 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/review/00002.png new file mode 100644 index 0000000..d871260 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_fund_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/review/00000.png new file mode 100644 index 0000000..ddd6f4a Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/review/00001.png new file mode 100644 index 0000000..2127f8e Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/review/00002.png new file mode 100644 index 0000000..9f27ef7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/review/00000.png new file mode 100644 index 0000000..ddd6f4a Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/review/00001.png new file mode 100644 index 0000000..fdac24e Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/review/00002.png new file mode 100644 index 0000000..9f27ef7 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_sell_valid_2/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/review/00000.png new file mode 100644 index 0000000..ee70d75 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/review/00001.png new file mode 100644 index 0000000..8827138 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/review/00002.png new file mode 100644 index 0000000..c4dbc0f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_1/review/00002.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/post_sign/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/post_sign/00000.png new file mode 100644 index 0000000..fd09d6f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/post_sign/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/post_sign/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/post_sign/00001.png new file mode 100644 index 0000000..3599465 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/post_sign/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/review/00000.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/review/00000.png new file mode 100644 index 0000000..ee70d75 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/review/00000.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/review/00001.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/review/00001.png new file mode 100644 index 0000000..3417a95 Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/review/00001.png differ diff --git a/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/review/00002.png b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/review/00002.png new file mode 100644 index 0000000..c4dbc0f Binary files /dev/null and b/test/python/snapshots/stax/test_tron_usdt_to_usdc_swap_valid_2/review/00002.png differ diff --git a/test/python/test_bitcoin.py b/test/python/test_bitcoin.py new file mode 100644 index 0000000..956c129 --- /dev/null +++ b/test/python/test_bitcoin.py @@ -0,0 +1,73 @@ +import pytest + +from .apps.exchange_test_runner import ExchangeTestRunner, ALL_TESTS_EXCEPT_MEMO +from .apps.bitcoin import BitcoinClient, BitcoinErrors +from ledger_bitcoin import WalletPolicy + +in_wallet = WalletPolicy( + "", + "wpkh(@0/**)", + [ + "[f5acc2fd/84'/0'/0']xpub6DUYn4moKgHkK2d7bXX3mHTPb6XQwRVFRMdZ6ZwLS5u3nonGVpJiFeZiQkHutwdFqxKP75jex8gvVm7ed4euYeDtMnoiF1Cz1z4CeBJYWin" + ], +) + +out_wallet = WalletPolicy( + "", + "wpkh(@0/**)", + [ + "xpub6CatWdiZiodmYVtWLtEQsAg1H9ooS1bmsJUBwQ83FE1Fyk386FWcyicJgEZv3quZSJKA5dh5Lo2PbubMGxCfZtRthV6ST2qquL9w3HSzcUn" + ], +) + +out_wallet_2 = WalletPolicy( + "", + "wpkh(@0/**)", + [ + "xpub6D7atwj3ewAGT347tUzTNzfTGos1rCFVX4v8gViXiM2R1QHvox1LhEf6NtCeNsCwpppFUoQuS6mHUwfTveA5tEEwn2LqZHfVBEz5qvYmYhf" + ], +) + +# ExchangeTestRunner implementation for Bitcoin +class BitcoinTests(ExchangeTestRunner): + + currency_ticker = "BTC" + valid_destination_1 = BitcoinClient.get_address_from_wallet(out_wallet) + valid_destination_memo_1 = "" + valid_destination_2 = BitcoinClient.get_address_from_wallet(out_wallet_2) + valid_destination_memo_2 = "0" + valid_refund = BitcoinClient.get_address_from_wallet(in_wallet) + valid_refund_memo = "" + valid_send_amount_1 = 20900000 + valid_send_amount_2 = 446739662 + valid_fees_1 = 100000 + valid_fees_2 = 10078 + fake_refund = "abcdabcd" + fake_refund_memo = "" + fake_payout = "abcdabcd" + fake_payout_memo = "" + signature_refusal_error_code = BitcoinErrors.SW_SWAP_CHECKING_FAIL + + def perform_final_tx(self, destination, send_amount, fees, memo): + if destination == BitcoinClient.get_address_from_wallet(out_wallet): + BitcoinClient(self.backend).send_simple_sign_tx(in_wallet=in_wallet, + fees=fees, + destination=out_wallet, + send_amount=send_amount) + + elif destination == BitcoinClient.get_address_from_wallet(out_wallet_2): + BitcoinClient(self.backend).send_simple_sign_tx(in_wallet=in_wallet, + fees=fees, + destination=out_wallet_2, + send_amount=send_amount) + + # TODO : assert signature validity + + +# Use a class to reuse the same Speculos instance +class TestsBitcoin: + + @pytest.mark.parametrize('test_to_run', ALL_TESTS_EXCEPT_MEMO) + def test_bitcoin(self, backend, exchange_navigation_helper, test_to_run): + BitcoinTests(backend, exchange_navigation_helper).run_test(test_to_run) + diff --git a/test/python/test_extension.py b/test/python/test_extension.py index 4d0d0e6..c07e1b4 100644 --- a/test/python/test_extension.py +++ b/test/python/test_extension.py @@ -4,7 +4,7 @@ from ragger.error import ExceptionRAPDU from .apps.exchange import ExchangeClient, Rate, SubCommand, Errors, Command, P2_EXTEND, P2_MORE, EXCHANGE_CLASS -from .apps.exchange_transaction_builder import get_partner_curve, craft_tx, encode_tx, LEGACY_SUBCOMMANDS, ALL_SUBCOMMANDS, NEW_SUBCOMMANDS, craft_transaction_proposal +from .apps.exchange_transaction_builder import get_partner_curve, LEGACY_SUBCOMMANDS, ALL_SUBCOMMANDS, NEW_SUBCOMMANDS, get_credentials, craft_and_sign_tx from .apps.signing_authority import SigningAuthority, LEDGER_SIGNER from .apps import cal as cal @@ -15,7 +15,7 @@ "payin_extra_id": b"", "refund_address": b"0xDad77910DbDFdE764fC21FCD4E74D71bBACA6D8D", "refund_extra_id": b"", - "payout_address": b"bc1qer57ma0fzhqys2cmydhuj9cprf9eg0nw922a8j", + "payout_address": b"bc1qqtl9jlrwcr3fsfcjj2du7pu6fcgaxl5dsw2vyg", "payout_extra_id": b"", "currency_from": "ETH", "currency_to": "BTC", @@ -54,9 +54,10 @@ def test_extension_forbidden_for_subcommand(self, backend, subcommand): ex = ExchangeClient(backend, Rate.FIXED, subcommand) partner = SigningAuthority(curve=get_partner_curve(subcommand), name="Name") transaction_id = ex.init_transaction().data - ex.set_partner_key(partner.credentials) - ex.check_partner_key(LEDGER_SIGNER.sign(partner.credentials)) - tx = craft_tx(subcommand, TX_INFOS[subcommand], transaction_id) + credentials = get_credentials(subcommand, partner) + ex.set_partner_key(credentials) + ex.check_partner_key(LEDGER_SIGNER.sign(credentials)) + tx, _ = craft_and_sign_tx(subcommand, TX_INFOS[subcommand], transaction_id, FEES, partner) # Send the exchange transaction proposal and its signature for ext in [P2_MORE, P2_EXTEND, (P2_EXTEND | P2_MORE)]: @@ -78,22 +79,21 @@ def test_extension_many_chunks(self, backend, subcommand): ex = ExchangeClient(backend, Rate.FIXED, subcommand) partner = SigningAuthority(curve=get_partner_curve(subcommand), name="Name") transaction_id = ex.init_transaction().data - ex.set_partner_key(partner.credentials) - ex.check_partner_key(LEDGER_SIGNER.sign(partner.credentials)) - tx = craft_tx(subcommand, TX_INFOS[subcommand], transaction_id) - signed_tx = encode_tx(subcommand, partner, tx) + credentials = get_credentials(subcommand, partner) + ex.set_partner_key(credentials) + ex.check_partner_key(LEDGER_SIGNER.sign(credentials)) + tx, tx_signature = craft_and_sign_tx(subcommand, TX_INFOS[subcommand], transaction_id, FEES, partner) # Artificially create many chunks to test the TX concatenation - payload = craft_transaction_proposal(subcommand, tx, FEES) - payload_split = [payload[x:x + 70] for x in range(0, len(payload), 70)] - for i, p in enumerate(payload_split): + tx_split = [tx[x:x + 70] for x in range(0, len(tx), 70)] + for i, p in enumerate(tx_split): p2 = subcommand - if i != len(payload_split) - 1: + if i != len(tx_split) - 1: p2 |= P2_MORE if i != 0: p2 |= P2_EXTEND backend.exchange(EXCHANGE_CLASS, Command.PROCESS_TRANSACTION_RESPONSE, p1=Rate.FIXED, p2=p2, data=p) - ex.check_transaction_signature(signed_tx) + ex.check_transaction_signature(tx_signature) @pytest.mark.parametrize("subcommand", NEW_SUBCOMMANDS) @@ -101,10 +101,10 @@ def test_extension_advanced_usage(self, backend, subcommand): ex = ExchangeClient(backend, Rate.FIXED, subcommand) partner = SigningAuthority(curve=get_partner_curve(subcommand), name="Name") transaction_id = ex.init_transaction().data - ex.set_partner_key(partner.credentials) - ex.check_partner_key(LEDGER_SIGNER.sign(partner.credentials)) - tx = craft_tx(subcommand, TX_INFOS[subcommand], transaction_id) - signed_tx = encode_tx(subcommand, partner, tx) + credentials = get_credentials(subcommand, partner) + ex.set_partner_key(credentials) + ex.check_partner_key(LEDGER_SIGNER.sign(credentials)) + tx, tx_signature = craft_and_sign_tx(subcommand, TX_INFOS[subcommand], transaction_id, FEES, partner) # Start with an EXTEND flag with pytest.raises(ExceptionRAPDU) as e: @@ -120,15 +120,14 @@ def test_extension_advanced_usage(self, backend, subcommand): backend.exchange(EXCHANGE_CLASS, Command.PROCESS_TRANSACTION_RESPONSE, p1=Rate.FIXED, p2=(subcommand | P2_MORE), data=b"0011233445566778899") # Restart a chunk send with correct data, artificially create many chunks to test the TX concatenation - payload = craft_transaction_proposal(subcommand, tx, FEES) - payload_split = [payload[x:x + 70] for x in range(0, len(payload), 70)] - for i, p in enumerate(payload_split): + tx_split = [tx[x:x + 70] for x in range(0, len(tx), 70)] + for i, p in enumerate(tx_split): p2 = subcommand - if i != len(payload_split) - 1: + if i != len(tx_split) - 1: p2 |= P2_MORE if i != 0: p2 |= P2_EXTEND backend.exchange(EXCHANGE_CLASS, Command.PROCESS_TRANSACTION_RESPONSE, p1=Rate.FIXED, p2=p2, data=p) # Check the signature to ensure the data received has not been corrupted - ex.check_transaction_signature(signed_tx) + ex.check_transaction_signature(tx_signature) diff --git a/test/python/test_fake_signer.py b/test/python/test_fake_signer.py index f172570..355dd43 100644 --- a/test/python/test_fake_signer.py +++ b/test/python/test_fake_signer.py @@ -4,7 +4,7 @@ from ragger.error import ExceptionRAPDU from .apps.exchange import ExchangeClient, Rate, SubCommand, Errors -from .apps.exchange_transaction_builder import get_partner_curve, craft_tx, encode_tx, extract_payout_ticker, extract_refund_ticker, ALL_SUBCOMMANDS, SWAP_SUBCOMMANDS +from .apps.exchange_transaction_builder import get_partner_curve, extract_payout_ticker, extract_refund_ticker, ALL_SUBCOMMANDS, SWAP_SUBCOMMANDS, get_credentials, craft_and_sign_tx from .apps import cal as cal from .apps.signing_authority import SigningAuthority, LEDGER_SIGNER @@ -15,7 +15,7 @@ "payin_extra_id": b"", "refund_address": b"0xDad77910DbDFdE764fC21FCD4E74D71bBACA6D8D", "refund_extra_id": b"", - "payout_address": b"bc1qer57ma0fzhqys2cmydhuj9cprf9eg0nw922a8j", + "payout_address": b"bc1qqtl9jlrwcr3fsfcjj2du7pu6fcgaxl5dsw2vyg", "payout_extra_id": b"", "currency_from": "ETH", "currency_to": "BTC", @@ -57,100 +57,106 @@ class TestFakeSigner: # CHECK THAT A PARTNER SIGNED BY THE LEDGER KEY BUT DIFFERENT THAN THE SET IS REFUSED - @pytest.mark.parametrize("operation", ALL_SUBCOMMANDS) - def test_fake_partner_credentials_sent(self, backend, operation): - ex = ExchangeClient(backend, Rate.FIXED, operation) - partner = SigningAuthority(curve=get_partner_curve(operation), name="partner") - partner_fake = SigningAuthority(curve=get_partner_curve(operation), name="partner_fake") + @pytest.mark.parametrize("subcommand", ALL_SUBCOMMANDS) + def test_fake_partner_credentials_sent(self, backend, subcommand): + ex = ExchangeClient(backend, Rate.FIXED, subcommand) + partner = SigningAuthority(curve=get_partner_curve(subcommand), name="partner") + partner_fake = SigningAuthority(curve=get_partner_curve(subcommand), name="partner_fake") ex.init_transaction() - ex.set_partner_key(partner_fake.credentials) + credentials_fake = get_credentials(subcommand, partner_fake) + credentials = get_credentials(subcommand, partner) + ex.set_partner_key(credentials_fake) with pytest.raises(ExceptionRAPDU) as e: - ex.check_partner_key(LEDGER_SIGNER.sign(partner.credentials)) + ex.check_partner_key(LEDGER_SIGNER.sign(credentials)) assert e.value.status == Errors.SIGN_VERIFICATION_FAIL # CHECK THAT A PARTNER NOT SIGNED BY THE LEDGER KEY IS REFUSED - @pytest.mark.parametrize("operation", ALL_SUBCOMMANDS) - def test_fake_partner_credentials_signed(self, backend, operation): + @pytest.mark.parametrize("subcommand", ALL_SUBCOMMANDS) + def test_fake_partner_credentials_signed(self, backend, subcommand): ledger_fake_signer = SigningAuthority(curve=ec.SECP256K1(), name="fake_signer") - ex = ExchangeClient(backend, Rate.FIXED, operation) - partner = SigningAuthority(curve=get_partner_curve(operation), name="partner") + ex = ExchangeClient(backend, Rate.FIXED, subcommand) + partner = SigningAuthority(curve=get_partner_curve(subcommand), name="partner") ex.init_transaction() - ex.set_partner_key(partner.credentials) + credentials = get_credentials(subcommand, partner) + ex.set_partner_key(credentials) with pytest.raises(ExceptionRAPDU) as e: - ex.check_partner_key(ledger_fake_signer.sign(partner.credentials)) + ex.check_partner_key(ledger_fake_signer.sign(credentials)) assert e.value.status == Errors.SIGN_VERIFICATION_FAIL # CHECK THAT A TRANSACTION INFORMATION NOT SIGNED BY THE PARTNER KEY IS REFUSED - @pytest.mark.parametrize("operation", ALL_SUBCOMMANDS) - def test_fake_transaction_infos(self, backend, operation): - ex = ExchangeClient(backend, Rate.FIXED, operation) - partner = SigningAuthority(curve=get_partner_curve(operation), name="partner") - partner_fake = SigningAuthority(curve=get_partner_curve(operation), name="partner_fake") + @pytest.mark.parametrize("subcommand", ALL_SUBCOMMANDS) + def test_fake_transaction_infos(self, backend, subcommand): + ex = ExchangeClient(backend, Rate.FIXED, subcommand) + partner = SigningAuthority(curve=get_partner_curve(subcommand), name="partner") + partner_fake = SigningAuthority(curve=get_partner_curve(subcommand), name="partner_fake") transaction_id = ex.init_transaction().data - ex.set_partner_key(partner.credentials) - ex.check_partner_key(LEDGER_SIGNER.sign(partner.credentials)) - tx = craft_tx(operation, TX_INFOS[operation], transaction_id) - ex.process_transaction(tx, FEES) + credentials = get_credentials(subcommand, partner) + ex.set_partner_key(credentials) + ex.check_partner_key(LEDGER_SIGNER.sign(credentials)) + tx, tx_signature = craft_and_sign_tx(subcommand, TX_INFOS[subcommand], transaction_id, FEES, partner_fake) + ex.process_transaction(tx) - encoded_tx = encode_tx(operation, partner_fake, tx) with pytest.raises(ExceptionRAPDU) as e: - ex.check_transaction_signature(encoded_tx) + ex.check_transaction_signature(tx_signature) assert e.value.status == Errors.SIGN_VERIFICATION_FAIL # CHECK THAT A COIN CONFIGURATION NOT SIGNED BY THE LEDGER KEY IS REFUSED - @pytest.mark.parametrize("operation", ALL_SUBCOMMANDS) - def test_fake_payout_coin_configuration(self, backend, operation): + @pytest.mark.parametrize("subcommand", ALL_SUBCOMMANDS) + def test_fake_payout_coin_configuration(self, backend, subcommand): ledger_fake_signer = SigningAuthority(curve=ec.SECP256K1(), name="fake_signer") - ex = ExchangeClient(backend, Rate.FIXED, operation) - partner = SigningAuthority(curve=get_partner_curve(operation), name="partner") + ex = ExchangeClient(backend, Rate.FIXED, subcommand) + partner = SigningAuthority(curve=get_partner_curve(subcommand), name="partner") transaction_id = ex.init_transaction().data - ex.set_partner_key(partner.credentials) - ex.check_partner_key(LEDGER_SIGNER.sign(partner.credentials)) - tx = craft_tx(operation, TX_INFOS[operation], transaction_id) - ex.process_transaction(tx, FEES) - encoded_tx = encode_tx(operation, partner, tx) - ex.check_transaction_signature(encoded_tx) - - payout_ticker = extract_payout_ticker(operation, TX_INFOS[operation]) + credentials = get_credentials(subcommand, partner) + ex.set_partner_key(credentials) + ex.check_partner_key(LEDGER_SIGNER.sign(credentials)) + tx, tx_signature = craft_and_sign_tx(subcommand, TX_INFOS[subcommand], transaction_id, FEES, partner) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) + + payout_ticker = extract_payout_ticker(subcommand, TX_INFOS[subcommand]) payout_conf = cal.get_conf_for_ticker(payout_ticker, overload_signer=ledger_fake_signer) with pytest.raises(ExceptionRAPDU) as e: - if operation == SubCommand.SWAP or operation == SubCommand.SWAP_NG: + if subcommand == SubCommand.SWAP or subcommand == SubCommand.SWAP_NG: ex.check_payout_address(payout_conf) else: with ex.check_asset_in(payout_conf): pass assert e.value.status == Errors.SIGN_VERIFICATION_FAIL - @pytest.mark.parametrize("operation", SWAP_SUBCOMMANDS) - def test_fake_refund_coin_configuration_swap(self, backend, operation): + @pytest.mark.parametrize("subcommand", SWAP_SUBCOMMANDS) + def test_fake_refund_coin_configuration_swap(self, backend, subcommand): ledger_fake_signer = SigningAuthority(curve=ec.SECP256K1(), name="fake_signer") - ex = ExchangeClient(backend, Rate.FIXED, operation) - partner = SigningAuthority(curve=get_partner_curve(operation), name="partner") + ex = ExchangeClient(backend, Rate.FIXED, subcommand) + partner = SigningAuthority(curve=get_partner_curve(subcommand), name="partner") transaction_id = ex.init_transaction().data - ex.set_partner_key(partner.credentials) - ex.check_partner_key(LEDGER_SIGNER.sign(partner.credentials)) - tx = craft_tx(operation, SWAP_TX_INFOS, transaction_id) - ex.process_transaction(tx, FEES) - encoded_tx = encode_tx(operation, partner, tx) - ex.check_transaction_signature(encoded_tx) - - payout_conf = cal.get_conf_for_ticker(SWAP_TX_INFOS["currency_to"]) - refund_conf = cal.get_conf_for_ticker(SWAP_TX_INFOS["currency_from"], overload_signer=ledger_fake_signer) + credentials = get_credentials(subcommand, partner) + ex.set_partner_key(credentials) + ex.check_partner_key(LEDGER_SIGNER.sign(credentials)) + tx, tx_signature = craft_and_sign_tx(subcommand, TX_INFOS[subcommand], transaction_id, FEES, partner) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) + + payout_ticker = extract_payout_ticker(subcommand, TX_INFOS[subcommand]) + payout_conf = cal.get_conf_for_ticker(payout_ticker) ex.check_payout_address(payout_conf) + + refund_ticker = extract_refund_ticker(subcommand, TX_INFOS[subcommand]) + refund_conf = cal.get_conf_for_ticker(refund_ticker, overload_signer=ledger_fake_signer) with pytest.raises(ExceptionRAPDU) as e: with ex.check_refund_address(refund_conf): pass diff --git a/test/python/test_flow_order.py b/test/python/test_flow_order.py index e04375e..a90edcb 100644 --- a/test/python/test_flow_order.py +++ b/test/python/test_flow_order.py @@ -5,7 +5,7 @@ from ragger.error import ExceptionRAPDU from .apps.exchange import ExchangeClient, Rate, SubCommand, Errors, Command, P2_EXTEND, P2_MORE, EXCHANGE_CLASS -from .apps.exchange_transaction_builder import get_partner_curve, craft_tx, encode_tx, extract_payout_ticker, extract_refund_ticker, LEGACY_SUBCOMMANDS, ALL_SUBCOMMANDS, NEW_SUBCOMMANDS, craft_transaction_proposal +from .apps.exchange_transaction_builder import get_partner_curve, extract_payout_ticker, extract_refund_ticker, LEGACY_SUBCOMMANDS, ALL_SUBCOMMANDS, NEW_SUBCOMMANDS, get_credentials, craft_and_sign_tx from .apps.signing_authority import SigningAuthority, LEDGER_SIGNER from .apps import cal as cal @@ -16,7 +16,7 @@ "payin_extra_id": b"", "refund_address": b"0xDad77910DbDFdE764fC21FCD4E74D71bBACA6D8D", "refund_extra_id": b"", - "payout_address": b"bc1qer57ma0fzhqys2cmydhuj9cprf9eg0nw922a8j", + "payout_address": b"bc1qqtl9jlrwcr3fsfcjj2du7pu6fcgaxl5dsw2vyg", "payout_extra_id": b"", "currency_from": "ETH", "currency_to": "BTC", @@ -87,19 +87,19 @@ def test_wrong_flow_order(backend, subcommand, exchange_navigation_helper): transaction_id = ex.init_transaction().data try_all_commands_for_subcommand_except(ex, subcommand, Command.SET_PARTNER_KEY) - ex.set_partner_key(partner.credentials) + credentials = get_credentials(subcommand, partner) + ex.set_partner_key(credentials) try_all_commands_for_subcommand_except(ex, subcommand, Command.CHECK_PARTNER) - ex.check_partner_key(LEDGER_SIGNER.sign(partner.credentials)) + ex.check_partner_key(LEDGER_SIGNER.sign(credentials)) try_all_commands_for_subcommand_except(ex, subcommand, Command.PROCESS_TRANSACTION_RESPONSE) tx_infos = TX_INFOS[subcommand] - tx = craft_tx(subcommand, tx_infos, transaction_id) - ex.process_transaction(tx, FEES) + tx, tx_signature = craft_and_sign_tx(subcommand, TX_INFOS[subcommand], transaction_id, FEES, partner) + ex.process_transaction(tx) try_all_commands_for_subcommand_except(ex, subcommand, Command.CHECK_TRANSACTION_SIGNATURE) - signed_tx = encode_tx(subcommand, partner, tx) - ex.check_transaction_signature(signed_tx) + ex.check_transaction_signature(tx_signature) payout_ticker = extract_payout_ticker(subcommand, tx_infos) payout_configuration = cal.get_conf_for_ticker(payout_ticker) diff --git a/test/python/test_fund_flow_ethereum.py b/test/python/test_fund_flow_ethereum.py index 64b34be..f96f2bc 100644 --- a/test/python/test_fund_flow_ethereum.py +++ b/test/python/test_fund_flow_ethereum.py @@ -2,7 +2,7 @@ from .apps.ethereum import EthereumClient, eth_amount_to_wei from .apps.signing_authority import SigningAuthority, LEDGER_SIGNER -from .apps.exchange_transaction_builder import get_partner_curve, craft_tx, encode_tx, extract_payout_ticker, extract_refund_ticker +from .apps.exchange_transaction_builder import get_partner_curve, extract_payout_ticker, extract_refund_ticker, craft_and_sign_tx from .apps import cal as cal @@ -21,11 +21,11 @@ def test_fund_flow_ethereum_max_partner_name_length(backend, exchange_navigation "in_amount": b"\032\200\250]$T\000", "in_address": "0x252fb4acbe0de4f0bd2409a5ed59a71e4ef1d2bc" } + fees = eth_amount_to_wei(0.004520765) - tx = craft_tx(SubCommand.FUND, tx_infos, transaction_id) - ex.process_transaction(tx, eth_amount_to_wei(0.004520765)) - encoded_tx = encode_tx(SubCommand.FUND, partner, tx) - ex.check_transaction_signature(encoded_tx) + tx, tx_signature = craft_and_sign_tx(SubCommand.FUND, tx_infos, transaction_id, fees, partner) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) with ex.check_asset_in(cal.get_conf_for_ticker(tx_infos["in_currency"])): exchange_navigation_helper.simple_accept() ex.start_signing_transaction() @@ -33,7 +33,7 @@ def test_fund_flow_ethereum_max_partner_name_length(backend, exchange_navigation eth = EthereumClient(backend) assert eth.get_public_key().status == 0x9000 # The original bug was that the Ethereum app was returning just after - # launch, and the first Ethereum:get_public_key call was in fact catched + # launch, and the first Ethereum:get_public_key call was in fact caught # by the Exchange app and interpreted as an Exchange::get_version call. # Exchange version are on 3 bytes, so we check the call does not return # 3 bytes of data @@ -56,11 +56,11 @@ def test_fund_flow_ethereum_min_partner_name_length(backend, exchange_navigation "in_amount": b"\032\200\250]$T\000", "in_address": "0x252fb4acbe0de4f0bd2409a5ed59a71e4ef1d2bc" } + fees = eth_amount_to_wei(0.004520765) - tx = craft_tx(SubCommand.FUND, tx_infos, transaction_id) - ex.process_transaction(tx, eth_amount_to_wei(0.004520765)) - encoded_tx = encode_tx(SubCommand.FUND, partner, tx) - ex.check_transaction_signature(encoded_tx) + tx, tx_signature = craft_and_sign_tx(SubCommand.FUND, tx_infos, transaction_id, fees, partner) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) with ex.check_asset_in(cal.get_conf_for_ticker(tx_infos["in_currency"])): exchange_navigation_helper.simple_accept() ex.start_signing_transaction() @@ -68,7 +68,7 @@ def test_fund_flow_ethereum_min_partner_name_length(backend, exchange_navigation eth = EthereumClient(backend) assert eth.get_public_key().status == 0x9000 # The original bug was that the Ethereum app was returning just after - # launch, and the first Ethereum:get_public_key call was in fact catched + # launch, and the first Ethereum:get_public_key call was in fact caught # by the Exchange app and interpreted as an Exchange::get_version call. # Exchange version are on 3 bytes, so we check the call does not return # 3 bytes of data diff --git a/test/python/test_input_robustness.py b/test/python/test_input_robustness.py index a2d492d..628db33 100644 --- a/test/python/test_input_robustness.py +++ b/test/python/test_input_robustness.py @@ -2,7 +2,7 @@ from ragger.backend import RaisePolicy from .apps.exchange import ExchangeClient, Rate, SubCommand, Errors, Command -from .apps.exchange_transaction_builder import get_partner_curve, craft_tx, encode_tx +from .apps.exchange_transaction_builder import get_partner_curve, craft_and_sign_tx from .apps.signing_authority import SigningAuthority, LEDGER_SIGNER from .apps import cal as cal @@ -60,10 +60,9 @@ def _restart_test(self, backend, ex): transaction_id = ex.init_transaction().data ex.set_partner_key(partner.credentials) ex.check_partner_key(LEDGER_SIGNER.sign(partner.credentials)) - tx = craft_tx(SubCommand.SWAP, self.tx_infos, transaction_id) - ex.process_transaction(tx, self.fees) - encoded_tx = encode_tx(SubCommand.SWAP, partner, tx) - ex.check_transaction_signature(encoded_tx) + tx, tx_signature = craft_and_sign_tx(SubCommand.SWAP, self.tx_infos, transaction_id, self.fees, partner) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) def test_robustness_check_payout_address(self, backend): ex = ExchangeClient(backend, Rate.FIXED, SubCommand.SWAP) @@ -221,10 +220,9 @@ def test_currency_normalization_fund(backend, exchange_navigation_helper): backend.wait_for_home_screen() ex.set_partner_key(partner.credentials) ex.check_partner_key(LEDGER_SIGNER.sign(partner.credentials)) - tx = craft_tx(SubCommand.FUND, tx_infos, transaction_id) - ex.process_transaction(tx, fees) - encoded_tx = encode_tx(SubCommand.FUND, partner, tx) - ex.check_transaction_signature(encoded_tx) + tx, tx_signature = craft_and_sign_tx(SubCommand.FUND, tx_infos, transaction_id, fees, partner) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) payload = prefix_with_len(conf) + cal.sign_currency_conf(conf) + prefix_with_len(cal.get_derivation_path(tx_infos["in_currency"])) backend.raise_policy = RaisePolicy.RAISE_NOTHING @@ -259,10 +257,9 @@ def test_currency_alias(self, backend): backend.wait_for_home_screen() ex.set_partner_key(partner.credentials) ex.check_partner_key(LEDGER_SIGNER.sign(partner.credentials)) - tx = craft_tx(SubCommand.SWAP, tx_infos, transaction_id) - ex.process_transaction(tx, fees) - encoded_tx = encode_tx(SubCommand.SWAP, partner, tx) - ex.check_transaction_signature(encoded_tx) + tx, tx_signature = craft_and_sign_tx(SubCommand.SWAP, tx_infos, transaction_id, fees, partner) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) # If the alias does not work, CHECK_PAYOUT_ADDRESS will crash payload = prefix_with_len(conf) + LEDGER_SIGNER.sign(conf) + prefix_with_len(cal.get_derivation_path(tx_infos["currency_to"])) diff --git a/test/python/test_ng_configuration.py b/test/python/test_ng_configuration.py new file mode 100644 index 0000000..c9d1f09 --- /dev/null +++ b/test/python/test_ng_configuration.py @@ -0,0 +1,92 @@ +import pytest +import copy + +from cryptography.hazmat.primitives.asymmetric import ec + +from .apps.exchange import ExchangeClient, Rate, SubCommand +from .apps.exchange_transaction_builder import SWAP_NG_SPECS, SELL_NG_SPECS, FUND_NG_SPECS, get_partner_curve, get_credentials, craft_and_sign_tx, SignatureComputation, SignatureEncoding, PayloadEncoding +from .apps.signing_authority import SigningAuthority, LEDGER_SIGNER + +# Some valid infos for TX. Content is irrelevant for the test + +SWAP_TX_INFOS = { + "payin_address": b"0xd692Cb1346262F584D17B4B470954501f6715a82", + "payin_extra_id": b"", + "refund_address": b"0xDad77910DbDFdE764fC21FCD4E74D71bBACA6D8D", + "refund_extra_id": b"", + "payout_address": b"bc1qqtl9jlrwcr3fsfcjj2du7pu6fcgaxl5dsw2vyg", + "payout_extra_id": b"", + "currency_from": "ETH", + "currency_to": "BTC", + "amount_to_provider": bytes.fromhex("013fc3a717fb5000"), + "amount_to_wallet": b"\x0b\xeb\xc2\x00", +} +FUND_TX_INFOS = { + "user_id": "John Wick", + "account_name": "Remember Daisy", + "in_currency": "ETH", + "in_amount": b"\032\200\250]$T\000", + "in_address": "0x252fb4acbe0de4f0bd2409a5ed59a71e4ef1d2bc" +} +SELL_TX_INFOS = { + "trader_email": "john@doe.lost", + "out_currency": "USD", + "out_amount": {"coefficient": b"\x01", "exponent": 3}, + "in_currency": "ETH", + "in_amount": b"\032\200\250]$T\000", + "in_address": "0x252fb4acbe0de4f0bd2409a5ed59a71e4ef1d2bc" +} +TX_INFOS = { + SubCommand.SWAP_NG: SWAP_TX_INFOS, + SubCommand.FUND_NG: FUND_TX_INFOS, + SubCommand.SELL_NG: SELL_TX_INFOS, +} +TEST_NAME_SUFFIX = { + SubCommand.SWAP_NG: "swap_ng", + SubCommand.FUND_NG: "fund_ng", + SubCommand.SELL_NG: "sell_ng", +} +FEES = 100 + +class TestNGConfiguration: + + @pytest.mark.parametrize("specs_param", [SWAP_NG_SPECS, SELL_NG_SPECS, FUND_NG_SPECS], ids=["swap_ng", "sell_ng", "fund_ng"]) + @pytest.mark.parametrize("payload_encoding", [PayloadEncoding.BASE_64_URL, PayloadEncoding.BYTES_ARRAY], ids=["base_56", "b_array"]) + @pytest.mark.parametrize("signature_encoding", [SignatureEncoding.PLAIN_R_S, SignatureEncoding.DER], ids=["R,S", "DER"]) + @pytest.mark.parametrize("signature_computation", [SignatureComputation.DOT_PREFIXED_BASE_64_URL, SignatureComputation.BINARY_ENCODED_PAYLOAD], ids=["dot_prefixed", "not_prefixed"]) + def test_ng_tx_configuration(self, backend, specs_param, payload_encoding, signature_encoding, signature_computation): + specs = copy.deepcopy(specs_param) + specs.payload_encoding = payload_encoding + specs.signature_encoding = signature_encoding + specs.signature_computation = signature_computation + + tx_infos = TX_INFOS[specs.subcommand_id] + + ex = ExchangeClient(backend, Rate.FIXED, specs.subcommand_id) + partner = SigningAuthority(curve=get_partner_curve(specs.subcommand_id), name="Name") + transaction_id = ex.init_transaction().data + credentials = get_credentials(specs.subcommand_id, partner) + ex.set_partner_key(credentials) + ex.check_partner_key(LEDGER_SIGNER.sign(credentials)) + tx, tx_signature = craft_and_sign_tx(specs, TX_INFOS[specs.subcommand_id], transaction_id, FEES, partner) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) + + + @pytest.mark.parametrize("specs_param", [SWAP_NG_SPECS, SELL_NG_SPECS, FUND_NG_SPECS], ids=["swap_ng", "sell_ng", "fund_ng"]) + @pytest.mark.parametrize("partner_curve", [ec.SECP256R1(), ec.SECP256K1()], ids=["R1", "K1"]) + def test_ng_curve_configuration(self, backend, specs_param, partner_curve): + specs = copy.deepcopy(specs_param) + specs.partner_curve = partner_curve + + tx_infos = TX_INFOS[specs.subcommand_id] + + ex = ExchangeClient(backend, Rate.FIXED, specs.subcommand_id) + partner = SigningAuthority(curve=get_partner_curve(specs.subcommand_id), name="Name") + transaction_id = ex.init_transaction().data + credentials = get_credentials(specs.subcommand_id, partner) + ex.set_partner_key(credentials) + ex.check_partner_key(LEDGER_SIGNER.sign(credentials)) + tx, tx_signature = craft_and_sign_tx(specs, TX_INFOS[specs.subcommand_id], transaction_id, FEES, partner) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) diff --git a/test/python/test_polkadot.py b/test/python/test_polkadot.py new file mode 100644 index 0000000..b8385c7 --- /dev/null +++ b/test/python/test_polkadot.py @@ -0,0 +1,47 @@ +import pytest + +from .apps.exchange_test_runner import ExchangeTestRunner, ALL_TESTS_EXCEPT_MEMO_AND_FEES +from .apps.polkadot import PolkadotClient, ERR_SWAP_CHECK_WRONG_METHOD, ERR_SWAP_CHECK_WRONG_DEST_ADDR, ERR_SWAP_CHECK_WRONG_AMOUNT + +# ExchangeTestRunner implementation for Polkadot +class PolkadotTests(ExchangeTestRunner): + currency_ticker = "DOT" + valid_destination_1 = "14ypt3a2m9yiq4ZQDcJFrkD99C3ZoUjLCDz1gBpCDwJPqVDY" + valid_destination_memo_1 = "" + valid_destination_2 = "13zAiMiN2HdJfEXn4NkVCWxuemScdaXGYKJrbJr1Nt6kjBRD" + valid_destination_memo_2 = "" + valid_refund = "14TwSqXEoCPK7Q7Jnk2RFzbPZXppsxz24bHaQ7fakwio7DFn" + valid_refund_memo = "" + valid_send_amount_1 = 12345670000 + valid_send_amount_2 = 446739662 + valid_fees_1 = 100000000 + valid_fees_2 = 10000123 + fake_refund = "abcdabcd" + fake_refund_memo = "" + fake_payout = "abcdabcd" + fake_payout_memo = "" + wrong_method_error_code = ERR_SWAP_CHECK_WRONG_METHOD + wrong_destination_error_code = ERR_SWAP_CHECK_WRONG_DEST_ADDR + wrong_amount_error_code = ERR_SWAP_CHECK_WRONG_AMOUNT + + def perform_final_tx(self, destination, send_amount, fees, memo): + dot = PolkadotClient(self.backend) + # Get public key. + key = dot.get_pubkey() + # Init signature process and assert response APDU code is 0x9000 (OK). + dot.sign_init().status + # craft tx + message = PolkadotClient.craft_valid_polkadot_transaction(destination, send_amount, None, None) + # Send message to be signed + sign_response = dot.sign_last(message) + + # Assert signature is verified properly with key and message + assert dot.verify_signature(hex_key=key,signature=sign_response.data[1:],message=message.hex().encode()) == True + + +# Use a class to reuse the same Speculos instance +class TestsPolkadot: + + @pytest.mark.parametrize('test_to_run', ALL_TESTS_EXCEPT_MEMO_AND_FEES) + def test_polkadot(self, backend, exchange_navigation_helper, test_to_run): + PolkadotTests(backend, exchange_navigation_helper).run_test(test_to_run) diff --git a/test/python/test_sell_flow_ethereum.py b/test/python/test_sell_flow_ethereum.py index 00763c2..6c339dd 100644 --- a/test/python/test_sell_flow_ethereum.py +++ b/test/python/test_sell_flow_ethereum.py @@ -2,7 +2,7 @@ from .apps.ethereum import EthereumClient, eth_amount_to_wei from .apps.signing_authority import SigningAuthority, LEDGER_SIGNER -from .apps.exchange_transaction_builder import get_partner_curve, craft_tx, encode_tx, extract_payout_ticker, extract_refund_ticker +from .apps.exchange_transaction_builder import get_partner_curve, extract_payout_ticker, extract_refund_ticker, craft_and_sign_tx from .apps import cal as cal @@ -22,11 +22,11 @@ def test_sell_flow(backend, exchange_navigation_helper): "in_amount": b"\032\200\250]$T\000", "in_address": "0x252fb4acbe0de4f0bd2409a5ed59a71e4ef1d2bc" } + fees = eth_amount_to_wei(0.004520765) - tx = craft_tx(SubCommand.SELL, tx_infos, transaction_id) - ex.process_transaction(tx, eth_amount_to_wei(0.004520765)) - encoded_tx = encode_tx(SubCommand.SELL, partner, tx) - ex.check_transaction_signature(encoded_tx) + tx, tx_signature = craft_and_sign_tx(SubCommand.SELL, tx_infos, transaction_id, fees, partner) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) with ex.check_asset_in(cal.get_conf_for_ticker(tx_infos["in_currency"])): exchange_navigation_helper.simple_accept() ex.start_signing_transaction() @@ -34,7 +34,7 @@ def test_sell_flow(backend, exchange_navigation_helper): eth = EthereumClient(backend) assert eth.get_public_key().status == 0x9000 # The original bug was that the Ethereum app was returning just after - # launch, and the first Ethereum:get_public_key call was in fact catched + # launch, and the first Ethereum:get_public_key call was in fact caught # by the Exchange app and interpreted as an Exchange::get_version call. # Exchange version are on 3 bytes, so we check the call does not return # 3 bytes of data diff --git a/test/python/test_swap_bsc_to_btc.py b/test/python/test_swap_bsc_to_btc.py index 03c63b0..cae4c71 100644 --- a/test/python/test_swap_bsc_to_btc.py +++ b/test/python/test_swap_bsc_to_btc.py @@ -5,7 +5,7 @@ from ragger.error import ExceptionRAPDU from .apps.signing_authority import SigningAuthority, LEDGER_SIGNER -from .apps.exchange_transaction_builder import get_partner_curve, craft_tx, encode_tx, extract_payout_ticker, extract_refund_ticker +from .apps.exchange_transaction_builder import get_partner_curve, extract_payout_ticker, extract_refund_ticker, craft_and_sign_tx from .apps import cal as cal from .apps.exchange import ExchangeClient, Rate, SubCommand @@ -25,7 +25,7 @@ def prepare_exchange(backend, exchange_navigation_helper, amount: str): "payin_extra_id": b"", "refund_address": b"0xDad77910DbDFdE764fC21FCD4E74D71bBACA6D8D", "refund_extra_id": b"", - "payout_address": b"bc1qer57ma0fzhqys2cmydhuj9cprf9eg0nw922a8j", + "payout_address": b"bc1qqtl9jlrwcr3fsfcjj2du7pu6fcgaxl5dsw2vyg", "payout_extra_id": b"", "currency_from": "BSC", "currency_to": "BTC", @@ -33,10 +33,10 @@ def prepare_exchange(backend, exchange_navigation_helper, amount: str): "amount_to_wallet": b"\x0b\xeb\xc2\x00", } fees = eth_amount_to_wei(0.000588) - tx = craft_tx(SubCommand.SWAP, tx_infos, transaction_id) - ex.process_transaction(tx, fees) - encoded_tx = encode_tx(SubCommand.SWAP, partner, tx) - ex.check_transaction_signature(encoded_tx) + + tx, tx_signature = craft_and_sign_tx(SubCommand.SWAP, tx_infos, transaction_id, fees, partner) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) payout_ticker = extract_payout_ticker(SubCommand.SWAP, tx_infos) refund_ticker = extract_refund_ticker(SubCommand.SWAP, tx_infos) diff --git a/test/python/test_swap_btc_to_etc.py b/test/python/test_swap_btc_to_etc.py index d68ffec..7ccbf0f 100644 --- a/test/python/test_swap_btc_to_etc.py +++ b/test/python/test_swap_btc_to_etc.py @@ -5,7 +5,7 @@ from .apps.litecoin import LitecoinClient from .apps.signing_authority import SigningAuthority, LEDGER_SIGNER -from .apps.exchange_transaction_builder import get_partner_curve, craft_tx, encode_tx, extract_payout_ticker, extract_refund_ticker +from .apps.exchange_transaction_builder import get_partner_curve, extract_payout_ticker, extract_refund_ticker, craft_and_sign_tx from .apps import cal as cal @@ -19,7 +19,7 @@ def test_swap_btc_to_etc(backend, exchange_navigation_helper): tx_infos = { "payin_address": "bc1q4uj6h8qmdq5699azdagacptw66p202kn0fte56", - "refund_address": "bc1qer57ma0fzhqys2cmydhuj9cprf9eg0nw922a8j", + "refund_address": "bc1qqtl9jlrwcr3fsfcjj2du7pu6fcgaxl5dsw2vyg", "payout_address": "0x97E22bAc30AAbC10fBEf472B3513812fc717B2fD", "payin_extra_id": "", "refund_extra_id": "", @@ -31,10 +31,9 @@ def test_swap_btc_to_etc(backend, exchange_navigation_helper): } fees = 2490 - tx = craft_tx(SubCommand.SWAP, tx_infos, transaction_id) - ex.process_transaction(tx, fees) - encoded_tx = encode_tx(SubCommand.SWAP, partner, tx) - ex.check_transaction_signature(encoded_tx) + tx, tx_signature = craft_and_sign_tx(SubCommand.SWAP, tx_infos, transaction_id, fees, partner) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) payout_ticker = extract_payout_ticker(SubCommand.SWAP, tx_infos) refund_ticker = extract_refund_ticker(SubCommand.SWAP, tx_infos) @@ -45,5 +44,5 @@ def test_swap_btc_to_etc(backend, exchange_navigation_helper): # client._client is the Speculos backend within the Ragger client, # because BitcoinClient is not Ragger-compatible (yet?) - with NewClient(backend._client, Chain.MAIN) as btc: + with NewClient(backend, Chain.MAIN) as btc: assert btc.get_master_fingerprint() == bytes.fromhex("f5acc2fd") diff --git a/test/python/test_swap_eth_to_btc.py b/test/python/test_swap_eth_to_btc.py index 4cb9aac..4a583a6 100644 --- a/test/python/test_swap_eth_to_btc.py +++ b/test/python/test_swap_eth_to_btc.py @@ -7,7 +7,7 @@ from .apps.ethereum import EthereumClient, ERR_SILENT_MODE_CHECK_FAILED, eth_amount_to_wei from .apps.signing_authority import SigningAuthority, LEDGER_SIGNER -from .apps.exchange_transaction_builder import get_partner_curve, craft_tx, encode_tx, extract_payout_ticker, extract_refund_ticker +from .apps.exchange_transaction_builder import get_partner_curve, extract_payout_ticker, extract_refund_ticker, craft_and_sign_tx from .apps import cal as cal @@ -24,7 +24,7 @@ def prepare_exchange(backend, exchange_navigation_helper, amount: str): "payin_extra_id": b"", "refund_address": b"0xDad77910DbDFdE764fC21FCD4E74D71bBACA6D8D", "refund_extra_id": b"", - "payout_address": b"bc1qer57ma0fzhqys2cmydhuj9cprf9eg0nw922a8j", + "payout_address": b"bc1qqtl9jlrwcr3fsfcjj2du7pu6fcgaxl5dsw2vyg", "payout_extra_id": b"", "currency_from": "ETH", "currency_to": "BTC", @@ -33,10 +33,9 @@ def prepare_exchange(backend, exchange_navigation_helper, amount: str): } fees = eth_amount_to_wei(0.000588) - tx = craft_tx(SubCommand.SWAP, tx_infos, transaction_id) - ex.process_transaction(tx, fees) - encoded_tx = encode_tx(SubCommand.SWAP, partner, tx) - ex.check_transaction_signature(encoded_tx) + tx, tx_signature = craft_and_sign_tx(SubCommand.SWAP, tx_infos, transaction_id, fees, partner) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) payout_ticker = extract_payout_ticker(SubCommand.SWAP, tx_infos) refund_ticker = extract_refund_ticker(SubCommand.SWAP, tx_infos) diff --git a/test/python/test_swap_ltc_to_eth.py b/test/python/test_swap_ltc_to_eth.py index 023ac09..f82bfad 100644 --- a/test/python/test_swap_ltc_to_eth.py +++ b/test/python/test_swap_ltc_to_eth.py @@ -4,7 +4,7 @@ from .apps.litecoin import LitecoinClient from .apps.signing_authority import SigningAuthority, LEDGER_SIGNER -from .apps.exchange_transaction_builder import get_partner_curve, craft_tx, encode_tx, extract_payout_ticker, extract_refund_ticker +from .apps.exchange_transaction_builder import get_partner_curve, extract_payout_ticker, extract_refund_ticker, craft_and_sign_tx from .apps import cal as cal @@ -30,10 +30,9 @@ def test_swap_ltc_to_eth(backend, exchange_navigation_helper): } fees = 339 - tx = craft_tx(SubCommand.SWAP, tx_infos, transaction_id) - ex.process_transaction(tx, fees) - encoded_tx = encode_tx(SubCommand.SWAP, partner, tx) - ex.check_transaction_signature(encoded_tx) + tx, tx_signature = craft_and_sign_tx(SubCommand.SWAP, tx_infos, transaction_id, fees, partner) + ex.process_transaction(tx) + ex.check_transaction_signature(tx_signature) payout_ticker = extract_payout_ticker(SubCommand.SWAP, tx_infos) refund_ticker = extract_refund_ticker(SubCommand.SWAP, tx_infos) diff --git a/test/python/test_transaction_id.py b/test/python/test_transaction_id.py index b61b364..e674ccc 100644 --- a/test/python/test_transaction_id.py +++ b/test/python/test_transaction_id.py @@ -18,6 +18,5 @@ def test_transaction_id(backend): ex = ExchangeClient(backend, Rate.FIXED, SubCommand.FUND) transaction_id = ex.init_transaction().data - print(transaction_id) # Assert length assert len(transaction_id) == 32 diff --git a/test/python/test_tron.py b/test/python/test_tron.py new file mode 100644 index 0000000..348e54f --- /dev/null +++ b/test/python/test_tron.py @@ -0,0 +1,155 @@ +import pytest + +from ragger.error import ExceptionRAPDU + +from .apps.exchange_test_runner import ExchangeTestRunner +from .apps.exchange_test_runner import VALID_TESTS, ALL_TESTS_EXCEPT_FEES +from .apps.tron import TronClient, TronErrors + + +# ExchangeTestRunner implementation for Tron +class TronTests(ExchangeTestRunner): + valid_destination_1 = "TNbtZSpknaQvC7jPCLU4znJMgm8fhuGTTY" + valid_destination_memo_1 = "" + valid_destination_2 = "TBoTZcARzWVgnNuB9SyE3S5g1RwsXoQL16" + valid_destination_memo_2 = "" + valid_refund = "TNbtZSpknaQvC7jPCLU4znJMgm8fhuGTTY" + valid_refund_memo = "" + valid_send_amount_1 = 1000000 + valid_send_amount_2 = 446739662 + valid_fees_1 = 0 + valid_fees_2 = 1 + fake_refund = "abcdabcd" + fake_refund_memo = "1" + fake_payout = "abcdabcd" + fake_payout_memo = "1" + signature_refusal_error_code = TronErrors.SW_SWAP_CHECKING_FAIL + + +################################################## +# ExchangeTestRunner implementation for Tron TRX # +################################################## +class TronTrxTests(TronTests): + currency_ticker = "TRX" + + def perform_final_tx(self, destination, send_amount, fees, memo): + TronClient(self.backend).send_tx(path="m/44'/148'/0'", + memo=memo, + destination=destination, + send_amount=send_amount, + token="TRX") + # TODO : assert signature validity + + +class TestsTrx: + @pytest.mark.parametrize('test_to_run', ALL_TESTS_EXCEPT_FEES) + def test_tron_trx(self, backend, exchange_navigation_helper, test_to_run): + TronTrxTests(backend, exchange_navigation_helper).run_test(test_to_run) + + +################################################### +# ExchangeTestRunner implementation for Tron USDT # +################################################### +class TronUsdtTests(TronTests): + currency_ticker = "USDT" + + def perform_final_tx(self, destination, send_amount, fees, memo): + TronClient(self.backend).send_tx(path="m/44'/148'/0'", + memo=memo, + destination=destination, + send_amount=send_amount, + token="USDT") + # TODO : assert signature validity + + +class TestsUsdt: + @pytest.mark.parametrize('test_to_run', ALL_TESTS_EXCEPT_FEES) + def test_tron_usdt(self, backend, exchange_navigation_helper, test_to_run): + TronUsdtTests(backend, exchange_navigation_helper).run_test(test_to_run) + + +################################################### +# ExchangeTestRunner implementation for Tron USDC # +################################################### +class TronUsdcTests(TronTests): + currency_ticker = "USDC" + + def perform_final_tx(self, destination, send_amount, fees, memo): + TronClient(self.backend).send_tx(path="m/44'/148'/0'", + memo=memo, + destination=destination, + send_amount=send_amount, + token="USDC") + # TODO : assert signature validity + + +class TestsUsdc: + @pytest.mark.parametrize('test_to_run', ALL_TESTS_EXCEPT_FEES) + def test_tron_usdc(self, backend, exchange_navigation_helper, test_to_run): + TronUsdcTests(backend, exchange_navigation_helper).run_test(test_to_run) + + +##################################################################### +# ExchangeTestRunner implementation for Tron TRX but wrong tx token # +##################################################################### +class TronTrxToUsdtTests(TronTests): + currency_ticker = "TRX" + + def perform_final_tx(self, destination, send_amount, fees, memo): + with pytest.raises(ExceptionRAPDU) as e: + TronClient(self.backend).send_tx(path="m/44'/148'/0'", + memo=memo, + destination=destination, + send_amount=send_amount, + token="USDT") + assert e.value.status == self.signature_refusal_error_code + + +class TestsTRXToUsdt: + @pytest.mark.parametrize('test_to_run', VALID_TESTS) + def test_tron_trx_to_usdt(self, backend, exchange_navigation_helper, test_to_run): + TronTrxToUsdtTests(backend, exchange_navigation_helper).run_test(test_to_run) + + +############################################################################ +# ExchangeTestRunner implementation for Tron USDT but wrong tx token (TRX) # +############################################################################ +class TronUsdttoTrxTests(TronTests): + currency_ticker = "USDT" + + def perform_final_tx(self, destination, send_amount, fees, memo): + with pytest.raises(ExceptionRAPDU) as e: + TronClient(self.backend).send_tx(path="m/44'/148'/0'", + memo=memo, + destination=destination, + send_amount=send_amount, + token="TRX") + assert e.value.status == self.signature_refusal_error_code + + +class TestsUsdtToTrx: + @pytest.mark.parametrize('test_to_run', VALID_TESTS) + def test_tron_usdt_to_trx(self, backend, exchange_navigation_helper, test_to_run): + TronUsdttoTrxTests(backend, exchange_navigation_helper).run_test(test_to_run) + + +############################################################################# +# ExchangeTestRunner implementation for Tron USDT but wrong tx token (USDC) # +############################################################################# +class TronUsdtoUsdcTests(TronTests): + currency_ticker = "USDT" + + def perform_final_tx(self, destination, send_amount, fees, memo): + with pytest.raises(ExceptionRAPDU) as e: + TronClient(self.backend).send_tx(path="m/44'/148'/0'", + memo=memo, + destination=destination, + send_amount=send_amount, + token="USDC") + assert e.value.status == self.signature_refusal_error_code + + +class TestsUsdtToUsdc: + @pytest.mark.parametrize('test_to_run', VALID_TESTS) + def test_tron_usdt_to_usdc(self, backend, exchange_navigation_helper, test_to_run): + TronUsdtoUsdcTests(backend, exchange_navigation_helper).run_test(test_to_run)