Dev Note #4: u128/i128 serialization in CosmWasm

Simon Warta
CosmWasm
Published in
2 min readMar 10, 2023

The upgrade to serde-json-wasm version 0.3.2 introduced support for serializing and deserializing the 128 bit integer types u128 and i128. This was implemented using JSON strings. Unfortunately, this decision was not checked against the implementations in serde-json and schemars, which use numbers.

Here is a small example that shows the different serializations:

Which one is the right one?

The decision to use strings instead of numbers can be explained by client support. Not many JSON implementations are compatible with long integers without a loss of precision. This includes JavaScript but also jq:

However, the JSON standard itself allows arbitrary length integers and leaves it up to implementations to worry about supported ranges. Both serde-json and schemars assume those types are encoded as numbers, and this decision makes sense. CosmWasm’s serde-json-wasm strives for full serde-json compatibility in the supported feature set. This allows cosmwasm-vm to use serde-json when communicating with the contract, and we can potentially replace the JSON library in the contracts at some point.

To overcome this limitation, CosmWasm introduced the integer types Uint64, Uint128, Uint256, and Uint512 a long time ago. They all serialize as strings for the best client support for large values.

So overall, 128 bit fields should be numbers.

Serde-json-was 1.0 / CosmWasm 2.0 breaking change

For serde-json-was 1.0 (to be included in CosmWasm 2.0), there is a breaking change scheduled, which turns u128/i128 fields from strings to numbers.

TL;DR, sir

For contract developers, we recommend not using u128/i128 whenever they are JSON seralized. This includes messages (ExecuteMsg, InstantiateMsg, …), query requests and responses, and structs stored to state.

They are discouraged now and will remain discouraged long term. For CosmWasm 1.x, they are incompatible with serde-json and schemars, giving you the wrong JSON Schema, which then gives you the wrong ts-codegen outputs. For CosmWasm 2.x, the u128/i128 will have poor client support. Neither Go nor JavaScript or jq can use the values without loss.

Using Uint64, Uint128, Uint256 and Uint512 as well as u32/i32 or u64/i64 are better alternatives.

Big shout out to Abdullah Eryuzlu, who pointed out that this is a bug in our implementation, not in other libraries!

--

--