176 uint8_t card_pin[CW_MAX_PIN_LENGTH] = {};
179 (void)CW_Utils::safe_memcpy(card_pin,
sizeof(card_pin),
180 reinterpret_cast<const uint8_t *
>(
CARD_PIN),
183 uint8_t calldata[68];
188 ESP_LOGI(
TAG,
"Hold Cryptnox card to reader to sign...");
190 CW_SecureSession session;
191 bool connected = wallet.connect(session);
193 vTaskDelay(pdMS_TO_TICKS(100U));
200 ESP_LOGE(
TAG,
"Failed to get nonce — retrying in 5 s");
201 wallet.disconnect(session);
202 vTaskDelay(pdMS_TO_TICKS(5000U));
221 if (unsigned_len == 0U) {
222 ESP_LOGE(
TAG,
"RLP encode unsigned overflow");
223 wallet.disconnect(session);
224 vTaskDelay(pdMS_TO_TICKS(2000U));
228 uint8_t hash[CW_HASH_SIZE];
229 keccak256(unsigned_tx, unsigned_len, hash);
231 ESP_LOGI(
TAG,
"Hash to sign:");
232 ESP_LOG_BUFFER_HEX_LEVEL(
TAG, hash, CW_HASH_SIZE, ESP_LOG_INFO);
237 static const uint8_t eth_path[20] = {
238 0x80U, 0x00U, 0x00U, 0x2CU,
239 0x80U, 0x00U, 0x00U, 0x3CU,
240 0x80U, 0x00U, 0x00U, 0x00U,
241 0x00U, 0x00U, 0x00U, 0x00U,
242 0x00U, 0x00U, 0x00U, 0x00U,
245 CW_SignRequest req(session,
247 CW_SIGN_SIG_ECDSA_LOW_S,
250 req.hashLength =
static_cast<uint8_t
>(CW_HASH_SIZE);
251 req.derivePath = eth_path;
252 req.derivePathLength =
static_cast<uint8_t
>(
sizeof(eth_path));
253 (void)CW_Utils::safe_memcpy(req.pin,
sizeof(req.pin),
254 card_pin, CW_MAX_PIN_LENGTH);
256 CW_SignResult result = wallet.sign(req);
257 wallet.disconnect(session);
259 if (result.errorCode != CW_OK) {
260 ESP_LOGE(
TAG,
"Sign failed: 0x%02X",
261 static_cast<unsigned int>(result.errorCode));
262 vTaskDelay(pdMS_TO_TICKS(2000U));
266 uint8_t sig_r[CW_HASH_SIZE];
267 uint8_t sig_s[CW_HASH_SIZE];
268 (void)CW_Utils::safe_memcpy(sig_r,
sizeof(sig_r),
269 result.signature + CW_SIG_R_OFFSET, CW_HASH_SIZE);
270 (void)CW_Utils::safe_memcpy(sig_s,
sizeof(sig_s),
271 result.signature + CW_SIG_S_OFFSET, CW_HASH_SIZE);
274 ESP_LOG_BUFFER_HEX_LEVEL(
TAG, sig_r, CW_HASH_SIZE, ESP_LOG_INFO);
276 ESP_LOG_BUFFER_HEX_LEVEL(
TAG, sig_s, CW_HASH_SIZE, ESP_LOG_INFO);
280 ESP_LOGI(
TAG,
"v = %u",
static_cast<unsigned int>(v));
285 signed_tx,
sizeof(signed_tx));
286 if (signed_len == 0U) {
287 ESP_LOGE(
TAG,
"RLP encode signed overflow");
288 vTaskDelay(pdMS_TO_TICKS(2000U));
292 ESP_LOGI(
TAG,
"Signed tx (%u bytes):", (
unsigned int)signed_len);
293 ESP_LOG_BUFFER_HEX_LEVEL(
TAG, signed_tx, signed_len, ESP_LOG_INFO);
296 char tx_hash[68] = { 0 };
298 tx_hash,
sizeof(tx_hash))) {
299 ESP_LOGI(
TAG,
"TX broadcast OK: %s", tx_hash);
301 ESP_LOGE(
TAG,
"TX broadcast failed");
305 vTaskDelay(pdMS_TO_TICKS(15000U));
322 esp_err_t nvs_ret = nvs_flash_init();
323 if ((nvs_ret == ESP_ERR_NVS_NO_FREE_PAGES) ||
324 (nvs_ret == ESP_ERR_NVS_NEW_VERSION_FOUND)) {
325 ESP_ERROR_CHECK(nvs_flash_erase());
326 nvs_ret = nvs_flash_init();
328 ESP_ERROR_CHECK(nvs_ret);
334 spi_bus_config_t buscfg = {};
341 ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
359 esp_err_t nfc_ret =
pn532_init(&nfc, &nfc_cfg);
360 if (nfc_ret != ESP_OK) {
361 ESP_LOGE(
TAG,
"PN532 init failed");
367 (void)logger.
begin(115200UL);
372 CryptnoxWallet wallet(nfcTransport, logger, cryptoProvider, platform);
374 if (!wallet.begin()) {
375 ESP_LOGE(
TAG,
"Wallet begin (SAMConfig) failed");
382#if defined(RPC_PROJECT_ID) && defined(RPC_API_SECRET)
387 ESP_LOGE(
TAG,
"WiFi connect failed — check config.h credentials");
391 ESP_LOGI(
TAG,
"Ready — will sign USDC transfer each card tap");
void app_main(void)
ESP-IDF application entry point.
#define SPI_MAX_TRANSFER_SZ
static const uint8_t TRANSFER_SELECTOR[4]
static void signing_loop(CryptnoxWallet &wallet)
Main application loop: sign and broadcast a USDC transfer each card tap.
static void build_usdc_calldata(uint8_t out[68], const char *to_hex, uint64_t amount)
Build the 68-byte ABI-encoded calldata for a USDC transfer call.
static void parse_address(const char *hex, uint8_t out[20])
Parse a hex string into a 20-byte Ethereum address.