Skip to content

Commit

Permalink
Merge pull request #151 from Zondax/invoke_contracts
Browse files Browse the repository at this point in the history
Invoke contracts
  • Loading branch information
ftheirs committed Mar 14, 2024
2 parents fba709d + 7dd1102 commit eb08475
Show file tree
Hide file tree
Showing 402 changed files with 4,373 additions and 11,419 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ file(GLOB_RECURSE LIB_SRC
${CMAKE_CURRENT_SOURCE_DIR}/app/src/rlp.c
${CMAKE_CURRENT_SOURCE_DIR}/app/src/uint256.c
${CMAKE_CURRENT_SOURCE_DIR}/app/src/eth_erc20.c
${CMAKE_CURRENT_SOURCE_DIR}/app/src/parser_invoke_evm.c
)

add_library(app_lib STATIC
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ TESTS_JS_PACKAGE = "@zondax/ledger-filecoin"
TESTS_JS_DIR =

ifeq ($(BOLOS_SDK),)
ZXLIB_COMPILE_STAX ?= 1
include $(CURDIR)/deps/ledger-zxlib/dockerized_build.mk
else
default:
Expand Down
4 changes: 2 additions & 2 deletions app/Makefile.version
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This is the major version of this release
APPVERSION_M=0
# This is the minor version of this release
APPVERSION_N=23
APPVERSION_N=24
# This is the patch version of this release
APPVERSION_P=13
APPVERSION_P=0
Binary file added app/glyphs/icon_stax_32.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/glyphs/icon_stax_64.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions app/src/common/tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include <string.h>
#include "zxmacros.h"

#if defined(TARGET_NANOX) || defined(TARGET_NANOS2)
#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined(TARGET_STAX)
#define RAM_BUFFER_SIZE 8192
#define FLASH_BUFFER_SIZE 16384
#elif defined(TARGET_NANOS)
Expand All @@ -38,7 +38,7 @@ typedef struct {
uint8_t buffer[FLASH_BUFFER_SIZE];
} storage_t;

#if defined(TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2)
#if defined(TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined(TARGET_STAX)
storage_t NV_CONST N_appdata_impl __attribute__ ((aligned(64)));
#define N_appdata (*(NV_VOLATILE storage_t *)PIC(&N_appdata_impl))
#endif
Expand Down
2 changes: 1 addition & 1 deletion app/src/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ zxerr_t keccak_digest(const unsigned char *in, unsigned int inLen,
zxerr_t blake_hash_cid(const unsigned char *in, unsigned int inLen,
unsigned char *out, unsigned int outLen);

#if defined(TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2)
#if defined(TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined(TARGET_STAX)
#else
#include "blake2.h"
typedef struct {
Expand Down
4 changes: 4 additions & 0 deletions app/src/crypto_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ extern uint8_t fil_chain_code;
#define ADDRESS_PROTOCOL_BLS_PAYLOAD_LEN 48
#define ADDRESS_PROTOCOL_DELEGATED_MAX_SUBADDRESS_LEN 54

#define SELECTOR_LENGTH 4
#define BIGINT_LENGTH 32
#define F4_ETH_ADDRESS_BYTES_LEN 22

zxerr_t blake_hash_init();
zxerr_t blake_hash_update(const uint8_t *in, uint16_t inLen);
zxerr_t blake_hash_finish(uint8_t *out, uint16_t outLen);
Expand Down
29 changes: 15 additions & 14 deletions app/src/eth_erc20.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@

// Prefix is calculated as: keccak256("transfer(address,uint256)") = 0xa9059cbb
const uint8_t ERC20_TRANSFER_PREFIX[] = {0xa9, 0x05, 0x9c, 0xbb};
#define ERC20_DATA_LENGTH 68 // 4 + 32 + 32
#define ADDRESS_CONTRACT_LENGTH 20
#define DECIMAL_BASE 10
const erc20_tokens_t supportedTokens[] = {

Expand Down Expand Up @@ -65,14 +63,14 @@ const erc20_tokens_t supportedTokens[] = {
18},
};

parser_error_t getERC20Token(const rlp_t *data, char tokenSymbol[MAX_SYMBOL_LEN], uint8_t *decimals) {
if (data == NULL || tokenSymbol == NULL || decimals == NULL ||
data->rlpLen != ERC20_DATA_LENGTH || memcmp(data->ptr, ERC20_TRANSFER_PREFIX, 4) != 0) {
parser_error_t getERC20Token(const eth_tx_t *ethObj, char tokenSymbol[MAX_SYMBOL_LEN], uint8_t *decimals) {
if (ethObj == NULL || tokenSymbol == NULL || decimals == NULL ||
ethObj->legacy.data.rlpLen != ERC20_TRANSFER_DATA_LENGTH || memcmp(ethObj->legacy.data.ptr, ERC20_TRANSFER_PREFIX, 4) != 0) {
return parser_unexpected_value;
}

// Verify address contract: first 12 bytes must be 0
const uint8_t *addressPtr = data->ptr + 4;
const uint8_t *addressPtr = ethObj->legacy.data.ptr + 4;
for (uint8_t i = 0; i < 12; i++) {
if (*(addressPtr++) != 0 ) {
return parser_unexpected_value;
Expand All @@ -82,7 +80,7 @@ parser_error_t getERC20Token(const rlp_t *data, char tokenSymbol[MAX_SYMBOL_LEN]
// Check if token is in the list
const uint8_t supportedTokensSize = sizeof(supportedTokens)/sizeof(supportedTokens[0]);
for (uint8_t i = 0; i < supportedTokensSize; i++) {
if (memcmp(addressPtr, supportedTokens[i].address, ADDRESS_CONTRACT_LENGTH) == 0) {
if (memcmp(ethObj->legacy.to.ptr, supportedTokens[i].address, ETH_ADDRESS_LEN) == 0) {
// Set symbol and decimals
snprintf(tokenSymbol, 10, "%s", (char*) PIC(supportedTokens[i].symbol));
*decimals = supportedTokens[i].decimals;
Expand All @@ -95,20 +93,20 @@ parser_error_t getERC20Token(const rlp_t *data, char tokenSymbol[MAX_SYMBOL_LEN]
*decimals = 0;
return parser_ok;
}
parser_error_t printERC20Value(const rlp_t *data, char *outVal, uint16_t outValLen,
parser_error_t printERC20Value(const eth_tx_t *ethObj, char *outVal, uint16_t outValLen,
uint8_t pageIdx, uint8_t *pageCount) {
if (data == NULL || outVal == NULL || pageCount == NULL) {
if (ethObj == NULL || outVal == NULL || pageCount == NULL) {
return parser_unexpected_error;
}

// [identifier (4) | token contract (12 + 20) | value (32)]
char tokenSymbol[10] = {0};
uint8_t decimals = 0;
CHECK_PARSER_ERR(getERC20Token(data, tokenSymbol, &decimals))
CHECK_PARSER_ERR(getERC20Token(ethObj, tokenSymbol, &decimals))

uint256_t value = {0};
const uint8_t *valuePtr = data->ptr + 4 + 12 + ADDRESS_CONTRACT_LENGTH;
parser_context_t tmpCtx = {.buffer = valuePtr, .bufferLen = 32, .offset = 0, .tx_type = eth_tx};
const uint8_t *valuePtr = ethObj->legacy.data.ptr + SELECTOR_LENGTH + BIGINT_LENGTH;
parser_context_t tmpCtx = {.buffer = valuePtr, .bufferLen = BIGINT_LENGTH, .offset = 0, .tx_type = eth_tx};
CHECK_PARSER_ERR(readu256BE(&tmpCtx, &value));

char bufferUI[100] = {0};
Expand All @@ -131,9 +129,12 @@ parser_error_t printERC20Value(const rlp_t *data, char *outVal, uint16_t outValL
return parser_ok;
}

bool validateERC20(rlp_t data) {
bool validateERC20(eth_tx_t *ethObj) {
// Check that data start with ERC20 prefix
if (data.ptr == NULL || data.rlpLen != ERC20_DATA_LENGTH || memcmp(data.ptr, ERC20_TRANSFER_PREFIX, 4) != 0) {
const bool isPayable = false; //ethObj->legacy.value;

if (ethObj == NULL || isPayable || ethObj->legacy.to.rlpLen != ETH_ADDRESS_LEN ||
ethObj->legacy.data.ptr == NULL || ethObj->legacy.data.rlpLen != ERC20_TRANSFER_DATA_LENGTH || memcmp(ethObj->legacy.data.ptr, ERC20_TRANSFER_PREFIX, sizeof(ERC20_TRANSFER_PREFIX)) != 0) {
return false;
}

Expand Down
8 changes: 5 additions & 3 deletions app/src/eth_erc20.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,24 @@
#include "parser_common.h"
#include "rlp.h"
#include "coin.h"
#include "parser_txdef.h"


#ifdef __cplusplus
extern "C" {
#endif

#define ERC20_TRANSFER_DATA_LENGTH 68 // 4 + 32 + 32
#define MAX_SYMBOL_LEN 10
typedef struct {
uint8_t address[ETH_ADDR_LEN];
char symbol[MAX_SYMBOL_LEN];
uint8_t decimals;
} erc20_tokens_t;

bool validateERC20(rlp_t data);
parser_error_t getERC20Token(const rlp_t *data, char tokenSymbol[MAX_SYMBOL_LEN], uint8_t *decimals);
parser_error_t printERC20Value(const rlp_t *data, char *outVal, uint16_t outValLen,
bool validateERC20(eth_tx_t *ethObj);
parser_error_t getERC20Token(const eth_tx_t *ethObj, char tokenSymbol[MAX_SYMBOL_LEN], uint8_t *decimals);
parser_error_t printERC20Value(const eth_tx_t *ethObj, char *outVal, uint16_t outValLen,
uint8_t pageIdx, uint8_t *pageCount);

#ifdef __cplusplus
Expand Down
33 changes: 32 additions & 1 deletion app/src/fil_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,34 @@ parser_error_t readAddress(address_t *address, CborValue *value) {
return parser_ok;
}

parser_error_t print0xToF0(const uint8_t *ethAddress, uint8_t ethAddressLen, char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount) {
if (ethAddress == NULL || outVal == NULL || pageCount == NULL || ethAddressLen != ETH_ADDRESS_LEN) {
return parser_unexpected_error;
}

if (*ethAddress != 0xFF) {
return parser_unexpected_error;
}

uint64_t id = 0;
for (uint8_t i = 1; i < ETH_ADDRESS_LEN; i++) {
id = (id << 8) + *(ethAddress + i);
}
if (id > UINT64_MAX) {
return parser_value_out_of_range;
}

char to_f0[30] = {0};
to_f0[0] = isTestnet() ? 't' : 'f';
to_f0[1] = '0';
if (uint64_to_str(to_f0 + 2, sizeof(to_f0) - 2, id) != NULL) {
return parser_unexpected_error;
}
pageStringExt(outVal, outValLen, to_f0, strnlen(to_f0, sizeof(to_f0)), pageIdx, pageCount);

return parser_ok;
}

parser_error_t printAddress(const address_t *a, char *outVal,
uint16_t outValLen, uint8_t pageIdx,
uint8_t *pageCount) {
Expand Down Expand Up @@ -119,7 +147,7 @@ parser_error_t printEthAddress(const address_t *a, char *outVal,
uint64_t actorId = 0;
const uint16_t actorIdSize = decompressLEB128(a->buffer + 1, a->len - 1, &actorId);
const uint16_t payloadSize = a->len - 1 - actorIdSize;
if (payloadSize != 20) {
if (payloadSize != ETH_ADDRESS_LEN) {
return parser_unexpected_error;
}

Expand Down Expand Up @@ -193,6 +221,9 @@ parser_error_t parser_printBigIntFixedPoint(const bigint_t *b, char *outVal,
}

fpstr_to_str(overlapped.output, sizeof(overlapped.output), bignum, decimals);
if (z_str3join(overlapped.output, sizeof(overlapped.output), "FIL ", NULL) != zxerr_ok) {
return parser_unexpected_error;
}
pageString(outVal, outValLen, overlapped.output, pageIdx, pageCount);
return parser_ok;
}
Expand Down
4 changes: 4 additions & 0 deletions app/src/fil_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ parser_error_t printEthAddress(const address_t *a, char *outVal,
uint16_t outValLen, uint8_t pageIdx,
uint8_t *pageCount);

parser_error_t print0xToF0( const uint8_t *ethAddress, uint8_t ethAddressLen,
char *outVal, uint16_t outValLen,
uint8_t pageIdx, uint8_t *pageCount);

parser_error_t printCid(cid_t *cid, char *outVal, uint16_t outValLen,
uint8_t pageIdx, uint8_t *pageCount);

Expand Down
27 changes: 21 additions & 6 deletions app/src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@
#include "zxformat.h"
#include <stdio.h>
#include <zxmacros.h>
#include "parser_invoke_evm.h"

#if defined(TARGET_NANOX) || defined(TARGET_NANOS2)
#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined(TARGET_STAX)
// For some reason NanoX requires this function
void __assert_fail(__Z_UNUSED const char *assertion,
__Z_UNUSED const char *file, __Z_UNUSED unsigned int line,
Expand Down Expand Up @@ -221,6 +222,11 @@ parser_error_t _getItemFil(const parser_context_t *ctx, uint8_t displayIdx,
return parser_no_data;
}

// If the transaction is InvokeEVM and it's a transfer from ERC20 token
if (isInvokeEVM_ERC20Transfer(&parser_tx_obj.base_tx)) {
return printInvokeEVM(&parser_tx_obj.base_tx, displayIdx, outKey, outKeyLen, outVal, outValLen, pageIdx, pageCount);
}

uint8_t adjustedIndex = displayIdx;
if (parser_tx_obj.base_tx.to.buffer[0] != ADDRESS_PROTOCOL_DELEGATED) {
adjustedIndex++;
Expand Down Expand Up @@ -257,14 +263,23 @@ parser_error_t _getItemFil(const parser_context_t *ctx, uint8_t displayIdx,
outValLen, pageIdx, pageCount,
COIN_AMOUNT_DECIMAL_PLACES);

case 5:
case 5: {
char tmpBuffer[80] = {0};
snprintf(outKey, outKeyLen, "Gas Limit ");
if (int64_to_str(outVal, outValLen, parser_tx_obj.base_tx.gaslimit) !=
NULL) {
return parser_unexpected_error;
if (int64_to_str(tmpBuffer, sizeof(tmpBuffer), parser_tx_obj.base_tx.gaslimit) != NULL) {
return parser_unexpected_error;
}
*pageCount = 1;

if (insertDecimalPoint(tmpBuffer, sizeof(tmpBuffer), COIN_AMOUNT_DECIMAL_PLACES) != zxerr_ok) {
return parser_unexpected_error;
}
if (z_str3join(tmpBuffer, sizeof(tmpBuffer), "FIL ", NULL) != zxerr_ok) {
return parser_unexpected_error;
}

pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount);
return parser_ok;
}

case 6:
snprintf(outKey, outKeyLen, "Gas Fee Cap ");
Expand Down
33 changes: 21 additions & 12 deletions app/src/parser_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "parser_txdef.h"
#include "zxformat.h"
#include <zxmacros.h>
#include "parser_invoke_evm.h"

parser_tx_t parser_tx_obj;

Expand Down Expand Up @@ -409,19 +410,27 @@ parser_error_t _validateTx(__Z_UNUSED const parser_context_t *c,
uint8_t _getNumItems(__Z_UNUSED const parser_context_t *c,
const fil_base_tx_t *v) {

uint8_t itemCount = 6;
uint8_t itemCount = 6;

if (app_mode_expert()) {
itemCount = 8;
}
// Items for InvokeEVM + ERC20 transfer
if (isInvokeEVM_ERC20Transfer(v)) {
if (getNumItemsInvokeEVM(&itemCount, v) != parser_ok) {
return 0;
}
return itemCount;
}

// For f4 addresses dispaly f4 and 0x addresses
if (v->from.buffer[0] == ADDRESS_PROTOCOL_DELEGATED) {
itemCount++;
}
if (v->to.buffer[0] == ADDRESS_PROTOCOL_DELEGATED) {
itemCount++;
}
if (app_mode_expert()) {
itemCount = 8;
}

// For f4 addresses dispaly f4 and 0x addresses
if (v->from.buffer[0] == ADDRESS_PROTOCOL_DELEGATED) {
itemCount++;
}
if (v->to.buffer[0] == ADDRESS_PROTOCOL_DELEGATED) {
itemCount++;
}

return itemCount + v->numparams;
return itemCount + v->numparams;
}
19 changes: 10 additions & 9 deletions app/src/parser_impl_eth.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ parser_error_t _readEth(parser_context_t *ctx, eth_tx_t *tx_obj) {
}

parser_error_t _validateTxEth() {
if (!validateERC20(eth_tx_obj.legacy.data) && !app_mode_expert()) {
if (!validateERC20(&eth_tx_obj) && !app_mode_expert()) {
return parser_unsupported_tx;
}

Expand All @@ -186,25 +186,26 @@ static parser_error_t printERC20(uint8_t displayIdx, char *outKey, uint16_t outK
const eth_base_t *legacy = &eth_tx_obj.legacy;
char tokenSymbol[10] = {0};
uint8_t decimals = 0;
CHECK_PARSER_ERR(getERC20Token(&eth_tx_obj.legacy.data, tokenSymbol, &decimals));
CHECK_PARSER_ERR(getERC20Token(&eth_tx_obj, tokenSymbol, &decimals));
bool hideContract = (memcmp(tokenSymbol, "?? ", 3) != 0);

displayIdx += (displayIdx && hideContract) ? 1 : 0;
switch (displayIdx) {
case 0:
snprintf(outKey, outKeyLen, "To");
CHECK_PARSER_ERR(printEVMAddress(&legacy->to, outVal, outValLen, pageIdx, pageCount));
rlp_t to = {.kind = RLP_KIND_STRING, .ptr = (eth_tx_obj.legacy.data.ptr + 4 + 12), .rlpLen = ETH_ADDRESS_LEN};
CHECK_PARSER_ERR(printEVMAddress(&to, outVal, outValLen, pageIdx, pageCount));
break;

case 1:
snprintf(outKey, outKeyLen, "Contract");
rlp_t contractAddress = {.kind = RLP_KIND_STRING, .ptr = (legacy->data.ptr + 4 + 12), .rlpLen = 20};
snprintf(outKey, outKeyLen, "Token Contract");
rlp_t contractAddress = {.kind = RLP_KIND_STRING, .ptr = eth_tx_obj.legacy.to.ptr, .rlpLen = ETH_ADDRESS_LEN};
CHECK_PARSER_ERR(printEVMAddress(&contractAddress, outVal, outValLen, pageIdx, pageCount));
break;

case 2:
snprintf(outKey, outKeyLen, "Value");
CHECK_PARSER_ERR(printERC20Value(&legacy->data, outVal, outValLen, pageIdx, pageCount));
CHECK_PARSER_ERR(printERC20Value(&eth_tx_obj, outVal, outValLen, pageIdx, pageCount));
break;

case 3:
Expand Down Expand Up @@ -235,7 +236,7 @@ parser_error_t _getItemEth(const parser_context_t *ctx, uint8_t displayIdx,
uint8_t *pageCount) {

// At the moment, clear signing is available only for ERC20
if (validateERC20(eth_tx_obj.legacy.data)) {
if (validateERC20(&eth_tx_obj)) {
return printERC20(displayIdx, outKey, outKeyLen, outVal, outValLen, pageIdx, pageCount);
}

Expand Down Expand Up @@ -277,10 +278,10 @@ parser_error_t _getNumItemsEth(uint8_t* numItems) {
}
// Verify that tx is ERC20

if (validateERC20(eth_tx_obj.legacy.data)) {
if (validateERC20(&eth_tx_obj)) {
char tokenSymbol[10] = {0};
uint8_t decimals = 0;
CHECK_PARSER_ERR(getERC20Token(&eth_tx_obj.legacy.data, tokenSymbol, &decimals));
CHECK_PARSER_ERR(getERC20Token(&eth_tx_obj, tokenSymbol, &decimals));
// If token is not recognized, print value address
*numItems = (memcmp(tokenSymbol, "?? ", 3) != 0) ? 5 : 6;
return parser_ok;
Expand Down
Loading

0 comments on commit eb08475

Please sign in to comment.