cryptnox-pos 1.0.0
Standalone USDC payment terminal firmware (ESP32 + Cryptnox smart card)
Loading...
Searching...
No Matches
eth_rpc.cpp File Reference

Ethereum JSON-RPC client implementation (HTTPS). Network bring-up (Wi-Fi, SNTP) lives in net.cpp. More...

#include "eth_rpc.h"
#include "eth_json.h"
#include "https_post.h"
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include "CW_Utils.h"
#include "esp_log.h"
Include dependency graph for eth_rpc.cpp:

Go to the source code of this file.

Macros

#define RESP_BUF_SIZE   1024U
#define HEX_PER_BYTE   2U
#define RESP_LOG_MAX   80
#define NONCE_MAX   0xFFFFFFFFULL
#define RESULT_STR_MAX   80U

Functions

static bool do_post (const char *body, char *resp_buf, size_t resp_buf_size)
 POST a JSON-RPC body to the configured endpoint over HTTPS.
static char hex_nibble (uint8_t n)
 Convert a nibble value to its lowercase ASCII hex digit.
static void bytes_to_hex (const uint8_t *data, size_t len, char *out)
 Hex-encode a byte buffer (lowercase, no prefix, no NUL).
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.
bool eth_rpc_set_from (const char *addr)
 Replace the from-address — the account a sale spends from.
void eth_rpc_set_auth (const char *project_id, const char *api_secret)
 Optional: set Infura-style HTTP Basic Auth credentials.
void eth_rpc_set_ca_cert (const char *ca_pem)
 Optional: pin the RPC endpoint's TLS certificate.
bool eth_rpc_get_nonce (uint64_t *nonce_out)
 Fetch the confirmed transaction count (nonce) for from_addr.
static const char * from_no_prefix (void)
 The configured from-address with any "0x" prefix removed.
bool eth_rpc_get_balance (uint64_t *wei_out)
 Fetch the native balance of from_addr, in wei.
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.
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).
bool eth_rpc_get_token_decimals (const char *token_addr, uint64_t *dec_out)
 Read an ERC-20 contract's decimals().
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", "known transaction") — i.e. an earlier attempt whose answer was lost got through.
eth_rpc_receipt_result_t eth_rpc_get_tx_receipt (const eth_receipt_expect_t *want)
 Poll the receipt of a broadcast transaction (one shot).

Variables

static const char *const TAG = "eth_rpc"
static const char * s_rpc_url = NULL
static const char * s_from_addr = NULL
static const char * s_project_id = NULL
static const char * s_api_secret = NULL
static const char * s_ca_cert = NULL
static char s_from_buf [43]

Detailed Description

Ethereum JSON-RPC client implementation (HTTPS). Network bring-up (Wi-Fi, SNTP) lives in net.cpp.

Definition in file eth_rpc.cpp.

Macro Definition Documentation

◆ HEX_PER_BYTE

#define HEX_PER_BYTE   2U

Definition at line 39 of file eth_rpc.cpp.

Referenced by bytes_to_hex(), and eth_rpc_send_raw_tx().

◆ NONCE_MAX

#define NONCE_MAX   0xFFFFFFFFULL

Definition at line 47 of file eth_rpc.cpp.

Referenced by eth_rpc_get_nonce().

◆ RESP_BUF_SIZE

◆ RESP_LOG_MAX

◆ RESULT_STR_MAX

#define RESULT_STR_MAX   80U

Function Documentation

◆ bytes_to_hex()

void bytes_to_hex ( const uint8_t * data,
size_t len,
char * out )
static

Hex-encode a byte buffer (lowercase, no prefix, no NUL).

Parameters
[in]dataInput bytes.
[in]lenNumber of input bytes.
[out]outOutput buffer of at least 2*len chars; not NUL-terminated.

Definition at line 106 of file eth_rpc.cpp.

References hex_nibble(), and HEX_PER_BYTE.

Referenced by eth_rpc_send_raw_tx().

◆ do_post()

bool do_post ( const char * body,
char * resp_buf,
size_t resp_buf_size )
static

POST a JSON-RPC body to the configured endpoint over HTTPS.

Thin wrapper over https_post_json that supplies this module's endpoint, optional Infura credentials and optional pinned certificate.

Parameters
[in]bodyJSON request body (NUL-terminated).
[out]resp_bufResponse buffer, NUL-terminated on return.
[in]resp_buf_sizeCapacity of resp_buf.
Returns
true on an HTTP 200 with a non-empty body, false otherwise.

