diff --git a/.github/workflows/cflite_cron.yml b/.github/workflows/cflite_cron.yml
new file mode 100644
index 00000000..44ac10c2
--- /dev/null
+++ b/.github/workflows/cflite_cron.yml
@@ -0,0 +1,41 @@
+name: ClusterFuzzLite cron tasks
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - main # Use your actual default branch here.
+ schedule:
+ - cron: '0 13 * * 6' # At 01:00 PM, only on Saturday
+permissions: read-all
+jobs:
+ Fuzzing:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - mode: batch
+ sanitizer: address
+ - mode: batch
+ sanitizer: memory
+ - mode: prune
+ sanitizer: address
+ - mode: coverage
+ sanitizer: coverage
+ steps:
+ - name: Build Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }})
+ id: build
+ uses: google/clusterfuzzlite/actions/build_fuzzers@v1
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ language: c # Change this to the language you are fuzzing.
+ sanitizer: ${{ matrix.sanitizer }}
+ - name: Run Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }})
+ id: run
+ uses: google/clusterfuzzlite/actions/run_fuzzers@v1
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ fuzz-seconds: 300 # 5 minutes
+ mode: ${{ matrix.mode }}
+ sanitizer: ${{ matrix.sanitizer }}
+
\ No newline at end of file
diff --git a/.github/workflows/cflite_pr.yml b/.github/workflows/cflite_pr.yml
new file mode 100644
index 00000000..8810c6d6
--- /dev/null
+++ b/.github/workflows/cflite_pr.yml
@@ -0,0 +1,43 @@
+name: ClusterFuzzLite PR fuzzing
+on:
+ pull_request:
+ paths:
+ - "**"
+permissions: read-all
+jobs:
+ PR:
+ runs-on: ubuntu-latest
+ concurrency:
+ group: ${{ github.workflow }}-${{ matrix.sanitizer }}-${{ github.ref }}
+ cancel-in-progress: true
+ strategy:
+ fail-fast: false
+ matrix:
+ sanitizer: [address, undefined, memory] # Override this with the sanitizers you want.
+ steps:
+ - name: Build Fuzzers (${{ matrix.sanitizer }})
+ id: build
+ uses: google/clusterfuzzlite/actions/build_fuzzers@v1
+ with:
+ language: c # Change this to the language you are fuzzing.
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ sanitizer: ${{ matrix.sanitizer }}
+ # Optional but recommended: used to only run fuzzers that are affected
+ # by the PR.
+ # storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git
+ # storage-repo-branch: main # Optional. Defaults to "main"
+ # storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages".
+ - name: Run Fuzzers (${{ matrix.sanitizer }})
+ id: run
+ uses: google/clusterfuzzlite/actions/run_fuzzers@v1
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ fuzz-seconds: 300 # 5 minutes
+ mode: "code-change"
+ sanitizer: ${{ matrix.sanitizer }}
+ output-sarif: true
+ # Optional but recommended: used to download the corpus produced by
+ # batch fuzzing.
+ # storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git
+ # storage-repo-branch: main # Optional. Defaults to "main"
+ # storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages".
diff --git a/PLUGIN_SPECIFICATION.md b/PLUGIN_SPECIFICATION.md
index 70bd44f5..3ed21927 100644
--- a/PLUGIN_SPECIFICATION.md
+++ b/PLUGIN_SPECIFICATION.md
@@ -27,9 +27,9 @@ For the smart contracts implemented, the functions covered by the plugin shall b
|Contract | Function | Selector | Displayed Parameters |
| --- | --- | --- | --- |
-|Stakewise | burnOsToken | `0x066055e0`|
uint128 osTokenShares |
uint256 timestamp |
uint256 exitQueueIndex |
|
-|Stakewise | claimExitedAssets | `0x8697d2c2`| address receiver |
address referrer |
|
-|Stakewise | deposit | `0xf9609f08`| |
+|Stakewise | burnOsToken | `0x066055e0`| |
+|Stakewise | claimExitedAssets | `0x8697d2c2`| uint256 positionTicket |
uint256 timestamp |
uint256 exitQueueIndex |
|
+|Stakewise | deposit | `0xf9609f08`| address receiver |
address referrer |
|
|Stakewise | enterExitQueue | `0x8ceab9aa`| uint256 shares |
address receiver |
|
|Stakewise | mintOsToken | `0x201b9eb5`| address receiver |
uint256 osTokenShares |
address referrer |
|
|Stakewise | redeem | `0x7bde82f2`| uint256 shares |
address receiver |
|
diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt
index cda1168e..eb6dee47 100644
--- a/fuzzing/CMakeLists.txt
+++ b/fuzzing/CMakeLists.txt
@@ -73,6 +73,7 @@ add_compile_definitions(
include_directories(
${BOLOS_SDK}/include
+ ${BOLOS_SDK}/lib_standard_app
${BOLOS_SDK}/lib_cxng/include
${BOLOS_SDK}/lib_cxng/src
${BOLOS_SDK}/target/nanox/include
@@ -91,11 +92,16 @@ add_executable(fuzz
${SRC_DIR}/handle_provide_token.c
${SRC_DIR}/handle_query_contract_ui.c
${SRC_DIR}/handle_query_contract_id.c
+ ${SRC_DIR}/utils.c
# Ethereum SDK
${ETH_DIR}/src/common_utils.c
${ETH_DIR}/src/plugin_utils.c
+ # sdk utils
+ ${BOLOS_SDK}/src/ledger_assert.c
+ ${BOLOS_SDK}/lib_standard_app/format.c
+
# cxng
${BOLOS_SDK}/lib_cxng/src/cx_hash.c
${BOLOS_SDK}/lib_cxng/src/cx_sha256.c
diff --git a/fuzzing/mocks.c b/fuzzing/mocks.c
index 5b5358cb..1c0ec847 100644
--- a/fuzzing/mocks.c
+++ b/fuzzing/mocks.c
@@ -1,4 +1,7 @@
#include "plugin.h"
+#include "lcx_common.h"
+#include "lcx_hash.h"
+#include
size_t strlcat(char *dst, const char *src, size_t size) {
size_t srclen; /* Length of source string */
@@ -33,3 +36,13 @@ size_t strlcpy(char *dst, const char *src, size_t size) {
return (srclen);
}
+
+cx_err_t cx_keccak_256_hash_iovec(const cx_iovec_t *iovec,
+ size_t iovec_len,
+ uint8_t digest[static CX_KECCAK_256_SIZE]) {
+ return CX_OK;
+}
+
+void os_sched_exit(bolos_task_status_t exit_code) {
+ return;
+}
\ No newline at end of file
diff --git a/src/handle_provide_parameter.c b/src/handle_provide_parameter.c
index 0a71e28d..6115775c 100644
--- a/src/handle_provide_parameter.c
+++ b/src/handle_provide_parameter.c
@@ -1,4 +1,5 @@
#include "plugin.h"
+#include "utils.h"
static void handle_stakewise_deposit(ethPluginProvideParameter_t *msg, context_t *context) {
switch (context->next_param) {
@@ -135,6 +136,7 @@ static void handle_stakewise_mint_os_token(ethPluginProvideParameter_t *msg, con
}
static void handle_eigenlayer_delegate_to(ethPluginProvideParameter_t *msg, context_t *context) {
+ uint8_t expected_bytes[3] = {0x60, 0x40, 0x41};
switch (context->next_param) {
case OPERATOR:
copy_address(context->receiver, msg->parameter, sizeof(context->receiver));
@@ -142,7 +144,12 @@ static void handle_eigenlayer_delegate_to(ethPluginProvideParameter_t *msg, cont
break;
case OFFSET_1:
- context->next_param = APPROVER_SALT;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[0], 1)) {
+ context->next_param = APPROVER_SALT;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case APPROVER_SALT:
@@ -151,7 +158,12 @@ static void handle_eigenlayer_delegate_to(ethPluginProvideParameter_t *msg, cont
break;
case OFFSET_2:
- context->next_param = EXPIRY;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[1], 1)) {
+ context->next_param = EXPIRY;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case EXPIRY:
@@ -160,7 +172,12 @@ static void handle_eigenlayer_delegate_to(ethPluginProvideParameter_t *msg, cont
break;
case ARRAY_LEN_1:
- context->next_param = SIGNATURE_1;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[2], 1)) {
+ context->next_param = SIGNATURE_1;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case SIGNATURE_1:
@@ -214,13 +231,31 @@ static void handle_eigenlayer_inc_dec_delegated_shares(ethPluginProvideParameter
static void handle_eigenlayer_complete_queued_withdrawal(ethPluginProvideParameter_t *msg,
context_t *context) {
+ uint8_t expected_bytes[5] = {
+ 0x80,
+ 0x01,
+ 0xe0,
+ 0x01,
+ 0x20,
+ };
switch (context->next_param) {
case OFFSET_1:
- context->next_param = OFFSET_2;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[0], 1)) {
+ context->next_param = OFFSET_2;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
+
break;
case OFFSET_2:
- context->next_param = MIDDLEWARE_TIMES_INDEX;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[1], 2)) {
+ context->next_param = MIDDLEWARE_TIMES_INDEX;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case MIDDLEWARE_TIMES_INDEX:
@@ -259,20 +294,35 @@ static void handle_eigenlayer_complete_queued_withdrawal(ethPluginProvideParamet
break;
case START_BLOCK:
- copy_parameter(context->uint32_var, msg->parameter + 28, sizeof(context->uint32_var));
+ copy_parameter(context->os_token_shares, msg->parameter + 28, 4);
context->next_param = OFFSET_3;
break;
case OFFSET_3:
- context->next_param = OFFSET_4;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[2], 1)) {
+ context->next_param = OFFSET_4;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case OFFSET_4:
- context->next_param = ARRAY_LEN_1;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[3], 2)) {
+ context->next_param = ARRAY_LEN_1;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case ARRAY_LEN_1:
- context->next_param = STRATEGY;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[1], 1)) {
+ context->next_param = STRATEGY;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case STRATEGY:
@@ -282,7 +332,12 @@ static void handle_eigenlayer_complete_queued_withdrawal(ethPluginProvideParamet
break;
case ARRAY_LEN_2:
- context->next_param = SHARES;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[1], 1)) {
+ context->next_param = SHARES;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case SHARES:
@@ -291,7 +346,12 @@ static void handle_eigenlayer_complete_queued_withdrawal(ethPluginProvideParamet
break;
case ARRAY_LEN_3:
- context->next_param = TOKENS;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[1], 1)) {
+ context->next_param = TOKENS;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case TOKENS:
@@ -310,25 +370,57 @@ static void handle_eigenlayer_complete_queued_withdrawal(ethPluginProvideParamet
static void handle_eigenlayer_queue_withdrawal(ethPluginProvideParameter_t *msg,
context_t *context) {
+ uint8_t expected_bytes[5] = {
+ 0x20,
+ 0x01,
+ 0x60,
+ 0xa0,
+ };
switch (context->next_param) {
case OFFSET_1:
- context->next_param = ARRAY_LEN_1;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[0], 1)) {
+ context->next_param = ARRAY_LEN_1;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
+
break;
case ARRAY_LEN_1:
- context->next_param = OFFSET_2;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[1], 1)) {
+ context->next_param = OFFSET_2;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case OFFSET_2:
- context->next_param = OFFSET_3;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[0], 1)) {
+ context->next_param = OFFSET_3;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case OFFSET_3:
- context->next_param = OFFSET_4;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[2], 1)) {
+ context->next_param = OFFSET_4;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case OFFSET_4:
- context->next_param = WITHDRAWER;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[3], 1)) {
+ context->next_param = WITHDRAWER;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case WITHDRAWER:
@@ -337,7 +429,12 @@ static void handle_eigenlayer_queue_withdrawal(ethPluginProvideParameter_t *msg,
break;
case ARRAY_LEN_2:
- context->next_param = STRATEGY;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[1], 1)) {
+ context->next_param = STRATEGY;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case STRATEGY:
@@ -346,7 +443,12 @@ static void handle_eigenlayer_queue_withdrawal(ethPluginProvideParameter_t *msg,
break;
case ARRAY_LEN_3:
- context->next_param = SHARES;
+ if (compare_last_n_bytes(msg->parameter, &expected_bytes[1], 1)) {
+ context->next_param = SHARES;
+ } else {
+ msg->result = ETH_PLUGIN_RESULT_ERROR;
+ context->next_param = UNEXPECTED_PARAMETER;
+ }
break;
case SHARES:
diff --git a/src/handle_query_contract_ui.c b/src/handle_query_contract_ui.c
index 824f0c82..9edb0d9b 100644
--- a/src/handle_query_contract_ui.c
+++ b/src/handle_query_contract_ui.c
@@ -264,12 +264,7 @@ static bool eigenlayer_complete_queued_withdrawal_ui(ethQueryContractUI_t *msg,
case 4:
strlcpy(msg->title, "Start Block", msg->titleLength);
- amountToString(context->uint32_var,
- sizeof(context->uint32_var),
- 0,
- "",
- msg->msg,
- msg->msgLength);
+ amountToString(context->os_token_shares, 4, 0, "", msg->msg, msg->msgLength);
return true;
case 5:
diff --git a/src/plugin.h b/src/plugin.h
index 1dc7208b..0cdae3cd 100644
--- a/src/plugin.h
+++ b/src/plugin.h
@@ -63,7 +63,8 @@ extern const uint32_t SELECTORS[SELECTOR_COUNT];
// Enumeration used to parse the smart contract data.
// EDIT THIS: Adapt the parameter names here.
typedef enum {
- RECEIVER = 0, // Address
+ // Stakewise
+ RECEIVER = 0,
REFERRER,
OS_TOKEN_SHARES,
VAULT_SHARES,
@@ -71,7 +72,7 @@ typedef enum {
TIMESTAMP,
EXIT_QUEUE_INDEX,
OWNER,
- // EIGENLAYER
+ // Eigenlayer
OPERATOR,
OFFSET_1,
OFFSET_2,
@@ -94,7 +95,7 @@ typedef enum {
MIDDLEWARE_TIMES_INDEX,
RECEIVE_AS_TOKENS,
SHARES,
- // Sybiotic
+ // Symbiotic
DEADLINE,
UNEXPECTED_PARAMETER,
} parameter;
@@ -111,7 +112,6 @@ typedef struct context_s {
uint8_t timestamp[INT256_LENGTH];
uint8_t exit_queue_index[INT256_LENGTH];
- uint8_t uint32_var[4];
uint8_t bool_var;
// For parsing data.
diff --git a/src/utils.c b/src/utils.c
index 1812fd3a..c3918143 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,4 +1,5 @@
#include
+#include "utils.h"
const char HEX_CHARS[] = "0123456789ABCDEF";
@@ -29,3 +30,14 @@ void display_first_and_last_bytes(ethQueryContractUI_t *msg,
next_ptr += 2;
}
}
+
+bool compare_last_n_bytes(const uint8_t *parameter, const uint8_t *expected_bytes, size_t n) {
+ if (memcmp(parameter, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 32 - n) !=
+ 0) {
+ return false;
+ }
+ if (memcmp(¶meter[32 - n], expected_bytes, n) != 0) {
+ return false;
+ }
+ return true;
+}
diff --git a/src/utils.h b/src/utils.h
index 814c9ded..01bac53b 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -4,4 +4,4 @@ void display_first_and_last_bytes(ethQueryContractUI_t *msg,
uint8_t *address,
int array_offset,
int first_last_size);
-void display_hexa(ethQueryContractUI_t *msg, uint8_t *data, size_t length);
\ No newline at end of file
+bool compare_last_n_bytes(const uint8_t *parameter, const uint8_t *expected_bytes, size_t n);
diff --git a/tests/test_eigenlayer.py b/tests/test_eigenlayer.py
index e904eea7..00589059 100644
--- a/tests/test_eigenlayer.py
+++ b/tests/test_eigenlayer.py
@@ -38,6 +38,26 @@ def test_eigenlayer_delegate_to(ledger_utils):
ledger_utils.send_tx_and_compare_snapshots(tx_params)
+def test_eigenlayer_delegate_to_different_length(ledger_utils):
+ operator = bytes.fromhex("0102030000000000000000000000000000030201")
+ signature_expiry = (
+ "0x01020322222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333040506",
+ 123456789,
+ )
+ approver_salt = "0xfffefdfffffffffffffffffffffffffffffffffffffffffffffffffffffcfbfa"
+
+ data = contract.encode_abi(
+ "delegateTo", [operator, signature_expiry, approver_salt]
+ )
+
+ ledger_utils.set_external_plugin(
+ contract.address,
+ data,
+ )
+ tx_params = get_default_tx_params(contract.address, data)
+ ledger_utils.send_tx_expect_error(tx_params)
+
+
def test_eigenlayer_increase_delegated_shares_wallet_address(ledger_utils):
receiver = ledger_utils.get()
strategy = bytes.fromhex("0405060000000000000000000000000000070809")
@@ -98,6 +118,43 @@ def test_eigenlayer_decrease_delegated_shares(ledger_utils):
ledger_utils.send_tx_and_compare_snapshots(tx_params)
+def test_eigenlayer_complete_queued_withdrawal_more_than_one_element(ledger_utils):
+ if ledger_utils.firmware.device.startswith("stax"):
+ # This test is failing in stax when we try to show
+ # 8 screens or more: see https://github.com/LedgerHQ/app-plugin-boilerplate/issues/152
+ return
+ withdrawal = (
+ bytes.fromhex("0102030000000000000000000000000000040506"),
+ bytes.fromhex("07080900000000000000000000000000000a0b0c"),
+ bytes.fromhex("0d0e0f0000000000000000000000000000101112"),
+ 19,
+ 99,
+ [
+ bytes.fromhex("13141500000000000000000000000000001c1d1e"),
+ bytes.fromhex("1f20210000000000000000000000000000222324"),
+ ],
+ [10, 11],
+ )
+ tokens = [
+ bytes.fromhex("252627000000000000000000000000000028292a"),
+ bytes.fromhex("2b2c2d00000000000000000000000000002e2f30"),
+ ]
+ middleware_times_index = 255
+ receive_as_tokens = True
+
+ data = contract.encode_abi(
+ "completeQueuedWithdrawal",
+ [withdrawal, tokens, middleware_times_index, receive_as_tokens],
+ )
+
+ ledger_utils.set_external_plugin(
+ contract.address,
+ data,
+ )
+ tx_params = get_default_tx_params(contract.address, data)
+ ledger_utils.send_tx_expect_error(tx_params)
+
+
def test_eigenlayer_complete_queued_withdrawal(ledger_utils):
if ledger_utils.firmware.device.startswith("stax"):
# This test is failing in stax when we try to show
@@ -148,6 +205,49 @@ def test_eigenlayer_queue_withdrawal(ledger_utils):
ledger_utils.send_tx_and_compare_snapshots(tx_params)
+def test_eigenlayer_queue_withdrawal_different_offset(ledger_utils):
+ withdrawal = [
+ (
+ [bytes.fromhex("0102030000000000000000000000000000040506")],
+ [255],
+ bytes.fromhex("07080900000000000000000000000000000a0b0c"),
+ )
+ ]
+
+ data = contract.encode_abi("queueWithdrawals", [withdrawal])
+ data = data[:264] + "7" + data[265:]
+ print("DATA", data)
+
+ ledger_utils.set_external_plugin(
+ contract.address,
+ data,
+ )
+ tx_params = get_default_tx_params(contract.address, data)
+ ledger_utils.send_tx_expect_error(tx_params)
+
+
+def test_eigenlayer_queue_withdrawal_more_than_one_element(ledger_utils):
+ withdrawal = [
+ (
+ [
+ bytes.fromhex("0102030000000000000000000000000000040506"),
+ bytes.fromhex("07080900000000000000000000000000000a0b0c"),
+ ],
+ [255, 254],
+ bytes.fromhex("0d0e0f0000000000000000000000000000101112"),
+ )
+ ]
+
+ data = contract.encode_abi("queueWithdrawals", [withdrawal])
+
+ ledger_utils.set_external_plugin(
+ contract.address,
+ data,
+ )
+ tx_params = get_default_tx_params(contract.address, data)
+ ledger_utils.send_tx_expect_error(tx_params)
+
+
def test_eigenlayer_undelegate(ledger_utils):
staker = bytes.fromhex("07080900000000000000000000000000000a0b0c")
diff --git a/tests/utils.py b/tests/utils.py
index 2bb4c41d..6b3ce736 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -6,6 +6,7 @@
from web3 import Web3
from ledger_app_clients.ethereum.utils import recover_transaction
from ragger.navigator import NavInsID
+import ragger
from eth_typing import ChainId
from ledger_app_clients.ethereum.client import EthAppClient
from ledger_app_clients.ethereum.utils import get_selector_from_data
@@ -63,27 +64,11 @@ def get_default_tx_params(contract, data):
return tx_params
-def send_tx_and_compare_snapshots(client, navigator, wallet_addr, test_name, tx_params):
- # send the transaction
- with client.sign(DERIVATION_PATH, tx_params):
- # Validate the on-screen request by performing the navigation appropriate for this device
- navigator.navigate_until_text_and_compare(
- NavInsID.RIGHT_CLICK,
- [NavInsID.BOTH_CLICK],
- "Accept",
- ROOT_SCREENSHOT_PATH,
- test_name,
- )
- # verify signature
- vrs = ResponseParser.signature(client.response().data)
- addr = recover_transaction(tx_params, vrs)
- assert addr == wallet_addr.get()
-
-
class LedgerUtils:
client: EthAppClient
test_name: str
firmware: str
+ navigator: ragger.navigator.Navigator
def __init__(self, backend, navigator, firmware, test_name):
self.client = EthAppClient(backend)
@@ -104,6 +89,14 @@ def set_external_plugin(self, contract_address, data):
get_selector_from_data(data),
)
+ def send_tx_expect_error(self, tx_params):
+ try:
+ with self.client.sign(DERIVATION_PATH, tx_params):
+ pass
+ except ragger.error.ExceptionRAPDU as e:
+ return
+ assert False
+
def send_tx_and_compare_snapshots(self, tx_params):
# send the transaction
with self.client.sign(DERIVATION_PATH, tx_params):
@@ -123,7 +116,7 @@ def send_tx_and_compare_snapshots(self, tx_params):
end_text,
ROOT_SCREENSHOT_PATH,
self.test_name,
- screen_change_after_last_instruction=False
+ screen_change_after_last_instruction=False,
)
# verify signature
vrs = ResponseParser.signature(self.client.response().data)