Skip to content

Commit

Permalink
Add support for governor contract (#14)
Browse files Browse the repository at this point in the history
* 🌱 Implement selectors for governor contract

 - Also add a unit tests

* 🌱 Update to support the propose method

 - Also update the unit test and generate new snapshots

---------

Co-authored-by: hatef <[email protected]>
  • Loading branch information
nagdahimanshu and hrmhatef authored May 30, 2024
1 parent 6243802 commit 9e77462
Show file tree
Hide file tree
Showing 151 changed files with 2,385 additions and 1 deletion.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_STAX TARGET_FLEX))
DEFINES += ICONBITMAP=C_stax_$(NORMAL_NAME)_64px_bitmap
endif

DEFINES += HAVE_SPRINTF

CURVE_APP_LOAD_PARAMS = secp256k1
PATH_APP_LOAD_PARAMS = "44'/134'"

Expand Down
9 changes: 9 additions & 0 deletions src/handle_finalize.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ void handle_finalize(ethPluginFinalize_t *msg) {
case REWARD_EXTEND_DURATION:
msg->numScreens = context->lisk.body.rewardIncLockingAmount.len * 2;
break;
case GOVERNOR_CAST_VOTE:
msg->numScreens = 2;
break;
case GOVERNOR_CAST_VOTE_WITH_REASON:
msg->numScreens = 3;
break;
case GOVERNOR_PROPOSE:
msg->numScreens = context->lisk.body.governorPropose.target_len * 2;
break;
default:
msg->result = ETH_PLUGIN_RESULT_ERROR;
return;
Expand Down
5 changes: 5 additions & 0 deletions src/handle_init_contract.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,16 @@ void handle_init_contract(ethPluginInitContract_t *msg) {
case REWARD_INC_LOCKING_AMOUNT:
case REWARD_EXTEND_DURATION:
case REWARD_DELETE_POSITIONS:
case GOVERNOR_PROPOSE:
context->next_param = OFFSET;
break;
case CLAIM_AIRDROP:
context->next_param = LSK_ADDRESS;
break;
case GOVERNOR_CAST_VOTE:
case GOVERNOR_CAST_VOTE_WITH_REASON:
context->next_param = PROPOSAL_ID;
break;
// Keep this
default:
PRINTF("Missing selectorIndex: %d\n", context->selectorIndex);
Expand Down
172 changes: 172 additions & 0 deletions src/handle_provide_parameter.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
#include "plugin.h"

uint16_t max_counter = 0;
uint16_t counter = 0;

static void copy_text(uint8_t *dst, uint16_t dst_len, uint16_t max_len, uint8_t *src) {
size_t len = MIN(dst_len, max_len);
memcpy(dst, src, len);
}

static void handle_claim_regular_account(ethPluginProvideParameter_t *msg, context_t *context) {
switch (context->next_param) {
case PROOF: // _proof
Expand Down Expand Up @@ -271,6 +277,163 @@ static void handle_claim_airdrop(ethPluginProvideParameter_t *msg, context_t *co
}
}

static void handle_governor_cast_vote(ethPluginProvideParameter_t *msg, context_t *context) {
switch (context->next_param) {
case PROPOSAL_ID: // proposalId
copy_parameter(context->lisk.body.governor.proposal_id, msg->parameter, INT256_LENGTH);
context->next_param = SUPPORT;
break;
case SUPPORT: // support
copy_parameter(context->lisk.body.governor.support,
msg->parameter,
sizeof(context->lisk.body.governor.support));
context->next_param = NONE;
break;
case NONE:
break;
default:
PRINTF("Param not supported: %d\n", context->next_param);
msg->result = ETH_PLUGIN_RESULT_ERROR;
break;
}
}

static void handle_governor_cast_vote_with_reason(ethPluginProvideParameter_t *msg,
context_t *context) {
uint16_t tmp;
switch (context->next_param) {
case PROPOSAL_ID: // proposalId
copy_parameter(context->lisk.body.governor.proposal_id, msg->parameter, INT256_LENGTH);
context->next_param = SUPPORT;
break;
case SUPPORT: // support
copy_parameter(context->lisk.body.governor.support,
msg->parameter,
sizeof(context->lisk.body.governor.support));
context->next_param = OFFSET;
break;
case OFFSET:
context->next_param = REASON_LENGTH;
break;
case REASON_LENGTH: // reason
if (!U2BE_from_parameter(msg->parameter, &tmp)) {
msg->result = ETH_PLUGIN_RESULT_ERROR;
return;
}

context->lisk.body.governor.reason.len = tmp;
if (context->lisk.body.governor.reason.len % PARAMETER_LENGTH != 0) {
counter = context->lisk.body.governor.reason.len / PARAMETER_LENGTH + 1;
} else {
counter = context->lisk.body.governor.reason.len / PARAMETER_LENGTH;
}

max_counter = counter;
context->next_param = REASON;
break;
case REASON:
if (counter == max_counter) {
copy_text(context->lisk.body.governor.reason.value,
context->lisk.body.governor.reason.len,
PARAMETER_LENGTH,
(uint8_t *) msg->parameter);
}

counter--;
if (counter == 0) {
context->next_param = NONE;
}
break;
case NONE:
break;
default:
PRINTF("Param not supported: %d\n", context->next_param);
msg->result = ETH_PLUGIN_RESULT_ERROR;
break;
}
}

static void handle_governor_propose(ethPluginProvideParameter_t *msg, context_t *context) {
if (context->go_to_offset) {
if (msg->parameterOffset != context->offset + SELECTOR_SIZE) {
return;
}
context->go_to_offset = false;
}

switch (context->next_param) {
case OFFSET:
context->offset = U2BE(msg->parameter, PARAMETER_LENGTH - sizeof(context->offset));
context->go_to_offset = true;
context->next_param = PROPOSE_TARGET_LEN;
break;
case PROPOSE_TARGET_LEN:
if (!U2BE_from_parameter(msg->parameter,
&context->lisk.body.governorPropose.target_len) ||
context->lisk.body.governorPropose.target_len > 2 ||
context->lisk.body.governorPropose.target_len == 0) {
msg->result = ETH_PLUGIN_RESULT_ERROR;
}

context->offset = msg->parameterOffset - SELECTOR_SIZE + PARAMETER_LENGTH;
context->go_to_offset = true;
context->next_param = TARGET_ADDRESS;
break;
case TARGET_ADDRESS:
copy_address(context->lisk.body.governorPropose.targets[counter].value,
msg->parameter,
sizeof(context->lisk.body.governorPropose.targets[counter].value));
if (counter + 1 < context->lisk.body.governorPropose.target_len) {
counter++;
context->next_param = SECOND_TARGET_ADDRESS;
} else {
context->next_param = PROPOSE_VALUE_LEN;
}
break;
case SECOND_TARGET_ADDRESS:
copy_address(context->lisk.body.governorPropose.targets[counter].value,
msg->parameter,
sizeof(context->lisk.body.governorPropose.targets[counter].value));
counter = 0;
context->next_param = PROPOSE_VALUE_LEN;
break;
case PROPOSE_VALUE_LEN:
if (!U2BE_from_parameter(msg->parameter,
&context->lisk.body.governorPropose.value_len) ||
context->lisk.body.governorPropose.value_len > 2 ||
context->lisk.body.governorPropose.value_len == 0 ||
context->lisk.body.governorPropose.target_len !=
context->lisk.body.governorPropose.value_len) {
msg->result = ETH_PLUGIN_RESULT_ERROR;
}
context->next_param = VALUE;
break;
case VALUE:
copy_parameter(context->lisk.body.governorPropose.values[counter].value,
msg->parameter,
INT256_LENGTH);
if (counter + 1 < context->lisk.body.governorPropose.value_len) {
counter++;
context->next_param = SECOND_VALUE;
} else {
context->next_param = NONE;
}
break;
case SECOND_VALUE:
copy_parameter(context->lisk.body.governorPropose.values[counter].value,
msg->parameter,
INT256_LENGTH);
context->next_param = NONE;
break;
case NONE:
break;
default:
PRINTF("Param not supported: %d\n", context->next_param);
msg->result = ETH_PLUGIN_RESULT_ERROR;
break;
}
}

void handle_provide_parameter(ethPluginProvideParameter_t *msg) {
context_t *context = (context_t *) msg->pluginContext;
// We use `%.*H`: it's a utility function to print bytes. You first give
Expand Down Expand Up @@ -314,6 +477,15 @@ void handle_provide_parameter(ethPluginProvideParameter_t *msg) {
case CLAIM_AIRDROP:
handle_claim_airdrop(msg, context);
break;
case GOVERNOR_CAST_VOTE:
handle_governor_cast_vote(msg, context);
break;
case GOVERNOR_CAST_VOTE_WITH_REASON:
handle_governor_cast_vote_with_reason(msg, context);
break;
case GOVERNOR_PROPOSE:
handle_governor_propose(msg, context);
break;
default:
PRINTF("Selector Index not supported: %d\n", context->selectorIndex);
msg->result = ETH_PLUGIN_RESULT_ERROR;
Expand Down
7 changes: 7 additions & 0 deletions src/handle_query_contract_id.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ void handle_query_contract_id(ethQueryContractID_t *msg) {
} else if (context->selectorIndex == CLAIM_AIRDROP) {
strlcpy(msg->version, "Claim Airdrop", msg->versionLength);
msg->result = ETH_PLUGIN_RESULT_OK;
} else if (context->selectorIndex == GOVERNOR_CAST_VOTE ||
context->selectorIndex == GOVERNOR_CAST_VOTE_WITH_REASON) {
strlcpy(msg->version, "Cast Vote", msg->versionLength);
msg->result = ETH_PLUGIN_RESULT_OK;
} else if (context->selectorIndex == GOVERNOR_PROPOSE) {
strlcpy(msg->version, "Propose", msg->versionLength);
msg->result = ETH_PLUGIN_RESULT_OK;
} else {
PRINTF("Selector index: %d not supported\n", context->selectorIndex);
msg->result = ETH_PLUGIN_RESULT_ERROR;
Expand Down
94 changes: 94 additions & 0 deletions src/handle_query_contract_ui.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <stdio.h>
#include "plugin.h"

static bool set_bytes_to_hex(char *msg, size_t msgLen, const uint8_t *value, uint16_t valueLen) {
Expand Down Expand Up @@ -167,6 +168,54 @@ static bool set_unused_delay_ui(ethQueryContractUI_t *msg, context_t *context) {
msg->msgLength);
}

// Set UI for "Proposal ID" screen.
static bool set_proposal_id_ui(ethQueryContractUI_t *msg, context_t *context) {
strlcpy(msg->title, "Proposal ID", msg->titleLength);
return uint256_to_decimal(context->lisk.body.governor.proposal_id,
INT256_LENGTH,
msg->msg,
msg->msgLength);
}

// Set UI for "Support" screen.
static bool set_support_ui(ethQueryContractUI_t *msg, context_t *context) {
strlcpy(msg->title, "Support", msg->titleLength);
return uint256_to_decimal(context->lisk.body.governor.support,
sizeof(context->lisk.body.governor.support),
msg->msg,
msg->msgLength);
}

static bool set_reason_ui(ethQueryContractUI_t *msg, string_uint8_t *reason) {
strlcpy(msg->title, "Reason", msg->titleLength);
snprintf(msg->msg, msg->msgLength, "%s", reason->value);
return true;
}

// Set UI for "Target Address" screen.
static bool set_target_ui(ethQueryContractUI_t *msg, arr_address_t *target) {
strlcpy(msg->title, "Target Address", msg->titleLength);

// Prefix the address with `0x`.
msg->msg[0] = '0';
msg->msg[1] = 'x';

// We need a random chainID for legacy reasons with `getEthAddressStringFromBinary`.
// Setting it to `0` will make it work with every chainID :)
uint64_t chainid = 0;

return getEthAddressStringFromBinary(
target->value,
msg->msg + 2, // +2 here because we've already prefixed with '0x'.
chainid);
}

// Set UI for "Value" screen.
static bool set_value_ui(ethQueryContractUI_t *msg, arr_uint8_t *value) {
strlcpy(msg->title, "Value", msg->titleLength);
return uint256_to_decimal(value->value, INT256_LENGTH, msg->msg, msg->msgLength);
}

void handle_query_contract_ui(ethQueryContractUI_t *msg) {
context_t *context = (context_t *) msg->pluginContext;
bool ret = false;
Expand Down Expand Up @@ -301,6 +350,51 @@ void handle_query_contract_ui(ethQueryContractUI_t *msg) {
PRINTF("Received an invalid screenIndex\n");
}
break;
case GOVERNOR_CAST_VOTE:
switch (msg->screenIndex) {
case 0:
ret = set_proposal_id_ui(msg, context);
break;
case 1:
ret = set_support_ui(msg, context);
break;
default:
PRINTF("Received an invalid screenIndex\n");
}
break;
case GOVERNOR_CAST_VOTE_WITH_REASON:
switch (msg->screenIndex) {
case 0:
ret = set_proposal_id_ui(msg, context);
break;
case 1:
ret = set_support_ui(msg, context);
break;
case 2:
ret = set_reason_ui(msg, &context->lisk.body.governor.reason);
break;
default:
PRINTF("Received an invalid screenIndex\n");
}
break;
case GOVERNOR_PROPOSE:
switch (msg->screenIndex) {
case 0:
ret = set_target_ui(msg, &context->lisk.body.governorPropose.targets[0]);
break;
case 1:
ret = set_value_ui(msg, &context->lisk.body.governorPropose.values[0]);
break;
case 2:
ret = set_target_ui(msg, &context->lisk.body.governorPropose.targets[1]);
break;
case 3:
ret = set_value_ui(msg, &context->lisk.body.governorPropose.values[1]);
break;
default:
PRINTF("Received an invalid screenIndex\n");
}
break;
default:
PRINTF("Selector index: %d not supported\n", context->selectorIndex);
}
Expand Down
Loading

0 comments on commit 9e77462

Please sign in to comment.