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

Tron HTTP API client implementation. More...

#include "tron_rpc.h"
#include "tron_tx.h"
#include "eth_json.h"
#include "https_post.h"
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <inttypes.h>
#include "CW_Utils.h"
#include "esp_log.h"
#include "mbedtls/sha256.h"
#include <sys/time.h>
#include "cJSON.h"
Include dependency graph for tron_rpc.cpp:

Go to the source code of this file.

Macros

#define RESP_BUF_SIZE   3072U
#define RESP_LOG_MAX   120
#define RAW_BYTES_MAX   (TRON_RAW_HEX_MAX / 2U)

Functions

static char nibble_hex (unsigned n)
static int nibble_val (char c)
static size_t hex_to_bytes (const char *hex, uint8_t *out, size_t out_size)
 Decode a hex string into bytes.
static void bytes_to_hex (const uint8_t *data, size_t len, char *out)
 Hex-encode len bytes into out (NUL-terminated).
static bool tron_post (const char *path, const char *body, char *resp, size_t resp_size)
 POST body to path under the configured base URL.
static uint64_t now_ms (void)
 Unix time in ms, 0 if the clock is unset (the checks then refuse).
static bool tx_ctx_from_json (const cJSON *txobj, tron_tx_ctx_t *out)
 Take a node-built transaction object apart into a tron_tx_ctx_t.
void tron_rpc_init (const char *base_url)
 Set the Tron HTTP API base URL (no trailing slash).
void tron_rpc_set_ca_cert (const char *ca_pem)
 Optional: pin the Tron endpoint's TLS certificate.
static uint64_t json_u64 (const cJSON *n)
 A cJSON number as a uint64, clamped at both ends.
bool tron_rpc_get_balance (const char *owner_hex, uint64_t *sun_out)
 Read an account's TRX balance, in sun.
bool tron_rpc_get_energy (const char *owner_hex, uint64_t *energy_out)
 Read the energy an account still has available.
bool tron_rpc_get_trc20_balance (const char *owner_hex, const char *contract_hex, uint64_t *units_out)
 Read an account's TRC-20 balance via a constant balanceOf call.
bool tron_rpc_get_trc20_decimals (const char *contract_hex, uint64_t *dec_out)
 Read a TRC-20 contract's decimals() — see eth_rpc_get_token_decimals for why it has to be 6.
bool tron_rpc_create_transfer (const char *owner_hex, const char *to_hex, uint64_t amount_sun, tron_tx_ctx_t *out)
 Create a TRX transfer and verify what the node serialised for us.
bool tron_rpc_create_trc20_transfer (const char *owner_hex, const char *contract_hex, const char *to_hex, uint64_t amount, uint64_t fee_limit_sun, tron_tx_ctx_t *out)
 Create a TRC-20 transfer (USDT, USDC, …) and verify what the node serialised for us.
bool tron_rpc_broadcast (const tron_tx_ctx_t *tx, const uint8_t sig[65])
 Broadcast a created transfer with its 65-byte signature.
tron_receipt_t tron_rpc_get_receipt (const char *txid_hex)
 Poll a broadcast transaction's receipt (one shot).

Variables

static const char *const TAG = "tron_rpc"
static const char * s_base_url = NULL
static const char * s_ca_cert = NULL

Detailed Description

Tron HTTP API client implementation.

Definition in file tron_rpc.cpp.

Macro Definition Documentation

◆ RAW_BYTES_MAX

#define RAW_BYTES_MAX   (TRON_RAW_HEX_MAX / 2U)

Definition at line 42 of file tron_rpc.cpp.

Referenced by tx_ctx_from_json().

◆ RESP_BUF_SIZE

#define RESP_BUF_SIZE   3072U

Definition at line 38 of file tron_rpc.cpp.

◆ RESP_LOG_MAX

#define RESP_LOG_MAX   120

Definition at line 39 of file tron_rpc.cpp.

Function Documentation

◆ bytes_to_hex()

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

Hex-encode len bytes into out (NUL-terminated).

Definition at line 89 of file tron_rpc.cpp.

References nibble_hex().

Referenced by tron_rpc_broadcast(), and tx_ctx_from_json().

