Floating point errors when decoding Cadence numbers larger than 32 bits
See original GitHub issueThe JSON-Cadence Data Interchange Format spec states:
Although JSON supports integer literals up to 64 bits, all integer types are encoded as strings for consistency.
FCL decodes all numeric types as to a number:
const decodeNumber = async (num, _, stack) => {
try {
return Number(num)
} catch (e) {
throw new Error(`Decode Number Error : ${stack.join(".")}`)
}
}
This causes floating point errors for numbers larger than 32 bits (the @onflow/decode library is used in the example below since it exposes the underlying decode method, but the same issue exists in the @onflow/fcl implementation):
import { decode } from '@onflow/decode'
const encoded = {
"type": "UInt64",
"value": "18446744073709551615"
}
const decoded = await decode(encoded)
console.log(decoded)
// Output is 18446744073709552000 instead of the expected value
I’m happy to submit a PR, but hoping for discussion on the preferred solution since I can’t think of a way to do this without breaking backward compatibility. My initial thought is to leave numeric values as a string when decoded and let the user handle this however they’d like in their userspace code, but this does put the responsibility on the user to know about this issue and implement a solution. Another option would be to wrap all numeric types as an object that properly handles large values.
Issue Analytics
- State:
- Created 2 years ago
- Comments:10 (5 by maintainers)

Top Related StackOverflow Question
I believe a safe solution to this issue would be to do the following:
–
The default decoders for
[U]Int*andWord*types should, if the value being decoded represents a number that exceeds Number.MAX_SAFE_INTEGER, emit a console error explaining how a Custom Decoder should be specified to safely handle these values:The error might look like:
This solution allows users to make use of whichever tool they desire to handle large numbers. By emitting a console error, we also inform the user that there is an issue, and of how to remedy the issue. Importantly, it allows us to avoid changing the return types of the existing decoders, or worse, have multiple return types.
–
When declaring an argument of type
[U]Int*orWord*, we should open them up to allow strings as arguments, along with numbers.eg:
or
JSON-CDC specifies the values of
[U]Int*orWord*types as strings https://docs.onflow.org/cadence/json-cadence-spec/#integers. The types declared in @onflow/types should be updated to directly use the argument value if it is a string, or if it is a number, convert it to a string.Libraries like
BigNumberandBigInthave functionality to convert their values to strings. For example, if a user wants to specify theirBigIntvalue as an argument to a script, they can easily convert it to string:–
Do you believe these proposals would adequately solve this issue? @chriswayoub @bluesign @chasefleming
@bluesign I agree, maybe I will create custom encoders as a separate enhancement request and submit a PR there if the team is open to that.