Skip to content

Neo Account-State Based Virtual Decimals (Opt-in "Decimal Mode") #4529

Description

@shargon

This proposal introduces an opt-in state for Neo N3 addresses to interact with NEP-17 tokens using human-readable decimal values instead of raw integers. By calling a new enableDecimals() method, an account flags itself to send and receive values scaled by the token's factor. This ensures full backward compatibility while allowing modern UIs to ignore raw integer calculations.

While the data parameter approach (#4528) works per transaction, it requires Dapps to constantly manage strings. A state-based approach allows a user to "set and forget." Once an account is in Decimal Mode, all interactions with that specific token contract automatically adjust to the correct scale, making integration with non-blockchain systems much simpler.

New Method: enableDecimals(UInt160 account, bool toggle)

​Users (or smart contracts) call this method to flip a bit in the contract's storage associated with their UInt160 address.

  • ​When true: The contract treats input/output values for that address as scaled decimals.
  • ​When false (Default): The contract behaves as a standard NEP-17 (integer-based).

New Method: decimalsOf(account)

​A mapping that returns the current decimal precision active for a specific account.

  • ​If the account is in standard mode, it returns 0.
  • ​If in Decimal Mode, it returns the token's defined decimals (e.g., 8).
  • ​This allows explorers and wallets to know exactly how to render the balance for that specific user.

Updated balanceOf(account)

​The method logic changes internally:

if (Storage_AccountSettings.Get(account).UseDecimals) {
    return rawBalance / Math.Pow(10, TokenDecimals);
}
return rawBalance;

Updated transfer(from, to, amount, data)

​To prevent "Type Mismatch" errors (where one person sends 1.5 tokens but the receiver expects integers), the transfer logic adds a safety check:

  • ​Scaling: If from has decimals enabled, amount is multiplied by the factor before processing.
  • ​Compatibility Check: The contract verifies if to is also decimal-enabled. If not, the contract can either:
    • ​Automatically convert to integer for the receiver.
    • ​(Optional) Revert if strict decimal-to-decimal consistency is required.

Rationale & Backward Compatibility

  • ​Exchanges & Custodians: Since all accounts default to enableDecimals = false, existing infrastructure (Binance, OKX, etc.) remains completely unaffected. They see and move integers as they always have.
  • ​Safety: The decimalsOf(account) method acts as a discovery mechanism for Wallets. A wallet can query this method to decide whether to show a "0.00000001" or "1" on the screen automatically.
  • Simplified Dapp Logic: Frontend developers no longer need to import BigNumber libraries to divide by 10^8 for every UI element; the contract provides the "ready-to-read" number.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    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