Fix nft transactions (#229)

* Removed pluginType "hack"

* Fix some ERC 721 & 1155 function signature hashes

* Fix UI for ERC721 operations

* Explicit Batch Transfer UI with ERC1155

* Unified some ERC721 & 1155 non-static functions naming

* Fix UI for ERC1155 operations

* Added missing pin-lock check when signing transactions

* Fix the shell script that builds the elf files for testing

* Add tests dependency ethers

* Removed the space in the test filename

* Tests build script refactoring

* Now works when called from anywhere (not just the script's directory)
* Now handles LNS & LNX builds together (less duplicated code)

* Temporarily disable Nano X tests

Until Zemu supports Nano X 2.0 SDK

* Tests now start with blind signing disabled

Makes it closer to reality & very few of them requires it

* Update to the latest sdk version

* make eth_plugin_perform_init() readable

Introduce 2 functions.

* Now properly parses the apdu and displays the total quantity of NFT IDs transferred in ERC1155 batch transfer

* Add NFT prod public keys

* Added extra checks for the chain ID handling

Following the security review

* NFTs now only supported by LNS

* Version bump

Co-authored-by: Alexandre Paillier <alexandre.paillier@ledger.fr>
Co-authored-by: greenknot <greenknot@users.noreply.github.com>
This commit is contained in:
Jean P
2021-12-17 12:04:51 +01:00
committed by GitHub
parent 586155c0d4
commit a53a2428cc
40 changed files with 735 additions and 208 deletions

View File

@@ -72,69 +72,77 @@ void eth_plugin_prepare_query_contract_UI(ethQueryContractUI_t *queryContractUI,
queryContractUI->msgLength = msgLength;
}
static void eth_plugin_perform_init_default(uint8_t *contractAddress,
ethPluginInitContract_t *init) {
// check if the registered external plugin matches the TX contract address / selector
if (memcmp(contractAddress,
dataContext.tokenContext.contractAddress,
sizeof(dataContext.tokenContext.contractAddress)) != 0) {
PRINTF("Got contract: %.*H\n", ADDRESS_LENGTH, contractAddress);
PRINTF("Expected contract: %.*H\n",
ADDRESS_LENGTH,
dataContext.tokenContext.contractAddress);
os_sched_exit(0);
}
if (memcmp(init->selector,
dataContext.tokenContext.methodSelector,
sizeof(dataContext.tokenContext.methodSelector)) != 0) {
PRINTF("Got selector: %.*H\n", SELECTOR_SIZE, init->selector);
PRINTF("Expected selector: %.*H\n", SELECTOR_SIZE, dataContext.tokenContext.methodSelector);
os_sched_exit(0);
}
PRINTF("Plugin will be used\n");
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_OK;
}
static bool eth_plugin_perform_init_old_internal(uint8_t *contractAddress,
ethPluginInitContract_t *init) {
uint8_t i, j;
const uint8_t **selectors;
// Search internal plugin list
for (i = 0;; i++) {
selectors = (const uint8_t **) PIC(INTERNAL_ETH_PLUGINS[i].selectors);
if (selectors == NULL) {
break;
}
for (j = 0; ((j < INTERNAL_ETH_PLUGINS[i].num_selectors) && (contractAddress != NULL));
j++) {
if (memcmp(init->selector, (const void *) PIC(selectors[j]), SELECTOR_SIZE) == 0) {
if ((INTERNAL_ETH_PLUGINS[i].availableCheck == NULL) ||
((PluginAvailableCheck) PIC(INTERNAL_ETH_PLUGINS[i].availableCheck))()) {
strlcpy(dataContext.tokenContext.pluginName,
INTERNAL_ETH_PLUGINS[i].alias,
PLUGIN_ID_LENGTH);
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_OK;
return true;
}
}
}
}
return false;
}
eth_plugin_result_t eth_plugin_perform_init(uint8_t *contractAddress,
ethPluginInitContract_t *init) {
uint8_t i;
const uint8_t **selectors;
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_UNAVAILABLE;
PRINTF("Selector %.*H\n", 4, init->selector);
switch (pluginType) {
case NOT_OLD_INTERNAL:
#ifdef HAVE_NFT_SUPPORT
case ERC1155:
case ERC721:
case EXTERNAL: {
// check if the registered external plugin matches the TX contract address / selector
if (memcmp(contractAddress,
dataContext.tokenContext.contractAddress,
sizeof(dataContext.tokenContext.contractAddress)) != 0) {
PRINTF("Got contract: %.*H\n", ADDRESS_LENGTH, contractAddress);
PRINTF("Expected contract: %.*H\n",
ADDRESS_LENGTH,
dataContext.tokenContext.contractAddress);
os_sched_exit(0);
}
if (memcmp(init->selector,
dataContext.tokenContext.methodSelector,
sizeof(dataContext.tokenContext.methodSelector)) != 0) {
PRINTF("Got selector: %.*H\n", SELECTOR_SIZE, init->selector);
PRINTF("Expected selector: %.*H\n",
SELECTOR_SIZE,
dataContext.tokenContext.methodSelector);
os_sched_exit(0);
}
PRINTF("Plugin will be used\n");
// TODO: Add check for chainid.
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_OK;
#endif // HAVE_NFT_SUPPORT
case EXTERNAL:
eth_plugin_perform_init_default(contractAddress, init);
contractAddress = NULL;
} break;
case OLD_INTERNAL: {
// Search internal plugin list
for (i = 0;; i++) {
uint8_t j;
selectors = (const uint8_t **) PIC(INTERNAL_ETH_PLUGINS[i].selectors);
if (selectors == NULL) {
break;
}
for (j = 0;
((j < INTERNAL_ETH_PLUGINS[i].num_selectors) && (contractAddress != NULL));
j++) {
if (memcmp(init->selector, (const void *) PIC(selectors[j]), SELECTOR_SIZE) ==
0) {
if ((INTERNAL_ETH_PLUGINS[i].availableCheck == NULL) ||
((PluginAvailableCheck) PIC(
INTERNAL_ETH_PLUGINS[i].availableCheck))()) {
strlcpy(dataContext.tokenContext.pluginName,
INTERNAL_ETH_PLUGINS[i].alias,
PLUGIN_ID_LENGTH);
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_OK;
contractAddress = NULL;
break;
}
}
}
break;
case OLD_INTERNAL:
if (eth_plugin_perform_init_old_internal(contractAddress, init)) {
contractAddress = NULL;
}
} break;
break;
default:
PRINTF("Unsupported pluginType %d\n", pluginType);
os_sched_exit(0);
@@ -242,8 +250,6 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
}
switch (pluginType) {
case NOT_OLD_INTERNAL:
break;
case EXTERNAL: {
uint32_t params[3];
params[0] = (uint32_t) alias;
@@ -262,6 +268,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
END_TRY;
break;
}
#ifdef HAVE_NFT_SUPPORT
case ERC721: {
erc721_plugin_call(method, parameter);
break;
@@ -270,6 +277,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
erc1155_plugin_call(method, parameter);
break;
}
#endif // HAVE_NFT_SUPPORT
case OLD_INTERNAL: {
// Perform the call
for (i = 0;; i++) {

View File

@@ -513,6 +513,7 @@ void handleApdu(unsigned int *flags, unsigned int *tx) {
tx);
break;
#ifdef HAVE_NFT_SUPPORT
case INS_PROVIDE_NFT_INFORMATION:
handleProvideNFTInformation(G_io_apdu_buffer[OFFSET_P1],
G_io_apdu_buffer[OFFSET_P2],
@@ -521,6 +522,7 @@ void handleApdu(unsigned int *flags, unsigned int *tx) {
flags,
tx);
break;
#endif // HAVE_NFT_SUPPORT
case INS_SET_EXTERNAL_PLUGIN:
handleSetExternalPlugin(G_io_apdu_buffer[OFFSET_P1],

View File

@@ -207,8 +207,7 @@ typedef enum {
EXTERNAL, // External plugin, set by setExternalPlugin.
ERC721, // Specific ERC721 internal plugin, set by setPlugin.
ERC1155, // Specific ERC1155 internal plugin, set by setPlugin
OLD_INTERNAL, // Old internal plugin, not set by any command.
NOT_OLD_INTERNAL, // Do not treat this tx as an old internal transaction.
OLD_INTERNAL // Old internal plugin, not set by any command.
} pluginType_t;
extern pluginType_t pluginType;