cryptnox-pos 1.0.0
Standalone USDC payment terminal firmware (ESP32 + Cryptnox smart card)
Loading...
Searching...
No Matches
pay_evm.cpp
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: LGPL-3.0-or-later
3 * Copyright (c) 2026 Cryptnox SA
4 */
5
12
13#include "pos_app.h"
14
15/* ── Unsigned and signed tx buffers (EIP-1559 type 2) ─────────── */
16#define TX_BUF_SIZE 300U
17
26void eth_rpc_select_for(bool polygon) {
27 if (polygon) {
29 "0x" ADDR_FROM);
30 eth_rpc_set_auth(NULL, NULL);
31#ifdef POLY_CA_CERT_PEM
32 eth_rpc_set_ca_cert(POLY_CA_CERT_PEM);
33#else
35#endif
36 } else {
37 eth_rpc_init(settings_net_str(RPC_URL, RPC_URL_MAIN), "0x" ADDR_FROM);
38#if defined(RPC_PROJECT_ID) && defined(RPC_API_SECRET)
39 eth_rpc_set_auth(RPC_PROJECT_ID, RPC_API_SECRET);
40#else
41 eth_rpc_set_auth(NULL, NULL);
42#endif
43#ifdef RPC_CA_CERT_PEM
44 eth_rpc_set_ca_cert(RPC_CA_CERT_PEM);
45#else
47#endif
48 }
49}
50
52
64void evm_fees_wei(bool polygon, uint64_t *max_fee, uint64_t *prio_fee)
65{
66 /* Fees from settings (config.h defaults); the Gwei-to-wei arithmetic, tip
67 * clamp and Polygon floor are evm_fees_from_gwei in money.h. */
70 (uint32_t)POLY_MIN_PRIORITY_FEE_GWEI, max_fee, prio_fee);
71}
72
91bool evm_balance_ok(const pos_amount_t *amount, char *err, size_t err_max)
92{
93 const bool native = chain_is_native_evm();
94 const bool polygon = chain_is_polygon();
95 const char *coin = polygon ? "POL" : "ETH";
96
97 /* The sale's snapshot, not a fresh read — see s_sale_fee. */
98 const uint64_t max_fee = s_sale_fee.max_fee;
99 /* A gas limit is ~1e5 at the most and max_fee is a uint32 of Gwei scaled by
100 * 1e9, so this product has ~25 bits of headroom. */
101 const uint64_t gas_cost =
102 (uint64_t)(native ? GAS_LIMIT_NATIVE : GAS_LIMIT_ERC20) * max_fee;
103
104 uint64_t have_wei = 0U;
105 if (!eth_rpc_get_balance(&have_wei)) {
106 ESP_LOGW(TAG, "pre-flight: balance read failed - letting the sale run");
107 return true;
108 }
109
110 /* The arithmetic, overflow guard included, is evm_funds_check in money.h. */
111 const evm_funds_t funds =
112 evm_funds_check(native, have_wei, gas_cost, amount->amount_minor);
113 if (funds == EVM_FUNDS_SHORT_GAS) {
114 (void)snprintf(err, err_max, "Not enough %s for the network fee", coin);
115 return false;
116 }
117
118 if (native) {
119 /* EVM_FUNDS_UNKNOWN is an amount past the keypad's cap; left to
120 * sign_and_broadcast, which refuses it by name. */
121 if (funds == EVM_FUNDS_SHORT_VALUE) {
122 (void)snprintf(err, err_max, "Not enough %s for this amount", coin);
123 return false;
124 }
125 return true;
126 }
127
128 const char *contract = active_token()->str; /* not native: returned above */
129 uint64_t have_units = 0U;
130 if (!eth_rpc_get_token_balance(contract, &have_units)) {
131 ESP_LOGW(TAG, "pre-flight: token balance read failed - letting it run");
132 return true;
133 }
134 if (have_units < amount->amount_minor) {
135 (void)snprintf(err, err_max, "Not enough %s on the card",
137 return false;
138 }
139 return true;
140}
141
165bcast_t sign_and_broadcast(CryptnoxWallet &wallet,
166 Pn532NfcTransport &transport,
167 const pos_amount_t *amount,
168 const pos_addr_t *to,
169 const char *pin, size_t pin_chars,
170 inflight_t *fl,
171 char *err_out, size_t err_max)
172{
173 /* The asset, read once so what is signed is what the confirm screen showed.
174 * `native`: recipient in `to`, amount in `value`, nothing is called. */
175 const bool native = chain_is_native_evm();
176 const token_t *const tk = native ? NULL : active_token();
177 if ((tk != NULL) && !tk->ok) {
178 (void)snprintf(err_out, err_max, "Token contract not configured");
179 return BCAST_FAILED;
180 }
181 const pos_addr_t *const token = (tk != NULL) ? &tk->addr : NULL;
182 const bool polygon = chain_is_polygon();
183
184 /* Endpoint first: the nonce below has to come from the network this will be
185 * broadcast to, and the chain id signed into the transaction is what stops it
186 * being replayed on the other one. */
188
189 /* Reconcile amount + recipient + contract right before they enter the calldata
190 * (§3.2/§7.1); a mismatch means the working copy was corrupted. A native
191 * transfer has no contract to reconcile — the recipient is the whole of it,
192 * which is why `to` is checked on both paths. */
193 if (!IS_TRUE32(amount_consistent(amount)) ||
195 ((token != NULL) && !IS_TRUE32(address_consistent(token)))) {
196 pos_handle_anomaly("pre-calldata reconcile");
197 (void)snprintf(err_out, err_max, "Integrity check failed");
198 return BCAST_FAILED;
199 }
200 const uint64_t amount_units = amount->amount_minor;
201
202 /* 6-decimal keypad units -> wei, for the 18-decimal coins only. Re-checked
203 * here rather than trusted from the keypad's cap: a wrapped multiply signs a
204 * value nobody entered (see POS_AMOUNT_UNITS_MAX_NATIVE). */
205 uint64_t native_wei = 0U;
206 if (native && !evm_units_to_wei(amount_units, &native_wei)) {
207 (void)snprintf(err_out, err_max, "Amount too large for this asset");
208 return BCAST_FAILED;
209 }
210
211 uint8_t calldata[USDC_CALLDATA_LEN];
212 if (!native) {
213 build_usdc_calldata(calldata, to->addr, amount_units);
214 }
215
216 /* The card comes before the RPC: the payer is whoever taps, so the nonce,
217 * balance and parity check all depend on the card's account. */
218 CW_SecureSession session;
219 if (!card_connect(wallet, transport, session)) {
220 if (!s_user_cancelled) {
221 (void)snprintf(err_out, err_max, "%s",
222 (s_card_fault != NULL) ? s_card_fault
223 : "Card not found");
224 }
225 return BCAST_FAILED;
226 }
227
228 if (!s_user_cancelled) {
230 }
231
232 /* PIN first: the key export needs a verified session, and only verifyPin
233 * reports a mistyped PIN as such (the sign APDU returns a generic error). */
234 if (!wallet.verifyPin(session, reinterpret_cast<const uint8_t *>(pin),
235 static_cast<uint8_t>(pin_chars))) {
236 (void)snprintf(err_out, err_max, "%s", pin_fail_text(transport, "Wrong PIN"));
237 wallet.disconnect(session);
238 return BCAST_FAILED;
239 }
240
241 /* The payer, derived from the card on the reader (ADDR_FROM is only the
242 * boot-time probe's address): keccak256 of the uncompressed public key,
243 * low 20 bytes. */
244 char from_addr[SETTINGS_PAYOUT_MAX] = "";
245 /* Kept past the address derivation: the recovery bit below is worked out
246 * against this key. */
247 uint8_t pubkey[64];
248 WipeGuard g_pub(pubkey, sizeof(pubkey));
249 {
250 uint8_t key_hash[32];
251 WipeGuard g_kh(key_hash, sizeof(key_hash));
252 if (!wallet.getPublicKey(session, ETH_DERIVE_PATH,
253 static_cast<uint8_t>(sizeof(ETH_DERIVE_PATH)),
254 pubkey)) {
255 wallet.disconnect(session);
256 (void)snprintf(err_out, err_max, "Cannot read card address");
257 return BCAST_FAILED;
258 }
259 keccak256(pubkey, sizeof(pubkey), key_hash);
260 (void)eth_addr_format(&key_hash[12], from_addr, sizeof(from_addr));
261 }
262 /* Refused rather than ignored: leaving the previous payer in force would
263 * fetch somebody else's nonce and sign a transaction against it. */
264 if (!eth_rpc_set_from(from_addr)) {
265 wallet.disconnect(session);
266 (void)snprintf(err_out, err_max, "Cannot read card address");
267 return BCAST_FAILED;
268 }
269 ESP_LOGI(TAG, "EVM sender (this card): %s", from_addr);
270
271 /* Before the nonce, signature and broadcast: nothing is spent on a no. */
272 ui_set_tx_info("Checking balance");
273 if (!evm_balance_ok(amount, err_out, err_max)) {
274 wallet.disconnect(session);
275 return BCAST_FAILED;
276 }
277 ui_set_tx_info(NULL);
278
279 uint64_t nonce = 0U;
280 if (!eth_rpc_get_nonce(&nonce)) {
281 wallet.disconnect(session);
282 (void)snprintf(err_out, err_max, "RPC: get nonce failed");
283 return BCAST_FAILED;
284 }
285
286 eth_tx_t tx;
287 CW_Utils::secure_wipe(reinterpret_cast<uint8_t *>(&tx), sizeof(tx));
288 /* Family from the selected chain, deployment from the settings flag. The
289 * chain id is the replay protection between mainnet and testnet, so it is
290 * read from the same setting the endpoint above was. */
292 ? (polygon ? CHAIN_ID_POLYGON : CHAIN_ID_MAINNET)
293 : (polygon ? CHAIN_ID_AMOY : CHAIN_ID_SEPOLIA);
294 tx.nonce = nonce;
295 /* The same snapshot the balance check and the confirm screen used. */
296 tx.max_priority_fee = s_sale_fee.prio_fee;
297 tx.max_fee = s_sale_fee.max_fee;
298 /* Token: amount in calldata, `to` is the contract. Coin: amount in `value`,
299 * `to` is the payee, flat 21000 gas. `to` decides who is paid, so it comes
300 * from the reconciled store on both paths, never a literal or fresh NVS
301 * read. Selected on `token` (not `native`) so the dereference is provably
302 * guarded. */
303 tx.gas_limit = native ? GAS_LIMIT_NATIVE : GAS_LIMIT_ERC20;
304 tx.eth_value = native ? native_wei : 0U;
305 tx.calldata = native ? NULL : calldata;
306 tx.calldata_len = native ? 0U : sizeof(calldata);
307 (void)CW_Utils::safe_memcpy(tx.to, sizeof(tx.to),
308 (token != NULL) ? token->addr : to->addr,
310
311 uint8_t unsigned_tx[TX_BUF_SIZE];
312 size_t unsigned_len = eth_rlp_encode_unsigned(&tx, unsigned_tx, sizeof(unsigned_tx));
313 if (unsigned_len == 0U) {
314 wallet.disconnect(session);
315 (void)snprintf(err_out, err_max, "RLP encode overflow");
316 return BCAST_FAILED;
317 }
318
319 uint8_t hash[CW_HASH_SIZE];
320 keccak256(unsigned_tx, unsigned_len, hash);
321
322 /* From here the message hash and (soon) the signature live on the stack.
323 * Scrub them and the encoded transactions on every exit path below. */
324 WipeGuard g_unsigned(unsigned_tx, sizeof(unsigned_tx));
325 WipeGuard g_hash(hash, sizeof(hash));
326
327 /* Re-reconcile amount + recipient + contract immediately before card_sign():
328 * the last point before the card produces an irreversible signature over
329 * the calldata (§3.2/§7.1). */
330 if (!IS_TRUE32(amount_consistent(amount)) ||
332 ((token != NULL) && !IS_TRUE32(address_consistent(token)))) {
333 pos_handle_anomaly("pre-sign reconcile");
334 (void)snprintf(err_out, err_max, "Integrity check failed");
335 wallet.disconnect(session);
336 return BCAST_FAILED;
337 }
338
339 uint8_t rs[64];
340 WipeGuard g_rs(rs, sizeof(rs));
341 if (!card_sign(wallet, session, hash, static_cast<uint8_t>(CW_HASH_SIZE),
343 static_cast<uint8_t>(sizeof(ETH_DERIVE_PATH)),
344 pin, pin_chars, rs, err_out, err_max)) {
345 return BCAST_FAILED;
346 }
347 const uint8_t *sig_r = rs;
348 const uint8_t *sig_s = rs + 32U;
349
350 if (!s_user_cancelled) {
352 }
353
354 /* The recovery bit, worked out locally against the key the card just
355 * exported rather than trusting the node. Doubles as a signature check: a
356 * failure is an internal inconsistency, not an operator setup error. */
357 uint8_t v = 0U;
358 if (!eth_sig_parity(hash, sig_r, sig_s, pubkey, &v)) {
359 ESP_LOGE(TAG, "signature does not verify under the card's own key");
360 (void)snprintf(err_out, err_max, "Signature check failed");
361 return BCAST_FAILED;
362 }
363
364 uint8_t signed_tx[TX_BUF_SIZE];
365 WipeGuard g_signed(signed_tx, sizeof(signed_tx));
366 size_t signed_len = eth_rlp_encode_signed(&tx, v, sig_r, sig_s,
367 signed_tx, sizeof(signed_tx));
368 if (signed_len == 0U) {
369 (void)snprintf(err_out, err_max, "RLP signed overflow");
370 return BCAST_FAILED;
371 }
372
373 /* last cancel check right before the irreversible broadcast. */
374 if (s_user_cancelled) {
375 return BCAST_FAILED;
376 }
377
378 /* The hash is computed here from the signed bytes, before the broadcast, so
379 * it exists even if the node never answers, and is never taken from the
380 * node, which could name any other transaction. The receipt poll asks
381 * about this hash and the receipt must match it. */
382 {
383 uint8_t h[32];
384 keccak256(signed_tx, signed_len, h);
385 fl->hash[0] = '0';
386 fl->hash[1] = 'x';
387 for (size_t i = 0U; i < sizeof(h); i++) {
388 (void)snprintf(&fl->hash[2U + (2U * i)], 3U, "%02x", h[i]);
389 }
390 }
391 fl->tron = false;
392 fl->token = (token != NULL);
393 (void)CW_Utils::safe_memcpy(fl->to, sizeof(fl->to),
394 (token != NULL) ? token->addr : to->addr,
396 (void)CW_Utils::safe_memcpy(fl->payee, sizeof(fl->payee), to->addr,
398 fl->amount = amount_units;
399 fl->polygon = polygon;
401
402 /* Roomier than err_out so the node's sentence arrives whole and is clipped
403 * once, at the point that knows the panel's width. */
404 char node_err[128] = "";
405 char node_hash[72] = "";
406 if (!eth_rpc_send_raw_tx(signed_tx, signed_len, node_hash, sizeof(node_hash),
407 node_err, sizeof(node_err))) {
408 if (eth_rpc_err_already_known(node_err)) {
409 /* An earlier attempt at these exact bytes got through. */
410 ESP_LOGW(TAG, "node already has %s", fl->hash);
411 return BCAST_SENT;
412 }
413 if (node_err[0] == '\0') {
414 /* No refusal, just no answer: a timeout, a dropped TLS session, a
415 * body that was not JSON. The node may well have taken it. */
416 ESP_LOGW(TAG, "no answer to the broadcast - polling %s", fl->hash);
417 return BCAST_UNKNOWN;
418 }
419 ESP_LOGE(TAG, "broadcast refused: %s", node_err);
420 rpc_error_text(node_err, native, polygon, err_out, err_max);
421 return BCAST_FAILED;
422 }
423 if (strcasecmp(node_hash, fl->hash) != 0) {
424 /* Not fatal (ours is the one polled), but it is why the receipt is
425 * checked against the transfer itself. */
426 ESP_LOGE(TAG, "node answered hash %s for %s", node_hash, fl->hash);
427 }
428 return BCAST_SENT;
429}
static const pos_asset_t * pos_asset_of(pos_chain_t chain)
The row describing chain.
Definition assets.h:145
bool card_sign(CryptnoxWallet &wallet, CW_SecureSession &session, const uint8_t *hash, uint8_t hash_len, const uint8_t *path, uint8_t path_len, const char *pin, size_t pin_chars, uint8_t rs_out[64], char *err_out, size_t err_max)
Have the card sign hash, then close the session.
Definition card_io.cpp:160
const char * s_card_fault
Definition card_io.cpp:18
bool card_connect(CryptnoxWallet &wallet, Pn532NfcTransport &transport, CW_SecureSession &session, bool setup)
Wait for a card and open a secure channel, cancellable from the UI.
Definition card_io.cpp:79
const char * pin_fail_text(Pn532NfcTransport &transport, const char *wrong)
Why verifyPin said no: the PIN, or the card leaving the field.
Definition card_io.cpp:52
#define GAS_LIMIT_NATIVE
#define POLY_RPC_URL
#define CHAIN_ID_POLYGON
#define POLY_MIN_PRIORITY_FEE_GWEI
#define CHAIN_ID_AMOY
#define POLY_RPC_URL_MAIN
#define RPC_URL_MAIN
#define CHAIN_ID_MAINNET
bool eth_addr_format(const uint8_t addr[ETH_ADDR_LEN], char *out, size_t n)
Render a 20-byte address as an EIP-55 mixed-case "0x..." string.
Definition eth_addr.cpp:109
#define ETH_ADDR_LEN
Length of a raw (binary) Ethereum address, in bytes.
Definition eth_addr.h:25
size_t eth_rlp_encode_signed(const eth_tx_t *tx, uint8_t v, const uint8_t r[32], const uint8_t s[32], uint8_t *out, size_t out_max)
Encode a signed EIP-1559 transaction: 0x02 || RLP([..., v, r, s]).
Definition eth_rlp.cpp:268
size_t eth_rlp_encode_unsigned(const eth_tx_t *tx, uint8_t *out, size_t out_max)
Encode an unsigned EIP-1559 transaction: 0x02 || RLP([chainId, nonce, ...]).
Definition eth_rlp.cpp:244
bool eth_rpc_get_nonce(uint64_t *nonce_out)
Fetch the confirmed transaction count (nonce) for from_addr.
Definition eth_rpc.cpp:157
static const char *const TAG
Definition eth_rpc.cpp:33
void eth_rpc_init(const char *rpc_url, const char *from_addr)
Set the RPC URL and the from-address used for nonce queries and ecrecover comparison.
Definition eth_rpc.cpp:122
void eth_rpc_set_auth(const char *project_id, const char *api_secret)
Optional: set Infura-style HTTP Basic Auth credentials.
Definition eth_rpc.cpp:146
bool eth_rpc_get_balance(uint64_t *wei_out)
Fetch the native balance of from_addr, in wei.
Definition eth_rpc.cpp:212
bool eth_rpc_get_token_balance(const char *token_addr, uint64_t *units_out)
Fetch from_addr's balance of an ERC-20, via balanceOf over eth_call.
Definition eth_rpc.cpp:239
bool eth_rpc_send_raw_tx(const uint8_t *tx, size_t tx_len, char *tx_hash_out, size_t tx_hash_max, char *err_out, size_t err_max)
Broadcast a raw signed transaction (type-prefixed RLP bytes).
Definition eth_rpc.cpp:286
bool eth_rpc_err_already_known(const char *node_err)
true if a broadcast error message means the node already HAS this transaction ("already known",...
Definition eth_rpc.cpp:377
void eth_rpc_set_ca_cert(const char *ca_pem)
Optional: pin the RPC endpoint's TLS certificate.
Definition eth_rpc.cpp:152
bool eth_rpc_set_from(const char *addr)
Replace the from-address — the account a sale spends from.
Definition eth_rpc.cpp:133
bool eth_sig_parity(const uint8_t hash[32], const uint8_t r[32], const uint8_t s[32], const uint8_t pub64[64], uint8_t *v_out)
Verify (r, s) over hash against pub64 and return its y-parity.
Definition eth_sig.cpp:16
void pos_handle_anomaly(const char *where)
Report an anomaly: bump a self-checked persisted counter, log it, and keep a local ring buffer for on...
Definition hardening.cpp:99
#define IS_TRUE32(x)
Definition hardening.h:43
static bool32 amount_consistent(const pos_amount_t *a)
Definition hardening.h:93
static bool32 address_consistent(const pos_addr_t *a)
Definition hardening.h:98
void keccak256(const uint8_t *input, size_t length, uint8_t digest[32])
Compute the Keccak-256 digest of a buffer.
std::atomic< bool > s_user_cancelled
Definition main.cpp:27
static void evm_fees_from_gwei(uint32_t max_gwei, uint32_t prio_gwei, bool polygon, uint32_t floor_gwei, uint64_t *max_fee, uint64_t *prio_fee)
The EIP-1559 fees one EVM sale will offer, in wei per gas, from the operator's Gwei settings.
Definition money.h:121
evm_funds_t
What the pre-flight balance check concluded.
Definition money.h:144
@ EVM_FUNDS_SHORT_VALUE
Definition money.h:147
@ EVM_FUNDS_SHORT_GAS
Definition money.h:146
static evm_funds_t evm_funds_check(bool native, uint64_t have_wei, uint64_t gas_cost, uint64_t units)
Can have_wei pay for this sale?
Definition money.h:159
static void build_usdc_calldata(uint8_t out[USDC_CALLDATA_LEN], const uint8_t to[ETH_ADDR_LEN], uint64_t amount)
Build the 68-byte ABI-encoded calldata for a USDC transfer call.
Definition money.h:216
#define USDC_CALLDATA_LEN
Definition money.h:199
static bool evm_units_to_wei(uint64_t units, uint64_t *wei)
6-decimal keypad units -> wei, for the 18-decimal coins only.
Definition money.h:103
token_t * active_token(pos_chain_t chain)
The selection's token, or NULL for a native coin.
Definition pay.cpp:45
sale_fee_t s_sale_fee
Definition pay.cpp:192
const uint8_t ETH_DERIVE_PATH[20]
Definition pay.cpp:16
void inflight_persist(const inflight_t *fl)
Write the sale to NVS just before it leaves the terminal.
Definition pay.cpp:228
void eth_rpc_select_for(bool polygon)
Point eth_rpc at the endpoint for the selected EVM network.
Definition pay_evm.cpp:26
bool evm_balance_ok(const pos_amount_t *amount, char *err, size_t err_max)
Refuse an EVM sale the tapped card cannot fund, before it signs.
Definition pay_evm.cpp:91
void eth_rpc_select(void)
Definition pay_evm.cpp:51
#define TX_BUF_SIZE
Definition pay_evm.cpp:16
bcast_t sign_and_broadcast(CryptnoxWallet &wallet, Pn532NfcTransport &transport, const pos_amount_t *amount, const pos_addr_t *to, const char *pin, size_t pin_chars, inflight_t *fl, char *err_out, size_t err_max)
Sign an EVM token or coin transfer on the card and broadcast it.
Definition pay_evm.cpp:165
void evm_fees_wei(bool polygon, uint64_t *max_fee, uint64_t *prio_fee)
The EIP-1559 fees one EVM sale will offer, in wei per gas.
Definition pay_evm.cpp:64
Private to the application files (main, boot, card_io, pay, pay_evm, pay_tron): the state they share ...
bcast_t
Definition pos_app.h:148
@ BCAST_UNKNOWN
Definition pos_app.h:151
@ BCAST_FAILED
Definition pos_app.h:149
@ BCAST_SENT
Definition pos_app.h:150
static bool chain_is_polygon(void)
true when the terminal is charging on Polygon rather than Ethereum.
Definition pos_app.h:79
static bool chain_is_native_evm(void)
true when charging in the network's own coin (ETH / POL), not a token.
Definition pos_app.h:84
static void rpc_error_text(const char *node_msg, bool native, bool polygon, char *out, size_t n)
Render a broadcast refusal for the Declined screen.
Definition rpc_error.h:64
const char * settings_net_str(const char *testnet, const char *mainnet)
Pick the string belonging to the network the terminal is on.
Definition settings.cpp:210
pos_chain_t settings_get_chain(void)
Selected chain, or POS_CHAIN_ETH_USDC if never set.
Definition settings.cpp:165
uint32_t settings_get_priority_fee_gwei(void)
EIP-1559 max priority fee (tip) per gas, in Gwei.
Definition settings.cpp:352
bool settings_get_mainnet(void)
true when the terminal is on the production networks.
Definition settings.cpp:189
uint32_t settings_get_max_fee_gwei(void)
EIP-1559 max fee per gas, in Gwei.
Definition settings.cpp:347
#define SETTINGS_PAYOUT_MAX
Longest payout address plus NUL — "0x" + 40 hex, or 34 base58 Tron.
Definition settings.h:214
Scrubs a buffer with CW_Utils::secure_wipe when it leaves scope.
Definition pos_app.h:215
EIP-1559 (type 2) transaction parameters.
Definition eth_rlp.h:31
size_t calldata_len
Definition eth_rlp.h:41
uint64_t gas_limit
Definition eth_rlp.h:36
uint64_t eth_value
Definition eth_rlp.h:38
const uint8_t * calldata
Definition eth_rlp.h:40
uint64_t max_fee
Definition eth_rlp.h:35
uint64_t max_priority_fee
Definition eth_rlp.h:34
uint64_t chain_id
Definition eth_rlp.h:32
uint8_t to[20]
Definition eth_rlp.h:37
uint64_t nonce
Definition eth_rlp.h:33
bool tron
Definition pos_app.h:159
char hash[72]
Definition pos_app.h:160
uint8_t to[ETH_ADDR_LEN]
Definition pos_app.h:162
uint8_t payee[ETH_ADDR_LEN]
Definition pos_app.h:163
bool polygon
Definition pos_app.h:168
bool token
Definition pos_app.h:164
uint64_t amount
Definition pos_app.h:165
uint8_t addr[ETH_ADDR_LEN]
Definition hardening.h:65
uint64_t amount_minor
Definition hardening.h:59
A token's contract, dual-stored.
Definition pos_app.h:98
pos_addr_t addr
Definition pos_app.h:100
bool ok
Definition pos_app.h:101
char str[SETTINGS_PAYOUT_MAX]
Definition pos_app.h:99
void ui_show_tx_status(ui_tx_state_t state, const char *info)
Switch to the transaction-status screen.
Definition ui.cpp:898
void ui_set_tx_info(const char *info)
Replace the transaction screen's info line without rebuilding it.
Definition ui.cpp:910
@ UI_TX_STATE_SIGNING
Definition ui.h:97
@ UI_TX_STATE_SENDING
Definition ui.h:98