May 09, 2-3 PM (12)
May 09, 3-4 PM (14)
May 09, 4-5 PM (7)
May 09, 5-6 PM (0)
May 09, 6-7 PM (2)
May 09, 7-8 PM (3)
May 09, 8-9 PM (1)
May 09, 9-10 PM (8)
May 09, 10-11 PM (33)
May 09, 11-12 AM (16)
May 10, 12-1 AM (15)
May 10, 1-2 AM (0)
May 10, 2-3 AM (0)
May 10, 3-4 AM (5)
May 10, 4-5 AM (0)
May 10, 5-6 AM (4)
May 10, 6-7 AM (0)
May 10, 7-8 AM (17)
May 10, 8-9 AM (8)
May 10, 9-10 AM (1)
May 10, 10-11 AM (26)
May 10, 11-12 PM (4)
May 10, 12-1 PM (49)
May 10, 1-2 PM (18)
May 10, 2-3 PM (8)
May 10, 3-4 PM (15)
May 10, 4-5 PM (26)
May 10, 5-6 PM (11)
May 10, 6-7 PM (7)
May 10, 7-8 PM (23)
May 10, 8-9 PM (12)
May 10, 9-10 PM (10)
May 10, 10-11 PM (29)
May 10, 11-12 AM (19)
May 11, 12-1 AM (12)
May 11, 1-2 AM (5)
May 11, 2-3 AM (5)
May 11, 3-4 AM (7)
May 11, 4-5 AM (3)
May 11, 5-6 AM (12)
May 11, 6-7 AM (28)
May 11, 7-8 AM (60)
May 11, 8-9 AM (34)
May 11, 9-10 AM (77)
May 11, 10-11 AM (58)
May 11, 11-12 PM (78)
May 11, 12-1 PM (84)
May 11, 1-2 PM (102)
May 11, 2-3 PM (41)
May 11, 3-4 PM (27)
May 11, 4-5 PM (24)
May 11, 5-6 PM (26)
May 11, 6-7 PM (42)
May 11, 7-8 PM (53)
May 11, 8-9 PM (57)
May 11, 9-10 PM (22)
May 11, 10-11 PM (49)
May 11, 11-12 AM (19)
May 12, 12-1 AM (2)
May 12, 1-2 AM (2)
May 12, 2-3 AM (3)
May 12, 3-4 AM (4)
May 12, 4-5 AM (8)
May 12, 5-6 AM (11)
May 12, 6-7 AM (17)
May 12, 7-8 AM (25)
May 12, 8-9 AM (26)
May 12, 9-10 AM (35)
May 12, 10-11 AM (82)
May 12, 11-12 PM (98)
May 12, 12-1 PM (38)
May 12, 1-2 PM (69)
May 12, 2-3 PM (54)
May 12, 3-4 PM (41)
May 12, 4-5 PM (57)
May 12, 5-6 PM (40)
May 12, 6-7 PM (24)
May 12, 7-8 PM (24)
May 12, 8-9 PM (18)
May 12, 9-10 PM (8)
May 12, 10-11 PM (40)
May 12, 11-12 AM (19)
May 13, 12-1 AM (10)
May 13, 1-2 AM (2)
May 13, 2-3 AM (4)
May 13, 3-4 AM (2)
May 13, 4-5 AM (5)
May 13, 5-6 AM (29)
May 13, 6-7 AM (52)
May 13, 7-8 AM (43)
May 13, 8-9 AM (44)
May 13, 9-10 AM (21)
May 13, 10-11 AM (22)
May 13, 11-12 PM (47)
May 13, 12-1 PM (25)
May 13, 1-2 PM (44)
May 13, 2-3 PM (57)
May 13, 3-4 PM (42)
May 13, 4-5 PM (33)
May 13, 5-6 PM (30)
May 13, 6-7 PM (51)
May 13, 7-8 PM (31)
May 13, 8-9 PM (9)
May 13, 9-10 PM (24)
May 13, 10-11 PM (29)
May 13, 11-12 AM (11)
May 14, 12-1 AM (18)
May 14, 1-2 AM (3)
May 14, 2-3 AM (4)
May 14, 3-4 AM (21)
May 14, 4-5 AM (11)
May 14, 5-6 AM (18)
May 14, 6-7 AM (18)
May 14, 7-8 AM (47)
May 14, 8-9 AM (53)
May 14, 9-10 AM (35)
May 14, 10-11 AM (20)
May 14, 11-12 PM (114)
May 14, 12-1 PM (54)
May 14, 1-2 PM (151)
May 14, 2-3 PM (32)
May 14, 3-4 PM (17)
May 14, 4-5 PM (14)
May 14, 5-6 PM (37)
May 14, 6-7 PM (12)
May 14, 7-8 PM (22)
May 14, 8-9 PM (36)
May 14, 9-10 PM (35)
May 14, 10-11 PM (27)
May 14, 11-12 AM (14)
May 15, 12-1 AM (18)
May 15, 1-2 AM (15)
May 15, 2-3 AM (5)
May 15, 3-4 AM (3)
May 15, 4-5 AM (13)
May 15, 5-6 AM (14)
May 15, 6-7 AM (10)
May 15, 7-8 AM (31)
May 15, 8-9 AM (23)
May 15, 9-10 AM (52)
May 15, 10-11 AM (71)
May 15, 11-12 PM (69)
May 15, 12-1 PM (73)
May 15, 1-2 PM (73)
May 15, 2-3 PM (66)
May 15, 3-4 PM (26)
May 15, 4-5 PM (12)
May 15, 5-6 PM (30)
May 15, 6-7 PM (29)
May 15, 7-8 PM (25)
May 15, 8-9 PM (8)
May 15, 9-10 PM (34)
May 15, 10-11 PM (34)
May 15, 11-12 AM (25)
May 16, 12-1 AM (2)
May 16, 1-2 AM (2)
May 16, 2-3 AM (3)
May 16, 3-4 AM (3)
May 16, 4-5 AM (0)
May 16, 5-6 AM (6)
May 16, 6-7 AM (2)
May 16, 7-8 AM (7)
May 16, 8-9 AM (1)
May 16, 9-10 AM (2)
May 16, 10-11 AM (1)
May 16, 11-12 PM (13)
May 16, 12-1 PM (11)
May 16, 1-2 PM (8)
May 16, 2-3 PM (1)
4,373 commits this week May 09, 2026 - May 16, 2026
fix: decode BigUInt values that fit in u64; strengthen wire-compat tests
Three improvements from PR review:

