Add Compound support as an internal plugin
This commit is contained in:
@@ -12,6 +12,7 @@ void eth_plugin_prepare_query_contract_UI(ethQueryContractUI_t *queryContractUI,
|
|||||||
int eth_plugin_perform_init(uint8_t *contractAddress, ethPluginInitContract_t *init);
|
int eth_plugin_perform_init(uint8_t *contractAddress, ethPluginInitContract_t *init);
|
||||||
// NULL for cached address, or base contract address
|
// NULL for cached address, or base contract address
|
||||||
int eth_plugin_call(uint8_t *contractAddress, int method, void *parameter);
|
int eth_plugin_call(uint8_t *contractAddress, int method, void *parameter);
|
||||||
|
int compound_plugin_call(uint8_t *contractAddress, int method, void *parameter);
|
||||||
|
|
||||||
void plugin_ui_start(void);
|
void plugin_ui_start(void);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "eth_plugin_internal.h"
|
#include "eth_plugin_internal.h"
|
||||||
|
|
||||||
void erc20_plugin_call(int message, void *parameters);
|
void erc20_plugin_call(int message, void *parameters);
|
||||||
|
void compound_plugin_call(int message, void *parameters);
|
||||||
void starkware_plugin_call(int message, void *parameters);
|
void starkware_plugin_call(int message, void *parameters);
|
||||||
|
|
||||||
static const uint8_t const ERC20_TRANSFER_SELECTOR[SELECTOR_SIZE] = { 0xa9, 0x05, 0x9c, 0xbb };
|
static const uint8_t const ERC20_TRANSFER_SELECTOR[SELECTOR_SIZE] = { 0xa9, 0x05, 0x9c, 0xbb };
|
||||||
@@ -10,6 +11,16 @@ const uint8_t* const ERC20_SELECTORS[NUM_ERC20_SELECTORS] = {
|
|||||||
ERC20_TRANSFER_SELECTOR, ERC20_APPROVE_SELECTOR
|
ERC20_TRANSFER_SELECTOR, ERC20_APPROVE_SELECTOR
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const uint8_t const COMPOUND_REDEEM_UNDERLYING_SELECTOR[SELECTOR_SIZE] = { 0x85, 0x2a, 0x12, 0xe3 };
|
||||||
|
static const uint8_t const COMPOUND_REDEEM_SELECTOR[SELECTOR_SIZE] = { 0xdb, 0x00, 0x6a, 0x75 };
|
||||||
|
static const uint8_t const COMPOUND_MINT_SELECTOR[SELECTOR_SIZE] = { 0xa0, 0x71, 0x2d, 0x68 };
|
||||||
|
static const uint8_t const CETH_MINT_SELECTOR[SELECTOR_SIZE] = { 0x12, 0x49, 0xc5, 0x8b };
|
||||||
|
|
||||||
|
const uint8_t* const COMPOUND_SELECTORS[NUM_COMPOUND_SELECTORS] = {
|
||||||
|
COMPOUND_REDEEM_UNDERLYING_SELECTOR, COMPOUND_REDEEM_SELECTOR,
|
||||||
|
COMPOUND_MINT_SELECTOR, CETH_MINT_SELECTOR
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef HAVE_STARKWARE
|
#ifdef HAVE_STARKWARE
|
||||||
|
|
||||||
static const uint8_t const STARKWARE_REGISTER_ID[SELECTOR_SIZE] = { 0x76, 0x57, 0x18, 0xd7 };
|
static const uint8_t const STARKWARE_REGISTER_ID[SELECTOR_SIZE] = { 0x76, 0x57, 0x18, 0xd7 };
|
||||||
@@ -42,6 +53,13 @@ const internalEthPlugin_t const INTERNAL_ETH_PLUGINS[NUM_INTERNAL_PLUGINS] = {
|
|||||||
erc20_plugin_call
|
erc20_plugin_call
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
COMPOUND_SELECTORS,
|
||||||
|
4,
|
||||||
|
"-cmpd",
|
||||||
|
compound_plugin_call
|
||||||
|
},
|
||||||
|
|
||||||
#ifdef HAVE_STARKWARE
|
#ifdef HAVE_STARKWARE
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,20 +12,22 @@ typedef struct internalEthPlugin_t {
|
|||||||
} internalEthPlugin_t;
|
} internalEthPlugin_t;
|
||||||
|
|
||||||
#define NUM_ERC20_SELECTORS 2
|
#define NUM_ERC20_SELECTORS 2
|
||||||
|
|
||||||
extern const uint8_t* const ERC20_SELECTORS[NUM_ERC20_SELECTORS];
|
extern const uint8_t* const ERC20_SELECTORS[NUM_ERC20_SELECTORS];
|
||||||
|
|
||||||
|
#define NUM_COMPOUND_SELECTORS 4
|
||||||
|
extern const uint8_t* const COMPOUND_SELECTORS[NUM_COMPOUND_SELECTORS];
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_STARKWARE
|
#ifdef HAVE_STARKWARE
|
||||||
|
|
||||||
#define NUM_INTERNAL_PLUGINS 2
|
#define NUM_INTERNAL_PLUGINS 3
|
||||||
|
|
||||||
#define NUM_STARKWARE_SELECTORS 10
|
#define NUM_STARKWARE_SELECTORS 10
|
||||||
|
|
||||||
extern const uint8_t* const STARKWARE_SELECTORS[NUM_STARKWARE_SELECTORS];
|
extern const uint8_t* const STARKWARE_SELECTORS[NUM_STARKWARE_SELECTORS];
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define NUM_INTERNAL_PLUGINS 1
|
#define NUM_INTERNAL_PLUGINS 2
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ UX_STEP_NOCB_INIT(
|
|||||||
bnnn_paging,
|
bnnn_paging,
|
||||||
plugin_ui_compute_fees(),
|
plugin_ui_compute_fees(),
|
||||||
{
|
{
|
||||||
.title = "Max fees",
|
.title = "Max Fees",
|
||||||
.text = strings.common.maxFee
|
.text = strings.common.maxFee
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -51,8 +51,7 @@ customStatus_e customProcessor(txContext_t *context) {
|
|||||||
dataContext.tokenContext.fieldOffset = 0;
|
dataContext.tokenContext.fieldOffset = 0;
|
||||||
copyTxData(context, NULL, 4);
|
copyTxData(context, NULL, 4);
|
||||||
if (context->currentFieldLength == 4) {
|
if (context->currentFieldLength == 4) {
|
||||||
dataContext.tokenContext.fieldIndex++;
|
return CUSTOM_NOT_HANDLED;
|
||||||
return CUSTOM_HANDLED;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
224
src_plugins/compound/compound_plugin.c
Normal file
224
src_plugins/compound/compound_plugin.c
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "eth_plugin_interface.h"
|
||||||
|
#include "shared_context.h" // TODO : rewrite as independant code
|
||||||
|
#include "eth_plugin_internal.h" // TODO : rewrite as independant code
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
COMPOUND_REDEEM_UNDERLYING = 0,
|
||||||
|
COMPOUND_REDEEM,
|
||||||
|
COMPOUND_MINT,
|
||||||
|
CETH_MINT
|
||||||
|
} compoundSelector_t;
|
||||||
|
|
||||||
|
static const uint8_t COMPOUND_EXPECTED_DATA_SIZE[] = {
|
||||||
|
4 + 32,
|
||||||
|
4 + 32,
|
||||||
|
4 + 32,
|
||||||
|
4,
|
||||||
|
};
|
||||||
|
|
||||||
|
// redeemUnderlying : redeemAmount (32)
|
||||||
|
// redeem underlying token
|
||||||
|
// redeem : redeemTokens (32)
|
||||||
|
// redeem Ctoken
|
||||||
|
// mint : mintAmount (32)
|
||||||
|
// lend some token
|
||||||
|
// mint :
|
||||||
|
// lend some Ether
|
||||||
|
|
||||||
|
typedef struct compound_parameters_t {
|
||||||
|
uint8_t selectorIndex;
|
||||||
|
uint8_t amount[32];
|
||||||
|
uint8_t ticker_1[MAX_TICKER_LEN];
|
||||||
|
uint8_t decimals;
|
||||||
|
} compound_parameters_t;
|
||||||
|
|
||||||
|
typedef struct underlying_asset_decimals_t {
|
||||||
|
char c_ticker[MAX_TICKER_LEN];
|
||||||
|
uint8_t decimals;
|
||||||
|
} underlying_asset_decimals_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Sadly, we don't have the information about the underlying asset's decimals, which can differ from the cToken decimals.
|
||||||
|
Therefore, we hardcode a binding table. If Compound adds a lot of token in the future, we will have to move to a CAL
|
||||||
|
based architecture instead, as this one doesn't scale well.*/
|
||||||
|
#define NUM_COMPOUND_BINDINGS 9
|
||||||
|
const underlying_asset_decimals_t const UNDERLYING_ASSET_DECIMALS[NUM_COMPOUND_BINDINGS] = {
|
||||||
|
{"cDAI", 18},
|
||||||
|
{"CETH", 18},
|
||||||
|
{"CUSDC", 6},
|
||||||
|
{"CZRX", 18},
|
||||||
|
{"CUSDT", 6},
|
||||||
|
{"CBTC", 8},
|
||||||
|
{"CBAT", 18},
|
||||||
|
{"CREP", 18},
|
||||||
|
{"cSAI", 18},
|
||||||
|
};
|
||||||
|
|
||||||
|
bool get_underlying_asset_decimals(char* compound_ticker, uint8_t* out_decimals){
|
||||||
|
for(size_t i = 0; i < NUM_COMPOUND_BINDINGS; i++){
|
||||||
|
underlying_asset_decimals_t* binding = (underlying_asset_decimals_t *)PIC(&UNDERLYING_ASSET_DECIMALS[i]);
|
||||||
|
if (strncmp(binding->c_ticker, compound_ticker, strnlen(binding->c_ticker, MAX_TICKER_LEN)) == 0){
|
||||||
|
*out_decimals = binding->decimals;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void compound_plugin_call(int message, void *parameters) {
|
||||||
|
|
||||||
|
switch(message) {
|
||||||
|
case ETH_PLUGIN_INIT_CONTRACT: {
|
||||||
|
ethPluginInitContract_t *msg = (ethPluginInitContract_t*)parameters;
|
||||||
|
compound_parameters_t *context = (compound_parameters_t*)msg->pluginContext;
|
||||||
|
size_t i;
|
||||||
|
for (i=0; i<NUM_COMPOUND_SELECTORS; i++) {
|
||||||
|
if (memcmp((uint8_t *)PIC(COMPOUND_SELECTORS[i]), msg->selector, SELECTOR_SIZE) == 0) {
|
||||||
|
context->selectorIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// enforce that ETH amount should be 0, except in ceth.mint case
|
||||||
|
if (!allzeroes(msg->pluginSharedRO->txContent->value.value, 32)){
|
||||||
|
if(context->selectorIndex != CETH_MINT){
|
||||||
|
msg->result = ETH_PLUGIN_RESULT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(context->selectorIndex == CETH_MINT){
|
||||||
|
// ETH amount 0x1234 is stored 0x12340000...000 instead of 0x00....001234, so we strip the following zeroes when copying
|
||||||
|
memset(context->amount, 0, sizeof(context->amount));
|
||||||
|
memmove(context->amount + sizeof(context->amount) - msg->pluginSharedRO->txContent->value.length, msg->pluginSharedRO->txContent->value.value, 32);
|
||||||
|
}
|
||||||
|
if (i == NUM_COMPOUND_SELECTORS) {
|
||||||
|
PRINTF("Unknown selector %.*H\n", SELECTOR_SIZE, msg->selector);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (msg->dataSize != COMPOUND_EXPECTED_DATA_SIZE[context->selectorIndex]) {
|
||||||
|
PRINTF("Unexpected data size for command %d expected %d got %d\n", context->selectorIndex,
|
||||||
|
COMPOUND_EXPECTED_DATA_SIZE[context->selectorIndex], msg->dataSize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PRINTF("compound plugin init\n");
|
||||||
|
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ETH_PLUGIN_PROVIDE_PARAMETER : {
|
||||||
|
ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t*)parameters;
|
||||||
|
compound_parameters_t *context = (compound_parameters_t*)msg->pluginContext;
|
||||||
|
PRINTF("compound plugin provide parameter %d %.*H\n", msg->parameterOffset, 32, msg->parameter);
|
||||||
|
if (context->selectorIndex != CETH_MINT){
|
||||||
|
switch(msg->parameterOffset) {
|
||||||
|
case 4:
|
||||||
|
memmove(context->amount, msg->parameter, 32);
|
||||||
|
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PRINTF("Unhandled parameter offset\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ETH_PLUGIN_FINALIZE: {
|
||||||
|
ethPluginFinalize_t *msg = (ethPluginFinalize_t*)parameters;
|
||||||
|
PRINTF("compound plugin finalize\n");
|
||||||
|
msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination;
|
||||||
|
msg->numScreens = 2;
|
||||||
|
msg->uiType = ETH_UI_TYPE_GENERIC;
|
||||||
|
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ETH_PLUGIN_PROVIDE_TOKEN: {
|
||||||
|
ethPluginProvideToken_t *msg = (ethPluginProvideToken_t*)parameters;
|
||||||
|
compound_parameters_t *context = (compound_parameters_t*)msg->pluginContext;
|
||||||
|
PRINTF("compound plugin provide token: %d\n", (msg->token1 != NULL));
|
||||||
|
if (msg->token1 != NULL) {
|
||||||
|
strcpy((char *)context->ticker_1, (char *)msg->token1->ticker);
|
||||||
|
switch (context->selectorIndex)
|
||||||
|
{
|
||||||
|
case COMPOUND_REDEEM_UNDERLYING:
|
||||||
|
case COMPOUND_MINT:
|
||||||
|
case CETH_MINT:
|
||||||
|
msg->result = get_underlying_asset_decimals(context->ticker_1, &context->decimals) ? ETH_PLUGIN_RESULT_OK : ETH_PLUGIN_RESULT_FALLBACK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Only case where we use the compound contract decimals
|
||||||
|
case COMPOUND_REDEEM:
|
||||||
|
context->decimals = msg->token1->decimals;
|
||||||
|
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
msg->result = ETH_PLUGIN_RESULT_FALLBACK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
msg->result = ETH_PLUGIN_RESULT_FALLBACK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ETH_PLUGIN_QUERY_CONTRACT_ID: {
|
||||||
|
ethQueryContractID_t *msg = (ethQueryContractID_t*)parameters;
|
||||||
|
compound_parameters_t *context = (compound_parameters_t*)msg->pluginContext;
|
||||||
|
strcpy(msg->name, "Type");
|
||||||
|
switch (context->selectorIndex)
|
||||||
|
{
|
||||||
|
case COMPOUND_REDEEM_UNDERLYING:
|
||||||
|
case COMPOUND_REDEEM:
|
||||||
|
strcpy(msg->version, "Redeem");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COMPOUND_MINT:
|
||||||
|
case CETH_MINT:
|
||||||
|
strcpy(msg->version, "Lend");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
strcat(msg->version, " Assets");
|
||||||
|
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ETH_PLUGIN_QUERY_CONTRACT_UI: {
|
||||||
|
ethQueryContractUI_t *msg = (ethQueryContractUI_t*)parameters;
|
||||||
|
compound_parameters_t *context = (compound_parameters_t*)msg->pluginContext;
|
||||||
|
switch(msg->screenIndex) {
|
||||||
|
case 0: {
|
||||||
|
strcpy(msg->title, "Amount");
|
||||||
|
char * ticker_ptr = (char *)context->ticker_1;
|
||||||
|
/* skip "c" in front of cToken unless we use "redeem", as
|
||||||
|
redeem is the only operation dealing with a cToken amount */
|
||||||
|
if(context->selectorIndex != COMPOUND_REDEEM){
|
||||||
|
ticker_ptr++;
|
||||||
|
}
|
||||||
|
amountToString(context->amount, sizeof(context->amount), context->decimals, ticker_ptr, msg->msg, 100);
|
||||||
|
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
strcpy(msg->title, "Contract");
|
||||||
|
strcpy(msg->msg, "Compound ");
|
||||||
|
strcat(msg->msg, (char *)context->ticker_1 + 1); // remove the 'c' char at beginning of compound ticker
|
||||||
|
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
PRINTF("Unhandled message %d\n", message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -153,8 +153,8 @@ void erc20_plugin_call(int message, void *parameters) {
|
|||||||
|
|
||||||
case ETH_PLUGIN_QUERY_CONTRACT_ID: {
|
case ETH_PLUGIN_QUERY_CONTRACT_ID: {
|
||||||
ethQueryContractID_t *msg = (ethQueryContractID_t*)parameters;
|
ethQueryContractID_t *msg = (ethQueryContractID_t*)parameters;
|
||||||
strcpy(msg->name, "Approve");
|
strcpy(msg->name, "Type");
|
||||||
strcpy(msg->version, "");
|
strcpy(msg->version, "Approve");
|
||||||
msg->result = ETH_PLUGIN_RESULT_OK;
|
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user