From af6c1022b710806688506e653221e04b68b23c5a Mon Sep 17 00:00:00 2001 From: "pwnh4 (@loicttn)" Date: Mon, 9 Dec 2024 19:03:50 +0100 Subject: [PATCH] fix(ocv2): parameters validation issue --- src/contracts.c | 5 + src/handle_init_contract.c | 6 + src/kiln_plugin.h | 60 ++++- .../handle_provide_parameter.c | 6 +- src/provide_parameter/ocv2.c | 249 ++++++++++++++++++ src/provide_parameter/provide_parameter.h | 4 + tests/src/multiClaim.v2.test.js | 5 +- 7 files changed, 332 insertions(+), 3 deletions(-) create mode 100644 src/provide_parameter/ocv2.c diff --git a/src/contracts.c b/src/contracts.c index ae42509..01bf5ce 100644 --- a/src/contracts.c +++ b/src/contracts.c @@ -56,6 +56,11 @@ static const uint32_t KILN_LR_DELEGATE_TO_SELECTOR = 0xeea9064b; // --- cast sig "undelegate(address)" static const uint32_t KILN_LR_UNDELEGATE_SELECTOR = 0xda8be864; +const char ocv2_exit_queues[OCV2_MAX_EXIT_QUEUES][ADDRESS_STR_LEN] = { + "0x8d6Fd650500f82c7D978a440348e5a9b886943bF", // Kiln + "0x86358F7B33b599c484e0335B8Ee4f7f7f92d8b60" // Coinbase +}; + const char lr_strategy_addresses[LR_STRATEGIES_COUNT][ADDRESS_STR_LEN] = { "0x54945180dB7943c0ed0FEE7EdaB2Bd24620256bc", // cbETH "0x93c4b944D05dfe6df7645A86cd2206016c51564D", // stETH diff --git a/src/handle_init_contract.c b/src/handle_init_contract.c index 1ac485b..634cdee 100644 --- a/src/handle_init_contract.c +++ b/src/handle_init_contract.c @@ -61,9 +61,15 @@ void handle_init_contract(ethPluginInitContract_t *msg) { break; case KILN_V2_STAKE: + break; case KILN_V2_REQUEST_EXIT: + context->next_param = V2_REQUEST_EXIT_AMOUNT; + break; case KILN_V2_MULTICLAIM: + context->next_param = V2_MULTICLAIM_EXIT_QUEUES_OFFSET; + break; case KILN_V2_CLAIM: + context->next_param = V2_CLAIM_TICKET_IDS_OFFSET; break; case KILN_LR_DEPOSIT_INTO_STRATEGY: diff --git a/src/kiln_plugin.h b/src/kiln_plugin.h index 7aa35cc..17a41ae 100644 --- a/src/kiln_plugin.h +++ b/src/kiln_plugin.h @@ -92,7 +92,9 @@ typedef enum { #define MAX_DISPLAYABLE_LR_STRATEGIES_COUNT 32 // must be > LR_STRATEGIES_COUNT #define ERC20_DECIMALS 18 #define PARAM_OFFSET 32 +#define OCV2_MAX_EXIT_QUEUES 2 +extern const char ocv2_exit_queues[OCV2_MAX_EXIT_QUEUES][ADDRESS_STR_LEN]; extern const char lr_strategy_addresses[LR_STRATEGIES_COUNT][ADDRESS_STR_LEN]; extern const char lr_erc20_addresses[LR_STRATEGIES_COUNT][ADDRESS_STR_LEN]; extern const char lr_tickers[LR_STRATEGIES_COUNT][MAX_TICKER_LEN]; @@ -100,6 +102,44 @@ extern const char lr_kiln_operator_address[ADDRESS_STR_LEN]; // **************************************************************************** +// Parameters and state machines for OCV2 parsing + +typedef enum { + V2_REQUEST_EXIT_UNEXPECTED_PARAMETER = 0, + V2_REQUEST_EXIT_AMOUNT, +} v2_request_exit_parameters; + +typedef enum { + V2_CLAIM_UNEXPECTED_PARAMETER = 0, + V2_CLAIM_TICKET_IDS_OFFSET, + V2_CLAIM_CASK_IDS_OFFSET, + V2_CLAIM_MAX_CLAIM_DEPTH, + V2_CLAIM_TICKET_IDS_LENGTH, + V2_CLAIM_TICKET_IDS__ITEMS, + V2_CLAIM_CASK_IDS_LENGTH, + V2_CLAIM_CASK_IDS__ITEMS, +} v2_claim; + +typedef enum { + V2_MULTICLAIM_UNEXPECTED_PARAMETER = 0, + V2_MULTICLAIM_EXIT_QUEUES_OFFSET, + V2_MULTICLAIM_TICKET_IDS_OFFSET, + V2_MULTICLAIM_CASK_IDS_OFFSET, + + V2_MULTICLAIM_EXIT_QUEUES_LENGTH, + V2_MULTICLAIM_EXIT_QUEUES__ITEMS, + + V2_MULTICLAIM_TICKETIDS_LENGTH, + V2_MULTICLAIM_TICKETIDS__OFFSET_ITEMS, + V2_MULTICLAIM_TICKETIDS__ITEM_LENGTH, + V2_MULTICLAIM_TICKETIDS__ITEM__ITEMS, + + V2_MULTICLAIM_CASKIDS_LENGTH, + V2_MULTICLAIM_CASKIDS__OFFSET_ITEMS, + V2_MULTICLAIM_CASKIDS__ITEM_LENGTH, + V2_MULTICLAIM_CASKIDS__ITEM__ITEMS, +} v2_multiclaim_parameters; + // Parameters and state machines for EigenLayer parsing typedef enum { @@ -173,6 +213,21 @@ typedef enum { // Parsing structures +typedef struct { + uint8_t amount[INT256_LENGTH]; +} v2_request_exit_t; + +typedef struct { + // -- utils + uint16_t current_item_count; +} v2_claim_t; + +typedef struct { + // -- utils + uint16_t parent_item_count; + uint16_t current_item_count; +} v2_multiclaim_t; + typedef struct { int strategy_to_display; int erc20_to_display; @@ -254,12 +309,15 @@ typedef struct { // **************************************************************************** // * SHARED PLUGIN CONTEXT MEMORY // **************************************************************************** -// [100] receiveAsTokens_offset typedef struct context_t { uint8_t next_param; union { + v2_request_exit_t v2_request_exit; + v2_claim_t v2_claim; + v2_multiclaim_t v2_multiclaim; + lr_deposit_t lr_deposit; lr_delegate_to_t lr_delegate_to; lr_queue_withdrawals_t lr_queue_withdrawals; diff --git a/src/provide_parameter/handle_provide_parameter.c b/src/provide_parameter/handle_provide_parameter.c index f514469..7a1bf0d 100644 --- a/src/provide_parameter/handle_provide_parameter.c +++ b/src/provide_parameter/handle_provide_parameter.c @@ -47,9 +47,13 @@ void handle_provide_parameter(ethPluginProvideParameter_t *msg) { msg->result = ETH_PLUGIN_RESULT_ERROR; break; case KILN_V2_REQUEST_EXIT: + handle_v2_request_exit(msg, context); + break; case KILN_V2_MULTICLAIM: + handle_v2_multiclaim(msg, context); + break; case KILN_V2_CLAIM: - msg->result = ETH_PLUGIN_RESULT_OK; + handle_v2_claim(msg, context); break; case KILN_LR_DEPOSIT_INTO_STRATEGY: diff --git a/src/provide_parameter/ocv2.c b/src/provide_parameter/ocv2.c new file mode 100644 index 0000000..6976603 --- /dev/null +++ b/src/provide_parameter/ocv2.c @@ -0,0 +1,249 @@ +/******************************************************************************* + * + * ██╗ ██╗██╗██╗ ███╗ ██╗ + * ██║ ██╔╝██║██║ ████╗ ██║ + * █████╔╝ ██║██║ ██╔██╗ ██║ + * ██╔═██╗ ██║██║ ██║╚██╗██║ + * ██║ ██╗██║███████╗██║ ╚████║ + * ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ + * + * Kiln Ethereum Ledger App + * (c) 2022-2024 Kiln + * + * contact@kiln.fi + ********************************************************************************/ + +#include "provide_parameter.h" + +void handle_v2_request_exit(ethPluginProvideParameter_t *msg, context_t *context) { + // ************************************************************************** + // FUNCTION TO PARSE + // ************************************************************************** + // + // function requestExit( + // uint256 amount + // ) external + // + // ************************************************************************** + // example + // [ 0] selector + // [ 4] amount + + v2_request_exit_t *params = &context->param_data.v2_request_exit; + + switch (context->next_param) { + case V2_REQUEST_EXIT_AMOUNT: + copy_parameter(params->amount, msg->parameter, sizeof(params->amount)); + context->next_param = V2_REQUEST_EXIT_UNEXPECTED_PARAMETER; + break; + default: + PRINTF("Param not supported: %d\n", context->next_param); + msg->result = ETH_PLUGIN_RESULT_ERROR; + return; + } + msg->result = ETH_PLUGIN_RESULT_OK; +} + +void handle_v2_claim(ethPluginProvideParameter_t *msg, context_t *context) { + // ************************************************************************** + // FUNCTION TO PARSE + // ************************************************************************** + // + // function claim( + // uint256[] ticketIds, + // uint32[] caskIds, + // uint16 maxClaimDepth + // ) + // + // ************************************************************************** + // example for 2 tickets and 3 cask ids + // [ 0] selector + // [ 4] ticketIds_offset + // [ 36] caskIds_offset + // [ 68] maxClaimDepth + // [100] ticketIds_length + // [132] ticketIds_0 + // [164] ticketIds_1 + // [196] caskIds_length + // [228] caskIds_0 + // [260] caskIds_1 + // [292] caskIds_2 + + v2_claim_t *params = &context->param_data.v2_claim; + + switch (context->next_param) { + case V2_CLAIM_TICKET_IDS_OFFSET: + context->next_param = V2_CLAIM_CASK_IDS_OFFSET; + break; + case V2_CLAIM_CASK_IDS_OFFSET: + context->next_param = V2_CLAIM_MAX_CLAIM_DEPTH; + break; + case V2_CLAIM_MAX_CLAIM_DEPTH: + context->next_param = V2_CLAIM_TICKET_IDS_LENGTH; + break; + case V2_CLAIM_TICKET_IDS_LENGTH: + U2BE_from_parameter(msg->parameter, ¶ms->current_item_count); + context->next_param = V2_CLAIM_TICKET_IDS__ITEMS; + break; + case V2_CLAIM_TICKET_IDS__ITEMS: + params->current_item_count -= 1; + if (params->current_item_count == 0) { + context->next_param = V2_CLAIM_CASK_IDS_LENGTH; + } + break; + case V2_CLAIM_CASK_IDS_LENGTH: + U2BE_from_parameter(msg->parameter, ¶ms->current_item_count); + context->next_param = V2_CLAIM_CASK_IDS__ITEMS; + break; + case V2_CLAIM_CASK_IDS__ITEMS: + params->current_item_count -= 1; + if (params->current_item_count == 0) { + context->next_param = V2_CLAIM_UNEXPECTED_PARAMETER; + } + break; + default: + PRINTF("Param not supported: %d\n", context->next_param); + msg->result = ETH_PLUGIN_RESULT_ERROR; + return; + } +} + +void handle_v2_multiclaim(ethPluginProvideParameter_t *msg, context_t *context) { + // ************************************************************************** + // FUNCTION TO PARSE + // ************************************************************************** + // + // function multiClaim( + // address[] exitQueues, + // uint256[][] ticketIds, + // uint32[][] casksIds + // ) + // + // ************************************************************************** + // example for 2 exit queues, 4 tickets and 4 cask ids + // [ 0] selector + // [ 4] exitQueues_offset + // [ 36] ticketIds_offset + // [ 68] caskIds_offset + // [100] exitQueues_length + // [132] exitQueues_0 + // [164] exitQueues_1 + // [196] ticketIds_length + // [228] ticketIds_0_offset + // [260] ticketIds_1_offset + // [292] ticketIds_0_length + // [324] ticketIds_0_0 + // [356] ticketIds_0_1 + // [388] ticketIds_1_length + // [420] ticketIds_1_0 + // [452] ticketIds_1_1 + // [484] caskIds_length + // [516] caskIds_0_offset + // [548] caskIds_1_offset + // [580] caskIds_0_length + // [612] caskIds_0_0 + // [644] caskIds_0_1 + // [676] caskIds_1_length + // [708] caskIds_1_0 + // [740] caskIds_1_1 + + v2_multiclaim_t *params = &context->param_data.v2_multiclaim; + + switch (context->next_param) { + case V2_MULTICLAIM_EXIT_QUEUES_OFFSET: + context->next_param = V2_MULTICLAIM_TICKET_IDS_OFFSET; + break; + case V2_MULTICLAIM_TICKET_IDS_OFFSET: + context->next_param = V2_MULTICLAIM_CASK_IDS_OFFSET; + break; + case V2_MULTICLAIM_CASK_IDS_OFFSET: + context->next_param = V2_MULTICLAIM_EXIT_QUEUES_LENGTH; + break; + case V2_MULTICLAIM_EXIT_QUEUES_LENGTH: + U2BE_from_parameter(msg->parameter, ¶ms->current_item_count); + context->next_param = V2_MULTICLAIM_EXIT_QUEUES__ITEMS; + break; + case V2_MULTICLAIM_EXIT_QUEUES__ITEMS: { + uint8_t buffer[ADDRESS_LENGTH]; + copy_address(buffer, msg->parameter, sizeof(buffer)); + char address_buffer[ADDRESS_STR_LEN]; + getEthDisplayableAddress(buffer, address_buffer, sizeof(address_buffer), 0); + // we add a check to make sure we know the exit queue addresses + // that will be called in the multiclaim tx + bool is_valid = false; + for (int i = 0; i < OCV2_MAX_EXIT_QUEUES; i += 1) { + if (memcmp(ocv2_exit_queues[i], address_buffer, ADDRESS_STR_LEN) == 0) { + is_valid = true; + break; + } + } + if (!is_valid) { + PRINTF("Unexpected exit queue address: %s\n", address_buffer); + msg->result = ETH_PLUGIN_RESULT_ERROR; + return; + } + + params->current_item_count -= 1; + if (params->current_item_count == 0) { + context->next_param = V2_MULTICLAIM_TICKETIDS_LENGTH; + } + break; + } + case V2_MULTICLAIM_TICKETIDS_LENGTH: + U2BE_from_parameter(msg->parameter, ¶ms->parent_item_count); + params->current_item_count = params->parent_item_count; + context->next_param = V2_MULTICLAIM_TICKETIDS__OFFSET_ITEMS; + break; + case V2_MULTICLAIM_TICKETIDS__OFFSET_ITEMS: + params->current_item_count -= 1; + if (params->current_item_count == 0) { + context->next_param = V2_MULTICLAIM_TICKETIDS__ITEM_LENGTH; + } + break; + case V2_MULTICLAIM_TICKETIDS__ITEM_LENGTH: + U2BE_from_parameter(msg->parameter, ¶ms->current_item_count); + context->next_param = V2_MULTICLAIM_TICKETIDS__ITEM__ITEMS; + break; + case V2_MULTICLAIM_TICKETIDS__ITEM__ITEMS: + params->current_item_count -= 1; + if (params->current_item_count == 0) { + params->parent_item_count -= 1; + if (params->parent_item_count == 0) { + context->next_param = V2_MULTICLAIM_CASKIDS_LENGTH; + } else { + context->next_param = V2_MULTICLAIM_TICKETIDS__ITEM_LENGTH; + } + } + break; + case V2_MULTICLAIM_CASKIDS_LENGTH: + U2BE_from_parameter(msg->parameter, ¶ms->parent_item_count); + params->current_item_count = params->parent_item_count; + context->next_param = V2_MULTICLAIM_CASKIDS__OFFSET_ITEMS; + break; + case V2_MULTICLAIM_CASKIDS__OFFSET_ITEMS: + params->current_item_count -= 1; + if (params->current_item_count == 0) { + context->next_param = V2_MULTICLAIM_CASKIDS__ITEM_LENGTH; + } + break; + case V2_MULTICLAIM_CASKIDS__ITEM_LENGTH: + U2BE_from_parameter(msg->parameter, ¶ms->current_item_count); + context->next_param = V2_MULTICLAIM_CASKIDS__ITEM__ITEMS; + break; + case V2_MULTICLAIM_CASKIDS__ITEM__ITEMS: + params->current_item_count -= 1; + if (params->current_item_count == 0) { + if (params->parent_item_count == 0) { + context->next_param = V2_MULTICLAIM_UNEXPECTED_PARAMETER; + } else { + context->next_param = V2_MULTICLAIM_CASKIDS__ITEM_LENGTH; + } + } + break; + default: + PRINTF("Param not supported: %d\n", context->next_param); + msg->result = ETH_PLUGIN_RESULT_ERROR; + return; + } + msg->result = ETH_PLUGIN_RESULT_OK; +} \ No newline at end of file diff --git a/src/provide_parameter/provide_parameter.h b/src/provide_parameter/provide_parameter.h index 6ac5634..9e9da7b 100644 --- a/src/provide_parameter/provide_parameter.h +++ b/src/provide_parameter/provide_parameter.h @@ -20,6 +20,10 @@ #include "kiln_plugin.h" +void handle_v2_request_exit(ethPluginProvideParameter_t *msg, context_t *context); +void handle_v2_claim(ethPluginProvideParameter_t *msg, context_t *context); +void handle_v2_multiclaim(ethPluginProvideParameter_t *msg, context_t *context); + void handle_lr_deposit_into_strategy(ethPluginProvideParameter_t *msg, context_t *context); void handle_lr_queue_withdrawals(ethPluginProvideParameter_t *msg, context_t *context); void handle_lr_complete_queued_withdrawals(ethPluginProvideParameter_t *msg, context_t *context); diff --git a/tests/src/multiClaim.v2.test.js b/tests/src/multiClaim.v2.test.js index dec6373..a210101 100644 --- a/tests/src/multiClaim.v2.test.js +++ b/tests/src/multiClaim.v2.test.js @@ -18,7 +18,10 @@ nano_models.forEach(function (model) { const contract = new ethers.Contract(contractAddr, abi); const { data } = await contract.populateTransaction.multiClaim( - ['0x5db5235b5c7e247488784986e58019fffd98fda4'], + [ + '0x8d6Fd650500f82c7D978a440348e5a9b886943bF', + '0x86358F7B33b599c484e0335B8Ee4f7f7f92d8b60', + ], [ [42, 47], [150, 2],