Skip to content

Widen NonNegativeNumber / MakeMint to BigInt so token vaults can hold > 2^63−1 #511

Description

@a-k-l-sdao

We want the asi coin/token on asi chain match the 18 decimals of the token on ethereum, but currently our node is set to use only 64 bit, where 256 bit is the standard on ethereum.
I used claude to investigate and produce the text below trying to be as exact as possible with paths to the relevant files.

Why Int is hard-capped at 2^63−1

Rholang Int is sint64 by grammar + normalizer, not convention:

  • rholang/src/main/bnfc/rholang_mercury.cf:5position token LongLiteral digit+; (literal token literally named Long).
  • rholang/src/main/bnfc/rholang_mercury.cf:168,196GroundInt ::= LongLiteral; SimpleType ::= "Int" (reserved keyword).
  • rholang/.../normalizer/GroundNormalizeMatcher.scala:24gi.longliteral_.toLong → JVM Long.parseLong. Any literal > 9_223_372_036_854_775_807 throws NumberFormatExceptionNormalizerError at compile time.
  • models/.../protobuf/RhoTypes.proto:196sint64 g_int = 2; (wire format).
  • Separate ground type exists: g_big_int = 35 (BigInt, arbitrary precision, literal suffix I). Different type — match Int will not match a BigInt.

Problem

System vault pinned to Int:

  • casper/src/main/resources/NonNegativeNumber.rho:53match init { Int => ... } rejects BigInt.
  • casper/src/main/resources/NonNegativeNumber.rho:22 — overflow guard v + x >= v assume i64 wrap; meaningless on BigInt.
  • casper/src/main/resources/MakeMint.rho:25,58,134,154 — forwards init/amount through the same i64 channel; every purse inherits the ceiling.

Hard cap: 9_223_372_036_854_775_807 base units. At 18 decimals → ~9.22 tokens. Bridge work around it with SCALE = 10^10 (ASI 8-dec vs ETH 18-dec, snet/asi-bridge/decimal-scaling.md) — costs precision on dust, needs amount % SCALE == 0 guard on EVM side.

Ask

Accept BigInt in vault so 18-dec / uint256-shaped amounts work without scaling.

Min changes:

  1. NonNegativeNumber.rho:53 — match BigInt (replace or widen Int arm).
  2. NonNegativeNumber.rho:22 — replace i64-wrap check with x >= 0I && v + x >= 0I (BigInt has no wrap, only need non-negativity).
  3. Re-register under new URI — existing rho:id:hxyadh1ffypra47ry9mk6b8r1i33ar1w9wjsez4khfe9huzrfcytx9 sealed (nonce = Long.MaxValue at NonNegativeNumber.rho:64, registry strict > at Registry.rho:602 → no successor possible).
  4. MakeMint.rho — no logic change; point lookup at new URI. Re-register under new URI too.

Acceptance

  • MakeMint!("makePurse", 10^30I, *p) returns purse; getBalance = 10^30I.
  • add / sub round-trip past 2^63−1 without truncation.
  • bridge.rho re-pointed at widened vault, accepts wei directly, SCALE = 10^10 removed.

Open

  1. Rho interpreter BigInt ops on hot path — does + - >= <= and equality vs 0I work end-to-end? Real blocker if not.
  2. Merge/replay on @(*MergeableTag, *valueStore) under multi-parent — identical for BigInt-tagged channels? Deliberate test needed; already lost writes on Long-backed bridge channel under multi-parent fork.
  3. Phlo cost — BigInt add vs Int add on transfer hot path; budgets need re-tune?

Refs

  • casper/src/main/resources/NonNegativeNumber.rho
  • casper/src/main/resources/MakeMint.rho
  • casper/src/main/resources/SystemVault.rho
  • casper/src/main/resources/Registry.rho
  • rholang/src/main/bnfc/rholang_mercury.cf
  • rholang/src/main/scala/coop/rchain/rholang/interpreter/compiler/normalizer/GroundNormalizeMatcher.scala
  • models/src/main/protobuf/RhoTypes.proto

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions