From b65cb1cdac3d279ed0fe7faca1d20c82724a23cf Mon Sep 17 00:00:00 2001 From: Francois Beutin Date: Mon, 6 Nov 2023 19:24:25 +0100 Subject: [PATCH] Improve plugin interface file --- src/eth_plugin_interface.h | 113 +++++++++++++++++++++++++------------ src/eth_plugin_internal.h | 1 + 2 files changed, 78 insertions(+), 36 deletions(-) diff --git a/src/eth_plugin_interface.h b/src/eth_plugin_interface.h index 9832ee8142..4ed1ff18b5 100644 --- a/src/eth_plugin_interface.h +++ b/src/eth_plugin_interface.h @@ -1,3 +1,5 @@ +// clang-format off + #ifndef _ETH_PLUGIN_INTERFACE_H_ #define _ETH_PLUGIN_INTERFACE_H_ @@ -7,7 +9,14 @@ #include "tokens.h" #include "shared_context.h" -// Interface version. To be updated everytime we introduce breaking changes to the plugin interface. +/************************************************************************************************* + * Comments provided in this file are quick reminders on the usage of the plugin interface * + * Reading the real plugin documentation is GREATLY recommended. * + * You can find the latest version here: * + * https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/ethapp_plugins.adoc * + *************************************************************************************************/ + +// Interface version. Will be updated every time a breaking change in the interface is introduced. typedef enum eth_plugin_interface_version_e { ETH_PLUGIN_INTERFACE_VERSION_1 = 1, ETH_PLUGIN_INTERFACE_VERSION_2 = 2, @@ -17,20 +26,26 @@ typedef enum eth_plugin_interface_version_e { ETH_PLUGIN_INTERFACE_VERSION_LATEST = 6, } eth_plugin_interface_version_t; -typedef enum eth_plugin_msg_e { +// Codes for the different requests Ethereum can send to the plugin +// The dispatch is handled by the SDK itself, the plugin code does not have to handle it +typedef enum eth_plugin_msg_e { + // Codes for actions the Ethereum app can ask the plugin to perform ETH_PLUGIN_INIT_CONTRACT = 0x0101, ETH_PLUGIN_PROVIDE_PARAMETER = 0x0102, ETH_PLUGIN_FINALIZE = 0x0103, ETH_PLUGIN_PROVIDE_INFO = 0x0104, ETH_PLUGIN_QUERY_CONTRACT_ID = 0x0105, ETH_PLUGIN_QUERY_CONTRACT_UI = 0x0106, - ETH_PLUGIN_CHECK_PRESENCE = 0x01FF, + // Special request: the Ethereum app is checking if we are installed on the device + ETH_PLUGIN_CHECK_PRESENCE = 0x01FF, } eth_plugin_msg_t; + +// Reply codes when responding to the Ethereum application typedef enum eth_plugin_result_e { - // Unsuccesful return values + // Unsuccessful return values ETH_PLUGIN_RESULT_ERROR = 0x00, ETH_PLUGIN_RESULT_UNAVAILABLE = 0x01, ETH_PLUGIN_RESULT_UNSUCCESSFUL = 0x02, // Used for comparison @@ -40,37 +55,57 @@ typedef enum eth_plugin_result_e { ETH_PLUGIN_RESULT_OK = 0x04, ETH_PLUGIN_RESULT_OK_ALIAS = 0x05, ETH_PLUGIN_RESULT_FALLBACK = 0x06, - } eth_plugin_result_t; -typedef enum eth_ui_type_e { +// Format of UI the Ethereum application has to use for this plugin +typedef enum eth_ui_type_e { + // If uiType is UI_AMOUNT_ADDRESS, Ethereum will use the amount/address UI + // the amount and address provided by the plugin will be used + // If tokenLookup1 is set, the amount is provided for this token ETH_UI_TYPE_AMOUNT_ADDRESS = 0x01, - ETH_UI_TYPE_GENERIC = 0x02, + // If uiType is UI_TYPE_GENERIC, Ethereum will use the dedicated ETH plugin UI + // the ETH application provides tokens if requested then prompts for each UI field + // The first field is forced by the ETH app to be the name + version of the plugin handling the + // request. The last field is the fee amount + ETH_UI_TYPE_GENERIC = 0x02, } eth_ui_type_t; -typedef void (*PluginCall)(int, void *); - -// Shared objects, read-write +// Scratch objects and utilities available to the plugin READ-WRITE typedef struct ethPluginSharedRW_s { cx_sha3_t *sha3; - } ethPluginSharedRW_t; -// Shared objects, read-only +// Transaction data available to the plugin READ-ONLY typedef struct ethPluginSharedRO_s { txContent_t *txContent; - } ethPluginSharedRO_t; + +// Plugin-only memory allocated by the Ethereum application and used by the plugin. +#define PLUGIN_CONTEXT_SIZE (5 * INT256_LENGTH) +// It is recommended to cast the raw uin8_t array to a structure meaningfull for your plugin +// Helper to check that the actual plugin context structure is not bigger than the allocated memory +#define ASSERT_SIZEOF_PLUGIN_CONTEXT(s) \ + _Static_assert(sizeof(s) <= PLUGIN_CONTEXT_SIZE, "Plugin context structure is too big.") + + +/* + * HANDLERS AND PARAMETERS + * Parameters associated with the requests the Ethereum application can ask the plugin to perform + * The plugin SDK will automatically call the relevant handler for the received code, so the plugin + * has to define each of the handler functions declared below. + */ + + // Init Contract typedef struct ethPluginInitContract_s { - uint8_t interfaceVersion; - uint8_t result; + eth_plugin_interface_version_t interfaceVersion; + eth_plugin_result_t result; // in ethPluginSharedRW_t *pluginSharedRW; @@ -84,25 +119,31 @@ typedef struct ethPluginInitContract_s { } ethPluginInitContract_t; +void handle_init_contract(ethPluginInitContract_t *parameters); + + // Provide parameter typedef struct ethPluginProvideParameter_s { ethPluginSharedRW_t *pluginSharedRW; ethPluginSharedRO_t *pluginSharedRO; - uint8_t *pluginContext; + uint8_t *pluginContext; // PLUGIN_CONTEXT_SIZE const uint8_t *parameter; // 32 bytes parameter uint32_t parameterOffset; - uint8_t result; + eth_plugin_result_t result; } ethPluginProvideParameter_t; +void handle_provide_parameter(ethPluginProvideParameter_t *parameters); + + // Finalize typedef struct ethPluginFinalize_s { ethPluginSharedRW_t *pluginSharedRW; ethPluginSharedRO_t *pluginSharedRO; - uint8_t *pluginContext; + uint8_t *pluginContext; // PLUGIN_CONTEXT_SIZE uint8_t *tokenLookup1; // set by the plugin if a token should be looked up uint8_t *tokenLookup2; @@ -111,26 +152,21 @@ typedef struct ethPluginFinalize_s { const uint8_t *address; // set to the destination address if uiType is UI_AMOUNT_ADDRESS. Set // to the user's address if uiType is UI_TYPE_GENERIC - uint8_t uiType; + eth_ui_type_t uiType; uint8_t numScreens; // ignored if uiType is UI_AMOUNT_ADDRESS - uint8_t result; + eth_plugin_result_t result; } ethPluginFinalize_t; -// If uiType is UI_AMOUNT_ADDRESS, the amount and address provided by the plugin will be used -// If tokenLookup1 is set, the amount is provided for this token +void handle_finalize(ethPluginFinalize_t *parameters); -// if uiType is UI_TYPE_GENERIC, the ETH application provides tokens if requested then prompts -// for each UI field -// The first field is forced by the ETH app to be the name + version of the plugin handling the -// request The last field is the fee amount // Provide token typedef struct ethPluginProvideInfo_s { ethPluginSharedRW_t *pluginSharedRW; ethPluginSharedRO_t *pluginSharedRO; - uint8_t *pluginContext; + uint8_t *pluginContext; // PLUGIN_CONTEXT_SIZE union extraInfo_t *item1; // set by the ETH application, to be saved by the plugin union extraInfo_t *item2; @@ -138,10 +174,13 @@ typedef struct ethPluginProvideInfo_s { uint8_t additionalScreens; // Used by the plugin if it needs to display additional screens // based on the information received from the token definitions. - uint8_t result; + eth_plugin_result_t result; } ethPluginProvideInfo_t; +void handle_provide_token(ethPluginProvideInfo_t *parameters); + + // Query Contract name and version // This is always called on the non aliased contract @@ -149,17 +188,20 @@ typedef struct ethPluginProvideInfo_s { typedef struct ethQueryContractID_s { ethPluginSharedRW_t *pluginSharedRW; ethPluginSharedRO_t *pluginSharedRO; - uint8_t *pluginContext; + uint8_t *pluginContext; // PLUGIN_CONTEXT_SIZE char *name; size_t nameLength; char *version; size_t versionLength; - uint8_t result; + eth_plugin_result_t result; } ethQueryContractID_t; +void handle_query_contract_id(ethQueryContractID_t *parameters); + + // Query Contract UI typedef struct ethQueryContractUI_s { @@ -168,7 +210,7 @@ typedef struct ethQueryContractUI_s { union extraInfo_t *item1; union extraInfo_t *item2; char network_ticker[MAX_TICKER_LEN]; - uint8_t *pluginContext; + uint8_t *pluginContext; // PLUGIN_CONTEXT_SIZE uint8_t screenIndex; char *title; @@ -176,13 +218,12 @@ typedef struct ethQueryContractUI_s { char *msg; size_t msgLength; - uint8_t result; + eth_plugin_result_t result; } ethQueryContractUI_t; -// Helper to check that the plugin context structure is not bigger than 5 * 32 -#define PLUGIN_CONTEXT_SIZE (5 * INT256_LENGTH) -#define ASSERT_SIZEOF_PLUGIN_CONTEXT(s) \ - _Static_assert(sizeof(s) <= PLUGIN_CONTEXT_SIZE, "Plugin context structure is too big.") +void handle_query_contract_ui(ethQueryContractUI_t *parameters); #endif // _ETH_PLUGIN_INTERFACE_H_ + +// clang-format on diff --git a/src/eth_plugin_internal.h b/src/eth_plugin_internal.h index 2d2ca03693..956cec4b89 100644 --- a/src/eth_plugin_internal.h +++ b/src/eth_plugin_internal.h @@ -21,6 +21,7 @@ bool U2BE_from_parameter(const uint8_t* parameter, uint16_t* value); bool U4BE_from_parameter(const uint8_t* parameter, uint32_t* value); typedef bool (*PluginAvailableCheck)(void); +typedef void (*PluginCall)(int, void *); typedef struct internalEthPlugin_t { PluginAvailableCheck availableCheck;