Definition at line 77 of file eth_rpc.cpp.

References https_post_json(), s_api_secret, s_ca_cert, s_project_id, and s_rpc_url.

Referenced by eth_rpc_get_balance(), eth_rpc_get_nonce(), eth_rpc_get_token_balance(), eth_rpc_get_token_decimals(), eth_rpc_get_tx_receipt(), and eth_rpc_send_raw_tx().

◆ eth_rpc_err_already_known()

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", "known transaction") — i.e. an earlier attempt whose answer was lost got through.

Definition at line 377 of file eth_rpc.cpp.

Referenced by sign_and_broadcast().

◆ eth_rpc_get_balance()

bool eth_rpc_get_balance ( uint64_t * wei_out)

Fetch the native balance of from_addr, in wei.

For the pre-flight check that refuses a sale the payer cannot fund before the customer is asked for anything — see evm_balance_ok in main.cpp. Without it the first news of an empty account is the node's refusal after the PIN, the tap and the signature.

Saturating at UINT64_MAX (see eth_json_hex_quantity): 20 ETH does not fit a uint64 of wei, and over-reporting can only fail to refuse.

Parameters
[out]wei_outBalance on success; untouched on failure.
Returns
true on success, false on transport or parse error.

Definition at line 212 of file eth_rpc.cpp.

References do_post(), eth_json_hex_quantity(), eth_json_result_string(), RESP_BUF_SIZE, RESP_LOG_MAX, RESULT_STR_MAX, s_from_addr, and TAG.

Referenced by evm_balance_ok().

◆ eth_rpc_get_nonce()

bool eth_rpc_get_nonce ( uint64_t * nonce_out)

Fetch the confirmed transaction count (nonce) for from_addr.

"latest", not "pending": a sale whose broadcast answer was lost may still be in the mempool, and a retry must REPLACE it (same nonce, only one can land) rather than queue behind it as a second payment.

Responses with an HTTP status other than 200, malformed JSON, or a nonce above 2^32-1 are rejected.

Parameters
[out]nonce_outNonce on success; untouched on failure.
Returns
true on success, false on transport, parse or range error.

Definition at line 157 of file eth_rpc.cpp.

References do_post(), eth_json_result_string(), NONCE_MAX, RESP_BUF_SIZE, RESP_LOG_MAX, RESULT_STR_MAX, s_from_addr, and TAG.

Referenced by pos_boot(), and sign_and_broadcast().

◆ eth_rpc_get_token_balance()

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.

The token half of the same check, and the one that saves more: a transfer of more tokens than the account holds is not refused by the node at all. It is broadcast, mined, reverted, and charged for — so the customer waits through the whole confirmation only to be declined, and pays the gas for the privilege.

Saturating, like eth_rpc_get_balance.

Parameters
[in]token_addr"0x..."-prefixed contract address to call.
[out]units_outBalance in the token's base units on success; untouched on failure.
Returns
true on success, false on transport or parse error, or if the configured from_addr is not a 20-byte hex address.

Definition at line 239 of file eth_rpc.cpp.

References do_post(), eth_json_hex_quantity(), eth_json_result_string(), from_no_prefix(), RESP_BUF_SIZE, RESP_LOG_MAX, RESULT_STR_MAX, s_from_addr, and TAG.

Referenced by evm_balance_ok().

◆ eth_rpc_get_token_decimals()

bool eth_rpc_get_token_decimals ( const char * token_addr,
uint64_t * dec_out )

Read an ERC-20 contract's decimals().

Every amount this terminal signs is in 6-decimal base units, so a contract with any other precision would be charged the wrong sum — 10^12 too little for an 18-decimal token. Checked before such a contract can be accepted.

Parameters
[in]token_addr"0x"-prefixed contract address.
[out]dec_outdecimals() on success; untouched on failure.
Returns
false on transport error, no contract code, or a malformed answer.

Definition at line 354 of file eth_rpc.cpp.

References do_post(), eth_json_hex_quantity(), eth_json_result_string(), RESP_BUF_SIZE, RESP_LOG_MAX, RESULT_STR_MAX, and TAG.

Referenced by token_decimals_ok().

◆ eth_rpc_get_tx_receipt()

eth_rpc_receipt_result_t eth_rpc_get_tx_receipt ( const eth_receipt_expect_t * want)

Poll the receipt of a broadcast transaction (one shot).

Calls eth_getTransactionReceipt. A broadcast acceptance only means the tx entered the mempool — a POS must wait for the mined receipt (status 0x1) before declaring the payment approved.

