CBOR Int finally covers the whole range the spec allows — and everything that was quietly truncating, clamping or panicking at the edges of that range now says so out loud.
Breaking changes
-
CBOR
Intboundary extended to the full RFC 8949 range[-2^64, 2^64 - 1].Int::from_str("-18446744073709551616")(-2^64) now succeeds. As a knock-on:Int::as_negative()returnsNonefor-2^64, whose magnitude2^64does not fit aBigNum. In 15.0.3 it returnedSome(BigNum(0))through a silentas u64cast.BigInt::as_int()returnsSome(Int)for-2^64instead ofNone, including the two-limb[0, 1]representation.
-
Mint::as_positive_multiasset()andMint::as_negative_multiasset()returnResult<MultiAsset, JsError>instead ofMultiAsset.MultiAssetamounts areu64-backed, so-2^64— reachable only through the deliberately permissive CBOR/JSON deserializers — has no representable projection. In 15.0.3 this path hid the problem behind a truncating cast, so a-2^64burn projected to an amount of0; wideningIntturned the same spot into a reachable.unwrap(), i.e. a panic (an unrecoverable abort across the wasm boundary, not a catchableJsError) triggerable by wire data. It now returnsErrnaming the offending policy and amount. The projection is all-or-nothing — no entry is silently dropped, so entry counts between aMintand its projection still match. Callers must add?/.unwrap().TransactionBuilder::get_total_input()andget_total_output()(alreadyResult) can now surface this error.add_mint_asset_and_output()andadd_mint_asset_and_output_min_required_coin()are unaffected in practice —MintAssets::insertrejects out-of-int64amounts before the projection runs. -
MintAssets::insertandMintAssets::new_from_entrynow enforce Conwaymint = {+ policy_id => {+ asset_name => nonzero_int64}}(also matching Maryint64). Any value with|x| > i64::MAXis rejected — that includes-2^64and the previously-tolerated band(i64::MAX, u64::MAX]∪[-u64::MAX, i64::MIN). In 15.0.3 only zero was rejected, so out-of-int64amounts flowed through and produced on-chain-invalid mints. Clamp intoint64before insertion. Deserialization paths (CBOR, serde JSON) are left permissive so callers can apply their own policy. -
CostModel::from(Vec<i128>)replaced withimpl TryFrom<Vec<i128>> for CostModel. Values outside the CBORintrange now returnErr(JsError)instead of producing a silently-malformedInt. Switch call sites toCostModel::try_from(vec![...])?, and bringstd::convert::TryFrominto scope on 2018-edition crates. -
Value::checked_subno longer clamps multiassets. The coin path still errors on underflow. The multiasset path now returnsErr(JsError("underflow"))when an RHS amount exceeds the matching LHS amount, or when the RHS holds a non-zero asset the LHS lacks. UseValue::clamped_sub(backed bySaturatingSub) for the old behaviour. -
Value::is_zero()is now semantic —truewhenever every asset amount is zero. 15.0.3 additionally requiredmultiasset.len() == 0, so aValuecarrying an all-zeroMultiAssetwas not considered zero. -
ValueandMultiAssetarithmetic (checked_add,checked_sub,clamped_sub,MultiAsset::sub) now routes throughnum_traits::{CheckedSub, SaturatingSub}and drops zero asset entries plus policies that become empty; a multiasset that ends up semantically zero is replaced withNoneinValue, including the case where the LHS already carried an all-zeroMultiAssetand the RHS has none. 15.0.3 only dropped entries whenlen()literally hit zero, so any all-zero or empty-but-presentMultiAssetcarried straight through. -
encode_json_value_to_metadatum(BasicConversions): JSON object keys whose integer value falls outside[-2^64, 2^64 - 1]now fall back to string encoding instead of constructing a malformedInt.
Other changes
- Rust ergonomics across numeric wrappers,
Value,MultiAsset,Assets,PlutusDataand the Vec wrappers: additionalFrom/Default/Hash/Eqimpls, iterator traits, builder-style methods,PlutusList::push,impl_btmap_wrapper, and constructor macros —assets!,multi_asset!,plutus_list!,plutus_map!,plutus_bytes!,plutus_constr!. None of this changes the JS/WASM API. Intgains inherentchecked_{add,sub,mul}andsaturating_{add,sub}, plusFrom<i32 / u32 / i64 / u64 / BigNum>,From<&Int> for i128,TryFrom<i128>,DisplayandFromStr. The encoder now picks canonical major-1 headers across the full range, which fixes a debug-build panic oni64::MINand lets values down to-2^64serialize.cbor_eventbumped2.1.3→2.4.0(additive only — new*_szwriter methods and theSzenum; nothing removed, no signature changed).- Fix: post-alonzo
TransactionOutputdeserialization accepts indefinite-length maps (bf … ff). The trailing break byte previously failed withUnexpectedKeyType(Special). Unterminated maps, and maps missing the mandatory amount, still error. - Fix:
from_bech32on hash types no longer panics on a bech32 string with a valid checksum but an invalid base32 payload length (e.g.addr_vkh1q5x4pp8) — it returnsJsError. Previouslyfrom_base32().unwrap()aborted, which is not catchable across the wasm boundary. - Fix: CSL compiles as a Rust dependency on
wasm32-unknown-unknownunderdont-expose-wasm(noop_proc_macrois now reachable on every target). - Fix:
property-test-apiandwith-benchfeature compilation; emptyMultiAssetarithmetic case. - Tests: RFC 8949 / CDDL byte-exact
IntCBOR serialization across every header-size boundary (1 / 2 / 3 / 5 / 9 bytes), positive and negative, includingi64::MINand-2^64; branch coverage for everyBigInt::as_int()match arm. - Build:
wasm-bindgenwidened to">=0.2.93, <0.3". The npm pipeline pins per variant withcargo update --precisebefore each build (asm.js→0.2.93, others →0.2.103) because binaryen'swasm2jsrejects the multi-table modules emitted from0.2.95+. - CI now runs
cargo test --all-features --all-targets.rust/Cargo.lockis committed — this does not affect downstream consumers, since cargo ignores a library dependency's lockfile.
Thanks
Special thanks to @AmbientTea (Nikolaos Dymitriadis), who is behind the bulk of this release. Eleven PRs — #744, #745, #746, #747, #748, #749, #750, #751, #752, #753, #754 — brought the numeric and Value types up to idiomatic Rust: real num_traits arithmetic, the std trait impls that were missing, the constructor macros, and the all-features build fix. Several of the behaviour corrections listed above (checked_sub no longer clamping, semantic is_zero, consistent zero-entry handling) came out of that work — it turned a pile of quiet edge-case surprises into explicit, testable semantics. Thank you for the patience on the review round-trips, and for waiting on the release.
Thanks also to @baima365-web for #759, which removed the panicking unwrap from from_bech32.
Published
https://www.npmjs.com/package/@emurgo/cardano-serialization-lib-browser/v/16.0.0
https://www.npmjs.com/package/@emurgo/cardano-serialization-lib-nodejs/v/16.0.0
https://www.npmjs.com/package/@emurgo/cardano-serialization-lib-asmjs/v/16.0.0
https://crates.io/crates/cardano-serialization-lib/16.0.0
Experimental packages with gc support
https://www.npmjs.com/package/@emurgo/cardano-serialization-lib-nodejs-gc/v/16.0.0
https://www.npmjs.com/package/@emurgo/cardano-serialization-lib-browser-gc/v/16.0.0
https://www.npmjs.com/package/@emurgo/cardano-serialization-lib-asmjs-gc/v/16.0.0
Full Changelog: 15.0.3...16.0.0