Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invoke contracts #151

Merged
merged 7 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
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) {
ftheirs marked this conversation as resolved.
Show resolved Hide resolved
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++;
}
ftheirs marked this conversation as resolved.
Show resolved Hide resolved

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
Loading