mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-24 16:38:15 +00:00
feat(core): confirm ETH stake, unstake, claim
This commit is contained in:
parent
e1f696b4dd
commit
ebcf3e2db2
128
common/tests/fixtures/ethereum/sign_tx_staking.json
vendored
Normal file
128
common/tests/fixtures/ethereum/sign_tx_staking.json
vendored
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
{
|
||||||
|
"setup": {
|
||||||
|
"mnemonic": "alcohol woman abuse must during monitor noble actual mixed trade anger aisle",
|
||||||
|
"passphrase": ""
|
||||||
|
},
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"name": "stake_holesky",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Stake transaction - Holesky testnet",
|
||||||
|
"data": "3a29dbae0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0xAFA848357154a6a624686b348303EF9a13F63264",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_price": "0x14",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"tx_type": null,
|
||||||
|
"value": "0x16345785D8A0000"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 37,
|
||||||
|
"sig_r": "1a43606f1a3e9a61c4986cc9b324dd74f84557942cddf2e4ffccea82c2c54824",
|
||||||
|
"sig_s": "63e8595bfa1e383a1fea7205bff5afcf3b3d3513b45a2f792396f2f4251f4c55"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "stake_main",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Stake transaction - Mainnet",
|
||||||
|
"data": "3a29dbae0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0xD523794C879D9eC028960a231F866758e405bE34",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_price": "0x14",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"tx_type": null,
|
||||||
|
"value": "0x16345785D8A0000"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 37,
|
||||||
|
"sig_r": "104ae56ff2ec396a86191fa94b6e79af20efcc28e5d16b39d90fe05c990a2ce6",
|
||||||
|
"sig_s": "504fd80e50890df83a9b004d0ba97db11b93354327e717df5c0874036f616d47"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "unstake_holesky",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Unstake transaction - Holesky testnet",
|
||||||
|
"data": "76ec871c000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0xAFA848357154a6a624686b348303EF9a13F63264",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_price": "0x14",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"tx_type": null,
|
||||||
|
"value": "0x0"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 38,
|
||||||
|
"sig_r": "f6553486737da2ceb42067047d0e8dd0add8e82f49b524cf657215e1d2487d16",
|
||||||
|
"sig_s": "21336e4c53537bcdf06a71ed6cbefc3374461476d8da6e988e6cf4957b6a8bb1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "unstake_main",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Unstake transaction - Mainnet",
|
||||||
|
"data": "76ec871c000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0xD523794C879D9eC028960a231F866758e405bE34",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_price": "0x14",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"tx_type": null,
|
||||||
|
"value": "0x0"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 38,
|
||||||
|
"sig_r": "09077008477f40468928a94c45bfdb0b0ff473473401cd918740af4c98734bea",
|
||||||
|
"sig_s": "3cad467c41810a2d8901020a803d6836d1d5a39d8198eaba3eec121a48997b18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "claim_holesky",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Claim transaction - Holesky testnet",
|
||||||
|
"data": "33986ffa",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0x624087DD1904ab122A32878Ce9e933C7071F53B9",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_price": "0x14",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"tx_type": null,
|
||||||
|
"value": "0x0"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 37,
|
||||||
|
"sig_r": "4a77a5f7437c4744c8dc4e48f968a6fedccd86db0ee15ce6a832e71b17f11a9a",
|
||||||
|
"sig_s": "75e8efc0ecf1484ce745bbcd19899fbc458677869f3008be5ddb9c8ad8766d40"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "claim_mainnet",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Claim transaction - Mainnet",
|
||||||
|
"data": "33986ffa",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0x7a7f0b3c23C23a31cFcb0c44709be70d4D545c6e",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_price": "0x14",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"tx_type": null,
|
||||||
|
"value": "0x0"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 37,
|
||||||
|
"sig_r": "c477417e2471d94c089d082fe1570fa8ba114e6572211c4b539244e2d40457d1",
|
||||||
|
"sig_s": "0bb029ed5dbe76016f74263c0a8709bcbd89affac62504196a1cf546d7c723a3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
108
common/tests/fixtures/ethereum/sign_tx_staking_data_error.json
vendored
Normal file
108
common/tests/fixtures/ethereum/sign_tx_staking_data_error.json
vendored
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
{
|
||||||
|
"setup": {
|
||||||
|
"mnemonic": "alcohol woman abuse must during monitor noble actual mixed trade anger aisle",
|
||||||
|
"passphrase": ""
|
||||||
|
},
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"name": "stake_bad_inputs_1",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Stake transaction - Holesky testnet. Wrong source argument (should be 1).",
|
||||||
|
"data": "3a29dbae0000000000000000000000000000000000000000000000000000000000000002",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0xAFA848357154a6a624686b348303EF9a13F63264",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_price": "0x14",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"tx_type": null,
|
||||||
|
"value": "0x16345785D8A0000"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 0,
|
||||||
|
"sig_r": "0x0",
|
||||||
|
"sig_s": "0x0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "stake_bad_inputs_2",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Stake transaction - Mainnet. Missing arguments.",
|
||||||
|
"data": "3a29dbae",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0xD523794C879D9eC028960a231F866758e405bE34",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_price": "0x14",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"tx_type": null,
|
||||||
|
"value": "0x16345785D8A0000"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 0,
|
||||||
|
"sig_r": "0x0",
|
||||||
|
"sig_s": "0x0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "unstake_bad_inputs_1",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Unstake transaction - Holesky testnet. Wrong source argument (should be 1).",
|
||||||
|
"data": "76ec871c000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0xAFA848357154a6a624686b348303EF9a13F63264",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_price": "0x14",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"tx_type": null,
|
||||||
|
"value": "0x0"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 0,
|
||||||
|
"sig_r": "0x0",
|
||||||
|
"sig_s": "0x0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "unstake_bad_inputs_2",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Unstake transaction - Holesky testnet. Misaligned arguments.",
|
||||||
|
"data": "76ec871c000000000000000000",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0xAFA848357154a6a624686b348303EF9a13F63264",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_price": "0x14",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"tx_type": null,
|
||||||
|
"value": "0x0"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 0,
|
||||||
|
"sig_r": "0x0",
|
||||||
|
"sig_s": "0x0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "claim_bad_inputs_1",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Claim transaction - Mainnet. Misaligned data.",
|
||||||
|
"data": "33986ffaaa000aaa",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0x7a7f0b3c23C23a31cFcb0c44709be70d4D545c6e",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_price": "0x14",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"tx_type": null,
|
||||||
|
"value": "0x0"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 0,
|
||||||
|
"sig_r": "0x0",
|
||||||
|
"sig_s": "0x0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
128
common/tests/fixtures/ethereum/sign_tx_staking_eip1559.json
vendored
Normal file
128
common/tests/fixtures/ethereum/sign_tx_staking_eip1559.json
vendored
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
{
|
||||||
|
"setup": {
|
||||||
|
"mnemonic": "alcohol woman abuse must during monitor noble actual mixed trade anger aisle",
|
||||||
|
"passphrase": ""
|
||||||
|
},
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"name": "stake_holesky",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Stake transaction - Holesky testnet",
|
||||||
|
"data": "3a29dbae0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0xAFA848357154a6a624686b348303EF9a13F63264",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"max_gas_fee": "0x14",
|
||||||
|
"max_priority_fee": "0x1",
|
||||||
|
"value": "0x16345785D8A0000"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 0,
|
||||||
|
"sig_r": "77d68a17e2bcacccb791ca3d7e298588be0511a7d3c055abbb2030f54b56c6fa",
|
||||||
|
"sig_s": "567092e781fe1aedc458bdbc9ce4328398bf1d7d635787191881131c1afa7143"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "stake_main",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Stake transaction - Mainnet",
|
||||||
|
"data": "3a29dbae0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0xD523794C879D9eC028960a231F866758e405bE34",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"max_gas_fee": "0x14",
|
||||||
|
"max_priority_fee": "0x1",
|
||||||
|
"value": "0x16345785D8A0000"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 0,
|
||||||
|
"sig_r": "05a37bf477df7f256729ec8607aa20a6286c42a246b5deebaf6d54915c0f87e3",
|
||||||
|
"sig_s": "30ffe2e80119452403bbf238b02def90a120ade2e73ab60926060ed10562f5ed"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "unstake_holesky",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Unstake transaction - Holesky testnet",
|
||||||
|
"data": "76ec871c000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0xAFA848357154a6a624686b348303EF9a13F63264",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"max_gas_fee": "0x14",
|
||||||
|
"max_priority_fee": "0x1",
|
||||||
|
"value": "0x0"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 0,
|
||||||
|
"sig_r": "9dfa73ea497785ffcb61598c554a57e46fce0a605c9ed06a4c8f265fccfd912e",
|
||||||
|
"sig_s": "45db0bd2189d4bc4828c859d28b907b3d47c4a35eef707052cde2f4fff4ef4fe"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "unstake_main",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Unstake transaction - Mainnet",
|
||||||
|
"data": "76ec871c000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0xD523794C879D9eC028960a231F866758e405bE34",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"max_gas_fee": "0x14",
|
||||||
|
"max_priority_fee": "0x1",
|
||||||
|
"value": "0x0"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 0,
|
||||||
|
"sig_r": "15eb458e473c7f74abf99ba8833885e25435f913e77e5bc1259396942f6b9539",
|
||||||
|
"sig_s": "14ea7a1417cfab7bb2cdbd0750aa7929f02a30999b624dd2ae1029c6be9dc9d8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "claim_holesky",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Claim transaction - Holesky testnet",
|
||||||
|
"data": "33986ffa",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0x624087DD1904ab122A32878Ce9e933C7071F53B9",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"max_gas_fee": "0x14",
|
||||||
|
"max_priority_fee": "0x1",
|
||||||
|
"value": "0x0"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 1,
|
||||||
|
"sig_r": "5abf2a99ac6431fce9e436234e2962502b1a67d4b582f90f4bc592e790f8fd7e",
|
||||||
|
"sig_s": "60b01cd76d40f089dc9464cb442c6bbac435f80a35b5a1ed128de7cb9718aa3a"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "claim_mainnet",
|
||||||
|
"parameters": {
|
||||||
|
"comment": "Claim transaction - Mainnet",
|
||||||
|
"data": "33986ffa",
|
||||||
|
"path": "m/44'/60'/0'/0/0",
|
||||||
|
"to_address": "0x7a7f0b3c23C23a31cFcb0c44709be70d4D545c6e",
|
||||||
|
"chain_id": 1,
|
||||||
|
"nonce": "0x0",
|
||||||
|
"gas_limit": "0x14",
|
||||||
|
"max_gas_fee": "0x14",
|
||||||
|
"max_priority_fee": "0x1",
|
||||||
|
"value": "0x0"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"sig_v": 0,
|
||||||
|
"sig_r": "7b3a09f1e0b28b2a25ddc3de02168fc20e9faada1d97181679dfb6f8383382da",
|
||||||
|
"sig_s": "6667dbb7b7b63d3e51df012a62dc6b01f13b60c7598b04aa499722cfb26864f3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
1
core/.changelog.d/3517.added
Normal file
1
core/.changelog.d/3517.added
Normal file
@ -0,0 +1 @@
|
|||||||
|
Clear sign ETH staking transactions on Everstake pool.
|
@ -367,6 +367,14 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_ethereum__show_full_message;
|
MP_QSTR_ethereum__show_full_message;
|
||||||
MP_QSTR_ethereum__show_full_struct;
|
MP_QSTR_ethereum__show_full_struct;
|
||||||
MP_QSTR_ethereum__sign_eip712;
|
MP_QSTR_ethereum__sign_eip712;
|
||||||
|
MP_QSTR_ethereum__staking_claim;
|
||||||
|
MP_QSTR_ethereum__staking_claim_address;
|
||||||
|
MP_QSTR_ethereum__staking_claim_intro;
|
||||||
|
MP_QSTR_ethereum__staking_stake;
|
||||||
|
MP_QSTR_ethereum__staking_stake_address;
|
||||||
|
MP_QSTR_ethereum__staking_stake_intro;
|
||||||
|
MP_QSTR_ethereum__staking_unstake;
|
||||||
|
MP_QSTR_ethereum__staking_unstake_intro;
|
||||||
MP_QSTR_ethereum__title_confirm_data;
|
MP_QSTR_ethereum__title_confirm_data;
|
||||||
MP_QSTR_ethereum__title_confirm_domain;
|
MP_QSTR_ethereum__title_confirm_domain;
|
||||||
MP_QSTR_ethereum__title_confirm_message;
|
MP_QSTR_ethereum__title_confirm_message;
|
||||||
@ -898,6 +906,7 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_stellar__your_account;
|
MP_QSTR_stellar__your_account;
|
||||||
MP_QSTR_subprompt;
|
MP_QSTR_subprompt;
|
||||||
MP_QSTR_subtitle;
|
MP_QSTR_subtitle;
|
||||||
|
MP_QSTR_text_mono;
|
||||||
MP_QSTR_tezos__baker_address;
|
MP_QSTR_tezos__baker_address;
|
||||||
MP_QSTR_tezos__balance;
|
MP_QSTR_tezos__balance;
|
||||||
MP_QSTR_tezos__ballot;
|
MP_QSTR_tezos__ballot;
|
||||||
|
@ -844,6 +844,14 @@ pub enum TranslatedString {
|
|||||||
words__yes = 831,
|
words__yes = 831,
|
||||||
reboot_to_bootloader__just_a_moment = 832,
|
reboot_to_bootloader__just_a_moment = 832,
|
||||||
inputs__previous = 833,
|
inputs__previous = 833,
|
||||||
|
ethereum__staking_claim = 834,
|
||||||
|
ethereum__staking_claim_address = 835,
|
||||||
|
ethereum__staking_claim_intro = 836,
|
||||||
|
ethereum__staking_stake = 837,
|
||||||
|
ethereum__staking_stake_address = 838,
|
||||||
|
ethereum__staking_stake_intro = 839,
|
||||||
|
ethereum__staking_unstake = 840,
|
||||||
|
ethereum__staking_unstake_intro = 841,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TranslatedString {
|
impl TranslatedString {
|
||||||
@ -1683,6 +1691,14 @@ impl TranslatedString {
|
|||||||
Self::words__yes => "Yes",
|
Self::words__yes => "Yes",
|
||||||
Self::reboot_to_bootloader__just_a_moment => "Just a moment...",
|
Self::reboot_to_bootloader__just_a_moment => "Just a moment...",
|
||||||
Self::inputs__previous => "PREVIOUS",
|
Self::inputs__previous => "PREVIOUS",
|
||||||
|
Self::ethereum__staking_claim => "CLAIM",
|
||||||
|
Self::ethereum__staking_claim_address => "CLAIM ADDRESS",
|
||||||
|
Self::ethereum__staking_claim_intro => "Claim ETH from Everstake?",
|
||||||
|
Self::ethereum__staking_stake => "STAKE",
|
||||||
|
Self::ethereum__staking_stake_address => "STAKE ADDRESS",
|
||||||
|
Self::ethereum__staking_stake_intro => "Stake ETH on Everstake?",
|
||||||
|
Self::ethereum__staking_unstake => "UNSTAKE",
|
||||||
|
Self::ethereum__staking_unstake_intro => "Unstake ETH from Everstake?",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2523,6 +2539,14 @@ impl TranslatedString {
|
|||||||
Qstr::MP_QSTR_words__yes => Some(Self::words__yes),
|
Qstr::MP_QSTR_words__yes => Some(Self::words__yes),
|
||||||
Qstr::MP_QSTR_reboot_to_bootloader__just_a_moment => Some(Self::reboot_to_bootloader__just_a_moment),
|
Qstr::MP_QSTR_reboot_to_bootloader__just_a_moment => Some(Self::reboot_to_bootloader__just_a_moment),
|
||||||
Qstr::MP_QSTR_inputs__previous => Some(Self::inputs__previous),
|
Qstr::MP_QSTR_inputs__previous => Some(Self::inputs__previous),
|
||||||
|
Qstr::MP_QSTR_ethereum__staking_claim => Some(Self::ethereum__staking_claim),
|
||||||
|
Qstr::MP_QSTR_ethereum__staking_claim_address => Some(Self::ethereum__staking_claim_address),
|
||||||
|
Qstr::MP_QSTR_ethereum__staking_claim_intro => Some(Self::ethereum__staking_claim_intro),
|
||||||
|
Qstr::MP_QSTR_ethereum__staking_stake => Some(Self::ethereum__staking_stake),
|
||||||
|
Qstr::MP_QSTR_ethereum__staking_stake_address => Some(Self::ethereum__staking_stake_address),
|
||||||
|
Qstr::MP_QSTR_ethereum__staking_stake_intro => Some(Self::ethereum__staking_stake_intro),
|
||||||
|
Qstr::MP_QSTR_ethereum__staking_unstake => Some(Self::ethereum__staking_unstake),
|
||||||
|
Qstr::MP_QSTR_ethereum__staking_unstake_intro => Some(Self::ethereum__staking_unstake_intro),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,6 +463,7 @@ struct ConfirmBlobParams {
|
|||||||
info_button: bool,
|
info_button: bool,
|
||||||
hold: bool,
|
hold: bool,
|
||||||
chunkify: bool,
|
chunkify: bool,
|
||||||
|
text_mono: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfirmBlobParams {
|
impl ConfirmBlobParams {
|
||||||
@ -485,6 +486,7 @@ impl ConfirmBlobParams {
|
|||||||
info_button: false,
|
info_button: false,
|
||||||
hold,
|
hold,
|
||||||
chunkify: false,
|
chunkify: false,
|
||||||
|
text_mono: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,6 +510,11 @@ impl ConfirmBlobParams {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn with_text_mono(mut self, text_mono: bool) -> Self {
|
||||||
|
self.text_mono = text_mono;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn into_layout(self) -> Result<Obj, Error> {
|
fn into_layout(self) -> Result<Obj, Error> {
|
||||||
let paragraphs = ConfirmBlob {
|
let paragraphs = ConfirmBlob {
|
||||||
description: self.description.unwrap_or_else(StrBuffer::empty),
|
description: self.description.unwrap_or_else(StrBuffer::empty),
|
||||||
@ -518,8 +525,10 @@ impl ConfirmBlobParams {
|
|||||||
data_font: if self.chunkify {
|
data_font: if self.chunkify {
|
||||||
let data: StrBuffer = self.data.try_into()?;
|
let data: StrBuffer = self.data.try_into()?;
|
||||||
theme::get_chunkified_text_style(data.len())
|
theme::get_chunkified_text_style(data.len())
|
||||||
} else {
|
} else if self.text_mono {
|
||||||
&theme::TEXT_MONO
|
&theme::TEXT_MONO
|
||||||
|
} else {
|
||||||
|
&theme::TEXT_NORMAL
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
.into_paragraphs();
|
.into_paragraphs();
|
||||||
@ -738,6 +747,7 @@ extern "C" fn new_show_info_with_cancel(n_args: usize, args: *const Obj, kwargs:
|
|||||||
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||||
let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?;
|
let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?;
|
||||||
let horizontal: bool = kwargs.get_or(Qstr::MP_QSTR_horizontal, false)?;
|
let horizontal: bool = kwargs.get_or(Qstr::MP_QSTR_horizontal, false)?;
|
||||||
|
let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?;
|
||||||
|
|
||||||
let mut paragraphs = ParagraphVecShort::new();
|
let mut paragraphs = ParagraphVecShort::new();
|
||||||
|
|
||||||
@ -746,7 +756,14 @@ extern "C" fn new_show_info_with_cancel(n_args: usize, args: *const Obj, kwargs:
|
|||||||
let key: StrBuffer = key.try_into()?;
|
let key: StrBuffer = key.try_into()?;
|
||||||
let value: StrBuffer = value.try_into()?;
|
let value: StrBuffer = value.try_into()?;
|
||||||
paragraphs.add(Paragraph::new(&theme::TEXT_NORMAL, key).no_break());
|
paragraphs.add(Paragraph::new(&theme::TEXT_NORMAL, key).no_break());
|
||||||
paragraphs.add(Paragraph::new(&theme::TEXT_MONO, value));
|
if chunkify {
|
||||||
|
paragraphs.add(Paragraph::new(
|
||||||
|
theme::get_chunkified_text_style(value.len()),
|
||||||
|
value,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
paragraphs.add(Paragraph::new(&theme::TEXT_MONO, value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let axis = match horizontal {
|
let axis = match horizontal {
|
||||||
@ -787,11 +804,13 @@ extern "C" fn new_confirm_value(n_args: usize, args: *const Obj, kwargs: *mut Ma
|
|||||||
.try_into_option()?;
|
.try_into_option()?;
|
||||||
let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?;
|
let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?;
|
||||||
let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?;
|
let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?;
|
||||||
|
let text_mono: bool = kwargs.get_or(Qstr::MP_QSTR_text_mono, true)?;
|
||||||
|
|
||||||
ConfirmBlobParams::new(title, value, description, verb, verb_cancel, hold)
|
ConfirmBlobParams::new(title, value, description, verb, verb_cancel, hold)
|
||||||
.with_subtitle(subtitle)
|
.with_subtitle(subtitle)
|
||||||
.with_info_button(info_button)
|
.with_info_button(info_button)
|
||||||
.with_chunkify(chunkify)
|
.with_chunkify(chunkify)
|
||||||
|
.with_text_mono(text_mono)
|
||||||
.into_layout()
|
.into_layout()
|
||||||
};
|
};
|
||||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||||
@ -1779,6 +1798,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// title: str,
|
/// title: str,
|
||||||
/// items: Iterable[Tuple[str, str]],
|
/// items: Iterable[Tuple[str, str]],
|
||||||
/// horizontal: bool = False,
|
/// horizontal: bool = False,
|
||||||
|
/// chunkify: bool = False,
|
||||||
/// ) -> object:
|
/// ) -> object:
|
||||||
/// """Show metadata for outgoing transaction."""
|
/// """Show metadata for outgoing transaction."""
|
||||||
Qstr::MP_QSTR_show_info_with_cancel => obj_fn_kw!(0, new_show_info_with_cancel).as_obj(),
|
Qstr::MP_QSTR_show_info_with_cancel => obj_fn_kw!(0, new_show_info_with_cancel).as_obj(),
|
||||||
@ -1794,6 +1814,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// info_button: bool = False,
|
/// info_button: bool = False,
|
||||||
/// hold: bool = False,
|
/// hold: bool = False,
|
||||||
/// chunkify: bool = False,
|
/// chunkify: bool = False,
|
||||||
|
/// text_mono: bool = True,
|
||||||
/// ) -> object:
|
/// ) -> object:
|
||||||
/// """Confirm value. Merge of confirm_total and confirm_output."""
|
/// """Confirm value. Merge of confirm_total and confirm_output."""
|
||||||
Qstr::MP_QSTR_confirm_value => obj_fn_kw!(0, new_confirm_value).as_obj(),
|
Qstr::MP_QSTR_confirm_value => obj_fn_kw!(0, new_confirm_value).as_obj(),
|
||||||
|
@ -574,6 +574,7 @@ def show_info_with_cancel(
|
|||||||
title: str,
|
title: str,
|
||||||
items: Iterable[Tuple[str, str]],
|
items: Iterable[Tuple[str, str]],
|
||||||
horizontal: bool = False,
|
horizontal: bool = False,
|
||||||
|
chunkify: bool = False,
|
||||||
) -> object:
|
) -> object:
|
||||||
"""Show metadata for outgoing transaction."""
|
"""Show metadata for outgoing transaction."""
|
||||||
|
|
||||||
@ -590,6 +591,7 @@ def confirm_value(
|
|||||||
info_button: bool = False,
|
info_button: bool = False,
|
||||||
hold: bool = False,
|
hold: bool = False,
|
||||||
chunkify: bool = False,
|
chunkify: bool = False,
|
||||||
|
text_mono: bool = True,
|
||||||
) -> object:
|
) -> object:
|
||||||
"""Confirm value. Merge of confirm_total and confirm_output."""
|
"""Confirm value. Merge of confirm_total and confirm_output."""
|
||||||
|
|
||||||
|
@ -288,6 +288,14 @@ class TR:
|
|||||||
ethereum__show_full_message: str = "Show full message"
|
ethereum__show_full_message: str = "Show full message"
|
||||||
ethereum__show_full_struct: str = "Show full struct"
|
ethereum__show_full_struct: str = "Show full struct"
|
||||||
ethereum__sign_eip712: str = "Really sign EIP-712 typed data?"
|
ethereum__sign_eip712: str = "Really sign EIP-712 typed data?"
|
||||||
|
ethereum__staking_claim: str = "CLAIM"
|
||||||
|
ethereum__staking_claim_address: str = "CLAIM ADDRESS"
|
||||||
|
ethereum__staking_claim_intro: str = "Claim ETH from Everstake?"
|
||||||
|
ethereum__staking_stake: str = "STAKE"
|
||||||
|
ethereum__staking_stake_address: str = "STAKE ADDRESS"
|
||||||
|
ethereum__staking_stake_intro: str = "Stake ETH on Everstake?"
|
||||||
|
ethereum__staking_unstake: str = "UNSTAKE"
|
||||||
|
ethereum__staking_unstake_intro: str = "Unstake ETH from Everstake?"
|
||||||
ethereum__title_confirm_data: str = "CONFIRM DATA"
|
ethereum__title_confirm_data: str = "CONFIRM DATA"
|
||||||
ethereum__title_confirm_domain: str = "CONFIRM DOMAIN"
|
ethereum__title_confirm_domain: str = "CONFIRM DOMAIN"
|
||||||
ethereum__title_confirm_message: str = "CONFIRM MESSAGE"
|
ethereum__title_confirm_message: str = "CONFIRM MESSAGE"
|
||||||
|
@ -535,6 +535,8 @@ if not utils.BITCOIN_ONLY:
|
|||||||
import apps.ethereum.sign_tx_eip1559
|
import apps.ethereum.sign_tx_eip1559
|
||||||
apps.ethereum.sign_typed_data
|
apps.ethereum.sign_typed_data
|
||||||
import apps.ethereum.sign_typed_data
|
import apps.ethereum.sign_typed_data
|
||||||
|
apps.ethereum.staking_tx_constants
|
||||||
|
import apps.ethereum.staking_tx_constants
|
||||||
apps.ethereum.tokens
|
apps.ethereum.tokens
|
||||||
import apps.ethereum.tokens
|
import apps.ethereum.tokens
|
||||||
apps.ethereum.verify_message
|
apps.ethereum.verify_message
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from ubinascii import hexlify
|
from ubinascii import hexlify
|
||||||
|
|
||||||
|
from trezor import TR
|
||||||
|
|
||||||
from . import networks
|
from . import networks
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from trezor.messages import EthereumFieldType
|
from typing import Iterable
|
||||||
|
|
||||||
|
from trezor.messages import EthereumFieldType, EthereumTokenInfo
|
||||||
|
|
||||||
from .networks import EthereumNetworkInfo
|
from .networks import EthereumNetworkInfo
|
||||||
|
|
||||||
|
|
||||||
RSKIP60_NETWORKS = (30, 31)
|
RSKIP60_NETWORKS = (30, 31)
|
||||||
|
|
||||||
|
|
||||||
@ -126,6 +129,72 @@ def decode_typed_data(data: bytes, type_name: str) -> str:
|
|||||||
raise ValueError # Unsupported data type for direct field decoding
|
raise ValueError # Unsupported data type for direct field decoding
|
||||||
|
|
||||||
|
|
||||||
|
def get_fee_items_regular(
|
||||||
|
gas_price: int, gas_limit: int, network: EthereumNetworkInfo
|
||||||
|
) -> Iterable[tuple[str, str]]:
|
||||||
|
# regular
|
||||||
|
gas_limit_str = TR.ethereum__units_template.format(gas_limit)
|
||||||
|
gas_price_str = format_ethereum_amount(
|
||||||
|
gas_price, None, network, force_unit_gwei=True
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
(TR.ethereum__gas_limit, gas_limit_str),
|
||||||
|
(TR.ethereum__gas_price, gas_price_str),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_fee_items_eip1559(
|
||||||
|
max_gas_fee: int,
|
||||||
|
max_priority_fee: int,
|
||||||
|
gas_limit: int,
|
||||||
|
network: EthereumNetworkInfo,
|
||||||
|
) -> Iterable[tuple[str, str]]:
|
||||||
|
# EIP-1559
|
||||||
|
gas_limit_str = TR.ethereum__units_template.format(gas_limit)
|
||||||
|
max_gas_fee_str = format_ethereum_amount(
|
||||||
|
max_gas_fee, None, network, force_unit_gwei=True
|
||||||
|
)
|
||||||
|
max_priority_fee_str = format_ethereum_amount(
|
||||||
|
max_priority_fee, None, network, force_unit_gwei=True
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
(TR.ethereum__gas_limit, gas_limit_str),
|
||||||
|
(TR.ethereum__max_gas_price, max_gas_fee_str),
|
||||||
|
(TR.ethereum__priority_fee, max_priority_fee_str),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def format_ethereum_amount(
|
||||||
|
value: int,
|
||||||
|
token: EthereumTokenInfo | None,
|
||||||
|
network: EthereumNetworkInfo,
|
||||||
|
force_unit_gwei: bool = False,
|
||||||
|
) -> str:
|
||||||
|
from trezor.strings import format_amount
|
||||||
|
|
||||||
|
if token:
|
||||||
|
suffix = token.symbol
|
||||||
|
decimals = token.decimals
|
||||||
|
else:
|
||||||
|
suffix = network.symbol
|
||||||
|
decimals = 18
|
||||||
|
|
||||||
|
if force_unit_gwei:
|
||||||
|
assert token is None
|
||||||
|
assert decimals >= 9
|
||||||
|
decimals = decimals - 9
|
||||||
|
suffix = "Gwei"
|
||||||
|
elif decimals > 9 and value < 10 ** (decimals - 9):
|
||||||
|
# Don't want to display wei values for tokens with small decimal numbers
|
||||||
|
suffix = "Wei " + suffix
|
||||||
|
decimals = 0
|
||||||
|
|
||||||
|
amount = format_amount(value, decimals)
|
||||||
|
return f"{amount} {suffix}"
|
||||||
|
|
||||||
|
|
||||||
def _from_bytes_bigendian_signed(b: bytes) -> int:
|
def _from_bytes_bigendian_signed(b: bytes) -> int:
|
||||||
negative = b[0] & 0x80
|
negative = b[0] & 0x80
|
||||||
if negative:
|
if negative:
|
||||||
|
@ -4,12 +4,12 @@ from trezor import TR, ui
|
|||||||
from trezor.enums import ButtonRequestType
|
from trezor.enums import ButtonRequestType
|
||||||
from trezor.ui.layouts import (
|
from trezor.ui.layouts import (
|
||||||
confirm_blob,
|
confirm_blob,
|
||||||
confirm_ethereum_tx,
|
confirm_ethereum_staking_tx,
|
||||||
confirm_text,
|
confirm_text,
|
||||||
should_show_more,
|
should_show_more,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .helpers import address_from_bytes, decode_typed_data
|
from .helpers import address_from_bytes, decode_typed_data, format_ethereum_amount
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Awaitable, Iterable
|
from typing import Awaitable, Iterable
|
||||||
@ -25,12 +25,14 @@ if TYPE_CHECKING:
|
|||||||
async def require_confirm_tx(
|
async def require_confirm_tx(
|
||||||
to_bytes: bytes,
|
to_bytes: bytes,
|
||||||
value: int,
|
value: int,
|
||||||
gas_price: int,
|
maximum_fee: str,
|
||||||
gas_limit: int,
|
fee_info_items: Iterable[tuple[str, str]],
|
||||||
network: EthereumNetworkInfo,
|
network: EthereumNetworkInfo,
|
||||||
token: EthereumTokenInfo | None,
|
token: EthereumTokenInfo | None,
|
||||||
chunkify: bool,
|
chunkify: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
from trezor.ui.layouts import confirm_ethereum_tx
|
||||||
|
|
||||||
if to_bytes:
|
if to_bytes:
|
||||||
to_str = address_from_bytes(to_bytes, network)
|
to_str = address_from_bytes(to_bytes, network)
|
||||||
else:
|
else:
|
||||||
@ -38,56 +40,80 @@ async def require_confirm_tx(
|
|||||||
chunkify = False
|
chunkify = False
|
||||||
|
|
||||||
total_amount = format_ethereum_amount(value, token, network)
|
total_amount = format_ethereum_amount(value, token, network)
|
||||||
maximum_fee = format_ethereum_amount(gas_price * gas_limit, None, network)
|
|
||||||
gas_limit_str = TR.ethereum__units_template.format(gas_limit)
|
|
||||||
gas_price_str = format_ethereum_amount(
|
|
||||||
gas_price, None, network, force_unit_gwei=True
|
|
||||||
)
|
|
||||||
|
|
||||||
items = (
|
|
||||||
(TR.ethereum__gas_limit, gas_limit_str),
|
|
||||||
(TR.ethereum__gas_price, gas_price_str),
|
|
||||||
)
|
|
||||||
|
|
||||||
await confirm_ethereum_tx(
|
await confirm_ethereum_tx(
|
||||||
to_str, total_amount, maximum_fee, items, chunkify=chunkify
|
to_str, total_amount, maximum_fee, fee_info_items, chunkify=chunkify
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def require_confirm_tx_eip1559(
|
async def require_confirm_stake(
|
||||||
to_bytes: bytes,
|
addr_bytes: bytes,
|
||||||
value: int,
|
value: int,
|
||||||
max_gas_fee: int,
|
maximum_fee: str,
|
||||||
max_priority_fee: int,
|
fee_info_items: Iterable[tuple[str, str]],
|
||||||
gas_limit: int,
|
|
||||||
network: EthereumNetworkInfo,
|
network: EthereumNetworkInfo,
|
||||||
token: EthereumTokenInfo | None,
|
|
||||||
chunkify: bool,
|
chunkify: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
if to_bytes:
|
|
||||||
to_str = address_from_bytes(to_bytes, network)
|
|
||||||
else:
|
|
||||||
to_str = TR.ethereum__new_contract
|
|
||||||
chunkify = False
|
|
||||||
|
|
||||||
total_amount = format_ethereum_amount(value, token, network)
|
addr_str = address_from_bytes(addr_bytes, network)
|
||||||
maximum_fee = format_ethereum_amount(max_gas_fee * gas_limit, None, network)
|
total_amount = format_ethereum_amount(value, None, network)
|
||||||
gas_limit_str = TR.ethereum__units_template.format(gas_limit)
|
await confirm_ethereum_staking_tx(
|
||||||
max_gas_fee_str = format_ethereum_amount(
|
TR.ethereum__staking_stake, # title
|
||||||
max_gas_fee, None, network, force_unit_gwei=True
|
TR.ethereum__staking_stake_intro, # intro_question
|
||||||
)
|
TR.ethereum__staking_stake, # verb
|
||||||
max_priority_fee_str = format_ethereum_amount(
|
total_amount, # total_amount
|
||||||
max_priority_fee, None, network, force_unit_gwei=True
|
maximum_fee, # maximum_fee
|
||||||
|
addr_str, # address
|
||||||
|
TR.ethereum__staking_stake_address, # address_title
|
||||||
|
fee_info_items, # info_items
|
||||||
|
chunkify=chunkify,
|
||||||
)
|
)
|
||||||
|
|
||||||
items: tuple[tuple[str, str], ...] = (
|
|
||||||
(TR.ethereum__gas_limit, gas_limit_str),
|
async def require_confirm_unstake(
|
||||||
(TR.ethereum__max_gas_price, max_gas_fee_str),
|
addr_bytes: bytes,
|
||||||
(TR.ethereum__priority_fee, max_priority_fee_str),
|
value: int,
|
||||||
|
maximum_fee: str,
|
||||||
|
fee_info_items: Iterable[tuple[str, str]],
|
||||||
|
network: EthereumNetworkInfo,
|
||||||
|
chunkify: bool,
|
||||||
|
) -> None:
|
||||||
|
|
||||||
|
addr_str = address_from_bytes(addr_bytes, network)
|
||||||
|
total_amount = format_ethereum_amount(value, None, network)
|
||||||
|
|
||||||
|
await confirm_ethereum_staking_tx(
|
||||||
|
TR.ethereum__staking_unstake, # title
|
||||||
|
TR.ethereum__staking_unstake_intro, # intro_question
|
||||||
|
TR.ethereum__staking_unstake, # verb
|
||||||
|
total_amount, # total_amount
|
||||||
|
maximum_fee, # maximum_fee
|
||||||
|
addr_str, # address
|
||||||
|
TR.ethereum__staking_stake_address, # address_title
|
||||||
|
fee_info_items, # info_items
|
||||||
|
chunkify=chunkify,
|
||||||
)
|
)
|
||||||
|
|
||||||
await confirm_ethereum_tx(
|
|
||||||
to_str, total_amount, maximum_fee, items, chunkify=chunkify
|
async def require_confirm_claim(
|
||||||
|
addr_bytes: bytes,
|
||||||
|
maximum_fee: str,
|
||||||
|
fee_info_items: Iterable[tuple[str, str]],
|
||||||
|
network: EthereumNetworkInfo,
|
||||||
|
chunkify: bool,
|
||||||
|
) -> None:
|
||||||
|
|
||||||
|
addr_str = address_from_bytes(addr_bytes, network)
|
||||||
|
await confirm_ethereum_staking_tx(
|
||||||
|
TR.ethereum__staking_claim, # title
|
||||||
|
TR.ethereum__staking_claim_intro, # intro_question
|
||||||
|
TR.ethereum__staking_claim, # verb
|
||||||
|
"", # total_amount
|
||||||
|
maximum_fee, # maximum_fee
|
||||||
|
addr_str, # address
|
||||||
|
TR.ethereum__staking_claim_address, # address_title
|
||||||
|
fee_info_items, # info_items
|
||||||
|
chunkify=chunkify,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -119,7 +145,7 @@ def require_confirm_address(address_bytes: bytes) -> Awaitable[None]:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def require_confirm_data(data: bytes, data_total: int) -> Awaitable[None]:
|
def require_confirm_other_data(data: bytes, data_total: int) -> Awaitable[None]:
|
||||||
return confirm_blob(
|
return confirm_blob(
|
||||||
"confirm_data",
|
"confirm_data",
|
||||||
TR.ethereum__title_confirm_data,
|
TR.ethereum__title_confirm_data,
|
||||||
@ -258,35 +284,6 @@ async def confirm_typed_value(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def format_ethereum_amount(
|
|
||||||
value: int,
|
|
||||||
token: EthereumTokenInfo | None,
|
|
||||||
network: EthereumNetworkInfo,
|
|
||||||
force_unit_gwei: bool = False,
|
|
||||||
) -> str:
|
|
||||||
from trezor.strings import format_amount
|
|
||||||
|
|
||||||
if token:
|
|
||||||
suffix = token.symbol
|
|
||||||
decimals = token.decimals
|
|
||||||
else:
|
|
||||||
suffix = network.symbol
|
|
||||||
decimals = 18
|
|
||||||
|
|
||||||
if force_unit_gwei:
|
|
||||||
assert token is None
|
|
||||||
assert decimals >= 9
|
|
||||||
decimals = decimals - 9
|
|
||||||
suffix = "Gwei"
|
|
||||||
elif decimals > 9 and value < 10 ** (decimals - 9):
|
|
||||||
# Don't want to display wei values for tokens with small decimal numbers
|
|
||||||
suffix = "Wei " + suffix
|
|
||||||
decimals = 0
|
|
||||||
|
|
||||||
amount = format_amount(value, decimals)
|
|
||||||
return f"{amount} {suffix}"
|
|
||||||
|
|
||||||
|
|
||||||
def limit_str(s: str, limit: int = 16) -> str:
|
def limit_str(s: str, limit: int = 16) -> str:
|
||||||
"""Shortens string to show the last <limit> characters."""
|
"""Shortens string to show the last <limit> characters."""
|
||||||
if len(s) <= limit + 2:
|
if len(s) <= limit + 2:
|
||||||
|
@ -2,13 +2,23 @@ from typing import TYPE_CHECKING
|
|||||||
|
|
||||||
from trezor.crypto import rlp
|
from trezor.crypto import rlp
|
||||||
from trezor.messages import EthereumTxRequest
|
from trezor.messages import EthereumTxRequest
|
||||||
|
from trezor.utils import BufferReader
|
||||||
from trezor.wire import DataError
|
from trezor.wire import DataError
|
||||||
|
|
||||||
|
from apps.ethereum import staking_tx_constants as constants
|
||||||
|
|
||||||
from .helpers import bytes_from_address
|
from .helpers import bytes_from_address
|
||||||
from .keychain import with_keychain_from_chain_id
|
from .keychain import with_keychain_from_chain_id
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from trezor.messages import EthereumSignTx, EthereumTokenInfo, EthereumTxAck
|
from typing import Iterable
|
||||||
|
|
||||||
|
from trezor.messages import (
|
||||||
|
EthereumNetworkInfo,
|
||||||
|
EthereumSignTx,
|
||||||
|
EthereumTokenInfo,
|
||||||
|
EthereumTxAck,
|
||||||
|
)
|
||||||
|
|
||||||
from apps.common.keychain import Keychain
|
from apps.common.keychain import Keychain
|
||||||
|
|
||||||
@ -33,7 +43,9 @@ async def sign_tx(
|
|||||||
|
|
||||||
from apps.common import paths
|
from apps.common import paths
|
||||||
|
|
||||||
from .layout import require_confirm_data, require_confirm_tx
|
from .helpers import format_ethereum_amount, get_fee_items_regular
|
||||||
|
|
||||||
|
data_total = msg.data_length # local_cache_attribute
|
||||||
|
|
||||||
# check
|
# check
|
||||||
if msg.tx_type not in [1, 6, None]:
|
if msg.tx_type not in [1, 6, None]:
|
||||||
@ -42,26 +54,20 @@ async def sign_tx(
|
|||||||
raise DataError("Fee overflow")
|
raise DataError("Fee overflow")
|
||||||
check_common_fields(msg)
|
check_common_fields(msg)
|
||||||
|
|
||||||
|
# have a user confirm signing
|
||||||
await paths.validate_path(keychain, msg.address_n)
|
await paths.validate_path(keychain, msg.address_n)
|
||||||
|
address_bytes = bytes_from_address(msg.to)
|
||||||
# Handle ERC20s
|
gas_price = int.from_bytes(msg.gas_price, "big")
|
||||||
token, address_bytes, recipient, value = await handle_erc20(msg, defs)
|
gas_limit = int.from_bytes(msg.gas_limit, "big")
|
||||||
|
maximum_fee = format_ethereum_amount(gas_price * gas_limit, None, defs.network)
|
||||||
data_total = msg.data_length # local_cache_attribute
|
fee_items = get_fee_items_regular(
|
||||||
|
gas_price,
|
||||||
if token is None and data_total > 0:
|
gas_limit,
|
||||||
await require_confirm_data(msg.data_initial_chunk, data_total)
|
|
||||||
|
|
||||||
await require_confirm_tx(
|
|
||||||
recipient,
|
|
||||||
value,
|
|
||||||
int.from_bytes(msg.gas_price, "big"),
|
|
||||||
int.from_bytes(msg.gas_limit, "big"),
|
|
||||||
defs.network,
|
defs.network,
|
||||||
token,
|
|
||||||
bool(msg.chunkify),
|
|
||||||
)
|
)
|
||||||
|
await confirm_tx_data(msg, defs, address_bytes, maximum_fee, fee_items, data_total)
|
||||||
|
|
||||||
|
# sign
|
||||||
data = bytearray()
|
data = bytearray()
|
||||||
data += msg.data_initial_chunk
|
data += msg.data_initial_chunk
|
||||||
data_left = data_total - len(msg.data_initial_chunk)
|
data_left = data_total - len(msg.data_initial_chunk)
|
||||||
@ -99,16 +105,89 @@ async def sign_tx(
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
async def handle_erc20(
|
async def confirm_tx_data(
|
||||||
|
msg: MsgInSignTx,
|
||||||
|
defs: Definitions,
|
||||||
|
address_bytes: bytes,
|
||||||
|
maximum_fee: str,
|
||||||
|
fee_items: Iterable[tuple[str, str]],
|
||||||
|
data_total_len: int,
|
||||||
|
) -> None:
|
||||||
|
# function distinguishes between staking / smart contracts / regular transactions
|
||||||
|
from .layout import require_confirm_other_data, require_confirm_tx
|
||||||
|
|
||||||
|
if await handle_staking(msg, defs.network, address_bytes, maximum_fee, fee_items):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Handle ERC-20, currently only 'transfer' function
|
||||||
|
token, recipient, value = await handle_erc20_transfer(msg, defs, address_bytes)
|
||||||
|
|
||||||
|
if token is None and data_total_len > 0:
|
||||||
|
await require_confirm_other_data(msg.data_initial_chunk, data_total_len)
|
||||||
|
|
||||||
|
await require_confirm_tx(
|
||||||
|
recipient,
|
||||||
|
value,
|
||||||
|
maximum_fee,
|
||||||
|
fee_items,
|
||||||
|
defs.network,
|
||||||
|
token,
|
||||||
|
bool(msg.chunkify),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def handle_staking(
|
||||||
|
msg: MsgInSignTx,
|
||||||
|
network: EthereumNetworkInfo,
|
||||||
|
address_bytes: bytes,
|
||||||
|
maximum_fee: str,
|
||||||
|
fee_items: Iterable[tuple[str, str]],
|
||||||
|
) -> bool:
|
||||||
|
|
||||||
|
data_reader = BufferReader(msg.data_initial_chunk)
|
||||||
|
if data_reader.remaining_count() < constants.SC_FUNC_SIG_BYTES:
|
||||||
|
return False
|
||||||
|
|
||||||
|
func_sig = data_reader.read_memoryview(constants.SC_FUNC_SIG_BYTES)
|
||||||
|
if address_bytes in constants.ADDRESSES_POOL:
|
||||||
|
if func_sig == constants.SC_FUNC_SIG_STAKE:
|
||||||
|
await _handle_staking_tx_stake(
|
||||||
|
data_reader, msg, network, address_bytes, maximum_fee, fee_items
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
if func_sig == constants.SC_FUNC_SIG_UNSTAKE:
|
||||||
|
await _handle_staking_tx_unstake(
|
||||||
|
data_reader, msg, network, address_bytes, maximum_fee, fee_items
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
if address_bytes in constants.ADDRESSES_ACCOUNTING:
|
||||||
|
if func_sig == constants.SC_FUNC_SIG_CLAIM:
|
||||||
|
await _handle_staking_tx_claim(
|
||||||
|
data_reader,
|
||||||
|
address_bytes,
|
||||||
|
maximum_fee,
|
||||||
|
fee_items,
|
||||||
|
network,
|
||||||
|
bool(msg.chunkify),
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# data not corresponding to staking transaction
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
async def handle_erc20_transfer(
|
||||||
msg: MsgInSignTx,
|
msg: MsgInSignTx,
|
||||||
definitions: Definitions,
|
definitions: Definitions,
|
||||||
) -> tuple[EthereumTokenInfo | None, bytes, bytes, int]:
|
address_bytes: bytes,
|
||||||
|
) -> tuple[EthereumTokenInfo | None, bytes, int]:
|
||||||
from . import tokens
|
from . import tokens
|
||||||
from .layout import require_confirm_unknown_token
|
from .layout import require_confirm_unknown_token
|
||||||
|
|
||||||
data_initial_chunk = msg.data_initial_chunk # local_cache_attribute
|
data_initial_chunk = msg.data_initial_chunk # local_cache_attribute
|
||||||
token = None
|
token = None
|
||||||
address_bytes = recipient = bytes_from_address(msg.to)
|
recipient = address_bytes
|
||||||
value = int.from_bytes(msg.value, "big")
|
value = int.from_bytes(msg.value, "big")
|
||||||
if (
|
if (
|
||||||
len(msg.to) in (40, 42)
|
len(msg.to) in (40, 42)
|
||||||
@ -125,7 +204,7 @@ async def handle_erc20(
|
|||||||
if token is tokens.UNKNOWN_TOKEN:
|
if token is tokens.UNKNOWN_TOKEN:
|
||||||
await require_confirm_unknown_token(address_bytes)
|
await require_confirm_unknown_token(address_bytes)
|
||||||
|
|
||||||
return token, address_bytes, recipient, value
|
return token, recipient, value
|
||||||
|
|
||||||
|
|
||||||
def _get_total_length(msg: EthereumSignTx, data_total: int) -> int:
|
def _get_total_length(msg: EthereumSignTx, data_total: int) -> int:
|
||||||
@ -208,3 +287,92 @@ def check_common_fields(msg: MsgInSignTx) -> None:
|
|||||||
|
|
||||||
if msg.chain_id == 0:
|
if msg.chain_id == 0:
|
||||||
raise DataError("Chain ID out of bounds")
|
raise DataError("Chain ID out of bounds")
|
||||||
|
|
||||||
|
|
||||||
|
async def _handle_staking_tx_stake(
|
||||||
|
data_reader: BufferReader,
|
||||||
|
msg: MsgInSignTx,
|
||||||
|
network: EthereumNetworkInfo,
|
||||||
|
address_bytes: bytes,
|
||||||
|
maximum_fee: str,
|
||||||
|
fee_items: Iterable[tuple[str, str]],
|
||||||
|
) -> None:
|
||||||
|
from .layout import require_confirm_stake
|
||||||
|
|
||||||
|
# stake args:
|
||||||
|
# - arg0: uint64, source (should be 1)
|
||||||
|
try:
|
||||||
|
source = int.from_bytes(
|
||||||
|
data_reader.read_memoryview(constants.SC_ARGUMENT_BYTES), "big"
|
||||||
|
)
|
||||||
|
if source != 1:
|
||||||
|
raise ValueError # wrong value of 1st argument ('source' should be 1)
|
||||||
|
if data_reader.remaining_count() != 0:
|
||||||
|
raise ValueError # wrong number of arguments for stake (should be 1)
|
||||||
|
except (ValueError, EOFError):
|
||||||
|
raise DataError("Invalid staking transaction call")
|
||||||
|
|
||||||
|
await require_confirm_stake(
|
||||||
|
address_bytes,
|
||||||
|
int.from_bytes(msg.value, "big"),
|
||||||
|
maximum_fee,
|
||||||
|
fee_items,
|
||||||
|
network,
|
||||||
|
bool(msg.chunkify),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def _handle_staking_tx_unstake(
|
||||||
|
data_reader: BufferReader,
|
||||||
|
msg: MsgInSignTx,
|
||||||
|
network: EthereumNetworkInfo,
|
||||||
|
address_bytes: bytes,
|
||||||
|
maximum_fee: str,
|
||||||
|
fee_items: Iterable[tuple[str, str]],
|
||||||
|
) -> None:
|
||||||
|
from .layout import require_confirm_unstake
|
||||||
|
|
||||||
|
# unstake args:
|
||||||
|
# - arg0: uint256, value
|
||||||
|
# - arg1: uint16, isAllowedInterchange (bool)
|
||||||
|
# - arg2: uint64, source, should be 1
|
||||||
|
try:
|
||||||
|
value = int.from_bytes(
|
||||||
|
data_reader.read_memoryview(constants.SC_ARGUMENT_BYTES), "big"
|
||||||
|
)
|
||||||
|
_ = data_reader.read_memoryview(constants.SC_ARGUMENT_BYTES) # skip arg1
|
||||||
|
source = int.from_bytes(
|
||||||
|
data_reader.read_memoryview(constants.SC_ARGUMENT_BYTES), "big"
|
||||||
|
)
|
||||||
|
if source != 1:
|
||||||
|
raise ValueError # wrong value of 3rd argument ('source' should be 1)
|
||||||
|
if data_reader.remaining_count() != 0:
|
||||||
|
raise ValueError # wrong number of arguments for unstake (should be 3)
|
||||||
|
except (ValueError, EOFError):
|
||||||
|
raise DataError("Invalid staking transaction call")
|
||||||
|
|
||||||
|
await require_confirm_unstake(
|
||||||
|
address_bytes,
|
||||||
|
value,
|
||||||
|
maximum_fee,
|
||||||
|
fee_items,
|
||||||
|
network,
|
||||||
|
bool(msg.chunkify),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def _handle_staking_tx_claim(
|
||||||
|
data_reader: BufferReader,
|
||||||
|
staking_addr: bytes,
|
||||||
|
maximum_fee: str,
|
||||||
|
fee_items: Iterable[tuple[str, str]],
|
||||||
|
network: EthereumNetworkInfo,
|
||||||
|
chunkify: bool,
|
||||||
|
) -> None:
|
||||||
|
from .layout import require_confirm_claim
|
||||||
|
|
||||||
|
# claim has no args
|
||||||
|
if data_reader.remaining_count() != 0:
|
||||||
|
raise DataError("Invalid staking transaction call")
|
||||||
|
|
||||||
|
await require_confirm_claim(staking_addr, maximum_fee, fee_items, network, chunkify)
|
||||||
|
@ -42,8 +42,8 @@ async def sign_tx_eip1559(
|
|||||||
|
|
||||||
from apps.common import paths
|
from apps.common import paths
|
||||||
|
|
||||||
from .layout import require_confirm_data, require_confirm_tx_eip1559
|
from .helpers import format_ethereum_amount, get_fee_items_eip1559
|
||||||
from .sign_tx import check_common_fields, handle_erc20, send_request_chunk
|
from .sign_tx import check_common_fields, confirm_tx_data, send_request_chunk
|
||||||
|
|
||||||
gas_limit = msg.gas_limit # local_cache_attribute
|
gas_limit = msg.gas_limit # local_cache_attribute
|
||||||
data_total = msg.data_length # local_cache_attribute
|
data_total = msg.data_length # local_cache_attribute
|
||||||
@ -55,25 +55,23 @@ async def sign_tx_eip1559(
|
|||||||
raise wire.DataError("Fee overflow")
|
raise wire.DataError("Fee overflow")
|
||||||
check_common_fields(msg)
|
check_common_fields(msg)
|
||||||
|
|
||||||
|
# have a user confirm signing
|
||||||
await paths.validate_path(keychain, msg.address_n)
|
await paths.validate_path(keychain, msg.address_n)
|
||||||
|
address_bytes = bytes_from_address(msg.to)
|
||||||
|
|
||||||
# Handle ERC20s
|
max_gas_fee = int.from_bytes(msg.max_gas_fee, "big")
|
||||||
token, address_bytes, recipient, value = await handle_erc20(msg, defs)
|
max_priority_fee = int.from_bytes(msg.max_priority_fee, "big")
|
||||||
|
gas_limit = int.from_bytes(msg.gas_limit, "big")
|
||||||
if token is None and data_total > 0:
|
maximum_fee = format_ethereum_amount(max_gas_fee * gas_limit, None, defs.network)
|
||||||
await require_confirm_data(msg.data_initial_chunk, data_total)
|
fee_items = get_fee_items_eip1559(
|
||||||
|
max_gas_fee,
|
||||||
await require_confirm_tx_eip1559(
|
max_priority_fee,
|
||||||
recipient,
|
gas_limit,
|
||||||
value,
|
|
||||||
int.from_bytes(msg.max_gas_fee, "big"),
|
|
||||||
int.from_bytes(msg.max_priority_fee, "big"),
|
|
||||||
int.from_bytes(gas_limit, "big"),
|
|
||||||
defs.network,
|
defs.network,
|
||||||
token,
|
|
||||||
bool(msg.chunkify),
|
|
||||||
)
|
)
|
||||||
|
await confirm_tx_data(msg, defs, address_bytes, maximum_fee, fee_items, data_total)
|
||||||
|
|
||||||
|
# transaction data confirmed, proceed with signing
|
||||||
data = bytearray()
|
data = bytearray()
|
||||||
data += msg.data_initial_chunk
|
data += msg.data_initial_chunk
|
||||||
data_left = data_total - len(msg.data_initial_chunk)
|
data_left = data_total - len(msg.data_initial_chunk)
|
||||||
|
21
core/src/apps/ethereum/staking_tx_constants.py
Normal file
21
core/src/apps/ethereum/staking_tx_constants.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
from micropython import const
|
||||||
|
from ubinascii import unhexlify
|
||||||
|
|
||||||
|
# smart contract 'data' field lengths in bytes
|
||||||
|
SC_FUNC_SIG_BYTES = const(4)
|
||||||
|
SC_ARGUMENT_BYTES = const(32)
|
||||||
|
|
||||||
|
# staking operations function signatures
|
||||||
|
SC_FUNC_SIG_STAKE = unhexlify("3a29dbae")
|
||||||
|
SC_FUNC_SIG_UNSTAKE = unhexlify("76ec871c")
|
||||||
|
SC_FUNC_SIG_CLAIM = unhexlify("33986ffa")
|
||||||
|
|
||||||
|
# addresses for pool (stake/unstake) and accounting (claim) operations
|
||||||
|
ADDRESSES_POOL = (
|
||||||
|
unhexlify("AFA848357154a6a624686b348303EF9a13F63264"), # holesky testnet
|
||||||
|
unhexlify("D523794C879D9eC028960a231F866758e405bE34"), # mainnet
|
||||||
|
)
|
||||||
|
ADDRESSES_ACCOUNTING = (
|
||||||
|
unhexlify("624087DD1904ab122A32878Ce9e933C7071F53B9"), # holesky testnet
|
||||||
|
unhexlify("7a7f0b3c23C23a31cFcb0c44709be70d4D545c6e"), # mainnet
|
||||||
|
)
|
@ -1023,7 +1023,7 @@ async def confirm_value(
|
|||||||
title=info_title.upper(),
|
title=info_title.upper(),
|
||||||
action=info_value,
|
action=info_value,
|
||||||
description=description,
|
description=description,
|
||||||
verb=TR.buttons__back,
|
verb="",
|
||||||
verb_cancel="<",
|
verb_cancel="<",
|
||||||
hold=False,
|
hold=False,
|
||||||
reverse=False,
|
reverse=False,
|
||||||
@ -1067,6 +1067,56 @@ async def confirm_total(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_ethereum_staking_tx(
|
||||||
|
title: str,
|
||||||
|
intro_question: str,
|
||||||
|
verb: str,
|
||||||
|
total_amount: str,
|
||||||
|
maximum_fee: str,
|
||||||
|
address: str,
|
||||||
|
address_title: str,
|
||||||
|
info_items: Iterable[tuple[str, str]],
|
||||||
|
br_type: str = "confirm_ethereum_staking_tx",
|
||||||
|
br_code: ButtonRequestType = ButtonRequestType.SignTx,
|
||||||
|
chunkify: bool = False,
|
||||||
|
) -> None:
|
||||||
|
|
||||||
|
# intro
|
||||||
|
await confirm_value(
|
||||||
|
title,
|
||||||
|
intro_question,
|
||||||
|
"",
|
||||||
|
br_type,
|
||||||
|
br_code,
|
||||||
|
verb=verb,
|
||||||
|
info_items=((address_title, address),),
|
||||||
|
)
|
||||||
|
|
||||||
|
# confirmation
|
||||||
|
if verb == TR.ethereum__staking_claim:
|
||||||
|
amount_title = verb
|
||||||
|
amount_value = ""
|
||||||
|
else:
|
||||||
|
amount_title = TR.words__amount + ":"
|
||||||
|
amount_value = total_amount
|
||||||
|
await raise_if_not_confirmed(
|
||||||
|
interact(
|
||||||
|
RustLayout(
|
||||||
|
trezorui2.altcoin_tx_summary(
|
||||||
|
amount_title=amount_title,
|
||||||
|
amount_value=amount_value,
|
||||||
|
fee_title=TR.send__maximum_fee,
|
||||||
|
fee_value=maximum_fee,
|
||||||
|
items=info_items,
|
||||||
|
cancel_cross=True,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
br_type=br_type,
|
||||||
|
br_code=br_code,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def confirm_solana_tx(
|
async def confirm_solana_tx(
|
||||||
amount: str,
|
amount: str,
|
||||||
fee: str,
|
fee: str,
|
||||||
|
@ -859,6 +859,7 @@ def confirm_value(
|
|||||||
verb: str | None = None,
|
verb: str | None = None,
|
||||||
subtitle: str | None = None,
|
subtitle: str | None = None,
|
||||||
hold: bool = False,
|
hold: bool = False,
|
||||||
|
value_text_mono: bool = True,
|
||||||
info_items: Iterable[tuple[str, str]] | None = None,
|
info_items: Iterable[tuple[str, str]] | None = None,
|
||||||
) -> Awaitable[None]:
|
) -> Awaitable[None]:
|
||||||
"""General confirmation dialog, used by many other confirm_* functions."""
|
"""General confirmation dialog, used by many other confirm_* functions."""
|
||||||
@ -948,7 +949,11 @@ async def confirm_total(
|
|||||||
info_items.append((TR.confirm_total__fee_rate, fee_rate_amount))
|
info_items.append((TR.confirm_total__fee_rate, fee_rate_amount))
|
||||||
|
|
||||||
await confirm_summary(
|
await confirm_summary(
|
||||||
items, TR.words__title_summary, info_items, br_type=br_type, br_code=br_code
|
items,
|
||||||
|
TR.words__title_summary,
|
||||||
|
info_items=info_items,
|
||||||
|
br_type=br_type,
|
||||||
|
br_code=br_code,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -956,6 +961,7 @@ async def confirm_summary(
|
|||||||
items: Iterable[tuple[str, str]],
|
items: Iterable[tuple[str, str]],
|
||||||
title: str | None = None,
|
title: str | None = None,
|
||||||
info_items: Iterable[tuple[str, str]] | None = None,
|
info_items: Iterable[tuple[str, str]] | None = None,
|
||||||
|
info_title: str | None = None,
|
||||||
br_type: str = "confirm_total",
|
br_type: str = "confirm_total",
|
||||||
br_code: ButtonRequestType = ButtonRequestType.SignTx,
|
br_code: ButtonRequestType = ButtonRequestType.SignTx,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -971,7 +977,7 @@ async def confirm_summary(
|
|||||||
info_items = info_items or []
|
info_items = info_items or []
|
||||||
info_layout = RustLayout(
|
info_layout = RustLayout(
|
||||||
trezorui2.show_info_with_cancel(
|
trezorui2.show_info_with_cancel(
|
||||||
title=TR.words__title_information,
|
title=info_title.upper() if info_title else TR.words__title_information,
|
||||||
items=info_items,
|
items=info_items,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -1025,6 +1031,60 @@ async def confirm_ethereum_tx(
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_ethereum_staking_tx(
|
||||||
|
title: str,
|
||||||
|
intro_question: str,
|
||||||
|
verb: str,
|
||||||
|
total_amount: str,
|
||||||
|
maximum_fee: str,
|
||||||
|
address: str,
|
||||||
|
address_title: str,
|
||||||
|
info_items: Iterable[tuple[str, str]] | None = None,
|
||||||
|
chunkify: bool = False,
|
||||||
|
br_type: str = "confirm_ethereum_staking_tx",
|
||||||
|
br_code: ButtonRequestType = ButtonRequestType.SignTx,
|
||||||
|
) -> None:
|
||||||
|
|
||||||
|
# intro
|
||||||
|
# NOTE: this layout very similar to `confirm_value` with some adjustments
|
||||||
|
msg_layout = RustLayout(
|
||||||
|
trezorui2.confirm_value(
|
||||||
|
title=title,
|
||||||
|
value=intro_question,
|
||||||
|
description=None,
|
||||||
|
subtitle=None,
|
||||||
|
verb=verb,
|
||||||
|
info_button=True,
|
||||||
|
text_mono=False,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
info_layout = RustLayout(
|
||||||
|
trezorui2.show_info_with_cancel(
|
||||||
|
title=address_title,
|
||||||
|
items=(("", address),),
|
||||||
|
chunkify=chunkify,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
await raise_if_not_confirmed(with_info(msg_layout, info_layout, br_type, br_code))
|
||||||
|
|
||||||
|
# confirmation
|
||||||
|
if verb == TR.ethereum__staking_claim:
|
||||||
|
items = ((TR.send__maximum_fee, maximum_fee),)
|
||||||
|
else:
|
||||||
|
items = (
|
||||||
|
(TR.words__amount + ":", total_amount),
|
||||||
|
(TR.send__maximum_fee, maximum_fee),
|
||||||
|
)
|
||||||
|
await confirm_summary(
|
||||||
|
items, # items
|
||||||
|
title=title,
|
||||||
|
info_title=TR.confirm_total__title_fee,
|
||||||
|
info_items=info_items,
|
||||||
|
br_type=br_type,
|
||||||
|
br_code=br_code,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def confirm_solana_tx(
|
async def confirm_solana_tx(
|
||||||
amount: str,
|
amount: str,
|
||||||
fee: str,
|
fee: str,
|
||||||
|
@ -4,12 +4,11 @@ if not utils.BITCOIN_ONLY:
|
|||||||
from ethereum_common import make_network, make_token
|
from ethereum_common import make_network, make_token
|
||||||
|
|
||||||
from apps.ethereum import networks
|
from apps.ethereum import networks
|
||||||
from apps.ethereum.layout import format_ethereum_amount
|
from apps.ethereum.helpers import format_ethereum_amount
|
||||||
from apps.ethereum.tokens import UNKNOWN_TOKEN
|
from apps.ethereum.tokens import UNKNOWN_TOKEN
|
||||||
|
|
||||||
ETH = networks.by_chain_id(1)
|
ETH = networks.by_chain_id(1)
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(not utils.BITCOIN_ONLY, "altcoin")
|
@unittest.skipUnless(not utils.BITCOIN_ONLY, "altcoin")
|
||||||
class TestFormatEthereumAmount(unittest.TestCase):
|
class TestFormatEthereumAmount(unittest.TestCase):
|
||||||
def test_denominations(self):
|
def test_denominations(self):
|
||||||
|
@ -299,6 +299,14 @@
|
|||||||
"ethereum__units_template": "{} units",
|
"ethereum__units_template": "{} units",
|
||||||
"ethereum__unknown_token": "Unknown token",
|
"ethereum__unknown_token": "Unknown token",
|
||||||
"ethereum__valid_signature": "The signature is valid.",
|
"ethereum__valid_signature": "The signature is valid.",
|
||||||
|
"ethereum__staking_stake": "STAKE",
|
||||||
|
"ethereum__staking_stake_address": "STAKE ADDRESS",
|
||||||
|
"ethereum__staking_stake_intro": "Stake ETH on Everstake?",
|
||||||
|
"ethereum__staking_unstake": "UNSTAKE",
|
||||||
|
"ethereum__staking_unstake_intro": "Unstake ETH from Everstake?",
|
||||||
|
"ethereum__staking_claim": "CLAIM",
|
||||||
|
"ethereum__staking_claim_address": "CLAIM ADDRESS",
|
||||||
|
"ethereum__staking_claim_intro": "Claim ETH from Everstake?",
|
||||||
"experimental_mode__enable": "Enable experimental features?",
|
"experimental_mode__enable": "Enable experimental features?",
|
||||||
"experimental_mode__only_for_dev": "Only for development and beta testing!",
|
"experimental_mode__only_for_dev": "Only for development and beta testing!",
|
||||||
"experimental_mode__title": "EXPERIMENTAL MODE",
|
"experimental_mode__title": "EXPERIMENTAL MODE",
|
||||||
|
@ -832,5 +832,13 @@
|
|||||||
"830": "words__writable",
|
"830": "words__writable",
|
||||||
"831": "words__yes",
|
"831": "words__yes",
|
||||||
"832": "reboot_to_bootloader__just_a_moment",
|
"832": "reboot_to_bootloader__just_a_moment",
|
||||||
"833": "inputs__previous"
|
"833": "inputs__previous",
|
||||||
|
"834": "ethereum__staking_claim",
|
||||||
|
"835": "ethereum__staking_claim_address",
|
||||||
|
"836": "ethereum__staking_claim_intro",
|
||||||
|
"837": "ethereum__staking_stake",
|
||||||
|
"838": "ethereum__staking_stake_address",
|
||||||
|
"839": "ethereum__staking_stake_intro",
|
||||||
|
"840": "ethereum__staking_unstake",
|
||||||
|
"841": "ethereum__staking_unstake_intro"
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"current": {
|
"current": {
|
||||||
"merkle_root": "4add9b7a2b80544a382378bc1abdae38600460825ef8010d45da5c2f28d86d26",
|
"merkle_root": "ebba747f556487944a26b19deb5910648694670f0de05f5a1569e1e12cf47ea0",
|
||||||
"signature": null,
|
"signature": null,
|
||||||
"datetime": "2024-02-21T09:03:23.136322",
|
"datetime": "2024-02-21T15:09:10.231125",
|
||||||
"commit": "1dc00561ae04804aecbb0715d092c2a907e8eed8"
|
"commit": "4204ba14044132269dc708e3f0b0cfac3bbfd906"
|
||||||
},
|
},
|
||||||
"history": []
|
"history": []
|
||||||
}
|
}
|
||||||
|
@ -454,3 +454,74 @@ def test_signtx_data_pagination(client: Client, flow):
|
|||||||
client.watch_layout()
|
client.watch_layout()
|
||||||
client.set_input_flow(flow(client, cancel=True))
|
client.set_input_flow(flow(client, cancel=True))
|
||||||
_sign_tx_call()
|
_sign_tx_call()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip_t1("T1 does not support Everstake")
|
||||||
|
@parametrize_using_common_fixtures("ethereum/sign_tx_staking.json")
|
||||||
|
# TODO input flows to go into info screens - then also parametrizing chunkify might make sense
|
||||||
|
# @pytest.mark.parametrize("chunkify", (True, False))
|
||||||
|
def test_signtx_staking(client: Client, parameters: dict, result: dict):
|
||||||
|
with client:
|
||||||
|
sig_v, sig_r, sig_s = ethereum.sign_tx(
|
||||||
|
client,
|
||||||
|
n=parse_path(parameters["path"]),
|
||||||
|
nonce=int(parameters["nonce"], 16),
|
||||||
|
gas_price=int(parameters["gas_price"], 16),
|
||||||
|
gas_limit=int(parameters["gas_limit"], 16),
|
||||||
|
to=parameters["to_address"],
|
||||||
|
value=int(parameters["value"], 16),
|
||||||
|
data=bytes.fromhex(parameters["data"]),
|
||||||
|
chain_id=parameters["chain_id"],
|
||||||
|
tx_type=parameters["tx_type"],
|
||||||
|
definitions=None,
|
||||||
|
chunkify=False,
|
||||||
|
)
|
||||||
|
expected_v = 2 * parameters["chain_id"] + 35
|
||||||
|
assert sig_v in (expected_v, expected_v + 1)
|
||||||
|
assert sig_r.hex() == result["sig_r"]
|
||||||
|
assert sig_s.hex() == result["sig_s"]
|
||||||
|
assert sig_v == result["sig_v"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip_t1("T1 does not support Everstake")
|
||||||
|
@parametrize_using_common_fixtures("ethereum/sign_tx_staking_data_error.json")
|
||||||
|
def test_signtx_staking_bad_inputs(client: Client, parameters: dict, result: dict):
|
||||||
|
# result not needed
|
||||||
|
with pytest.raises(TrezorFailure, match=r"DataError"):
|
||||||
|
ethereum.sign_tx(
|
||||||
|
client,
|
||||||
|
n=parse_path(parameters["path"]),
|
||||||
|
nonce=int(parameters["nonce"], 16),
|
||||||
|
gas_price=int(parameters["gas_price"], 16),
|
||||||
|
gas_limit=int(parameters["gas_limit"], 16),
|
||||||
|
to=parameters["to_address"],
|
||||||
|
value=int(parameters["value"], 16),
|
||||||
|
data=bytes.fromhex(parameters["data"]),
|
||||||
|
chain_id=parameters["chain_id"],
|
||||||
|
tx_type=parameters["tx_type"],
|
||||||
|
definitions=None,
|
||||||
|
chunkify=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip_t1("T1 does not support Everstake")
|
||||||
|
@parametrize_using_common_fixtures("ethereum/sign_tx_staking_eip1559.json")
|
||||||
|
def test_signtx_staking_eip1559(client: Client, parameters: dict, result: dict):
|
||||||
|
with client:
|
||||||
|
sig_v, sig_r, sig_s = ethereum.sign_tx_eip1559(
|
||||||
|
client,
|
||||||
|
n=parse_path(parameters["path"]),
|
||||||
|
nonce=int(parameters["nonce"], 16),
|
||||||
|
max_gas_fee=int(parameters["max_gas_fee"], 16),
|
||||||
|
max_priority_fee=int(parameters["max_priority_fee"], 16),
|
||||||
|
gas_limit=int(parameters["gas_limit"], 16),
|
||||||
|
to=parameters["to_address"],
|
||||||
|
value=int(parameters["value"], 16),
|
||||||
|
data=bytes.fromhex(parameters["data"]),
|
||||||
|
chain_id=parameters["chain_id"],
|
||||||
|
definitions=None,
|
||||||
|
chunkify=True,
|
||||||
|
)
|
||||||
|
assert sig_r.hex() == result["sig_r"]
|
||||||
|
assert sig_s.hex() == result["sig_s"]
|
||||||
|
assert sig_v == result["sig_v"]
|
||||||
|
@ -4507,6 +4507,23 @@
|
|||||||
"TR_en_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "5ec441ee292a9034c7d859f216050e7af702dcc219ed16e4ca17352ae4784c9b",
|
"TR_en_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "5ec441ee292a9034c7d859f216050e7af702dcc219ed16e4ca17352ae4784c9b",
|
||||||
"TR_en_ethereum-test_signtx.py::test_signtx_fee_info": "b4ae728ff71c1e6112abbb0111b85b2760f957b677726b35734e63c318495408",
|
"TR_en_ethereum-test_signtx.py::test_signtx_fee_info": "b4ae728ff71c1e6112abbb0111b85b2760f957b677726b35734e63c318495408",
|
||||||
"TR_en_ethereum-test_signtx.py::test_signtx_go_back_from_summary": "263993daffe2a77a46a17d5b598aca84de52ba0e051e4cb5de5c524a48192ed3",
|
"TR_en_ethereum-test_signtx.py::test_signtx_go_back_from_summary": "263993daffe2a77a46a17d5b598aca84de52ba0e051e4cb5de5c524a48192ed3",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking[claim_holesky]": "8381fbc4aac0431757244c7813c33abee1a3457661a71b7b8b71fb4cd319d6f8",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking[claim_mainnet]": "8381fbc4aac0431757244c7813c33abee1a3457661a71b7b8b71fb4cd319d6f8",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking[stake_holesky]": "856bc0275109dcf0fbac25b20916ac78f358533e41e896b299959fbc0364a240",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking[stake_main]": "856bc0275109dcf0fbac25b20916ac78f358533e41e896b299959fbc0364a240",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking[unstake_holesky]": "4d80581b69013423285c924d837135a2c2b09b62cf2635fdbe3a8f224511bc7e",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking[unstake_main]": "4d80581b69013423285c924d837135a2c2b09b62cf2635fdbe3a8f224511bc7e",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[claim_bad_inputs_1]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[stake_bad_inputs_1]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[stake_bad_inputs_2]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[unstake_bad_inputs_1]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[unstake_bad_inputs_2]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[claim_holesky]": "bf6067c40a106b593ecd43632308fd384a505be4b10269eae07090d1bb24b3f1",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[claim_mainnet]": "bf6067c40a106b593ecd43632308fd384a505be4b10269eae07090d1bb24b3f1",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_holesky]": "5f0472c1ae8e221509b5568a89f7942e18caaa8e7b022d75519cfa0e671c94bc",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "5f0472c1ae8e221509b5568a89f7942e18caaa8e7b022d75519cfa0e671c94bc",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_holesky]": "9c0d8add3295ed7de71bc13084e1216149af5cce259a72dc9c558c4fbfc9e479",
|
||||||
|
"TR_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "9c0d8add3295ed7de71bc13084e1216149af5cce259a72dc9c558c4fbfc9e479",
|
||||||
"TR_en_misc-test_cosi.py::test_cosi_different_key": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095",
|
"TR_en_misc-test_cosi.py::test_cosi_different_key": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095",
|
||||||
"TR_en_misc-test_cosi.py::test_cosi_nonce": "df3420ca2395ced6fb2e3e5b984ece9d1a1151d877061681582c8f9404416600",
|
"TR_en_misc-test_cosi.py::test_cosi_nonce": "df3420ca2395ced6fb2e3e5b984ece9d1a1151d877061681582c8f9404416600",
|
||||||
"TR_en_misc-test_cosi.py::test_cosi_pubkey": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095",
|
"TR_en_misc-test_cosi.py::test_cosi_pubkey": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095",
|
||||||
@ -11564,6 +11581,23 @@
|
|||||||
"TT_en_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "243010310ac5a4c70c627507ea8501cc61c2e20728eb06bc796f093132bebb4f",
|
"TT_en_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "243010310ac5a4c70c627507ea8501cc61c2e20728eb06bc796f093132bebb4f",
|
||||||
"TT_en_ethereum-test_signtx.py::test_signtx_fee_info": "714e4c5f6e6b45fa3e78f74c7ee5e3332f39686f8b708a4f56232105bde0c3e4",
|
"TT_en_ethereum-test_signtx.py::test_signtx_fee_info": "714e4c5f6e6b45fa3e78f74c7ee5e3332f39686f8b708a4f56232105bde0c3e4",
|
||||||
"TT_en_ethereum-test_signtx.py::test_signtx_go_back_from_summary": "8bc38a773c40a70c1eb9b91a5d02ce0a61591ce9e42bd0073bc1395f560f2490",
|
"TT_en_ethereum-test_signtx.py::test_signtx_go_back_from_summary": "8bc38a773c40a70c1eb9b91a5d02ce0a61591ce9e42bd0073bc1395f560f2490",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking[claim_holesky]": "63a2b20a46d7eb9dbe188f45286f0e19b696b4fa072743156a1f70b8c33d5dad",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking[claim_mainnet]": "63a2b20a46d7eb9dbe188f45286f0e19b696b4fa072743156a1f70b8c33d5dad",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking[stake_holesky]": "f24ba4c504e12ec403aa99f19f9d9c78cc513edb2b7671063033902d089d894c",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking[stake_main]": "f24ba4c504e12ec403aa99f19f9d9c78cc513edb2b7671063033902d089d894c",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking[unstake_holesky]": "b24d5247a866e3aa69fe3fc17eabaa210890b285e3c4b84eb253570fcc0c8bed",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking[unstake_main]": "b24d5247a866e3aa69fe3fc17eabaa210890b285e3c4b84eb253570fcc0c8bed",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[claim_bad_inputs_1]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[stake_bad_inputs_1]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[stake_bad_inputs_2]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[unstake_bad_inputs_1]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[unstake_bad_inputs_2]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[claim_holesky]": "63a2b20a46d7eb9dbe188f45286f0e19b696b4fa072743156a1f70b8c33d5dad",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[claim_mainnet]": "63a2b20a46d7eb9dbe188f45286f0e19b696b4fa072743156a1f70b8c33d5dad",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_holesky]": "f24ba4c504e12ec403aa99f19f9d9c78cc513edb2b7671063033902d089d894c",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "f24ba4c504e12ec403aa99f19f9d9c78cc513edb2b7671063033902d089d894c",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_holesky]": "b24d5247a866e3aa69fe3fc17eabaa210890b285e3c4b84eb253570fcc0c8bed",
|
||||||
|
"TT_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "b24d5247a866e3aa69fe3fc17eabaa210890b285e3c4b84eb253570fcc0c8bed",
|
||||||
"TT_en_misc-test_cosi.py::test_cosi_different_key": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3",
|
"TT_en_misc-test_cosi.py::test_cosi_different_key": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3",
|
||||||
"TT_en_misc-test_cosi.py::test_cosi_nonce": "25a47ec1384fb563a6495d92d9319d19220cbb15b0f33fbdc26f01d3ccde1980",
|
"TT_en_misc-test_cosi.py::test_cosi_nonce": "25a47ec1384fb563a6495d92d9319d19220cbb15b0f33fbdc26f01d3ccde1980",
|
||||||
"TT_en_misc-test_cosi.py::test_cosi_pubkey": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3",
|
"TT_en_misc-test_cosi.py::test_cosi_pubkey": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3",
|
||||||
|
@ -6,7 +6,7 @@ EXCEPTIONS+=( "decred" ) # "decred" figures in field names used by the bitcoin
|
|||||||
EXCEPTIONS+=( "omni" ) # OMNI is part of the bitcoin app
|
EXCEPTIONS+=( "omni" ) # OMNI is part of the bitcoin app
|
||||||
# BIP39 or SLIP39 words that have "dash" in them
|
# BIP39 or SLIP39 words that have "dash" in them
|
||||||
EXCEPTIONS+=( "dash" )
|
EXCEPTIONS+=( "dash" )
|
||||||
EXCEPTIONS+=( "confirm_ethereum_tx" ) # is model-specific, so is in layout/__init__.py instead of ethereum/layout.py
|
EXCEPTIONS+=( "confirm_ethereum_tx" "confirm_ethereum_staking_tx" ) # model-specific, so is in layout/__init__.py instead of ethereum/layout.py
|
||||||
EXCEPTIONS+=( "__" ) # ignoring the translations blob (section__key delimiter)
|
EXCEPTIONS+=( "__" ) # ignoring the translations blob (section__key delimiter)
|
||||||
EXCEPTIONS+=( "{}" ) # ignoring the translations blob (template identifier)
|
EXCEPTIONS+=( "{}" ) # ignoring the translations blob (template identifier)
|
||||||
|
|
||||||
|
2
vendor/fido2-tests
vendored
2
vendor/fido2-tests
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 9cfd22ef20fec2c34d0f0e5c16a5d5152da30861
|
Subproject commit 28e177c4424820aee8a6f031474c890e5bafe72c
|
Loading…
Reference in New Issue
Block a user