|
cryptnox-pos 1.0.0
Standalone USDC payment terminal firmware (ESP32 + Cryptnox smart card)
|
Private to the application files (main, boot, card_io, pay, pay_evm, pay_tron): the state they share and the calls between them. More...
#include <stdio.h>#include <string.h>#include <sys/time.h>#include <strings.h>#include <stdlib.h>#include <inttypes.h>#include <atomic>#include "freertos/FreeRTOS.h"#include "freertos/task.h"#include "freertos/queue.h"#include "driver/spi_master.h"#include "driver/gpio.h"#include "esp_err.h"#include "esp_heap_caps.h"#include "esp_log.h"#include "esp_system.h"#include "esp_timer.h"#include "nvs_flash.h"#include "CryptnoxWallet.h"#include "CW_Utils.h"#include "Pn532NfcTransport.h"#include "ESP32Logger.h"#include "ESP32Platform.h"#include "esp32_crypto_provider.h"#include "CW_Tron.h"#include "settings.h"#include "assets.h"#include "provision.h"#include "ota.h"#include "ota_version.h"#include "wdt.h"#include "pn532.h"#include "keccak256.h"#include "eth_addr.h"#include "eth_sig.h"#include "card_status.h"#include "hardening.h"#include "eth_rlp.h"#include "eth_rpc.h"#include "rpc_error.h"#include "tron_rpc.h"#include "tron_tx.h"#include "net.h"#include "ui.h"#include "money.h"#include "config_defaults.h"Go to the source code of this file.
Classes | |
| struct | token_t |
| A token's contract, dual-stored. More... | |
| struct | token_cfg_t |
| struct | sale_fee_t |
| struct | inflight_t |
| struct | WipeGuard |
| Scrubs a buffer with CW_Utils::secure_wipe when it leaves scope. More... | |
| struct | ui_msg_t |
| struct | pos_hw_t |
| The card stack pos_boot() brought up; lives for the program. More... | |
Enumerations | |
| enum | bcast_t { BCAST_FAILED = 0 , BCAST_SENT , BCAST_UNKNOWN } |
Functions | |
| static bool | chain_is_tron (void) |
| true when the operator has switched the terminal to Tron. | |
| static bool | chain_is_polygon (void) |
| true when the terminal is charging on Polygon rather than Ethereum. | |
| static bool | chain_is_native_evm (void) |
| true when charging in the network's own coin (ETH / POL), not a token. | |
| token_t * | active_token (pos_chain_t chain=settings_get_chain()) |
| The selection's token, or NULL for a native coin. | |
| void | token_load (const token_cfg_t *cfg, CW_CryptoProvider &crypto) |
| Load one token at boot: the operator's contract if one is set and parses, config.h otherwise. | |
| bool | token_decimals_ok (pos_chain_t chain, char *err, size_t err_max) |
| Before the first sale in an operator-set token, read its decimals() and refuse anything but 6. | |
| const pos_addr_t * | active_dest (void) |
| The reconciled recipient for the chain currently selected. | |
| void | sale_fee_text (char *out, size_t n) |
| The most network fee the customer's card can be charged on top of the sale, for the confirm screen. "" where there is no cap to state: a native TRX transfer burns bandwidth, not a fee limit. | |
| void | inflight_persist (const inflight_t *fl) |
| Write the sale to NVS just before it leaves the terminal. | |
| uint64_t | wall_ms (void) |
| Unix time in ms, 0 while the clock is unset. | |
| void | settle_inflight (void) |
| Poll the in-flight sale for up to 120 s and show what the chain says. | |
| bcast_t | pay_sign_and_broadcast (CryptnoxWallet &wallet, Pn532NfcTransport &transport, CW_CryptoProvider &crypto, const pos_amount_t *amount, const char *pin, size_t pin_chars, inflight_t *fl, char *err_out, size_t err_max) |
| Sign and broadcast the reconciled sale on whichever family is selected. The family is read once, here. | |
| void | eth_rpc_select_for (bool polygon) |
| Point eth_rpc at the endpoint for the selected EVM network. | |
| void | eth_rpc_select (void) |
| 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. | |
| 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. | |
| 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. | |
| void | tron_addr_to_hex (const uint8_t *addr21, char *out, size_t n) |
| Format a raw 21-byte Tron address as the "41..." hex the API wants. | |
| bcast_t | sign_and_broadcast_tron (CryptnoxWallet &wallet, Pn532NfcTransport &transport, CW_CryptoProvider &crypto, const pos_amount_t *amount, const pos_addr_t *to, const token_t *token, const char *pin, size_t pin_chars, inflight_t *fl, char *err_out, size_t err_max) |
| Sign a Tron transfer on the card and broadcast it — TRX or TRC-20. | |
| eth_rpc_receipt_result_t | tron_receipt_as_eth (tron_receipt_t r) |
| Map a Tron receipt onto the Ethereum verdicts the UI flow uses. | |
| const char * | pin_fail_text (Pn532NfcTransport &transport, const char *wrong) |
| Why verifyPin said no: the PIN, or the card leaving the field. | |
| bool | card_connect (CryptnoxWallet &wallet, Pn532NfcTransport &transport, CW_SecureSession &session, bool setup=false) |
| Wait for a card and open a secure channel, cancellable from the UI. | |
| 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. | |
| bool | card_read_payouts (CryptnoxWallet &wallet, Pn532NfcTransport &transport, CW_CryptoProvider &crypto, const char *pin, size_t pin_chars, char *eth_out, size_t eth_n, char *tron_out, size_t tron_n, char *err, size_t err_n) |
| Read the card's payout addresses and put them through the panel. | |
| void | ui_event_dispatch (ui_event_t event, uint64_t payload) |
| UI-task callback: forward a touch event to the main task queue. | |
| pos_hw_t | pos_boot (void) |
| Everything before the main loop. Returns the card stack, which lives for the life of the program. | |
| void | boot_fault (ui_boot_err_t kind, const char *detail) |
| Show a startup fault, then restart. Does not return. | |
| void | wifi_keep_or_drop (bool keep) |
| Persist or discard the pending picker credentials, then scrub them. | |
| void | wait_for_ui_event (ui_event_t want) |
Block until the UI reports want, discarding anything else. | |
| bool | wifi_try_saved (void) |
| Try the saved credentials, staying on the splash while it happens. | |
| bool | wifi_picker (const char *note) |
| Run the panel network picker (scan → list → keyboard → connect) until connected. | |
| bool | run_wizard (CryptnoxWallet &wallet, Pn532NfcTransport &transport, CW_CryptoProvider &crypto, bool wifi_only) |
| Run the browser wizard until the operator presses Finish. | |
| bool | sync_time (void) |
| Block on an SNTP sync so TLS certificate validity-period checks run against real time instead of the 1970 epoch. | |
Variables | |
| static const char *const | TAG = "cryptnox_pos" |
| const uint8_t | ETH_DERIVE_PATH [20] |
| char | s_payout_eth [SETTINGS_PAYOUT_MAX] |
| char | s_payout_tron [SETTINGS_PAYOUT_MAX] |
| token_t | s_token [POS_CHAIN__COUNT] |
| const token_cfg_t | TOKEN_CFG [] |
| const size_t | TOKEN_CFG_COUNT |
| pos_addr_t | s_dest |
| pos_addr_t | s_tron_dest |
| bool | s_payout_bad [2] |
| sale_fee_t | s_sale_fee |
| inflight_t | s_inflight |
| const char * | s_card_fault |
| QueueHandle_t | s_ui_queue |
| std::atomic< bool > | s_user_cancelled |
| const char *const | NOTE_JOIN_FAILED |
| const char *const | NOTE_NO_TIME |
Private to the application files (main, boot, card_io, pay, pay_evm, pay_tron): the state they share and the calls between them.
Definition in file pos_app.h.
| enum bcast_t |
| const pos_addr_t * active_dest | ( | void | ) |
The reconciled recipient for the chain currently selected.
Definition at line 188 of file pay.cpp.
References chain_is_tron(), s_dest, and s_tron_dest.
Referenced by app_main(), and settle_inflight().
| token_t * active_token | ( | pos_chain_t | chain = settings_get_chain() | ) |
The selection's token, or NULL for a native coin.
Definition at line 45 of file pay.cpp.
References pos_asset_t::native, pos_asset_of(), POS_CHAIN__COUNT, and s_token.
Referenced by app_main(), evm_balance_ok(), pay_sign_and_broadcast(), sale_fee_text(), sign_and_broadcast(), token_decimals_ok(), and ui_refresh_addresses_for().
| void boot_fault | ( | ui_boot_err_t | kind, |
| const char * | detail ) |
Show a startup fault, then restart. Does not return.
Most boot faults (a reader that missed its first I2C wake-up, a card stack that did not come up) clear on the next boot, and an unattended terminal must not stay stopped. On an unconfirmed update (ota_mark_valid runs after the wallet) the restart rolls back to the image that worked. A persistent fault keeps showing, 30 s at a time.
Definition at line 223 of file boot.cpp.
References BOOT_FAULT_RESTART_S, TAG, and ui_show_boot_error().
Referenced by pos_boot(), and resolve_evm_payout().
| 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.
Manual connect loop with cancel checks between PN532 polls, so a Cancel aborts within one PN532 timeout. Drives the "Tap your card" / "Processing" screens.
| [in] | wallet | Initialised wallet instance. |
| [in] | transport | PN532 transport, polled directly. |
| [out] | session | Open secure session on success. |
| [in] | setup | true when reading payout addresses rather than paying; shows the card-wait screen instead of the transaction one. |
session open; false on user cancel, after 60 s, or on a card that is not set up — the three are told apart by s_user_cancelled and s_card_fault. Definition at line 79 of file card_io.cpp.
References card_fault(), s_card_fault, s_user_cancelled, ui_show_card_wait(), ui_show_tx_status(), UI_TX_STATE_PLACE_CARD, UI_TX_STATE_PROCESSING, and wdt_feed().
Referenced by card_read_payouts(), sign_and_broadcast(), and sign_and_broadcast_tron().
| bool card_read_payouts | ( | CryptnoxWallet & | wallet, |
| Pn532NfcTransport & | transport, | ||
| CW_CryptoProvider & | crypto, | ||
| const char * | pin, | ||
| size_t | pin_chars, | ||
| char * | eth_out, | ||
| size_t | eth_n, | ||
| char * | tron_out, | ||
| size_t | tron_n, | ||
| char * | err, | ||
| size_t | err_n ) |
Read the card's payout addresses and put them through the panel.
The card will not export a public key without a verified PIN, so this needs the card PIN exactly as signing does — the caller collects it on the keypad first.
One tap yields both addresses (Ethereum m/44'/60'/0'/0/0, Tron m/44'/195'/0'/0/0), so a terminal is not left half configured, offering one network's payments to the compiled-in address.
Neither address is stored here. Both are proposed, through the same accept-on-the-panel handshake a browser submission goes through, because "the card said so" is not the same claim as "the operator checked it" — a card presented by a customer would otherwise redirect the takings.
| [out] | eth_out | EIP-55 "0x..." address, or "" if it could not be read. |
| [in] | eth_n | Capacity of eth_out. |
| [out] | tron_out | base58 "T..." address, or "". |
| [in] | tron_n | Capacity of tron_out. |
| [out] | err | Short reason for the panel when nothing could be read. |
| [in] | err_n | Capacity of err. |
Definition at line 233 of file card_io.cpp.
References card_connect(), eth_addr_format(), ETH_DERIVE_PATH, keccak256(), pin_fail_text(), s_card_fault, s_user_cancelled, and TAG.
Referenced by app_main(), and run_wizard().
| 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.
Shared tail of both payment paths: build the request, copy the PIN in as late as possible, sign, scrub the PIN, close the session, map the status byte to an operator-readable message. One copy of the PIN handling and wipe.
The caller reconciles its amount and addresses immediately before calling this, which makes that check the last thing before an irreversible signature. It stays with the caller because the anomaly label and values differ per path.
The session is disconnected on every exit — including the failures — so no caller can leave a card held open.
| [in] | wallet | Initialised wallet instance. |
| [in] | session | Open secure session; disconnected before returning. |
| [in] | hash | Digest to sign (the keccak of the RLP, or a Tron txID). |
| [in] | hash_len | Length of hash. |
| [in] | path | BIP-32 derivation path blob. |
| [in] | path_len | Length of path. |
| [in] | pin | Operator-entered card PIN; the caller still owns and scrubs its own copy. |
| [in] | pin_chars | Number of PIN characters in pin. |
| [out] | rs_out | 64 bytes: r || s. Wiped by the caller (WipeGuard). |
| [out] | err_out | Short UI-facing error message on failure. |
| [in] | err_max | Capacity of err_out. |
rs_out holds a signature. Definition at line 160 of file card_io.cpp.
Referenced by sign_and_broadcast(), and sign_and_broadcast_tron().
|
inlinestatic |
true when charging in the network's own coin (ETH / POL), not a token.
Definition at line 84 of file pos_app.h.
References pos_chain_is_native_evm(), and settings_get_chain().
Referenced by evm_balance_ok(), sale_fee_text(), and sign_and_broadcast().
|
inlinestatic |
true when the terminal is charging on Polygon rather than Ethereum.
Definition at line 79 of file pos_app.h.
References pos_chain_is_polygon(), and settings_get_chain().
Referenced by app_main(), eth_rpc_select(), evm_balance_ok(), sale_fee_text(), and sign_and_broadcast().
|
inlinestatic |
true when the operator has switched the terminal to Tron.
Definition at line 74 of file pos_app.h.
References pos_chain_is_tron(), and settings_get_chain().
Referenced by active_dest(), app_main(), pay_sign_and_broadcast(), pos_boot(), and sale_fee_text().
| void eth_rpc_select | ( | void | ) |
Definition at line 51 of file pay_evm.cpp.
References chain_is_polygon(), and eth_rpc_select_for().
Referenced by pos_boot(), sign_and_broadcast(), and token_decimals_ok().
| void eth_rpc_select_for | ( | bool | polygon | ) |
Point eth_rpc at the endpoint for the selected EVM network.
Called at boot and at the top of every payment, since the network can change between sales. URL, credentials and pinned cert are separate statics in eth_rpc, so all three are re-applied each time (a stale cert or auth from the other network shows up as an unexplained TLS failure).
Definition at line 26 of file pay_evm.cpp.
References eth_rpc_init(), eth_rpc_set_auth(), eth_rpc_set_ca_cert(), POLY_RPC_URL, POLY_RPC_URL_MAIN, RPC_URL_MAIN, and settings_net_str().
Referenced by eth_rpc_select(), settle_inflight(), and token_decimals_ok().
| 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.
Otherwise an underfunded token transfer is broadcast, mined, reverted and charged gas, and a short coin balance is refused only after signing.
The caller must have selected the endpoint and set the payer first. This does not call eth_rpc_select: that resets the from-address to config.h and would check the integrator's account instead of the tapped card.
A failed read is NOT a refusal: this improves a message, it does not gate payments.
| [in] | amount | The reconciled sale amount, in keypad base units. |
| [out] | err | Panel-facing reason on refusal; untouched otherwise. |
| [in] | err_max | Capacity of err. |
Definition at line 91 of file pay_evm.cpp.
References active_token(), pos_amount_t::amount_minor, chain_is_native_evm(), chain_is_polygon(), eth_rpc_get_balance(), eth_rpc_get_token_balance(), evm_funds_check(), EVM_FUNDS_SHORT_GAS, EVM_FUNDS_SHORT_VALUE, GAS_LIMIT_NATIVE, pos_asset_of(), s_sale_fee, settings_get_chain(), token_t::str, and TAG.
Referenced by sign_and_broadcast().
| 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.
One function so the signed transaction and the pre-flight check agree: a check against a cheaper fee than the tx carries would pass the very sale it exists to catch.
| [in] | polygon | true on Polygon, which has a tip floor of its own. |
| [out] | max_fee | Fee cap, wei per gas. |
| [out] | prio_fee | Tip, wei per gas; never above max_fee. |
Definition at line 64 of file pay_evm.cpp.
References evm_fees_from_gwei(), POLY_MIN_PRIORITY_FEE_GWEI, settings_get_max_fee_gwei(), and settings_get_priority_fee_gwei().
Referenced by app_main().
| void inflight_persist | ( | const inflight_t * | fl | ) |
Write the sale to NVS just before it leaves the terminal.
So a brownout or panic during the receipt poll does not lose whether the customer paid. Written as "broadcast not known": a record that survives a reset is by definition one whose answer nobody saw. One write per sale.
Definition at line 228 of file pay.cpp.
References inflight_t::active, inflight_t::broadcast_known, and settings_inflight_save().
Referenced by sign_and_broadcast(), and sign_and_broadcast_tron().
| bcast_t pay_sign_and_broadcast | ( | CryptnoxWallet & | wallet, |
| Pn532NfcTransport & | transport, | ||
| CW_CryptoProvider & | crypto, | ||
| const pos_amount_t * | amount, | ||
| const char * | pin, | ||
| size_t | pin_chars, | ||
| inflight_t * | fl, | ||
| char * | err_out, | ||
| size_t | err_max ) |
Sign and broadcast the reconciled sale on whichever family is selected. The family is read once, here.
Definition at line 347 of file pay.cpp.
References active_token(), BCAST_FAILED, chain_is_tron(), s_dest, s_tron_dest, settings_get_chain(), sign_and_broadcast(), sign_and_broadcast_tron(), and token_decimals_ok().
Referenced by app_main().
| const char * pin_fail_text | ( | Pn532NfcTransport & | transport, |
| const char * | wrong ) |
Why verifyPin said no: the PIN, or the card leaving the field.
verifyPin returns a bare bool, and a card pulled away mid-APDU fails exactly like a mistyped PIN. Asked before the session is dropped: if the card does not answer a SELECT, it was not the PIN.
Definition at line 52 of file card_io.cpp.
References CARD_SELECT_APDU, and TAG.
Referenced by card_read_payouts(), sign_and_broadcast(), and sign_and_broadcast_tron().
| pos_hw_t pos_boot | ( | void | ) |
Everything before the main loop. Returns the card stack, which lives for the life of the program.
Definition at line 496 of file boot.cpp.
References NullLogger::begin(), boot_fault(), chain_is_tron(), ETH_ADDR_LEN, eth_rpc_get_nonce(), eth_rpc_select(), LED_B, LED_G, LED_R, net_time_background(), net_wifi_init(), net_wifi_keep_trying(), NOTE_NO_TIME, ota_mark_valid(), ota_running_version(), ota_version_display(), OTA_VERSION_SHOWN_MAX, PN532_I2C_HZ, PN532_I2C_PORT, PN532_IRQ, PN532_RST, PN532_SCL, PN532_SDA, POS_CHAIN_ETH_USDC, POS_CHAIN_TRON_TRX, resolve_evm_payout(), run_wizard(), s_payout_bad, s_payout_eth, s_payout_tron, s_tron_dest, s_ui_queue, settings_get_mainnet(), settings_get_payout(), settings_get_tz_dst(), settings_get_tz_offset_min(), settings_has_admin_code(), settings_has_payout(), settings_has_wifi(), settings_net_str(), settings_set_chain(), settings_wipe_if_new_build(), sync_time(), TAG, TOKEN_CFG, TOKEN_CFG_COUNT, token_load(), tron_rpc_init(), tron_rpc_set_ca_cert(), TRON_URL_MAIN, UI_BOOT_ERR_CONFIG, UI_BOOT_ERR_NFC, UI_BOOT_ERR_WALLET, UI_EVENT_ADMIN_SET, ui_event_dispatch(), UI_EVENT_WELCOME_DONE, ui_init(), ui_refresh_addresses(), ui_set_boot_status(), ui_show_admin_set(), ui_show_splash(), ui_show_welcome(), wait_for_ui_event(), wifi_keep_or_drop(), wifi_picker(), and wifi_try_saved().
Referenced by app_main().
| bool run_wizard | ( | CryptnoxWallet & | wallet, |
| Pn532NfcTransport & | transport, | ||
| CW_CryptoProvider & | crypto, | ||
| bool | wifi_only ) |
Run the browser wizard until the operator presses Finish.
| [in] | wifi_only | Steps 5 and 6 only, for a configured terminal that lost its network. No admin code: the form can only propose what the panel must accept, and the AP passphrase on that panel is the perimeter (see prov_set_wifi_only). |
Definition at line 269 of file boot.cpp.
References card_read_payouts(), ui_msg_t::event, net_time_sync(), net_wifi_connect(), net_wifi_disconnect(), net_wifi_scan(), NOTE_JOIN_FAILED, NOTE_NO_TIME, PROV_ASK_PAYOUT_ETH, PROV_ASK_PAYOUT_TRON, prov_authed(), prov_mode(), PROV_MODE_OFF, PROV_MODE_WIZARD, prov_propose(), prov_set_note(), prov_set_scan(), prov_set_step(), prov_set_wifi_only(), prov_start(), prov_step(), PROV_STEP_ADDR, PROV_STEP_AUTH, PROV_STEP_DONE, PROV_STEP_WIFI, prov_stop(), s_ui_queue, s_user_cancelled, settings_has_payout(), settings_has_wifi(), SETTINGS_PAYOUT_MAX, settings_set_wifi(), TAG, UI_EVENT_CARD_PIN, ui_event_dispatch(), UI_EVENT_PROV_AUTH, UI_EVENT_PROV_CARD, UI_EVENT_PROV_FINISH, UI_EVENT_PROV_NEXT, UI_EVENT_PROV_SCAN, UI_EVENT_PROV_STOP, UI_EVENT_PROV_VALUE, UI_EVENT_PROV_VALUE_NO, UI_EVENT_PROV_VALUE_SET, UI_EVENT_WIFI_TRY, ui_set_boot_status(), ui_set_prov_note(), ui_show_card_pin(), ui_show_prov(), ui_show_prov_auth(), ui_show_prov_confirm(), ui_show_wifi_connecting(), ui_take_pin(), and ui_take_wifi_creds().
Referenced by pos_boot().
| void sale_fee_text | ( | char * | out, |
| size_t | n ) |
The most network fee the customer's card can be charged on top of the sale, for the confirm screen. "" where there is no cap to state: a native TRX transfer burns bandwidth, not a fee limit.
Definition at line 201 of file pay.cpp.
References active_token(), chain_is_native_evm(), chain_is_polygon(), chain_is_tron(), fmt_coin(), GAS_LIMIT_NATIVE, s_sale_fee, and TRON_TRC20_FEE_LIMIT_SUN.
Referenced by app_main().
| void settle_inflight | ( | void | ) |
Poll the in-flight sale for up to 120 s and show what the chain says.
Only three answers end a sale: mined and ours (Approved), mined and reverted (nothing moved), or — Tron only — expired without ever being included (nothing can ever move). Everything else, including a receipt that does not match the transfer and a broadcast whose answer was lost, is Unconfirmed: the screen keeps the hash, offers Check again, and never says Declined, because a declined sale is one the merchant charges a second time.
Definition at line 255 of file pay.cpp.
References inflight_t::active, active_dest(), inflight_t::amount, inflight_t::broadcast_known, inflight_t::decided, eth_rpc_get_tx_receipt(), ETH_RPC_RECEIPT_MISMATCH, ETH_RPC_RECEIPT_PENDING, ETH_RPC_RECEIPT_REVERTED, ETH_RPC_RECEIPT_SUCCESS, eth_rpc_select_for(), inflight_t::expiration_ms, expired(), inflight_t::hash, IS_TRUE32, inflight_t::payee, inflight_t::polygon, pos_handle_anomaly(), POS_VERDICT_APPROVED, POS_VERDICT_DECLINED, run_payment_decision(), s_inflight, settings_inflight_clear(), TAG, inflight_t::to, inflight_t::token, inflight_t::tron, tron_receipt_as_eth(), tron_rpc_get_receipt(), ui_set_tx_info(), ui_show_tx_status(), UI_TX_STATE_CONFIRMING, UI_TX_STATE_DONE, UI_TX_STATE_FAILED, UI_TX_STATE_UNCONFIRMED, wall_ms(), and wdt_feed().
Referenced by app_main().
| 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.
Pipeline: reconcile → calldata → card connect + PIN → payer address → balance → nonce → RLP + keccak256 → reconcile → sign (cancellable) → local parity check → broadcast. The PIN is scrubbed with CW_Utils::secure_wipe right after signing; hash, signature and encoded txs via WipeGuard.
| [in] | wallet | Initialised wallet instance. |
| [in] | transport | PN532 transport, used for the cancellable connect loop. |
| [in] | amount | Reconciled amount, keypad base units (6 decimals). |
| [in] | to | Reconciled recipient. |
| [in] | pin | Operator-entered card PIN (scrubbed after signing). |
| [in] | pin_chars | Number of PIN characters in pin. |
| [out] | fl | Filled once signed: the locally computed hash and what its receipt must show. |
| [out] | err_out | Short UI-facing error message on failure. |
| [in] | err_max | Capacity of err_out. |
fl), or BCAST_FAILED on refusal or user cancel (err_out is only meaningful when s_user_cancelled is clear). Definition at line 165 of file pay_evm.cpp.
References active_token(), pos_addr_t::addr, token_t::addr, address_consistent(), inflight_t::amount, amount_consistent(), pos_amount_t::amount_minor, BCAST_FAILED, BCAST_SENT, BCAST_UNKNOWN, build_usdc_calldata(), eth_tx_t::calldata, eth_tx_t::calldata_len, card_connect(), card_sign(), eth_tx_t::chain_id, CHAIN_ID_AMOY, CHAIN_ID_MAINNET, CHAIN_ID_POLYGON, chain_is_native_evm(), chain_is_polygon(), eth_addr_format(), ETH_ADDR_LEN, ETH_DERIVE_PATH, eth_rlp_encode_signed(), eth_rlp_encode_unsigned(), eth_rpc_err_already_known(), eth_rpc_get_nonce(), eth_rpc_select(), eth_rpc_send_raw_tx(), eth_rpc_set_from(), eth_sig_parity(), eth_tx_t::eth_value, evm_balance_ok(), evm_units_to_wei(), eth_tx_t::gas_limit, GAS_LIMIT_NATIVE, inflight_t::hash, inflight_persist(), IS_TRUE32, keccak256(), eth_tx_t::max_fee, eth_tx_t::max_priority_fee, eth_tx_t::nonce, token_t::ok, inflight_t::payee, pin_fail_text(), inflight_t::polygon, pos_handle_anomaly(), rpc_error_text(), s_card_fault, s_sale_fee, s_user_cancelled, settings_get_mainnet(), SETTINGS_PAYOUT_MAX, TAG, eth_tx_t::to, inflight_t::to, inflight_t::token, inflight_t::tron, TX_BUF_SIZE, ui_set_tx_info(), ui_show_tx_status(), UI_TX_STATE_SENDING, UI_TX_STATE_SIGNING, and USDC_CALLDATA_LEN.
Referenced by pay_sign_and_broadcast().
| bcast_t sign_and_broadcast_tron | ( | CryptnoxWallet & | wallet, |
| Pn532NfcTransport & | transport, | ||
| CW_CryptoProvider & | crypto, | ||
| const pos_amount_t * | amount, | ||
| const pos_addr_t * | to, | ||
| const token_t * | token, | ||
| const char * | pin, | ||
| size_t | pin_chars, | ||
| inflight_t * | fl, | ||
| char * | err_out, | ||
| size_t | err_max ) |
Sign a Tron transfer on the card and broadcast it — TRX or TRC-20.
Same shape as sign_and_broadcast, but Tron has no RLP and no local nonce: the full node serialises the transaction and we sign its txID. What the node returns is therefore verified before the card ever sees the hash (see tron_rpc.h), and the recipient handed to the node is derived from the dual-stored to right after the reconcile, never from a config literal.
TRX and TRC-20 differ only in which transaction the node builds, so they share one function and the security checks cannot drift apart.
| [in] | wallet | Initialised wallet instance. |
| [in] | transport | PN532 transport (cancellable connect loop). |
| [in] | amount | Dual-stored amount, 6 decimals — sun for TRX, token base units for TRC-20. |
| [in] | to | Dual-stored recipient (20-byte key hash). |
| [in] | token | Token to charge in, or NULL for native TRX. |
| [in] | pin | Operator-entered card PIN (scrubbed after signing). |
| [in] | pin_chars | Number of PIN characters in pin. |
| [out] | fl | Filled once built: the txID and its expiration. |
| [out] | err_out | Short UI-facing error message on failure. |
| [in] | err_max | Capacity of err_out. |
fl until it expires), or BCAST_FAILED on refusal or user cancel. Definition at line 125 of file pay_tron.cpp.
References pos_addr_t::addr, token_t::addr, address_consistent(), amount_consistent(), pos_amount_t::amount_minor, BCAST_FAILED, BCAST_SENT, BCAST_UNKNOWN, card_connect(), card_sign(), ETH_ADDR_LEN, inflight_t::expiration_ms, tron_tx_ctx_t::expiration_ms, inflight_t::hash, inflight_persist(), IS_TRUE32, token_t::ok, pin_fail_text(), pos_handle_anomaly(), s_card_fault, s_user_cancelled, TAG, inflight_t::tron, TRON_ADDR_HEX_LEN, tron_addr_to_hex(), tron_balance_ok(), tron_rpc_broadcast(), tron_rpc_create_transfer(), tron_rpc_create_trc20_transfer(), TRON_TRC20_FEE_LIMIT_SUN, tron_tx_ctx_t::txid, tron_tx_ctx_t::txid_hex, ui_show_tx_status(), UI_TX_STATE_SENDING, and UI_TX_STATE_SIGNING.
Referenced by pay_sign_and_broadcast().
| bool sync_time | ( | void | ) |
Block on an SNTP sync so TLS certificate validity-period checks run against real time instead of the 1970 epoch.
Definition at line 483 of file boot.cpp.
References net_time_sync(), TAG, and TIME_SYNC_ATTEMPTS.
Referenced by pos_boot().
| bool token_decimals_ok | ( | pos_chain_t | chain, |
| char * | err, | ||
| size_t | err_max ) |
Before the first sale in an operator-set token, read its decimals() and refuse anything but 6.
Every amount is signed in 6-decimal base units, so an 18-decimal contract would be charged 10^-12 of the figure on the screen. Checked here rather than when the contract is proposed: the config page runs with the station down, so no node can be asked then. A read that fails refuses the sale too, and the next sale asks again. Once per boot per token.
Definition at line 115 of file pay.cpp.
References active_token(), pos_addr_t::addr, token_t::addr, token_t::checked, ETH_ADDR_LEN, eth_rpc_get_token_decimals(), eth_rpc_select(), eth_rpc_select_for(), pos_chain_is_polygon(), pos_chain_is_tron(), token_t::str, TAG, TRON_ADDR_HEX_LEN, tron_addr_to_hex(), and tron_rpc_get_trc20_decimals().
Referenced by app_main(), and pay_sign_and_broadcast().
| void token_load | ( | const token_cfg_t * | cfg, |
| CW_CryptoProvider & | crypto ) |
Load one token at boot: the operator's contract if one is set and parses, config.h otherwise.
Non-fatal by design: a placeholder or a typo leaves ok false and that one asset is refused when selected, rather than stopping a terminal that charges in something else from booting.
Definition at line 84 of file pay.cpp.
References token_cfg_t::chain, token_t::checked, token_cfg_t::main, token_cfg_t::name, pos_asset_t::net, pos_asset_of(), pos_chain_is_tron(), pos_net_info(), s_token, settings_get_contract(), settings_net_str(), token_t::str, TAG, token_cfg_t::test, pos_asset_t::ticker, and token_parse().
Referenced by pos_boot().
| void tron_addr_to_hex | ( | const uint8_t * | addr21, |
| char * | out, | ||
| size_t | n ) |
Format a raw 21-byte Tron address as the "41..." hex the API wants.
| [in] | addr21 | 21-byte address (0x41 prefix included). |
| [out] | out | TRON_ADDR_HEX_LEN chars + NUL. |
| [in] | n | Capacity of out. |
Definition at line 25 of file pay_tron.cpp.
References TRON_ADDR_HEX_LEN.
Referenced by sign_and_broadcast_tron(), and token_decimals_ok().
| eth_rpc_receipt_result_t tron_receipt_as_eth | ( | tron_receipt_t | r | ) |
Map a Tron receipt onto the Ethereum verdicts the UI flow uses.
Definition at line 309 of file pay_tron.cpp.
References ETH_RPC_RECEIPT_PENDING, ETH_RPC_RECEIPT_REVERTED, ETH_RPC_RECEIPT_RPC_ERROR, ETH_RPC_RECEIPT_SUCCESS, TRON_RECEIPT_FAILED, TRON_RECEIPT_PENDING, and TRON_RECEIPT_SUCCESS.
Referenced by settle_inflight().
| void ui_event_dispatch | ( | ui_event_t | event, |
| uint64_t | payload ) |
UI-task callback: forward a touch event to the main task queue.
Runs in the UI task context. A Cancel tap also raises the atomic s_user_cancelled flag so the in-flight signing flow can abort without waiting for the queue to drain.
| [in] | event | UI event identifier. |
| [in] | payload | Event payload (amount in USDC base units, or 0). |
Definition at line 39 of file main.cpp.
References s_ui_queue, s_user_cancelled, and UI_EVENT_CONFIRM_CANCEL.
Referenced by pos_boot(), and run_wizard().
| void wait_for_ui_event | ( | ui_event_t | want | ) |
Block until the UI reports want, discarding anything else.
For the modal first-run steps. The queue is flushed on the way out so a repeated tap is not read by the next stage (wifi_picker() would rescan and throw away a half-typed password).
Definition at line 94 of file boot.cpp.
References ui_msg_t::event, and s_ui_queue.
Referenced by pos_boot().
| uint64_t wall_ms | ( | void | ) |
Unix time in ms, 0 while the clock is unset.
Definition at line 237 of file pay.cpp.
Referenced by app_main(), and settle_inflight().
| void wifi_keep_or_drop | ( | bool | keep | ) |
Persist or discard the pending picker credentials, then scrub them.
| [in] | keep | true once the clock is set — the only proof the network is actually usable; false to drop them unpersisted. |
Definition at line 77 of file boot.cpp.
References s_join_pass, s_join_ssid, settings_set_wifi(), and TAG.
Referenced by pos_boot().
| bool wifi_picker | ( | const char * | note | ) |
Run the panel network picker (scan → list → keyboard → connect) until connected.
Blocks until a connection succeeds. The fallback to the browser setup (run_wizard): reached from the settings menu, or when the SoftAP could not come up.
A network joined here is not persisted: the credentials are staged for wifi_keep_or_drop, which the caller invokes once the clock proves the uplink usable.
| [in] | note | One-line reason shown above the picker, or NULL. |
Definition at line 151 of file boot.cpp.
References ui_msg_t::event, net_wifi_connect(), net_wifi_scan(), NOTE_JOIN_FAILED, ok(), s_join_pass, s_join_ssid, s_ui_queue, UI_EVENT_WIFI_SCAN, UI_EVENT_WIFI_TRY, ui_show_wifi_connecting(), ui_show_wifi_list(), and ui_take_wifi_creds().
Referenced by pos_boot().
| bool wifi_try_saved | ( | void | ) |
Try the saved credentials, staying on the splash while it happens.
Unattended, so it reports through ui_set_boot_status. config.h Wi-Fi credentials are intentionally not used (NVS only).
Definition at line 113 of file boot.cpp.
References net_wifi_connect(), ok(), settings_get_wifi(), TAG, ui_set_boot_status(), and WIFI_SAVED_ATTEMPTS.
Referenced by pos_boot().
|
extern |
Definition at line 16 of file pay.cpp.
Referenced by card_read_payouts(), and sign_and_broadcast().
|
extern |
Definition at line 58 of file boot.cpp.
Referenced by app_main(), run_wizard(), and wifi_picker().
|
extern |
Definition at line 60 of file boot.cpp.
Referenced by app_main(), pos_boot(), and run_wizard().
|
extern |
Definition at line 18 of file card_io.cpp.
Referenced by card_connect(), card_read_payouts(), sign_and_broadcast(), and sign_and_broadcast_tron().
|
extern |
Definition at line 177 of file pay.cpp.
Referenced by active_dest(), pay_sign_and_broadcast(), and resolve_evm_payout().
|
extern |
Definition at line 219 of file pay.cpp.
Referenced by app_main(), and settle_inflight().
|
extern |
Definition at line 182 of file pay.cpp.
Referenced by app_main(), and pos_boot().
|
extern |
Definition at line 27 of file pay.cpp.
Referenced by app_main(), pos_boot(), resolve_evm_payout(), and ui_refresh_addresses_for().
|
extern |
Definition at line 28 of file pay.cpp.
Referenced by app_main(), pos_boot(), and ui_refresh_addresses_for().
|
extern |
Definition at line 192 of file pay.cpp.
Referenced by app_main(), evm_balance_ok(), sale_fee_text(), and sign_and_broadcast().
|
extern |
Definition at line 30 of file pay.cpp.
Referenced by active_token(), auth_post(), has_token(), prov_auth_resolve(), prov_pair_code(), prov_start(), prov_stop(), and token_load().
|
extern |
Definition at line 185 of file pay.cpp.
Referenced by active_dest(), pay_sign_and_broadcast(), and pos_boot().
|
extern |
Definition at line 23 of file main.cpp.
Referenced by app_main(), pos_boot(), run_wizard(), ui_event_dispatch(), wait_for_ui_event(), and wifi_picker().
|
extern |
Definition at line 27 of file main.cpp.
Referenced by app_main(), card_connect(), card_read_payouts(), run_wizard(), sign_and_broadcast(), sign_and_broadcast_tron(), and ui_event_dispatch().
|
extern |
Definition at line 32 of file pay.cpp.
Referenced by pos_boot().
|
extern |
Definition at line 41 of file pay.cpp.
Referenced by pos_boot().