cryptnox-pos 1.0.0
Standalone USDC payment terminal firmware (ESP32 + Cryptnox smart card)
Loading...
Searching...
No Matches
rpc_error.h
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
21
22#ifndef RPC_ERROR_H
23#define RPC_ERROR_H
24
25#include <stdbool.h>
26#include <stddef.h>
27#include <stdio.h>
28#include <string.h>
29
30#ifdef __cplusplus
31extern "C" {
32#endif
33
35static inline bool rpc_err_contains(const char *hay, const char *needle)
36{
37 if ((hay == NULL) || (needle == NULL) || (needle[0] == '\0')) { return false; }
38 for (size_t i = 0U; hay[i] != '\0'; i++) {
39 size_t j = 0U;
40 while (needle[j] != '\0') {
41 char a = hay[i + j];
42 char b = needle[j];
43 if ((a >= 'A') && (a <= 'Z')) { a = (char)(a + ('a' - 'A')); }
44 if ((b >= 'A') && (b <= 'Z')) { b = (char)(b + ('a' - 'A')); }
45 if (a != b) { break; }
46 j++;
47 }
48 if (needle[j] == '\0') { return true; }
49 }
50 return false;
51}
52
64static inline void rpc_error_text(const char *node_msg, bool native,
65 bool polygon, char *out, size_t n)
66{
67 /* Substring -> what to say instead. Substrings, not equality: the same
68 * condition is worded differently by geth, erigon and bor, and several of
69 * them append the offending numbers to the sentence. */
70 static const struct { const char *needle; const char *say; } MAP[] = {
71 { "nonce too low", "Already submitted - check the explorer" },
72 { "already known", "Already submitted - check the explorer" },
73 { "underpriced", "Fee too low - raise it on Settings > Tx" },
74 { "less than block base fee", "Fee too low - raise it on Settings > Tx" },
75 { "gas price too low", "Fee too low - raise it on Settings > Tx" },
76 { "intrinsic gas too low", "Gas limit too low for this transfer" },
77 { "exceeds block gas limit", "Gas limit too high for this network" },
78 { "gas limit reached", "Network is full - try again in a moment" },
79 };
80
81 if ((out == NULL) || (n == 0U)) { return; }
82
83 if ((node_msg == NULL) || (node_msg[0] == '\0')) {
84 /* No JSON-RPC error object: the request never completed, or the body was
85 * not something we could read. Distinct wording from a refusal, because
86 * the operator's next move is different — this one is worth retrying. */
87 (void)snprintf(out, n, "No answer from the node - try again");
88 return;
89 }
90
91 /* Handled ahead of the table because the right sentence depends on what was
92 * being sent: a token transfer needs gas only, the coin's own transfer needs
93 * the amount too, and saying "not enough ETH" during a USDT sale would send
94 * the operator to top up the wrong thing.
95 *
96 * Three spellings of one condition. geth's is the familiar one; "OutOfFunds"
97 * is what PublicNode's Sepolia endpoint actually returned on 2026-08-31, and
98 * it shares not one word with geth's — which is the argument for matching on
99 * a list of observed strings rather than on what the JSON-RPC spec implies
100 * a node ought to say. */
101 if (rpc_err_contains(node_msg, "insufficient funds") ||
102 rpc_err_contains(node_msg, "insufficient balance") ||
103 rpc_err_contains(node_msg, "outoffunds")) {
104 (void)snprintf(out, n,
105 native ? "Not enough %s for the amount plus gas"
106 : "Not enough %s on the card for gas",
107 polygon ? "POL" : "ETH");
108 return;
109 }
110
111 for (size_t i = 0U; i < (sizeof(MAP) / sizeof(MAP[0])); i++) {
112 if (rpc_err_contains(node_msg, MAP[i].needle)) {
113 (void)snprintf(out, n, "%s", MAP[i].say);
114 return;
115 }
116 }
117
118 /* Not one we have words for. Pass the node's own sentence through, clipped
119 * to the panel: an unfamiliar reason in the node's wording is still a lead,
120 * and this is the line somebody will read out over the phone. */
121 (void)snprintf(out, n, "%s", node_msg);
122}
123
124#ifdef __cplusplus
125}
126#endif
127
128#endif /* RPC_ERROR_H */
static bool rpc_err_contains(const char *hay, const char *needle)
Case-insensitive substring search — node wording varies by client.
Definition rpc_error.h:35
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