eth/eth_watch_cli.hpp¶
Namespaces¶
| Name |
|---|
| eth |
| eth::cli |
Classes¶
| Name | |
|---|---|
| struct | eth::cli::WatchSpec One watch subscription specified on the command line. |
| class | eth::cli::EventRegistry Registry mapping event signatures to their ABI parameter descriptors. |
Functions¶
| Name | |
|---|---|
| std::optional< uint8_t > | hex_nibble(char c) Parse a hex nibble character. Returns nullopt for invalid chars. |
| template <size_t N> bool |
parse_hex_array(std::string_view hex, std::array< uint8_t, N > & out) Parse a hex string into a fixed-size byte array. |
| std::optional< codec::Address > | parse_address(std::string_view hex) Parse a 0x-prefixed or bare 40-hex-char Ethereum address. |
| EventRegistry & | event_registry() Process-wide singleton registry, pre-populated with well-known events. |
| std::vector< abi::AbiParam > | infer_params(const std::string & sig) Convenience wrapper: look up sig in the global registry. Replaces the old infer_params() free function. |
Functions Documentation¶
function hex_nibble¶
Parse a hex nibble character. Returns nullopt for invalid chars.
function parse_hex_array¶
Parse a hex string into a fixed-size byte array.
Parameters:
- hex Must be exactly N*2 hex characters (no 0x prefix).
function parse_address¶
Parse a 0x-prefixed or bare 40-hex-char Ethereum address.
Return: Parsed address or nullopt if the format is invalid.
function event_registry¶
Process-wide singleton registry, pre-populated with well-known events.
The registry is initialised on first access. All registrations persist for the lifetime of the process, so call register_event() once at startup before creating any watchers.
function infer_params¶
Convenience wrapper: look up sig in the global registry. Replaces the old infer_params() free function.
Source code¶
// Copyright 2025 GeniusVentures
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <eth/abi_decoder.hpp>
#include <array>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
namespace eth::cli {
struct WatchSpec
{
std::string contract_hex;
std::string event_signature;
};
[[nodiscard]] inline std::optional<uint8_t> hex_nibble(char c) noexcept
{
if (c >= '0' && c <= '9') { return static_cast<uint8_t>(c - '0'); }
if (c >= 'a' && c <= 'f') { return static_cast<uint8_t>(10 + (c - 'a')); }
if (c >= 'A' && c <= 'F') { return static_cast<uint8_t>(10 + (c - 'A')); }
return std::nullopt;
}
template <size_t N>
[[nodiscard]] bool parse_hex_array(std::string_view hex, std::array<uint8_t, N>& out) noexcept
{
if (hex.size() != N * 2) { return false; }
for (size_t i = 0; i < N; ++i)
{
auto hi = hex_nibble(hex[i * 2]);
auto lo = hex_nibble(hex[i * 2 + 1]);
if (!hi || !lo) { return false; }
out[i] = static_cast<uint8_t>((*hi << 4) | *lo);
}
return true;
}
[[nodiscard]] inline std::optional<codec::Address> parse_address(std::string_view hex) noexcept
{
if (hex.size() >= 2 && hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X'))
{
hex = hex.substr(2);
}
codec::Address addr{};
if (!parse_hex_array(hex, addr)) { return std::nullopt; }
return addr;
}
// ---------------------------------------------------------------------------
// Known-event registry
// ---------------------------------------------------------------------------
class EventRegistry
{
public:
void register_event(std::string sig, std::vector<abi::AbiParam> params)
{
map_[std::move(sig)] = std::move(params);
}
[[nodiscard]] const std::vector<abi::AbiParam>* lookup(const std::string& sig) const noexcept
{
auto it = map_.find(sig);
return (it != map_.end()) ? &it->second : nullptr;
}
[[nodiscard]] std::vector<abi::AbiParam> params_for(const std::string& sig) const
{
if (const auto* p = lookup(sig)) { return *p; }
return {};
}
private:
std::unordered_map<std::string, std::vector<abi::AbiParam>> map_;
};
inline EventRegistry& event_registry()
{
static EventRegistry reg = []()
{
EventRegistry r;
// ── ERC-20 ────────────────────────────────────────────────────────────
r.register_event("Transfer(address,address,uint256)", {
{abi::AbiParamKind::kAddress, true, "from"},
{abi::AbiParamKind::kAddress, true, "to"},
{abi::AbiParamKind::kUint, false, "value"},
});
r.register_event("Approval(address,address,uint256)", {
{abi::AbiParamKind::kAddress, true, "owner"},
{abi::AbiParamKind::kAddress, true, "spender"},
{abi::AbiParamKind::kUint, false, "value"},
});
// ── ERC-721 ───────────────────────────────────────────────────────────
// Note: Transfer(address,address,uint256) is the same signature as ERC-20.
// The third param is indexed `tokenId` in ERC-721 vs non-indexed `value`
// in ERC-20. Register it separately under a distinct key so callers can
// opt in explicitly; the ERC-20 entry above is the default.
r.register_event("Transfer(address,address,uint256 indexed)", {
{abi::AbiParamKind::kAddress, true, "from"},
{abi::AbiParamKind::kAddress, true, "to"},
{abi::AbiParamKind::kUint, true, "tokenId"},
});
r.register_event("ApprovalForAll(address,address,bool)", {
{abi::AbiParamKind::kAddress, true, "owner"},
{abi::AbiParamKind::kAddress, true, "operator"},
{abi::AbiParamKind::kBool, false, "approved"},
});
// ── ERC-1155 ──────────────────────────────────────────────────────────
r.register_event("TransferSingle(address,address,address,uint256,uint256)", {
{abi::AbiParamKind::kAddress, true, "operator"},
{abi::AbiParamKind::kAddress, true, "from"},
{abi::AbiParamKind::kAddress, true, "to"},
{abi::AbiParamKind::kUint, false, "id"},
{abi::AbiParamKind::kUint, false, "value"},
});
r.register_event("TransferBatch(address,address,address,uint256[],uint256[])", {
{abi::AbiParamKind::kAddress, true, "operator"},
{abi::AbiParamKind::kAddress, true, "from"},
{abi::AbiParamKind::kAddress, true, "to"},
// uint256[] arrays decoded as raw bytes32 until dynamic array support is added
{abi::AbiParamKind::kBytes32, false, "ids"},
{abi::AbiParamKind::kBytes32, false, "values"},
});
// ── GNUS Bridge (GNUSBridge.sol) ──────────────────────────────────────
// event BridgeSourceBurned(address indexed sender, uint256 id, uint256 amount,
// uint256 srcChainID, uint256 destChainID)
r.register_event("BridgeSourceBurned(address,uint256,uint256,uint256,uint256)", {
{abi::AbiParamKind::kAddress, true, "sender"},
{abi::AbiParamKind::kUint, false, "id"},
{abi::AbiParamKind::kUint, false, "amount"},
{abi::AbiParamKind::kUint, false, "srcChainID"},
{abi::AbiParamKind::kUint, false, "destChainID"},
});
return r;
}();
return reg;
}
[[nodiscard]] inline std::vector<abi::AbiParam> infer_params(const std::string& sig)
{
return event_registry().params_for(sig);
}
} // namespace eth::cli
Updated on 2026-04-13 at 23:22:46 -0700