/* 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. It must not wrap to negative, and it must not // saturate to INT64_MAX either: a saturated maximum satisfies the covering // comparison in CheckPaid, so a node answering 0xffff…ff would mark any // order paid. int64 base units is already past EURC's entire supply, so an // unrepresentable balance is a broken or lying node — "unknown", which // neither settles nor lapses. Check(!ParseEthCallUint(R"({"result":"0x8000000000000000"})").has_value(), "eurc: an unrepresentable balance is unknown, not a covering maximum"); Check(!ParseEthCallUint( R"({"result":"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"})") .has_value(), "eurc: a lying node's 2^256-1 does not read as paid"); 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"); // Two chains with one name would share a connection-map slot, so the // second's requests would go to the first's host and one chain would never // be watched at all. Check(!Server::ParseEurcChains(R"({"chains":[ {"name":"base","rpc":"https://a.example", "contract":"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"}, {"name":"base","rpc":"https://b.example", "contract":"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c"}]})").has_value(), "eurc: duplicate chain names reject the whole file"); // 18 decimals is legal ERC-20 but not representable here: cents × 10^16 // overflows int64 above €9.22, and the overflow answers "unknown", which // neither settles nor lapses an order. Check(!Server::ParseEurcChains(R"({"chains":[ {"name":"base","rpc":"https://a.example","decimals":18, "contract":"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"}]})").has_value(), "eurc: decimals beyond what the arithmetic carries is refused"); // block_tag reaches the eth_call params array. A quote in it closed the // JSON string and appended another param; a typo silenced the chain. Check(!Server::ParseEurcChains(R"({"chains":[ {"name":"base","rpc":"https://a.example","block_tag":"latest\",\"0xdead", "contract":"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"}]})").has_value(), "eurc: a block_tag that injects JSON is refused"); Check(!Server::ParseEurcChains(R"({"chains":[ {"name":"base","rpc":"https://a.example","block_tag":"finalised", "contract":"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"}]})").has_value(), "eurc: a misspelled block_tag is refused, not silently never-settling"); Check(!Server::ParseEurcChains(R"({"chains":[ {"name":"base","rpc":"https://a.example","block_tag":"", "contract":"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"}]})").has_value(), "eurc: an empty block_tag is refused"); { // A specific block number stays legitimate. const auto ok = Server::ParseEurcChains(R"({"chains":[ {"name":"base","rpc":"https://a.example","block_tag":"0x1b4", "contract":"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"}]})"); Check(ok.has_value() && (*ok)[0].blockTag == "0x1b4", "eurc: a hex block number is still accepted"); } if (failures != 0) { std::println(std::cerr, "{} check(s) failed", failures); return 1; } return 0; }