Skip to content

Commit

Permalink
Merge pull request #7 from kobigurk/feat/staking
Browse files Browse the repository at this point in the history
feat: support staking displays
  • Loading branch information
fbeutin-ledger authored May 5, 2022
2 parents b6adf9c + 3ff6cf3 commit bd6cd40
Show file tree
Hide file tree
Showing 10 changed files with 358 additions and 43 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ APPVERSION_P=7
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)

# Celo
APP_LOAD_PARAMS += --path "44'/52752'" --path "44'/60'"
APP_LOAD_PARAMS += --path "44'/52752'"
APPNAME = "Celo"
APP_LOAD_FLAGS=--appFlags 0
ifeq ($(TARGET_NAME), TARGET_NANOX)
Expand Down
236 changes: 216 additions & 20 deletions src/celo.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@
#include <string.h>

static const uint8_t TOKEN_TRANSFER_ID[] = { 0xa9, 0x05, 0x9c, 0xbb };
static const uint8_t TOKEN_TRANSFER_WITH_COMMENT_ID[] = { 0xe1, 0xd6, 0xac, 0xeb };
static const uint8_t LOCK_METHOD_ID[] = { 0xf8, 0x3d, 0x08, 0xba };
static const uint8_t VOTE_METHOD_ID[] = { 0x58, 0x0d, 0x74, 0x7a };
static const uint8_t ACTIVATE_METHOD_ID[] = { 0x1c, 0x5a, 0x9d, 0x9c };
static const uint8_t REVOKE_PENDING_METHOD_ID[] = { 0x9d, 0xfb, 0x60, 0x81 };
static const uint8_t REVOKE_ACTIVE_METHOD_ID[] = { 0x6e, 0x19, 0x84, 0x75 };
static const uint8_t UNLOCK_METHOD_ID[] = { 0x61, 0x98, 0xe3, 0x39 };
static const uint8_t WITHDRAW_METHOD_ID[] = { 0x2e, 0x1a, 0x7d, 0x4d };
static const uint8_t RELOCK_METHOD_ID[] = { 0xb2, 0xfb, 0x30, 0xcb };
static const uint8_t CREATE_ACCOUNT_METHOD_ID[] = { 0x9d, 0xca, 0x36, 0x2f };

