Files
app-ethereum/src_plugins/compound/compound_plugin.c
pscott b646cf1b28 Fix compilation warnings (#159)
* Fix easy warnings for sdk 2.0

* Add attribute unused to bagl_elemt_t in callback functions

* Add attribute unused to io_event function

* Clang-format

* Use elfs from CI in tests (#167)

* Add Nano X build

* Use CI's build artifacts for CI's tests

* Add network display (#152)

* Add network name display instead of chainID

* Add display of correct ticker along with network

* Add FTM

* Clang-format

* Add comment in python script

* Rename SIZE_MAX to MAX_SIZE

* Change %u to %d in printf

* Remove needless PIC

* Update comment about get_chain_id()

* Update example script to follow EIP155

* Remove unused PIC calls

* Add whitespace between ticker and amount when using EIP155

* Remove decimal config per network, set back 18 everywhere

* Adapt u32_from_BE to swith cases

* Remove chainid from signTx.py

* Switch to switch in stead of if in get_chain_id

* Revert "Remove chainid from signTx.py"

This reverts commit 454e09f280ec3e3ec1c7d7cc0027247ef4390088.

* Change Ethereum chainid to 1

* Rename chainid_step to network_step

* Adapt finalizeParsing to new chainid for Ethereum

* Update snapshots

* clang-format

* Fix network display logic for clones

* Fix tests

* Add clone tests

Co-authored-by: TamtamHero <10632523+TamtamHero@users.noreply.github.com>

Co-authored-by: Jean P <10632523+TamtamHero@users.noreply.github.com>
2021-07-05 11:01:51 +02:00

242 lines
9.5 KiB
C

#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 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;
break;
}
}
if (i == NUM_COMPOUND_SELECTORS) {
PRINTF("Unknown selector %.*H\n", SELECTOR_SIZE, msg->selector);
msg->result = ETH_PLUGIN_RESULT_ERROR;
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);
msg->result = ETH_PLUGIN_RESULT_ERROR;
break;
}
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,
msg->pluginSharedRO->txContent->value.length);
}
PRINTF("compound plugin inititialized\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");
msg->result = ETH_PLUGIN_RESULT_ERROR;
break;
}
} else {
PRINTF("CETH contract expects no parameters\n");
msg->result = ETH_PLUGIN_RESULT_ERROR;
}
} 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((char *) &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);
}
}