◆ hex_to_bytes()

size_t hex_to_bytes ( const char * hex,
uint8_t * out,
size_t out_size )
static

Decode a hex string into bytes.

Parameters
[in]hexNUL-terminated hex, even length.
[out]outDestination bytes.
[in]out_sizeCapacity of out.
Returns
number of bytes written, 0 on odd length, non-hex input or overflow.

Definition at line 73 of file tron_rpc.cpp.

References nibble_val().

Referenced by tx_ctx_from_json().

◆ json_u64()

uint64_t json_u64 ( const cJSON * n)
static

A cJSON number as a uint64, clamped at both ends.

Tron reports sun and energy as JSON integers and cJSON hands them back as doubles, so past 2^53 the low digits are lost. For a balance that is a rounding error in the last drop of TRX; it is never the difference between funded and empty, which is the only question asked of these numbers.

A missing or non-numeric field reads as zero — for an account the chain has never seen, that is the answer rather than an error.

Definition at line 211 of file tron_rpc.cpp.

Referenced by tron_rpc_get_balance(), and tron_rpc_get_energy().

◆ nibble_hex()

char nibble_hex ( unsigned n)
static

Definition at line 51 of file tron_rpc.cpp.

Referenced by bytes_to_hex().

◆ nibble_val()

int nibble_val ( char c)
static

Definition at line 57 of file tron_rpc.cpp.

Referenced by hex_to_bytes().

◆ now_ms()

uint64_t now_ms ( void )
static

Unix time in ms, 0 if the clock is unset (the checks then refuse).

Definition at line 117 of file tron_rpc.cpp.

Referenced by raw_ok(), tron_rpc_create_transfer(), tron_rpc_create_trc20_transfer(), tron_tx_contract_ok(), and tron_tx_trc20_ok().

◆ tron_post()

bool tron_post ( const char * path,
const char * body,
char * resp,
size_t resp_size )
static

◆ tron_rpc_broadcast()

bool tron_rpc_broadcast ( const tron_tx_ctx_t * tx,
const uint8_t sig[65] )

Broadcast a created transfer with its 65-byte signature.

Parameters
[in]txContext returned by tron_rpc_create_transfer.
[in]sigSignature bytes: r(32) || s(32) || recovery id(1).
Returns
true if the node accepted the transaction into its mempool.

Definition at line 471 of file tron_rpc.cpp.

References bytes_to_hex(), ok(), tron_tx_ctx_t::raw_hex, RESP_BUF_SIZE, RESP_LOG_MAX, TAG, tron_post(), TRON_RAW_HEX_MAX, TRON_SIG_HEX_LEN, and tron_tx_envelope_hex().

Referenced by sign_and_broadcast_tron().

◆ tron_rpc_create_transfer()

bool tron_rpc_create_transfer ( const char * owner_hex,
const char * to_hex,
uint64_t amount_sun,
tron_tx_ctx_t * out )

Create a TRX transfer and verify what the node serialised for us.

Parameters
[in]owner_hexSender address, "41"-prefixed 42-char hex.
[in]to_hexRecipient address, same form.
[in]amount_sunAmount in sun (1 TRX = 1e6 sun); must be non-zero.
[out]outFilled on success; contents undefined on failure.
Returns
true only if the node answered AND the txID matches sha256(raw_data) AND raw_data contains exactly the requested TransferContract.

Definition at line 366 of file tron_rpc.cpp.

References tron_tx_ctx_t::expiration_ms, now_ms(), ok(), tron_tx_ctx_t::raw_hex, RESP_BUF_SIZE, RESP_LOG_MAX, TAG, tron_post(), tron_tx_contract_ok(), tx_ctx_from_json(), and tron_tx_ctx_t::txid_hex.

Referenced by sign_and_broadcast_tron().

◆ tron_rpc_create_trc20_transfer()

bool tron_rpc_create_trc20_transfer ( const char * owner_hex,
const char * contract_hex,
const char * to_hex,
uint64_t amount,
uint64_t fee_limit_sun,
tron_tx_ctx_t * out )

Create a TRC-20 transfer (USDT, USDC, …) and verify what the node serialised for us.