Parameters
[in]wantWhat the receipt must show (see eth_json.h); its tx_hash is the hash computed on the device, not the node's answer to the broadcast.
Return values
ETH_RPC_RECEIPT_PENDINGNot mined yet — poll again later.
ETH_RPC_RECEIPT_SUCCESSMined, execution succeeded, and it is our transfer.
ETH_RPC_RECEIPT_REVERTEDMined but reverted — funds NOT moved.
ETH_RPC_RECEIPT_RPC_ERRORTransport/parse error (may be transient).
ETH_RPC_RECEIPT_MISMATCHA receipt that is not our payment.

Definition at line 385 of file eth_rpc.cpp.

References do_post(), eth_json_receipt_check(), ETH_JSON_RECEIPT_ERROR, ETH_JSON_RECEIPT_MISMATCH, ETH_JSON_RECEIPT_PENDING, ETH_JSON_RECEIPT_REVERTED, ETH_JSON_RECEIPT_SUCCESS, ETH_RPC_RECEIPT_MISMATCH, ETH_RPC_RECEIPT_PENDING, ETH_RPC_RECEIPT_REVERTED, ETH_RPC_RECEIPT_RPC_ERROR, ETH_RPC_RECEIPT_SUCCESS, RESP_LOG_MAX, TAG, and eth_receipt_expect_t::tx_hash.

Referenced by settle_inflight().

◆ eth_rpc_init()

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.

Must be called before any other eth_rpc_* function.

Lifetime: the module stores the pointers as-is (no copy). Both strings must outlive every eth_rpc_* call — pass string literals or static storage, never stack buffers.

Parameters
[in]rpc_urlHTTPS JSON-RPC endpoint URL.
[in]from_addr"0x..."-prefixed 40-hex-char sender address.

Definition at line 122 of file eth_rpc.cpp.

References s_from_addr, and s_rpc_url.

Referenced by eth_rpc_select_for().

◆ eth_rpc_send_raw_tx()

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).

Parameters
[in]txSigned transaction bytes.
[in]tx_lenLength of tx in bytes.
[out]tx_hash_out"0x..."-prefixed tx hash on success; must be at least 68 bytes (2 + 64 + NUL).
[in]tx_hash_maxCapacity of tx_hash_out.
[out]err_outOn failure, the node's own error.message when it sent one ("insufficient funds for gas * price + value", "nonce too low", …), truncated to fit; set to "" when the failure was a transport or parse error with no message to report. May be NULL.
[in]err_maxCapacity of err_out.
Returns
true on success, false on transport error, JSON-RPC error response, or undersized tx_hash_out.

Definition at line 286 of file eth_rpc.cpp.

References bytes_to_hex(), do_post(), eth_json_error_message(), eth_json_result_string(), HEX_PER_BYTE, ok(), RESP_BUF_SIZE, RESP_LOG_MAX, RESULT_STR_MAX, and TAG.

Referenced by sign_and_broadcast().

◆ eth_rpc_set_auth()

void eth_rpc_set_auth ( const char * project_id,
const char * api_secret )

Optional: set Infura-style HTTP Basic Auth credentials.

Same lifetime contract as eth_rpc_init: pointers are stored, not copied.

Parameters
[in]project_idUsername (Infura project ID); NULL/empty disables auth.
[in]api_secretPassword (Infura API secret); NULL/empty disables auth.

Definition at line 146 of file eth_rpc.cpp.

References s_api_secret, and s_project_id.

Referenced by eth_rpc_select_for().

◆ eth_rpc_set_ca_cert()

void eth_rpc_set_ca_cert ( const char * ca_pem)

Optional: pin the RPC endpoint's TLS certificate.

When set, the HTTPS connection is validated only against this PEM (leaf or its issuing CA) instead of the full Mozilla CA bundle, so no unrelated CA can MITM the RPC traffic. Pointer stored as-is (must outlive every call — pass a static/embedded literal). NULL keeps the CA bundle.

Parameters
[in]ca_pemNUL-terminated PEM certificate, or NULL for the bundle.

Definition at line 152 of file eth_rpc.cpp.

References s_ca_cert.

Referenced by eth_rpc_select_for().

◆ eth_rpc_set_from()

bool eth_rpc_set_from ( const char * addr)

Replace the from-address — the account a sale spends from.

The payer is the card on the reader, so it is not known until somebody taps. eth_rpc_init's from_addr is only the boot-time default (the config.h literal, used for the startup reachability probe); this is the per-tap override, and everything that reads the sender — the nonce, the balance, the ecrecover comparison — follows it.

