|
|
|
@ -41,15 +41,34 @@
|
|
|
|
|
uint32). chain_ids larger than this will only return one bit and the caller must
|
|
|
|
|
recalculate the full value: v = 2 * chain_id + 35 + v_bit */
|
|
|
|
|
#define MAX_CHAIN_ID ((0xFFFFFFFF - 36) >> 1)
|
|
|
|
|
#define EIP1559_TX_TYPE 2
|
|
|
|
|
|
|
|
|
|
static bool ethereum_signing = false;
|
|
|
|
|
static uint32_t data_total, data_left;
|
|
|
|
|
static EthereumTxRequest msg_tx_request;
|
|
|
|
|
static CONFIDENTIAL uint8_t privkey[32];
|
|
|
|
|
static uint64_t chain_id;
|
|
|
|
|
static uint32_t tx_type;
|
|
|
|
|
static bool eip1559;
|
|
|
|
|
struct SHA3_CTX keccak_ctx = {0};
|
|
|
|
|
|
|
|
|
|
struct signing_params {
|
|
|
|
|
bool pubkeyhash_set;
|
|
|
|
|
uint8_t pubkeyhash[20];
|
|
|
|
|
uint64_t chain_id;
|
|
|
|
|
|
|
|
|
|
uint32_t data_length;
|
|
|
|
|
uint32_t data_initial_chunk_size;
|
|
|
|
|
const uint8_t *data_initial_chunk_bytes;
|
|
|
|
|
|
|
|
|
|
bool has_to;
|
|
|
|
|
const char *to;
|
|
|
|
|
|
|
|
|
|
const TokenType *token;
|
|
|
|
|
|
|
|
|
|
uint32_t value_size;
|
|
|
|
|
const uint8_t *value_bytes;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static inline void hash_data(const uint8_t *buf, size_t size) {
|
|
|
|
|
sha3_Update(&keccak_ctx, buf, size);
|
|
|
|
|
}
|
|
|
|
@ -192,11 +211,15 @@ static void send_signature(void) {
|
|
|
|
|
uint8_t v = 0;
|
|
|
|
|
layoutProgress(_("Signing"), 1000);
|
|
|
|
|
|
|
|
|
|
/* eip-155 replay protection */
|
|
|
|
|
/* hash v=chain_id, r=0, s=0 */
|
|
|
|
|
hash_rlp_number(chain_id);
|
|
|
|
|
hash_rlp_length(0, 0);
|
|
|
|
|
hash_rlp_length(0, 0);
|
|
|
|
|
if (eip1559) {
|
|
|
|
|
hash_rlp_list_length(0);
|
|
|
|
|
} else {
|
|
|
|
|
/* eip-155 replay protection */
|
|
|
|
|
/* hash v=chain_id, r=0, s=0 */
|
|
|
|
|
hash_rlp_number(chain_id);
|
|
|
|
|
hash_rlp_length(0, 0);
|
|
|
|
|
hash_rlp_length(0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
keccak_Final(&keccak_ctx, hash);
|
|
|
|
|
if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v,
|
|
|
|
@ -212,7 +235,7 @@ static void send_signature(void) {
|
|
|
|
|
msg_tx_request.has_data_length = false;
|
|
|
|
|
|
|
|
|
|
msg_tx_request.has_signature_v = true;
|
|
|
|
|
if (chain_id > MAX_CHAIN_ID) {
|
|
|
|
|
if (eip1559 || chain_id > MAX_CHAIN_ID) {
|
|
|
|
|
msg_tx_request.signature_v = v;
|
|
|
|
|
} else {
|
|
|
|
|
msg_tx_request.signature_v = v + 2 * chain_id + 35;
|
|
|
|
@ -375,6 +398,34 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len,
|
|
|
|
|
_("for gas?"), NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void layoutEthereumFeeEIP1559(const char *description,
|
|
|
|
|
const uint8_t *amount_bytes,
|
|
|
|
|
uint32_t amount_len,
|
|
|
|
|
const uint8_t *multiplier_bytes,
|
|
|
|
|
uint32_t multiplier_len) {
|
|
|
|
|
bignum256 amount_val = {0};
|
|
|
|
|
uint8_t padded[32] = {0};
|
|
|
|
|
char amount_str[32] = {0};
|
|
|
|
|
|
|
|
|
|
memcpy(padded + (32 - amount_len), amount_bytes, amount_len);
|
|
|
|
|
bn_read_be(padded, &amount_val);
|
|
|
|
|
|
|
|
|
|
if (multiplier_len > 0) {
|
|
|
|
|
bignum256 multiplier_val = {0};
|
|
|
|
|
|
|
|
|
|
memzero(padded, sizeof(padded));
|
|
|
|
|
memcpy(padded + (32 - multiplier_len), multiplier_bytes, multiplier_len);
|
|
|
|
|
bn_read_be(padded, &multiplier_val);
|
|
|
|
|
bn_multiply(&multiplier_val, &amount_val, &secp256k1.prime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ethereumFormatAmount(&amount_val, NULL, amount_str, sizeof(amount_str));
|
|
|
|
|
|
|
|
|
|
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
|
|
|
|
|
_("Confirm fee"), description, amount_str, NULL, NULL,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* RLP fields:
|
|
|
|
|
* - nonce (0 .. 32)
|
|
|
|
@ -385,139 +436,158 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len,
|
|
|
|
|
* - data (0 ..)
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static bool ethereum_signing_check(const EthereumSignTx *msg) {
|
|
|
|
|
size_t tolen = msg->has_to ? strlen(msg->to) : 0;
|
|
|
|
|
|
|
|
|
|
if (tolen != 42 && tolen != 40 && tolen != 0) {
|
|
|
|
|
/* Address has wrong length */
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// sending transaction to address 0 (contract creation) without a data field
|
|
|
|
|
if (tolen == 0 && (!msg->has_data_length || msg->data_length == 0)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (msg->gas_price.size + msg->gas_limit.size > 30) {
|
|
|
|
|
// sanity check that fee doesn't overflow
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) {
|
|
|
|
|
static bool ethereum_signing_init_common(struct signing_params *params) {
|
|
|
|
|
ethereum_signing = true;
|
|
|
|
|
sha3_256_Init(&keccak_ctx);
|
|
|
|
|
|
|
|
|
|
data_total = data_left = 0;
|
|
|
|
|
chain_id = 0;
|
|
|
|
|
|
|
|
|
|
memzero(&msg_tx_request, sizeof(EthereumTxRequest));
|
|
|
|
|
/* set fields to 0, to avoid conditions later */
|
|
|
|
|
if (!msg->has_value) msg->value.size = 0;
|
|
|
|
|
if (!msg->has_data_initial_chunk) msg->data_initial_chunk.size = 0;
|
|
|
|
|
bool toset;
|
|
|
|
|
uint8_t pubkeyhash[20] = {0};
|
|
|
|
|
if (msg->has_to && ethereum_parse(msg->to, pubkeyhash)) {
|
|
|
|
|
toset = true;
|
|
|
|
|
} else {
|
|
|
|
|
msg->to[0] = 0;
|
|
|
|
|
toset = false;
|
|
|
|
|
memzero(pubkeyhash, sizeof(pubkeyhash));
|
|
|
|
|
}
|
|
|
|
|
if (!msg->has_nonce) msg->nonce.size = 0;
|
|
|
|
|
|
|
|
|
|
/* eip-155 chain id */
|
|
|
|
|
if (msg->chain_id < 1) {
|
|
|
|
|
if (params->chain_id < 1) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_DataError, _("Chain ID out of bounds"));
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
chain_id = msg->chain_id;
|
|
|
|
|
|
|
|
|
|
/* Wanchain txtype */
|
|
|
|
|
if (msg->has_tx_type) {
|
|
|
|
|
if (msg->tx_type == 1 || msg->tx_type == 6) {
|
|
|
|
|
tx_type = msg->tx_type;
|
|
|
|
|
} else {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_DataError, _("Txtype out of bounds"));
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
tx_type = 0;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
chain_id = params->chain_id;
|
|
|
|
|
|
|
|
|
|
if (msg->has_data_length && msg->data_length > 0) {
|
|
|
|
|
if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) {
|
|
|
|
|
if (params->data_length > 0) {
|
|
|
|
|
if (params->data_initial_chunk_size == 0) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_DataError,
|
|
|
|
|
_("Data length provided, but no initial chunk"));
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
/* Our encoding only supports transactions up to 2^24 bytes. To
|
|
|
|
|
* prevent exceeding the limit we use a stricter limit on data length.
|
|
|
|
|
*/
|
|
|
|
|
if (msg->data_length > 16000000) {
|
|
|
|
|
if (params->data_length > 16000000) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_DataError,
|
|
|
|
|
_("Data length exceeds limit"));
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
data_total = msg->data_length;
|
|
|
|
|
data_total = params->data_length;
|
|
|
|
|
} else {
|
|
|
|
|
data_total = 0;
|
|
|
|
|
}
|
|
|
|
|
if (msg->data_initial_chunk.size > data_total) {
|
|
|
|
|
if (params->data_initial_chunk_size > data_total) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_DataError,
|
|
|
|
|
_("Invalid size of initial chunk"));
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// safety checks
|
|
|
|
|
if (!ethereum_signing_check(msg)) {
|
|
|
|
|
|
|
|
|
|
size_t tolen = params->has_to ? strlen(params->to) : 0;
|
|
|
|
|
/* Address has wrong length */
|
|
|
|
|
bool wrong_length = (tolen != 42 && tolen != 40 && tolen != 0);
|
|
|
|
|
|
|
|
|
|
// sending transaction to address 0 (contract creation) without a data field
|
|
|
|
|
bool contract_without_data = (tolen == 0 && params->data_length == 0);
|
|
|
|
|
|
|
|
|
|
if (wrong_length || contract_without_data) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_DataError, _("Safety check failed"));
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const TokenType *token = NULL;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ethereum_signing_handle_erc20(struct signing_params *params) {
|
|
|
|
|
if (params->has_to && ethereum_parse(params->to, params->pubkeyhash)) {
|
|
|
|
|
params->pubkeyhash_set = true;
|
|
|
|
|
} else {
|
|
|
|
|
params->pubkeyhash_set = false;
|
|
|
|
|
memzero(params->pubkeyhash, sizeof(params->pubkeyhash));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// detect ERC-20 token
|
|
|
|
|
if (toset && msg->value.size == 0 && data_total == 68 &&
|
|
|
|
|
msg->data_initial_chunk.size == 68 &&
|
|
|
|
|
memcmp(msg->data_initial_chunk.bytes,
|
|
|
|
|
if (params->pubkeyhash_set && params->value_size == 0 && data_total == 68 &&
|
|
|
|
|
params->data_initial_chunk_size == 68 &&
|
|
|
|
|
memcmp(params->data_initial_chunk_bytes,
|
|
|
|
|
"\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
|
|
|
|
16) == 0) {
|
|
|
|
|
token = tokenByChainAddress(chain_id, pubkeyhash);
|
|
|
|
|
params->token = tokenByChainAddress(chain_id, params->pubkeyhash);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (token != NULL) {
|
|
|
|
|
layoutEthereumConfirmTx(msg->data_initial_chunk.bytes + 16, 20,
|
|
|
|
|
msg->data_initial_chunk.bytes + 36, 32, token);
|
|
|
|
|
static bool ethereum_signing_confirm_common(
|
|
|
|
|
const struct signing_params *params) {
|
|
|
|
|
if (params->token != NULL) {
|
|
|
|
|
layoutEthereumConfirmTx(params->data_initial_chunk_bytes + 16, 20,
|
|
|
|
|
params->data_initial_chunk_bytes + 36, 32,
|
|
|
|
|
params->token);
|
|
|
|
|
} else {
|
|
|
|
|
layoutEthereumConfirmTx(pubkeyhash, 20, msg->value.bytes, msg->value.size,
|
|
|
|
|
NULL);
|
|
|
|
|
layoutEthereumConfirmTx(params->pubkeyhash, 20, params->value_bytes,
|
|
|
|
|
params->value_size, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (params->token == NULL && data_total > 0) {
|
|
|
|
|
layoutEthereumData(params->data_initial_chunk_bytes,
|
|
|
|
|
params->data_initial_chunk_size, data_total);
|
|
|
|
|
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ethereum_signing_init(const EthereumSignTx *msg, const HDNode *node) {
|
|
|
|
|
struct signing_params params = {
|
|
|
|
|
.chain_id = msg->chain_id,
|
|
|
|
|
|
|
|
|
|
.data_length = msg->data_length,
|
|
|
|
|
.data_initial_chunk_size = msg->data_initial_chunk.size,
|
|
|
|
|
.data_initial_chunk_bytes = msg->data_initial_chunk.bytes,
|
|
|
|
|
|
|
|
|
|
.has_to = msg->has_to,
|
|
|
|
|
.to = msg->to,
|
|
|
|
|
|
|
|
|
|
.value_size = msg->value.size,
|
|
|
|
|
.value_bytes = msg->value.bytes,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
eip1559 = false;
|
|
|
|
|
if (!ethereum_signing_init_common(¶ms)) {
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (token == NULL && data_total > 0) {
|
|
|
|
|
layoutEthereumData(msg->data_initial_chunk.bytes,
|
|
|
|
|
msg->data_initial_chunk.size, data_total);
|
|
|
|
|
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
|
|
|
|
|
// sanity check that fee doesn't overflow
|
|
|
|
|
if (msg->gas_price.size + msg->gas_limit.size > 30) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_DataError, _("Safety check failed"));
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t tx_type = 0;
|
|
|
|
|
/* Wanchain txtype */
|
|
|
|
|
if (msg->has_tx_type) {
|
|
|
|
|
if (msg->tx_type == 1 || msg->tx_type == 6) {
|
|
|
|
|
tx_type = msg->tx_type;
|
|
|
|
|
} else {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_DataError, _("Txtype out of bounds"));
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ethereum_signing_handle_erc20(¶ms);
|
|
|
|
|
|
|
|
|
|
if (!ethereum_signing_confirm_common(¶ms)) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layoutEthereumFee(msg->value.bytes, msg->value.size, msg->gas_price.bytes,
|
|
|
|
|
msg->gas_price.size, msg->gas_limit.bytes,
|
|
|
|
|
msg->gas_limit.size, token != NULL);
|
|
|
|
|
msg->gas_limit.size, params.token != NULL);
|
|
|
|
|
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
@ -534,10 +604,11 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) {
|
|
|
|
|
rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]);
|
|
|
|
|
rlp_length +=
|
|
|
|
|
rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]);
|
|
|
|
|
rlp_length += rlp_calculate_length(toset ? 20 : 0, pubkeyhash[0]);
|
|
|
|
|
rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]);
|
|
|
|
|
rlp_length += rlp_calculate_length(params.pubkeyhash_set ? 20 : 0,
|
|
|
|
|
params.pubkeyhash[0]);
|
|
|
|
|
rlp_length += rlp_calculate_length(params.value_size, params.value_bytes[0]);
|
|
|
|
|
rlp_length +=
|
|
|
|
|
rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]);
|
|
|
|
|
rlp_calculate_length(data_total, params.data_initial_chunk_bytes[0]);
|
|
|
|
|
if (tx_type) {
|
|
|
|
|
rlp_length += rlp_calculate_number_length(tx_type);
|
|
|
|
|
}
|
|
|
|
@ -556,11 +627,122 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) {
|
|
|
|
|
hash_rlp_field(msg->nonce.bytes, msg->nonce.size);
|
|
|
|
|
hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size);
|
|
|
|
|
hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size);
|
|
|
|
|
hash_rlp_field(pubkeyhash, toset ? 20 : 0);
|
|
|
|
|
hash_rlp_field(msg->value.bytes, msg->value.size);
|
|
|
|
|
hash_rlp_length(data_total, msg->data_initial_chunk.bytes[0]);
|
|
|
|
|
hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size);
|
|
|
|
|
data_left = data_total - msg->data_initial_chunk.size;
|
|
|
|
|
hash_rlp_field(params.pubkeyhash, params.pubkeyhash_set ? 20 : 0);
|
|
|
|
|
hash_rlp_field(params.value_bytes, params.value_size);
|
|
|
|
|
hash_rlp_length(data_total, params.data_initial_chunk_bytes[0]);
|
|
|
|
|
hash_data(params.data_initial_chunk_bytes, params.data_initial_chunk_size);
|
|
|
|
|
data_left = data_total - params.data_initial_chunk_size;
|
|
|
|
|
|
|
|
|
|
memcpy(privkey, node->private_key, 32);
|
|
|
|
|
|
|
|
|
|
if (data_left > 0) {
|
|
|
|
|
send_request_chunk();
|
|
|
|
|
} else {
|
|
|
|
|
send_signature();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ethereum_signing_init_eip1559(const EthereumSignTxEIP1559 *msg,
|
|
|
|
|
const HDNode *node) {
|
|
|
|
|
struct signing_params params = {
|
|
|
|
|
.chain_id = msg->chain_id,
|
|
|
|
|
|
|
|
|
|
.data_length = msg->data_length,
|
|
|
|
|
.data_initial_chunk_size = msg->data_initial_chunk.size,
|
|
|
|
|
.data_initial_chunk_bytes = msg->data_initial_chunk.bytes,
|
|
|
|
|
|
|
|
|
|
.has_to = msg->has_to,
|
|
|
|
|
.to = msg->to,
|
|
|
|
|
|
|
|
|
|
.value_size = msg->value.size,
|
|
|
|
|
.value_bytes = msg->value.bytes,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
eip1559 = true;
|
|
|
|
|
if (!ethereum_signing_init_common(¶ms)) {
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// sanity check that fee doesn't overflow
|
|
|
|
|
if (msg->max_gas_fee.size + msg->gas_limit.size > 30 ||
|
|
|
|
|
msg->max_priority_fee.size + msg->gas_limit.size > 30) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_DataError, _("Safety check failed"));
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ethereum_signing_handle_erc20(¶ms);
|
|
|
|
|
|
|
|
|
|
if (!ethereum_signing_confirm_common(¶ms)) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layoutEthereumFeeEIP1559(_("Maximum fee per gas"), msg->max_gas_fee.bytes,
|
|
|
|
|
msg->max_gas_fee.size, NULL, 0);
|
|
|
|
|
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layoutEthereumFeeEIP1559(_("Priority fee per gas"),
|
|
|
|
|
msg->max_priority_fee.bytes,
|
|
|
|
|
msg->max_priority_fee.size, NULL, 0);
|
|
|
|
|
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layoutEthereumFeeEIP1559(_("Maximum fee"), msg->gas_limit.bytes,
|
|
|
|
|
msg->gas_limit.size, msg->max_gas_fee.bytes,
|
|
|
|
|
msg->max_gas_fee.size);
|
|
|
|
|
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
|
|
|
|
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
|
|
|
|
|
ethereum_signing_abort();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Stage 1: Calculate total RLP length */
|
|
|
|
|
uint32_t rlp_length = 0;
|
|
|
|
|
|
|
|
|
|
layoutProgress(_("Signing"), 0);
|
|
|
|
|
|
|
|
|
|
rlp_length += rlp_calculate_number_length(chain_id);
|
|
|
|
|
rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]);
|
|
|
|
|
rlp_length += rlp_calculate_length(msg->max_priority_fee.size,
|
|
|
|
|
msg->max_priority_fee.bytes[0]);
|
|
|
|
|
rlp_length +=
|
|
|
|
|
rlp_calculate_length(msg->max_gas_fee.size, msg->max_gas_fee.bytes[0]);
|
|
|
|
|
rlp_length +=
|
|
|
|
|
rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]);
|
|
|
|
|
rlp_length += rlp_calculate_length(params.pubkeyhash_set ? 20 : 0,
|
|
|
|
|
params.pubkeyhash[0]);
|
|
|
|
|
rlp_length += rlp_calculate_length(params.value_size, params.value_bytes[0]);
|
|
|
|
|
rlp_length +=
|
|
|
|
|
rlp_calculate_length(data_total, params.data_initial_chunk_bytes[0]);
|
|
|
|
|
|
|
|
|
|
rlp_length += rlp_calculate_length(0, 0xff);
|
|
|
|
|
|
|
|
|
|
/* Stage 2: Store header fields */
|
|
|
|
|
hash_rlp_number(EIP1559_TX_TYPE);
|
|
|
|
|
hash_rlp_list_length(rlp_length);
|
|
|
|
|
|
|
|
|
|
layoutProgress(_("Signing"), 100);
|
|
|
|
|
|
|
|
|
|
hash_rlp_number(chain_id);
|
|
|
|
|
hash_rlp_field(msg->nonce.bytes, msg->nonce.size);
|
|
|
|
|
hash_rlp_field(msg->max_priority_fee.bytes, msg->max_priority_fee.size);
|
|
|
|
|
hash_rlp_field(msg->max_gas_fee.bytes, msg->max_gas_fee.size);
|
|
|
|
|
hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size);
|
|
|
|
|
hash_rlp_field(params.pubkeyhash, params.pubkeyhash_set ? 20 : 0);
|
|
|
|
|
hash_rlp_field(params.value_bytes, params.value_size);
|
|
|
|
|
hash_rlp_length(data_total, params.data_initial_chunk_bytes[0]);
|
|
|
|
|
hash_data(params.data_initial_chunk_bytes, params.data_initial_chunk_size);
|
|
|
|
|
data_left = data_total - params.data_initial_chunk_size;
|
|
|
|
|
|
|
|
|
|
memcpy(privkey, node->private_key, 32);
|
|
|
|
|
|
|
|
|
|