Same trust model as tron_rpc_create_transfer, with one more thing to get wrong: the token contract. A node free to choose it could have the card sign a transfer of a worthless token — or of a different one entirely — so the contract address is pinned by the check just like the recipient is, and so is the fee limit (see tron_tx_trc20_ok).

Parameters
[in]owner_hexSender address, "41"-prefixed 42-char hex.
[in]contract_hexToken contract address, same form.
[in]to_hexRecipient address, same form.
[in]amountAmount in token base units; must be non-zero.
[in]fee_limit_sunMax TRX (in sun) the call may burn; must be non-zero, or a failed call has no cap at all.
[out]outFilled on success; contents undefined on failure.
Returns
true only if the node answered AND txID == sha256(raw_data) AND raw_data carries exactly the requested transfer under the requested fee limit.

Definition at line 411 of file tron_rpc.cpp.

References tron_tx_ctx_t::expiration_ms, now_ms(), ok(), tron_tx_ctx_t::raw_hex, RESP_BUF_SIZE, RESP_LOG_MAX, TAG, tron_post(), tron_trc20_param_hex(), TRON_TRC20_PARAM_HEX_LEN, tron_tx_trc20_ok(), tx_ctx_from_json(), and tron_tx_ctx_t::txid_hex.

Referenced by sign_and_broadcast_tron().

◆ tron_rpc_get_balance()

bool tron_rpc_get_balance ( const char * owner_hex,
uint64_t * sun_out )

Read an account's TRX balance, in sun.

For the pre-flight check that refuses a sale the tapped card cannot fund, before it signs anything — see tron_balance_ok in main.cpp.

An account the chain has never seen answers with an empty object. That is reported as a balance of zero and not as an error, because it is the true answer and it is the case a terminal most needs to catch.

Parameters
[in]owner_hexAccount address, "41"-prefixed 42-char hex.
[out]sun_outBalance in sun on success; untouched on failure.
Returns
true if the node answered with parseable JSON.

Definition at line 218 of file tron_rpc.cpp.

References json_u64(), RESP_BUF_SIZE, RESP_LOG_MAX, TAG, and tron_post().

Referenced by tron_balance_ok().

◆ tron_rpc_get_energy()

bool tron_rpc_get_energy ( const char * owner_hex,
uint64_t * energy_out )

Read the energy an account still has available.

EnergyLimit minus EnergyUsed from /wallet/getaccountresource. Only the distinction between none and some is used: a TRC-20 transfer burns energy paid for out of a stake or out of TRX, so an account with zero TRX can still pay if it has frozen some — and refusing that sale would be worse than the late failure the check exists to avoid.

Parameters
[in]owner_hexAccount address, "41"-prefixed 42-char hex.
[out]energy_outEnergy available on success; untouched on failure.
Returns
true if the node answered with parseable JSON.

Definition at line 241 of file tron_rpc.cpp.

References json_u64(), RESP_BUF_SIZE, RESP_LOG_MAX, TAG, and tron_post().

Referenced by tron_balance_ok().

◆ tron_rpc_get_receipt()

tron_receipt_t tron_rpc_get_receipt ( const char * txid_hex)

Poll a broadcast transaction's receipt (one shot).

Parameters
[in]txid_hex64-char transaction id hex.
Returns
One of tron_receipt_t.

Definition at line 511 of file tron_rpc.cpp.

References RESP_BUF_SIZE, TAG, tron_post(), TRON_RECEIPT_FAILED, TRON_RECEIPT_PENDING, TRON_RECEIPT_RPC_ERROR, and TRON_RECEIPT_SUCCESS.

Referenced by settle_inflight().

◆ tron_rpc_get_trc20_balance()

bool tron_rpc_get_trc20_balance ( const char * owner_hex,
const char * contract_hex,
uint64_t * units_out )

Read an account's TRC-20 balance via a constant balanceOf call.

The check that tron_rpc_create_trc20_transfer cannot make: creating a TriggerSmartContract is only serialisation, and a node will serialise a transfer of tokens the account does not hold just as readily as one it does. Without this the card signs it, it broadcasts, it reverts on-chain, and the customer is declined after the full wait — having paid the energy for it.