Unlike every other setter in this header the string is copied, because its caller derives it into a stack buffer inside one sale.

Parameters
[in]addr"0x"-prefixed, 40 hex characters. A malformed one is refused rather than silently leaving the previous payer in force — the next nonce would otherwise be somebody else's.
Returns
true if the address was accepted and is now in force.

Definition at line 133 of file eth_rpc.cpp.

References s_from_addr, and s_from_buf.

Referenced by sign_and_broadcast().

◆ from_no_prefix()

const char * from_no_prefix ( void )
static

The configured from-address with any "0x" prefix removed.

Both callers below want the bare 40 characters — one to compare against what ecrecover returned, the other to pad into an ABI argument.

Definition at line 203 of file eth_rpc.cpp.

References s_from_addr.

Referenced by eth_rpc_get_token_balance().

◆ hex_nibble()

char hex_nibble ( uint8_t n)
static

Convert a nibble value to its lowercase ASCII hex digit.

Parameters
[in]nNibble value; only the range 0–15 is meaningful.
Returns
'0'–'9' or 'a'–'f'.

Definition at line 93 of file eth_rpc.cpp.

Referenced by bytes_to_hex().

Variable Documentation

◆ s_api_secret

const char* s_api_secret = NULL
static

Definition at line 59 of file eth_rpc.cpp.

Referenced by do_post(), and eth_rpc_set_auth().

◆ s_ca_cert

const char* s_ca_cert = NULL
static

Definition at line 60 of file eth_rpc.cpp.

Referenced by do_post(), eth_rpc_set_ca_cert(), tron_post(), and tron_rpc_set_ca_cert().

◆ s_from_addr

const char* s_from_addr = NULL
static

◆ s_from_buf

char s_from_buf[43]
static

Definition at line 131 of file eth_rpc.cpp.

Referenced by eth_rpc_set_from().

◆ s_project_id

const char* s_project_id = NULL
static

Definition at line 58 of file eth_rpc.cpp.

Referenced by do_post(), and eth_rpc_set_auth().

◆ s_rpc_url

const char* s_rpc_url = NULL
static

Definition at line 56 of file eth_rpc.cpp.

Referenced by do_post(), and eth_rpc_init().

◆ TAG

const char* const TAG = "eth_rpc"
static

Definition at line 33 of file eth_rpc.cpp.

Referenced by app_main(), auth_post(), boot_fault(), build_time_floor(), card_fault(), card_post(), card_read_payouts(), clock_corroborated(), clock_post(), dns_task(), dual_get(), dual_set(), eth_rpc_get_balance(), eth_rpc_get_nonce(), eth_rpc_get_token_balance(), eth_rpc_get_token_decimals(), eth_rpc_get_tx_receipt(), eth_rpc_send_raw_tx(), evm_balance_ok(), fees_post(), https_post_json(), indev_read(), net_ap_start(), net_ap_stop(), net_time_background(), net_time_sync(), net_wifi_connect(), net_wifi_disconnect(), network_post(), nvs_load_ctr(), nvs_store_ctr(), nvs_u32_set(), nvs_u8_set(), on_time_sync(), ota_abort(), ota_begin(), ota_commit(), ota_end(), ota_mark_valid(), ota_post(), ota_write(), pin_fail_text(), pos_boot(), pos_handle_anomaly(), prov_auth_resolve(), prov_propose(), prov_start(), prov_stop(), refuse(), rejoin_cb(), rejoin_schedule(), resolve_evm_payout(), run_wizard(), settings_check_admin_code(), settings_factory_reset(), settings_inflight_save(), settings_set_admin_code(), settings_set_mainnet(), settings_set_touch_cal(), settings_set_wifi(), settings_wipe_if_new_build(), settle_inflight(), sign_and_broadcast(), sign_and_broadcast_tron(), sntp_start(), sync_time(), token_decimals_ok(), token_load(), tron_balance_ok(), tron_post(), tron_rpc_broadcast(), tron_rpc_create_transfer(), tron_rpc_create_trc20_transfer(), tron_rpc_get_balance(), tron_rpc_get_energy(), tron_rpc_get_receipt(), tron_rpc_get_trc20_balance(), tron_rpc_get_trc20_decimals(), tx_ctx_from_json(), ui_task(), wifi_event_handler(), wifi_keep_or_drop(), wifi_post(), and wifi_try_saved().