1. **BigUInt → u64 when it fits** (`convert.rs::unwrap_u64`). Previously
   any `BigUInt` variant unconditionally produced `ConvertError::Overflow`,
   even for values well within u64 range. u5c is free to encode positive
   values as `BigUInt(bytes)` instead of `Int(i64)` regardless of size,
   so the strict behavior halted workers on legitimate data. The
   converter now decodes BigUInt's big-endian byte representation
   (trimming leading zeros) and returns `Overflow` only when the value
   truly exceeds u64::MAX. Negative values and `BigNInt` still halt.

2. **Datum payload assertion** in
   `balius-core/tests/u5c_v017_wire_compat.rs::wire_compat_tx_output_roundtrips_via_017`.
   The test constructed a `BoundedBytes` payload but never asserted it
   after decode — a regression where hash/CBOR survive but payload
   mapping drifts would have gone undetected.

3. **Datum & WitnessSet roundtrip coverage** in
   `balius-runtime::ledgers::u5c::convert::tests`. The `roundtrip_opt`
   helper assumes Datum and WitnessSet share an identical wire format
   between utxorpc-spec 0.17 and 0.18 — a load-bearing assumption that
   was exercised only with `None` inputs. Two new tests round-trip
   populated values (datum with a BoundedBytes payload, witness set
   with both a VKey witness and a plutus datum) through `convert_tx_output`
   / `convert_tx` and decode under 0.17 prost. If 0.18 ever diverges on
   these types the test will catch it at CI time instead of as a silent
   decode error in production.

Tests: balius-runtime --lib goes 8 → 13 (3 BigUInt + 2 roundtrip);
balius-core unchanged at 4; e2e::faucet_claim still passes.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
refactor: promote PParams shape into balius-core, slim runtime converter
The PParams wire shape — pbjson conventions from utxorpc-spec 0.17 —
deserved the same architectural treatment as Tx/UTxO: defined once in
balius-core, asserted with a wire-compat invariant test that proves
"what we emit, 0.17 decodes," and consumed unchanged on the runtime
and SDK sides.

Before: the shape lived implicitly inside a 100-line imperative JSON
builder in `balius-runtime::ledgers::u5c::convert::pparams_to_legacy_json`
that hand-assembled `serde_json::Value` to match pbjson. The SDK had a
parallel minimal PParams struct just for `coins_per_utxo_byte`. Two
mostly-implicit places to keep in sync; nothing in balius-core actually
owned the contract.

After:
 - `balius_core::proto::v0::cardano::PParams` + 7 nested types
   (RationalNumber, ProtocolVersion, ExUnits, ExPrices, CostModel,
   CostModels, VotingThresholds) own the wire shape via serde +
   serde_with derives: camelCase keys, u64 as JSON strings via
   DisplayFromStr, u32 as plain numbers, default-zero / None fields
   skip serialization. One source of truth.
 - The runtime converter shrinks to a flat `convert_pparams` that
   flattens upstream BigInts via `unwrap_u64` and field-copies into a
   `balius_core::proto::v0::cardano::PParams`. serde_json::to_vec on
   the typed value produces the wire bytes — no imperative JSON
   assembly. ~140 lines removed from convert.rs.
 - balius-sdk drops its inline PParams in favor of
   `pub use balius_core::proto::v0::cardano::PParams`.
 - balius-core/tests/u5c_v017_wire_compat.rs (renamed from
   wire_compat.rs for clarity) gains
   `wire_compat_pparams_roundtrips_via_017` mirroring the TxOutput
   test: build a balius-core PParams, serialize, decode under
   utxorpc-spec 0.17 pbjson, assert every field. Plus
   `wire_compat_pparams_omits_default_fields` for the skip-default
   invariant.
 - Runtime keeps `convert_pparams_decodes_under_017_pbjson` and
   `convert_pparams_overflow_propagates` — they cover the
   upstream-side BigInt seam (balius-core can't, no upstream dep).
   The now-redundant `convert_pparams_omits_default_fields` is dropped.

balius-core gains serde + serde_with as deps and serde_json as a dev-dep.

Verified: cargo check --workspace --tests clean; balius-core 4/4 (incl.
the two new PParams tests); balius-runtime --lib 8/8; e2e::faucet_claim
1/1 (full end-to-end through mock ledger). u5c-chainsync::wallet_balance
remains the pre-existing stale-wasm failure.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>