catcrafts.net/tests/ShouldParseEurcChains/main.cpp
Jorijn van der Graaf 2a4e2c1c85
All checks were successful
Deploy / build-deploy (push) Successful in 2m32s
crypto fix
2026-08-19 23:55:01 +02:00

142 lines
6.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
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;
}