Parameters
[in]owner_hexAccount address, "41"-prefixed 42-char hex.
[in]contract_hexToken contract address, same form.
[out]units_outBalance in the token's base units on success; untouched on failure. Saturating, as for the EVM side (see eth_json_hex_quantity).
Returns
true if the node answered with a well-formed constant result.

Definition at line 269 of file tron_rpc.cpp.

References eth_json_hex_quantity(), ok(), RESP_BUF_SIZE, RESP_LOG_MAX, TAG, TRON_ADDR_HEX_LEN, and tron_post().

Referenced by tron_balance_ok().

◆ tron_rpc_get_trc20_decimals()

bool tron_rpc_get_trc20_decimals ( const char * contract_hex,
uint64_t * dec_out )

Read a TRC-20 contract's decimals() — see eth_rpc_get_token_decimals for why it has to be 6.

Parameters
[in]contract_hexContract, TRON_ADDR_HEX_LEN hex chars, "41"-prefixed.
[out]dec_outdecimals() on success; untouched on failure.
Returns
false on transport error or a malformed answer.

Definition at line 330 of file tron_rpc.cpp.

References eth_json_hex_quantity(), ok(), RESP_BUF_SIZE, RESP_LOG_MAX, TAG, TRON_ADDR_HEX_LEN, and tron_post().

Referenced by token_decimals_ok().

◆ tron_rpc_init()

void tron_rpc_init ( const char * base_url)

Set the Tron HTTP API base URL (no trailing slash).

Lifetime: the pointer is stored as-is — pass a literal or static storage.

Parameters
[in]base_urle.g. "https://nile.trongrid.io".

Definition at line 190 of file tron_rpc.cpp.

References s_base_url.

Referenced by pos_boot().

◆ tron_rpc_set_ca_cert()

void tron_rpc_set_ca_cert ( const char * ca_pem)

Optional: pin the Tron endpoint's TLS certificate.

The sibling of eth_rpc_set_ca_cert, and for the same reason: unset, the connection is validated against the whole Mozilla CA bundle, so any one of ~150 CAs can stand in for the node. That is survivable here — tron_tx_contract_ok re-derives the bytes a transfer must contain, so a node (or anything impersonating one) cannot redirect a payment — but it is the difference between one check standing between an attacker and the funds and two. Pin it in production.

Pointer stored as-is (must outlive every call). NULL keeps the CA bundle.

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

Definition at line 195 of file tron_rpc.cpp.

References s_ca_cert.

Referenced by pos_boot().

◆ tx_ctx_from_json()

bool tx_ctx_from_json ( const cJSON * txobj,
tron_tx_ctx_t * out )
static

Take a node-built transaction object apart into a tron_tx_ctx_t.

Shared by both create paths. Proves txID == sha256(raw_data): without it the node could hand us the hash of an unrelated transaction and get it blind-signed by the card, and no amount of checking raw_data would notice, since the signature covers the hash and not the bytes.

The caller still has to check that raw_data pays what it asked for — that check differs per contract type, and it runs on out->raw_hex once this has established that raw_data is the thing being signed.

Parameters
[in]txobjcJSON object carrying txID and raw_data_hex.
[out]outFilled on success.
Returns
true if the object is well-formed and internally consistent.

Definition at line 141 of file tron_rpc.cpp.

References bytes_to_hex(), hex_to_bytes(), RAW_BYTES_MAX, tron_tx_ctx_t::raw_hex, TAG, TRON_RAW_HEX_MAX, tron_tx_ctx_t::txid, and tron_tx_ctx_t::txid_hex.

Referenced by tron_rpc_create_transfer(), and tron_rpc_create_trc20_transfer().

Variable Documentation

◆ s_base_url

const char* s_base_url = NULL
static

Definition at line 44 of file tron_rpc.cpp.

Referenced by tron_post(), and tron_rpc_init().

◆ s_ca_cert

const char* s_ca_cert = NULL
static

Definition at line 45 of file tron_rpc.cpp.

◆ TAG

const char* const TAG = "tron_rpc"
static

Definition at line 34 of file tron_rpc.cpp.