/* catcrafts.net Copyright (C) 2026 Catcrafts The source code of this website is made available for viewing purposes only. No permission is granted to copy, modify, distribute, or create derivative works. */ // The EURC rail's two parsers. // // The balance decoder is the line between "the buyer paid" and "the node // errored", and the chains parser is the line between "watching a chain" // and "silently not watching it". Both refuse rather than guess. import std; import Catcrafts.Shared; import Catcrafts.Server; using namespace Catcrafts; namespace { int failures = 0; void Check(bool ok, std::string_view what, std::string_view got = {}) { if (ok) return; ++failures; std::println(std::cerr, "FAIL: {}{}{}", what, got.empty() ? "" : " got: ", got); } } // namespace int main() { using Server::ParseEthCallUint; Check(ParseEthCallUint(R"({"jsonrpc":"2.0","id":1,"result":"0x0"})") == 0, "eurc: zero balance"); Check(ParseEthCallUint( R"({"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000000000000000022001230"})") == 570430000, "eurc: €570.43 as 6-decimal base units, full 32-byte word"); Check(ParseEthCallUint(R"({"result":"0xFF"})") == 255, "eurc: uppercase hex accepted"); // 2^63 does not fit; the decoder must saturate, never wrap to negative. Check(ParseEthCallUint(R"({"result":"0x8000000000000000"})") == std::numeric_limits::max(), "eurc: overflow saturates"); Check(!ParseEthCallUint( R"({"jsonrpc":"2.0","id":1,"error":{"code":-32000,"message":"x"}})") .has_value(), "eurc: an RPC error is not a zero balance"); Check(!ParseEthCallUint(R"({"result":"21ff361c"})").has_value(), "eurc: missing 0x rejected"); Check(!ParseEthCallUint(R"({"result":"0x"})").has_value(), "eurc: empty word rejected"); Check(!ParseEthCallUint(R"({"result":42})").has_value(), "eurc: numeric result rejected — the wire type is a hex string"); Check(!ParseEthCallUint("garbage").has_value(), "eurc: malformed payload"); const auto chains = Server::ParseEurcChains(R"({"chains":[ {"name":"base","rpc":"https://mainnet.base.org", "contract":"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42", "chain_id":8453,"note":"lowest fees"}, {"name":"ethereum","rpc":"https://ethereum-rpc.publicnode.com", "contract":"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c","chain_id":1}]})"); Check(chains.has_value() && chains->size() == 2, "eurc: chains file parses"); if (chains && chains->size() == 2) { Check((*chains)[0].name == "base" && (*chains)[0].chainId == 8453, "eurc: file order preserved — first entry is the recommendation"); Check((*chains)[0].contract == "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", "eurc: contract lowercased for comparison"); Check((*chains)[0].note == "lowest fees", "eurc: note carried"); Check((*chains)[1].blockTag == "finalized" && (*chains)[1].decimals == 6, "eurc: defaults"); } Check(!Server::ParseEurcChains(R"({"chains":[ {"name":"base","rpc":"https://x.org","contract":"0xdeadbeef"}]})").has_value(), "eurc: short contract rejects the whole file"); Check(!Server::ParseEurcChains(R"({"chains":[ {"name":"base","rpc":"ftp://x.org", "contract":"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"}]})").has_value(), "eurc: non-http rpc rejects the whole file"); Check(!Server::ParseEurcChains(R"({"chains":[]})").has_value(), "eurc: empty chain list rejected"); Check(!Server::ParseEurcChains("garbage").has_value(), "eurc: malformed chains file rejected"); if (failures != 0) { std::println(std::cerr, "{} check(s) failed", failures); return 1; } return 0; }