tip-8056.md
July 23, 2026 ยท View on GitHub
tip: 8056
title: Scaled UI Amount Extension for TRC-20 Tokens
description: Equity-token support for stock splits without rebasing raw balances
author: yanghang8612@gmail.com
discussions-to: https://github.com/tronprotocol/tips/issues/904
status: Draft
type: Standards Track
category: TRC
created: 2026-07-10
requires: 20, 165
Simple Summary
Publish a display-only multiplier so stock splits change shown TRC-20 amounts without changing raw balances.
Abstract
This standard adapts ERC-8056 to extend TRC-20 with an issuer-controlled multiplier used only to display token amounts. It lets wallets reflect stock splits without minting, transferring, or rebasing raw balances. Protocol accounting remains in ordinary TRC-20 units.
The core and conversion interfaces remain compatible with ERC-8056. An optional scheduling extension gives wallets and indexers an unambiguous pending-change query and an overwrite audit event.
Motivation
A 2-for-1 stock split should double the number of shares shown to a holder while halving the quoted price per displayed share. Minting to every holder is operationally expensive, and changing balanceOf would break cached balances, liquidity pools, lending positions, and share accounting. A separate UI multiplier preserves raw token economics while allowing opt-in display integration.
Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as described in RFC 2119.
Core Interface
interface IScaledUIAmount {
event UIMultiplierUpdated(
uint256 oldMultiplier,
uint256 newMultiplier,
uint256 effectiveAtTimestamp
);
event TransferWithUIAmount(
address indexed from,
address indexed to,
uint256 amount,
uint256 uiAmount
);
function uiMultiplier() external view returns (uint256);
}
The multiplier has 18 decimal places: 1e18 means no scaling. The transfer event is optional and does not change the interface id. It is a point-in-time display convenience and MUST NOT be used for accounting or historical balance reconstruction.
Pending Multiplier
interface IScaledUIAmountNewUIMultiplier {
function newUIMultiplier() external view returns (uint256);
function effectiveAt() external view returns (uint256);
}
Compliant contracts MUST implement this interface. When block.timestamp >= effectiveAt(), uiMultiplier() MUST return newUIMultiplier().
Optional Conversion and Balance Extensions
interface IScaledUIAmountConversion {
function toUIAmount(uint256 rawAmount) external view returns (uint256);
function fromUIAmount(uint256 uiAmount) external view returns (uint256);
}
interface IScaledUIAmountBalances {
function balanceOfUI(address account) external view returns (uint256);
function totalSupplyUI() external view returns (uint256);
}
Conversions use integer arithmetic:
toUIAmount(raw) = floor(raw * multiplier / 1e18)
fromUIAmount(ui) = floor(ui * 1e18 / multiplier)
These functions are not exact inverses for all inputs. totalSupplyUI() may differ from the sum of individually rounded balanceOfUI() values.
Both formulas are defined over mathematical integers with full-precision multiplication followed by flooring division, equivalent to a 512-bit mulDiv. An implementation MUST NOT revert merely because the intermediate 256-bit product overflows. It MAY revert only when the final quotient is greater than type(uint256).max; fromUIAmount cannot encounter a zero denominator because zero multipliers are forbidden.
Optional Scheduling Discovery Extension
interface IScaledUIAmountScheduled {
event UIMultiplierChangeOverwritten(
uint256 overwrittenMultiplier,
uint256 overwrittenEffectiveAt,
uint256 newMultiplier,
uint256 newEffectiveAt
);
function pendingMultiplier()
external view returns (uint256 multiplier, uint256 effectiveAtTimestamp);
function hasPendingMultiplier() external view returns (bool);
}
hasPendingMultiplier() MUST return true exactly when a scheduled multiplier has not taken effect (effectiveAt() > block.timestamp). pendingMultiplier() MUST return (0, 0) when no pending schedule exists and otherwise return the pending value and time.
Replacing a still-pending schedule MUST emit UIMultiplierChangeOverwritten before or together with the ordinary update event. This extension is a discovery and audit surface only. It does not prove that the pending schedule is locked; that depends on access control, governance, and timelock policy.
Interface Detection
Contracts MUST implement TRC-165 and report support for implemented interfaces:
| Interface | Identifier |
|---|---|
IScaledUIAmount | 0xa60bf13d |
IScaledUIAmountNewUIMultiplier | 0x4bd27648 |
IScaledUIAmountConversion | 0x57854fc3 |
IScaledUIAmountBalances | 0xd890fd71 |
IScaledUIAmountScheduled | 0xeb0093dd |
The scheduling id is pendingMultiplier() selector 0x6fe968a3 XOR hasPendingMultiplier() selector 0x84e9fb7e. Events do not contribute to an interface id.
Raw Amount Preservation
Standard TRC-20 totalSupply, balanceOf, transfer, transferFrom, allowance functions, and Transfer values MUST remain raw and MUST NOT apply the UI multiplier. All state-changing token operations MUST accept and settle raw amounts.
Scaled UI amounts MUST NOT be used for settlement, pricing, collateralization, AMM reserve accounting, share accounting, liquidation, or authorization limits. Such systems MUST use raw amounts and consistently raw-denominated oracle prices.
Scheduling Requirements
How an issuer authorizes updates is implementation-specific. Every implementation MUST:
- reject a zero multiplier;
- emit
UIMultiplierUpdatedwhenever it schedules or replaces a value; - use the same equality boundary in its getter and state-transition logic; and
- implement conversions with the full-precision semantics above.
Before writing any new schedule, the setter MUST evaluate the active multiplier under the old state and persist it as the current multiplier. The new schedule MUST NOT change uiMultiplier() before its own newEffectiveAt, including when replacing a still-pending schedule. The active boundary is block.timestamp >= effectiveAt; both getters and setters MUST use that same >= comparison. These rules prevent a later update, including one in the exact effective block, from temporarily restoring an older multiplier.
Issuers SHOULD use governance or a timelock and SHOULD provide enough notice for wallets, exchanges, indexers, and price feeds to prepare. Integrators MAY apply their own confirmation/finality policy; this standard does not mandate a universal block cooldown.
Reference State Machine
uint256 private constant SCALE = 1e18;
uint256 private _currentMultiplier = SCALE;
uint256 private _nextMultiplier = SCALE;
uint256 private _effectiveAt;
function uiMultiplier() public view returns (uint256) {
return block.timestamp >= _effectiveAt
? _nextMultiplier
: _currentMultiplier;
}
function setUIMultiplier(uint256 next, uint256 when) external onlyOwner {
require(next > 0, "zero multiplier");
require(when > block.timestamp, "not future");
bool pending = _effectiveAt > block.timestamp;
if (block.timestamp >= _effectiveAt) {
_currentMultiplier = _nextMultiplier;
}
if (pending) {
emit UIMultiplierChangeOverwritten(
_nextMultiplier, _effectiveAt, next, when
);
}
uint256 old = _currentMultiplier;
_nextMultiplier = next;
_effectiveAt = when;
emit UIMultiplierUpdated(old, next, when);
}
function hasPendingMultiplier() public view returns (bool) {
return _effectiveAt > block.timestamp;
}
function pendingMultiplier() public view returns (uint256, uint256) {
return hasPendingMultiplier() ? (_nextMultiplier, _effectiveAt) : (0, 0);
}
Production implementations MUST add appropriate access control and full-precision conversion. The example materializes the old schedule before writing the next one and fixes the exact-equality state-transition inconsistency present in early reference code.
Rationale
Not a Rebasing Token
Returning a scaled number from balanceOf would change the accounting meaning of the canonical TRC-20 balance without a transfer. Existing protocols that cache balances or compute share ratios would silently become incorrect. Keeping raw amounts stable is the central compatibility property.
Display Count and Price
For a 2-for-1 split, displayed token count doubles and displayed price per share halves. The price per raw token remains unchanged. Oracles and user interfaces quoting per displayed share must update together; AMMs and protocols accounting in raw units do not migrate.
Fixed-Point and Rounding
An 18-decimal fixed-point integer is deterministic and portable. Flooring is simple but lossy, so conversion helpers are display tools. In particular, fromUIAmount MUST NOT be used to decide how much value to transfer or withdraw.
Scheduling Discovery
The required pending interface contains enough information to derive whether a change is pending, but the optional extension avoids duplicated timestamp logic and makes the no-pending state explicit. Its overwrite event improves auditability without changing the ERC-8056-compatible core.
Backwards Compatibility
This is an opt-in TRC-20 extension. Non-aware protocols continue to see stable raw balances. Aware wallets may display scaled amounts after TRC-165 detection. Because TVM has no privileged token program, adoption by wallets, explorers, exchanges, and price providers is necessary for consistent ecosystem-wide display.
Test Cases
Implementations MUST test:
- initial multiplier
1e18and equality of raw/UI display; - forward and reverse splits;
- exact
block.timestamp == effectiveAtbehavior; - replacement of a pending schedule and overwrite event fields;
(0,0)after a schedule takes effect;- rounding cases where conversions are not inverse;
- full-precision conversion where the intermediate product exceeds 256 bits, plus rejection only when the final quotient exceeds
uint256; and - raw TRC-20 balances, allowances, and transfers remaining unchanged.
Security Considerations
- Multiplier authority can mislead users about holdings. Implementations need robust access control, and UIs SHOULD disclose issuer control and pending updates.
hasPendingMultiplieris not a lock. A mutable schedule can be overwritten unless governance prevents it.- A mutable display parameter invalidates cached displayed balances even when an account has no new transfer. Indexers MUST process schedule events and effective timestamps.
- UI helpers are unsafe for settlement and risk calculations because of mutability and rounding.
- An unbounded multiplier can make conversion views revert. Contracts MUST handle overflow and SHOULD choose documented bounds appropriate to the asset.
- An optional
TransferWithUIAmountvalue is historical, potentially stale under today's multiplier, and costs additional energy. Consumers MUST reconstruct current display values from raw transfers plus multiplier history. - All calls in one block observe one block timestamp. Confirmation policy around the effective boundary is an integration decision, not a substitute for raw-unit accounting.
Copyright
Copyright and related rights waived via CC0.