void io_seproxyhal_send_status(uint32_t sw) {
G_io_apdu_buffer[0] = ((sw >> 8) & 0xff);
Expand Down Expand Up @@ -116,22 +126,126 @@ customStatus_e customProcessor(txContext_t *context) {
return CUSTOM_FAULT;
}
// Initial check to see if the token content can be processed
tokenProvisioned =
(context->currentFieldLength == sizeof(dataContext.tokenContext.data)) &&
(memcmp(context->workBuffer, TOKEN_TRANSFER_ID, 4) == 0) &&
(getKnownToken(tmpContent.txContent.destination) != NULL);
if (
(
(
(context->currentFieldLength == sizeof(dataContext.tokenContext.data)) &&
(memcmp(context->workBuffer, TOKEN_TRANSFER_ID, 4) == 0)
) ||
(
(context->currentFieldLength >= sizeof(dataContext.tokenContext.data)) &&
(memcmp(context->workBuffer, TOKEN_TRANSFER_WITH_COMMENT_ID, 4) == 0)
)
) &&
(getKnownToken(tmpContent.txContent.destination) != NULL)
) {
provisionType = PROVISION_TOKEN;
}
// Initial check to see if the lock content can be processed
if (
(context->currentFieldLength == sizeof(dataContext.lockContext.data)) &&
(memcmp(context->workBuffer, LOCK_METHOD_ID, 4) == 0)) {
provisionType = PROVISION_LOCK;
}
// Initial check to see if the vote content can be processed
if (
(context->currentFieldLength == sizeof(dataContext.voteContext.data)) &&
(memcmp(context->workBuffer, VOTE_METHOD_ID, 4) == 0)) {
provisionType = PROVISION_VOTE;
}
// Initial check to see if the activate content can be processed
if (
(context->currentFieldLength == sizeof(dataContext.activateContext.data)) &&
(memcmp(context->workBuffer, ACTIVATE_METHOD_ID, 4) == 0)) {
provisionType = PROVISION_ACTIVATE;
}
// Initial check to see if the revoke content can be processed
if (
(context->currentFieldLength == sizeof(dataContext.revokeContext.data)) &&
((memcmp(context->workBuffer, REVOKE_PENDING_METHOD_ID, 4) == 0) || (memcmp(context->workBuffer, REVOKE_ACTIVE_METHOD_ID, 4) == 0))) {
provisionType = PROVISION_REVOKE;
}
// Initial check to see if the unlock content can be processed
if (
(context->currentFieldLength == sizeof(dataContext.unlockContext.data)) &&
(memcmp(context->workBuffer, UNLOCK_METHOD_ID, 4) == 0)) {
provisionType = PROVISION_UNLOCK;
}
// Initial check to see if the withdraw content can be processed
if (
(context->currentFieldLength == sizeof(dataContext.withdrawContext.data)) &&
(memcmp(context->workBuffer, WITHDRAW_METHOD_ID, 4) == 0)) {
provisionType = PROVISION_WITHDRAW;
}
// Initial check to see if the relock content can be processed
if (
(context->currentFieldLength == sizeof(dataContext.relockContext.data)) &&
(memcmp(context->workBuffer, RELOCK_METHOD_ID, 4) == 0)) {
provisionType = PROVISION_RELOCK;
}
// Initial check to see if the create account content can be processed
if (
(context->currentFieldLength == sizeof(dataContext.createAccountContext.data)) &&
(memcmp(context->workBuffer, CREATE_ACCOUNT_METHOD_ID, 4) == 0)) {
provisionType = PROVISION_CREATE_ACCOUNT;
}
}
if (tokenProvisioned) {
if (provisionType != PROVISION_NONE) {
if (context->currentFieldPos < context->currentFieldLength) {
uint32_t copySize = (context->commandLength <
((context->currentFieldLength -
context->currentFieldPos))
? context->commandLength
: context->currentFieldLength -
context->currentFieldPos);
copyTxData(context,
dataContext.tokenContext.data + context->currentFieldPos,
copySize);
switch (provisionType) {
case PROVISION_TOKEN:
copyTxData(context,
dataContext.tokenContext.data + context->currentFieldPos,
copySize);
break;
case PROVISION_LOCK:
copyTxData(context,
dataContext.lockContext.data + context->currentFieldPos,
copySize);
break;
case PROVISION_VOTE:
copyTxData(context,
dataContext.voteContext.data + context->currentFieldPos,
copySize);
break;
case PROVISION_ACTIVATE:
copyTxData(context,
dataContext.activateContext.data + context->currentFieldPos,
copySize);
break;
case PROVISION_REVOKE:
copyTxData(context,
dataContext.revokeContext.data + context->currentFieldPos,
copySize);
break;
case PROVISION_UNLOCK:
copyTxData(context,
dataContext.unlockContext.data + context->currentFieldPos,
copySize);
break;
case PROVISION_WITHDRAW:
copyTxData(context,
dataContext.withdrawContext.data + context->currentFieldPos,
copySize);
case PROVISION_RELOCK:
copyTxData(context,
dataContext.relockContext.data + context->currentFieldPos,
copySize);
case PROVISION_CREATE_ACCOUNT:
copyTxData(context,
dataContext.createAccountContext.data + context->currentFieldPos,
copySize);

break;
default:
break;
}
}
if (context->currentFieldPos == context->currentFieldLength) {
context->currentField++;
Expand Down Expand Up @@ -245,7 +359,7 @@ void finalizeParsing(bool direct) {
// Store the hash
cx_hash((cx_hash_t *)&sha3, CX_LAST, tmpCtx.transactionContext.hash, 0, tmpCtx.transactionContext.hash, 32);
// If there is a token to process, check if it is well known
if (tokenProvisioned) {
if (provisionType == PROVISION_TOKEN) {
tokenDefinition_t *currentToken = getKnownToken(tmpContent.txContent.destination);
if (currentToken != NULL) {
dataPresent = false;
Expand All @@ -256,8 +370,26 @@ void finalizeParsing(bool direct) {
memcpy(tmpContent.txContent.value.value, dataContext.tokenContext.data + 4 + 32, 32);
tmpContent.txContent.value.length = 32;
}
}
else {
} else if (provisionType == PROVISION_VOTE) {
tmpContent.txContent.destinationLength = 20;
memcpy(tmpContent.txContent.destination, dataContext.voteContext.data + 4 + 12, 20);
memcpy(tmpContent.txContent.value.value, dataContext.voteContext.data + 4 + 32, 32);
tmpContent.txContent.value.length = 32;
} else if (provisionType == PROVISION_ACTIVATE) {
tmpContent.txContent.destinationLength = 20;
memcpy(tmpContent.txContent.destination, dataContext.activateContext.data + 4 + 12, 20);
} else if (provisionType == PROVISION_REVOKE) {
tmpContent.txContent.destinationLength = 20;
memcpy(tmpContent.txContent.destination, dataContext.revokeContext.data + 4 + 12, 20);
memcpy(tmpContent.txContent.value.value, dataContext.revokeContext.data + 4 + 32, 32);
tmpContent.txContent.value.length = 32;
} else if (provisionType == PROVISION_UNLOCK) {
memcpy(tmpContent.txContent.value.value, dataContext.unlockContext.data + 4, 32);
tmpContent.txContent.value.length = 32;
} else if (provisionType == PROVISION_RELOCK) {
memcpy(tmpContent.txContent.value.value, dataContext.relockContext.data + 4 + 32, 32);
tmpContent.txContent.value.length = 32;
} else {
if (dataPresent && !N_storage.dataAllowed) {
reset_app_context();
PRINTF("Data field forbidden\n");
Expand Down Expand Up @@ -353,17 +485,81 @@ void finalizeParsing(bool direct) {
}
strings.common.maxFee[tickerOffset + i] = '\0';

switch (provisionType) {
case PROVISION_LOCK:
strcpy(strings.common.stakingType, "Lock");
break;
case PROVISION_VOTE:
strcpy(strings.common.stakingType, "Vote");
break;
case PROVISION_ACTIVATE:
strcpy(strings.common.stakingType, "Activate");
break;
case PROVISION_REVOKE:
strcpy(strings.common.stakingType, "Revoke");
break;
case PROVISION_UNLOCK:
strcpy(strings.common.stakingType, "Unlock");
break;
case PROVISION_WITHDRAW:
strcpy(strings.common.stakingType, "Withdraw");
break;
case PROVISION_RELOCK:
strcpy(strings.common.stakingType, "Relock");
break;
case PROVISION_CREATE_ACCOUNT:
strcpy(strings.common.stakingType, "Create Account");
break;
default:
break;
}

#ifdef NO_CONSENT
io_seproxyhal_touch_tx_ok(NULL);
#else // NO_CONSENT
if (tmpContent.txContent.gatewayDestinationLength != 0) {
ux_flow_init(0,
((dataPresent && !N_storage.contractDetails) ? ux_approval_celo_data_warning_gateway_tx_flow : ux_approval_celo_gateway_tx_flow),
NULL);
} else {
ux_flow_init(0,
((dataPresent && !N_storage.contractDetails) ? ux_approval_celo_data_warning_tx_flow : ux_approval_celo_tx_flow),
NULL);
switch(provisionType) {
case PROVISION_LOCK:
case PROVISION_UNLOCK:
ux_flow_init(0,
ux_approval_celo_lock_unlock_flow,
NULL);
break;
case PROVISION_WITHDRAW:
ux_flow_init(0,
ux_approval_celo_withdraw_flow,
NULL);
break;
case PROVISION_VOTE:
case PROVISION_REVOKE:
ux_flow_init(0,
ux_approval_celo_vote_revoke_flow,
NULL);
break;
case PROVISION_ACTIVATE:
ux_flow_init(0,
ux_approval_celo_activate_flow,
NULL);
break;
case PROVISION_RELOCK:
ux_flow_init(0,
ux_approval_celo_relock_flow,
NULL);
break;
case PROVISION_CREATE_ACCOUNT:
ux_flow_init(0,
ux_approval_celo_create_account_flow,
NULL);
break;
default:
if (tmpContent.txContent.gatewayDestinationLength != 0) {
ux_flow_init(0,
((dataPresent && !N_storage.contractDetails) ? ux_approval_celo_data_warning_gateway_tx_flow : ux_approval_celo_gateway_tx_flow),
NULL);
} else {
ux_flow_init(0,
((dataPresent && !N_storage.contractDetails) ? ux_approval_celo_data_warning_tx_flow : ux_approval_celo_tx_flow),
NULL);
}
}
#endif // NO_CONSENT
}
}
4 changes: 2 additions & 2 deletions src/celo.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ void reset_app_context();
tokenDefinition_t* getKnownToken(uint8_t *tokenAddr);

customStatus_e customProcessor(txContext_t *context);
void initTx(txContext_t *context, cx_sha3_t *sha3, txContent_t *content, ustreamProcess_t customProcessor, bool isEthereum, void *extra);
void initTx(txContext_t *context, cx_sha3_t *sha3, txContent_t *content, ustreamProcess_t customProcessor, void *extra);
void finalizeParsing(bool direct);

// TODO: this should not be exposed
Expand All @@ -22,4 +22,4 @@ typedef enum {
APP_STATE_SIGNING_MESSAGE
} app_state_t;

extern volatile uint8_t appState;
extern volatile uint8_t appState;
56 changes: 55 additions & 1 deletion src/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ typedef struct strData_t {
char fullAmount[50];
char maxFee[50];
char gatewayFee[50];
char stakingType[20];
} strData_t;

typedef struct strDataTmp_t {
Expand Down Expand Up @@ -92,12 +93,57 @@ extern const internalStorage_t N_storage_real;
extern char addressSummary[32];
extern cx_sha3_t sha3;

extern volatile bool tokenProvisioned;
typedef enum {
PROVISION_NONE,
PROVISION_TOKEN,
PROVISION_LOCK,
PROVISION_VOTE,
PROVISION_ACTIVATE,
PROVISION_REVOKE,
PROVISION_UNLOCK,
PROVISION_WITHDRAW,
PROVISION_RELOCK,
PROVISION_CREATE_ACCOUNT
} provision_type_t;

extern volatile provision_type_t provisionType;

typedef struct tokenContext_t {
uint8_t data[4 + 32 + 32];
} tokenContext_t;

typedef struct lockContext_t {
uint8_t data[4];
} lockContext_t;

typedef struct voteContext_t {
uint8_t data[4 + 32 + 32 + 32 + 32];
} voteContext_t;

typedef struct activateContext_t {
uint8_t data[4 + 32];
} activateContext_t;

typedef struct revokeContext_t {
uint8_t data[4 + 32 + 32 + 32 + 32 + 32];
} revokeContext_t;

typedef struct unlockContext_t {
uint8_t data[4 + 32];
} unlockContext_t;

typedef struct withdrawContext_t {
uint8_t data[4 + 32];
} withdrawContext_t;

typedef struct relockContext_t {
uint8_t data[4 + 32 + 32];
} relockContext_t;

typedef struct createAccountContext_t {
uint8_t data[4];
} createAccountContext_t;

typedef struct rawDataContext_t {
uint8_t data[32];
uint8_t fieldIndex;
Expand All @@ -106,6 +152,14 @@ typedef struct rawDataContext_t {

typedef union {
tokenContext_t tokenContext;
lockContext_t lockContext;
voteContext_t voteContext;
activateContext_t activateContext;
revokeContext_t revokeContext;
unlockContext_t unlockContext;
withdrawContext_t withdrawContext;
relockContext_t relockContext;
createAccountContext_t createAccountContext;
rawDataContext_t rawDataContext;
} dataContext_t;

Expand Down
Loading

0 comments on commit bd6cd40

Please sign in to comment.