Files
app-ethereum/src/eth_plugin_handler.c

367 lines
14 KiB
C

#include <string.h>
#include "eth_plugin_handler.h"
#include "eth_plugin_internal.h"
#include "plugin_utils.h"
#include "shared_context.h"
#include "network.h"
void eth_plugin_prepare_init(ethPluginInitContract_t *init,
const uint8_t *selector,
uint32_t dataSize) {
memset((uint8_t *) init, 0, sizeof(ethPluginInitContract_t));
init->selector = selector;
init->dataSize = dataSize;
}
void eth_plugin_prepare_provide_parameter(ethPluginProvideParameter_t *provideParameter,
uint8_t *parameter,
uint32_t parameterOffset) {
memset((uint8_t *) provideParameter, 0, sizeof(ethPluginProvideParameter_t));
provideParameter->parameter = parameter;
provideParameter->parameterOffset = parameterOffset;
}
void eth_plugin_prepare_finalize(ethPluginFinalize_t *finalize) {
memset((uint8_t *) finalize, 0, sizeof(ethPluginFinalize_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,
char *name,
uint32_t nameLength,
char *version,
uint32_t versionLength) {
memset((uint8_t *) queryContractID, 0, sizeof(ethQueryContractID_t));
queryContractID->name = name;
queryContractID->nameLength = nameLength;
queryContractID->version = version;
queryContractID->versionLength = versionLength;
}
void eth_plugin_prepare_query_contract_UI(ethQueryContractUI_t *queryContractUI,
uint8_t screenIndex,
char *title,
uint32_t titleLength,
char *msg,
uint32_t msgLength) {
uint64_t chain_id;
memset((uint8_t *) queryContractUI, 0, sizeof(ethQueryContractUI_t));
// If no extra information was found, set the pointer to NULL
if (NO_EXTRA_INFO(tmpCtx, 1)) {
queryContractUI->item1 = NULL;
} else {
queryContractUI->item1 = &tmpCtx.transactionContext.extraInfo[1];
}
// If no extra information was found, set the pointer to NULL
if (NO_EXTRA_INFO(tmpCtx, 0)) {
queryContractUI->item2 = NULL;
} else {
queryContractUI->item2 = &tmpCtx.transactionContext.extraInfo[0];
}
queryContractUI->screenIndex = screenIndex;
chain_id = get_tx_chain_id();
strlcpy(queryContractUI->network_ticker,
get_displayable_ticker(&chain_id, chainConfig),
sizeof(queryContractUI->network_ticker));
queryContractUI->title = title;
queryContractUI->titleLength = titleLength;
queryContractUI->msg = msg;
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) {
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_UNAVAILABLE;
PRINTF("Selector %.*H\n", 4, init->selector);
switch (pluginType) {
#ifdef HAVE_NFT_SUPPORT
case ERC1155:
case ERC721:
#endif // HAVE_NFT_SUPPORT
case EXTERNAL:
eth_plugin_perform_init_default(contractAddress, init);
contractAddress = NULL;
break;
case OLD_INTERNAL:
if (eth_plugin_perform_init_old_internal(contractAddress, init)) {
contractAddress = NULL;
}
break;
default:
PRINTF("Unsupported pluginType %d\n", pluginType);
os_sched_exit(0);
break;
}
// Do not handle a plugin if running in swap mode
if (G_called_from_swap && (contractAddress != NULL)) {
PRINTF("eth_plug_init aborted in swap mode\n");
return 0;
}
eth_plugin_result_t status = ETH_PLUGIN_RESULT_UNAVAILABLE;
if (contractAddress != NULL) {
PRINTF("No plugin available for %.*H\n", 20, contractAddress);
return status;
}
PRINTF("eth_plugin_init\n");
PRINTF("Trying plugin %s\n", dataContext.tokenContext.pluginName);
status = eth_plugin_call(ETH_PLUGIN_INIT_CONTRACT, (void *) init);
if (status <= ETH_PLUGIN_RESULT_UNSUCCESSFUL) {
return status;
}
PRINTF("eth_plugin_init ok %s\n", dataContext.tokenContext.pluginName);
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_OK;
return ETH_PLUGIN_RESULT_OK;
}
eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
ethPluginSharedRW_t pluginRW;
ethPluginSharedRO_t pluginRO;
char *alias;
uint8_t i;
pluginRW.sha3 = &global_sha3;
pluginRO.txContent = &tmpContent.txContent;
if (dataContext.tokenContext.pluginStatus <= ETH_PLUGIN_RESULT_UNSUCCESSFUL) {
PRINTF("Cached plugin call but no plugin available\n");
return dataContext.tokenContext.pluginStatus;
}
alias = dataContext.tokenContext.pluginName;
// Prepare the call
switch (method) {
case ETH_PLUGIN_INIT_CONTRACT:
PRINTF("-- PLUGIN INIT CONTRACT --\n");
((ethPluginInitContract_t *) parameter)->interfaceVersion =
ETH_PLUGIN_INTERFACE_VERSION_LATEST;
((ethPluginInitContract_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
((ethPluginInitContract_t *) parameter)->pluginSharedRW = &pluginRW;
((ethPluginInitContract_t *) parameter)->pluginSharedRO = &pluginRO;
((ethPluginInitContract_t *) parameter)->pluginContext =
(uint8_t *) &dataContext.tokenContext.pluginContext;
((ethPluginInitContract_t *) parameter)->pluginContextLength =
sizeof(dataContext.tokenContext.pluginContext);
((ethPluginInitContract_t *) parameter)->alias = dataContext.tokenContext.pluginName;
break;
case ETH_PLUGIN_PROVIDE_PARAMETER:
PRINTF("-- PLUGIN PROVIDE PARAMETER --\n");
((ethPluginProvideParameter_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
((ethPluginProvideParameter_t *) parameter)->pluginSharedRW = &pluginRW;
((ethPluginProvideParameter_t *) parameter)->pluginSharedRO = &pluginRO;
((ethPluginProvideParameter_t *) parameter)->pluginContext =
(uint8_t *) &dataContext.tokenContext.pluginContext;
break;
case ETH_PLUGIN_FINALIZE:
PRINTF("-- PLUGIN FINALIZE --\n");
((ethPluginFinalize_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
((ethPluginFinalize_t *) parameter)->pluginSharedRW = &pluginRW;
((ethPluginFinalize_t *) parameter)->pluginSharedRO = &pluginRO;
((ethPluginFinalize_t *) parameter)->pluginContext =
(uint8_t *) &dataContext.tokenContext.pluginContext;
break;
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:
PRINTF("-- PLUGIN QUERY CONTRACT ID --\n");
((ethQueryContractID_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
((ethQueryContractID_t *) parameter)->pluginSharedRW = &pluginRW;
((ethQueryContractID_t *) parameter)->pluginSharedRO = &pluginRO;
((ethQueryContractID_t *) parameter)->pluginContext =
(uint8_t *) &dataContext.tokenContext.pluginContext;
break;
case ETH_PLUGIN_QUERY_CONTRACT_UI:
PRINTF("-- PLUGIN QUERY CONTRACT UI --\n");
((ethQueryContractUI_t *) parameter)->pluginSharedRW = &pluginRW;
((ethQueryContractUI_t *) parameter)->pluginSharedRO = &pluginRO;
((ethQueryContractUI_t *) parameter)->pluginContext =
(uint8_t *) &dataContext.tokenContext.pluginContext;
break;
default:
PRINTF("Unknown plugin method %d\n", method);
return ETH_PLUGIN_RESULT_UNAVAILABLE;
}
switch (pluginType) {
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;
}
#ifdef HAVE_NFT_SUPPORT
case ERC721: {
erc721_plugin_call(method, parameter);
break;
}
case ERC1155: {
erc1155_plugin_call(method, parameter);
break;
}
#endif // HAVE_NFT_SUPPORT
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;
}
}
// Check the call result
PRINTF("method: %d\n", method);
switch (method) {
case ETH_PLUGIN_INIT_CONTRACT:
switch (((ethPluginInitContract_t *) parameter)->result) {
case ETH_PLUGIN_RESULT_OK:
break;
case ETH_PLUGIN_RESULT_ERROR:
return ETH_PLUGIN_RESULT_ERROR;
default:
return ETH_PLUGIN_RESULT_UNAVAILABLE;
}
break;
case ETH_PLUGIN_PROVIDE_PARAMETER:
switch (((ethPluginProvideParameter_t *) parameter)->result) {
case ETH_PLUGIN_RESULT_OK:
case ETH_PLUGIN_RESULT_FALLBACK:
break;
case ETH_PLUGIN_RESULT_ERROR:
return ETH_PLUGIN_RESULT_ERROR;
default:
return ETH_PLUGIN_RESULT_UNAVAILABLE;
}
break;
case ETH_PLUGIN_FINALIZE:
switch (((ethPluginFinalize_t *) parameter)->result) {
case ETH_PLUGIN_RESULT_OK:
case ETH_PLUGIN_RESULT_FALLBACK:
break;
case ETH_PLUGIN_RESULT_ERROR:
return ETH_PLUGIN_RESULT_ERROR;
default:
return ETH_PLUGIN_RESULT_UNAVAILABLE;
}
break;
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;
case ETH_PLUGIN_RESULT_ERROR:
return ETH_PLUGIN_RESULT_ERROR;
default:
return ETH_PLUGIN_RESULT_UNAVAILABLE;
}
break;
case ETH_PLUGIN_QUERY_CONTRACT_ID:
if (((ethQueryContractID_t *) parameter)->result != ETH_PLUGIN_RESULT_OK) {
return ETH_PLUGIN_RESULT_ERROR;
}
break;
case ETH_PLUGIN_QUERY_CONTRACT_UI:
if (((ethQueryContractUI_t *) parameter)->result != ETH_PLUGIN_RESULT_OK) {
return ETH_PLUGIN_RESULT_ERROR;
}
break;
default:
return ETH_PLUGIN_RESULT_UNAVAILABLE;
}
return ETH_PLUGIN_RESULT_OK;
}