Add support for ERC-721 and ERC-1155 (v3) (#218)
* First draft for erc721 token allowance * Split ui and provide parameters into their own files * Print txtype when not supported * fix compilation for erc721 * Use pluginType * Add debug statement in compound plugin * add debug error msg in plugin error * Add parameter parsing for all methods * Remove debug logs * Add SET_APPROVAL_FOR_ALL; Add correct parsing method on contract init * Add dst_size parameter to copy functions * Add query contract id code * format * Add UIs * update ethapp.asc * Change setExternalPlugin to setPlugin; Add support for ERC721 * clang-format * Fix typo Unconsistent -> Inconsistent * Add support for 721; use extraInfo * Add extraInfo to ethpluginQueryConractUI * Rename extraInfo to item * Add txFromEtherscan to tests * Add nft key and temp padding * Remove comments around HAVE_BYPASS_SIGNATURES * Rename TESTING_KEY to NFT_TESTING_KEY * Add comments regarding value of queryContractUI->item * Fix comment regarding method selector * Rename provideToken to provideInfo; Update plugin doc * fix caps of eth_plugin_prepare_provide_info * fix caps of handle_provide_info * Use verificationFn insead of hardcoded cx_ecdsa_verify * Add comments about nftInfo_t and tokenDefinition_t * Add erc721 test * Remove comment from plugin interface version * Fix network_ticker duplicate * Add setPlugin and provideNFTInfo to doc.asc * Add back setExternalPlugin; implement new setPlugin * Update plugin sdk * Call setPlugin instead of setExternalPlugin * setPlugin work without checking sig * Remove printf of displayed fees * Add working 721 test * Finalize ERC721 and add simple test * Display NFT address on set approval and operator * Support set approval for all for erc721 * Finish UI for set approval for all erc721 * Move copy_parameter and copy_address to eth_plugin_internal; Add tests for erc721 * update plugin sdk * Add erc1155 plugin and 1155 tests placeholder * Add restriction for AWS key and setPlugin * Add NOT_OLD_INTERNAL variant; Add erc_1155_plugin_call * Fixed compilation warnings (function pointer casting) Co-authored-by: pscott <scott.piriou@ledger.fr>
This commit is contained in:
@@ -22,8 +22,8 @@ void eth_plugin_prepare_finalize(ethPluginFinalize_t *finalize) {
|
||||
memset((uint8_t *) finalize, 0, sizeof(ethPluginFinalize_t));
|
||||
}
|
||||
|
||||
void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken) {
|
||||
memset((uint8_t *) provideToken, 0, sizeof(ethPluginProvideToken_t));
|
||||
void eth_plugin_prepare_provide_info(ethPluginProvideInfo_t *provideToken) {
|
||||
memset((uint8_t *) provideToken, 0, sizeof(ethPluginProvideInfo_t));
|
||||
}
|
||||
|
||||
void eth_plugin_prepare_query_contract_ID(ethQueryContractID_t *queryContractID,
|
||||
@@ -45,6 +45,23 @@ void eth_plugin_prepare_query_contract_UI(ethQueryContractUI_t *queryContractUI,
|
||||
char *msg,
|
||||
uint32_t msgLength) {
|
||||
memset((uint8_t *) queryContractUI, 0, sizeof(ethQueryContractUI_t));
|
||||
|
||||
// If no extra information was found, set the pointer to NULL
|
||||
if (allzeroes(&tmpCtx.transactionContext.extraInfo[1], sizeof(union extraInfo_t))) {
|
||||
queryContractUI->item1 = NULL;
|
||||
} else {
|
||||
queryContractUI->item1 = &tmpCtx.transactionContext.extraInfo[1];
|
||||
}
|
||||
|
||||
// If no extra information was found, set the pointer to NULL
|
||||
if (allzeroes(&tmpCtx.transactionContext.extraInfo[0], sizeof(union extraInfo_t))) {
|
||||
queryContractUI->item2 = NULL;
|
||||
} else {
|
||||
queryContractUI->item2 = &tmpCtx.transactionContext.extraInfo[0];
|
||||
}
|
||||
|
||||
strlcpy(queryContractUI->network_ticker, get_network_ticker(), MAX_TICKER_LEN);
|
||||
|
||||
queryContractUI->screenIndex = screenIndex;
|
||||
strlcpy(queryContractUI->network_ticker,
|
||||
get_network_ticker(),
|
||||
@@ -62,52 +79,66 @@ eth_plugin_result_t eth_plugin_perform_init(uint8_t *contractAddress,
|
||||
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_UNAVAILABLE;
|
||||
|
||||
PRINTF("Selector %.*H\n", 4, init->selector);
|
||||
if (externalPluginIsSet) {
|
||||
// check if the registered external plugin matches the TX contract address / method selector
|
||||
if (memcmp(contractAddress,
|
||||
dataContext.tokenContext.contract_address,
|
||||
sizeof(dataContext.tokenContext.contract_address)) != 0) {
|
||||
PRINTF("Got contract: %.*H\n", ADDRESS_LENGTH, contractAddress);
|
||||
PRINTF("Expected contract: %.*H\n",
|
||||
ADDRESS_LENGTH,
|
||||
dataContext.tokenContext.contract_address);
|
||||
os_sched_exit(0);
|
||||
}
|
||||
if (memcmp(init->selector,
|
||||
dataContext.tokenContext.method_selector,
|
||||
sizeof(dataContext.tokenContext.method_selector)) != 0) {
|
||||
PRINTF("Got selector: %.*H\n", SELECTOR_SIZE, init->selector);
|
||||
PRINTF("Expected selector: %.*H\n",
|
||||
SELECTOR_SIZE,
|
||||
dataContext.tokenContext.method_selector);
|
||||
os_sched_exit(0);
|
||||
}
|
||||
PRINTF("External plugin will be used\n");
|
||||
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_OK;
|
||||
contractAddress = NULL;
|
||||
} else {
|
||||
// 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;
|
||||
switch (pluginType) {
|
||||
case NOT_OLD_INTERNAL:
|
||||
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);
|
||||
}
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
default:
|
||||
PRINTF("Unsupported pluginType %d\n", pluginType);
|
||||
os_sched_exit(0);
|
||||
break;
|
||||
}
|
||||
|
||||
// Do not handle a plugin if running in swap mode
|
||||
@@ -140,7 +171,6 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
|
||||
ethPluginSharedRO_t pluginRO;
|
||||
char *alias;
|
||||
uint8_t i;
|
||||
uint8_t internalPlugin = 0;
|
||||
|
||||
pluginRW.sha3 = &global_sha3;
|
||||
pluginRO.txContent = &tmpContent.txContent;
|
||||
@@ -183,12 +213,12 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
|
||||
((ethPluginFinalize_t *) parameter)->pluginContext =
|
||||
(uint8_t *) &dataContext.tokenContext.pluginContext;
|
||||
break;
|
||||
case ETH_PLUGIN_PROVIDE_TOKEN:
|
||||
PRINTF("-- PLUGIN PROVIDE TOKEN --\n");
|
||||
((ethPluginProvideToken_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
|
||||
((ethPluginProvideToken_t *) parameter)->pluginSharedRW = &pluginRW;
|
||||
((ethPluginProvideToken_t *) parameter)->pluginSharedRO = &pluginRO;
|
||||
((ethPluginProvideToken_t *) parameter)->pluginContext =
|
||||
case ETH_PLUGIN_PROVIDE_INFO:
|
||||
PRINTF("-- PLUGIN PROVIDE INFO --\n");
|
||||
((ethPluginProvideInfo_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
|
||||
((ethPluginProvideInfo_t *) parameter)->pluginSharedRW = &pluginRW;
|
||||
((ethPluginProvideInfo_t *) parameter)->pluginSharedRO = &pluginRO;
|
||||
((ethPluginProvideInfo_t *) parameter)->pluginContext =
|
||||
(uint8_t *) &dataContext.tokenContext.pluginContext;
|
||||
break;
|
||||
case ETH_PLUGIN_QUERY_CONTRACT_ID:
|
||||
@@ -211,35 +241,52 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
|
||||
return ETH_PLUGIN_RESULT_UNAVAILABLE;
|
||||
}
|
||||
|
||||
// Perform the call
|
||||
|
||||
for (i = 0;; i++) {
|
||||
if (INTERNAL_ETH_PLUGINS[i].alias[0] == 0) {
|
||||
switch (pluginType) {
|
||||
case NOT_OLD_INTERNAL:
|
||||
break;
|
||||
case EXTERNAL: {
|
||||
uint32_t params[3];
|
||||
params[0] = (uint32_t) alias;
|
||||
params[1] = method;
|
||||
params[2] = (uint32_t) parameter;
|
||||
BEGIN_TRY {
|
||||
TRY {
|
||||
os_lib_call(params);
|
||||
}
|
||||
CATCH_OTHER(e) {
|
||||
PRINTF("Plugin call exception for %s\n", alias);
|
||||
}
|
||||
FINALLY {
|
||||
}
|
||||
}
|
||||
END_TRY;
|
||||
break;
|
||||
}
|
||||
if (strcmp(alias, INTERNAL_ETH_PLUGINS[i].alias) == 0) {
|
||||
internalPlugin = 1;
|
||||
((PluginCall) PIC(INTERNAL_ETH_PLUGINS[i].impl))(method, parameter);
|
||||
case ERC721: {
|
||||
erc721_plugin_call(method, parameter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!internalPlugin) {
|
||||
uint32_t params[3];
|
||||
params[0] = (uint32_t) alias;
|
||||
params[1] = method;
|
||||
params[2] = (uint32_t) parameter;
|
||||
BEGIN_TRY {
|
||||
TRY {
|
||||
os_lib_call(params);
|
||||
}
|
||||
CATCH_OTHER(e) {
|
||||
PRINTF("Plugin call exception for %s\n", alias);
|
||||
}
|
||||
FINALLY {
|
||||
}
|
||||
case ERC1155: {
|
||||
erc1155_plugin_call(method, parameter);
|
||||
break;
|
||||
}
|
||||
case OLD_INTERNAL: {
|
||||
// Perform the call
|
||||
for (i = 0;; i++) {
|
||||
if (INTERNAL_ETH_PLUGINS[i].alias[0] == 0) {
|
||||
break;
|
||||
}
|
||||
if (strcmp(alias, INTERNAL_ETH_PLUGINS[i].alias) == 0) {
|
||||
((PluginCall) PIC(INTERNAL_ETH_PLUGINS[i].impl))(method, parameter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
PRINTF("Error with pluginType: %d\n", pluginType);
|
||||
return ETH_PLUGIN_RESULT_ERROR;
|
||||
}
|
||||
END_TRY;
|
||||
}
|
||||
|
||||
// Check the call result
|
||||
@@ -277,9 +324,9 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
|
||||
return ETH_PLUGIN_RESULT_UNAVAILABLE;
|
||||
}
|
||||
break;
|
||||
case ETH_PLUGIN_PROVIDE_TOKEN:
|
||||
PRINTF("RESULT: %d\n", ((ethPluginProvideToken_t *) parameter)->result);
|
||||
switch (((ethPluginProvideToken_t *) parameter)->result) {
|
||||
case ETH_PLUGIN_PROVIDE_INFO:
|
||||
PRINTF("RESULT: %d\n", ((ethPluginProvideInfo_t *) parameter)->result);
|
||||
switch (((ethPluginProvideInfo_t *) parameter)->result) {
|
||||
case ETH_PLUGIN_RESULT_OK:
|
||||
case ETH_PLUGIN_RESULT_FALLBACK:
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user