Protocol contract · Non-negotiable

Wallet Invariants

Global invariants for every Unit wallet movement. Send, Deposit, and Withdraw differ by funding source — and the rules differ with them. Display values must never become executable values.

Source of truth
§ 0 · The Global Principle

Percentage controls signal known internal balance

The single rule from which most others follow.

Only flows that spend from a known internal Unit balance may use percentage-based inputs.
SEND spends an internal Unit balance — quick-fill required.
WITHDRAW spends an internal Unit-wrapped balance — quick-fill required.
DEPOSIT is an external inflow — quick-fill forbidden.
Why this is the rule: the existence of percentage controls is a SIGNAL to the user that the system knows their balance. Showing them where the system does not know the balance teaches false behavior, regardless of any "convenience" intent.
§ 1 · Module comparison

Send vs Deposit vs Withdraw at a glance

Same lifecycle shape. Different funding models. Different rules.

Aspect Send Deposit Withdraw Receive Activity Vault
Funding source Internal Unit balance External chain (unknown) Internal wrapped Unit balance External (incoming) Internal vault stake
Asset type Internal Unit asset External native (BTC, ETH, …) Wrapped Unit-native (BTCU, …) External native Internal Unit asset
Quick-fill (25/50/75/Max) Required Forbidden Required N/A N/A Allowed
"Available balance" surface Required Forbidden Required Allowed
Address book / saved address Optional (recipients) Single-use deposit address Required (matching chain) N/A N/A
Optional tx-hash submission No User-facing Operator-only
Forbidden post-submit causes USER_CANCELLED, USER_REJECTED, INSUFFICIENT_BALANCE USER_CANCELLED, USER_REJECTED, BELOW_MINIMUM USER_CANCELLED, USER_REJECTED, INSUFFICIENT_BALANCE USER_CANCELLED, USER_REJECTED
§ 2 · Display ≠ executable

Decimal precision discipline

Four kinds of precision. Never confused. Display rounding is for reading; the executable amount preserves full asset precision.

A

Computational precision

  • Full chain-defined decimals
  • Used for arithmetic + storage
  • Never lossy
B

Validation precision

  • Asset's allowed decimal count
  • Rejects over-precision input
  • Never silently rounds to "valid"
C

Display precision

  • Readability rounding only
  • Output of toFixed / fiat formatter
  • NEVER reused as executable
D

Input precision

  • What the input field accepts
  • Mode-aware (token vs USD)
  • Always normalized to token before validation
Rule: the executable amount sent to chain is computed from the user's typed token quantity, parsed via parseUnits(_, asset.decimals). It is independent of every toFixed() in the codebase.
§ 3 · Asset decimal standard

Per-asset native precision

Asset Native decimals Display
BTCU / BTC8up to 8
ETHU / ETH18 (computational)6–8 significant
BNBU / BNB18 (computational)6–8 significant
SOLU / SOL9up to 9
TONU / TON9up to 9
USDTU / USDT6up to 6
USDCU / USDC6up to 6
$UNITCOINfrom chain configfrom chain config
Fiat (USDU, EURU, …)chain config2 decimals
Other tokens: precision MUST be supplied by token metadata. If precision is unknown, executable submission is blocked — never guessed.
§ 4 · Error safety

No raw backend enums in user UI

Internal rejection reasons stay internal. Users see one safe sentence that tells them what they need to know.

Internal (admin / ops)

Never user-facing

  • UNDERPAID, OVERPAID
  • AMOUNT_MISMATCH
  • WRONG_ASSET, WRONG_NETWORK
  • TX_NOT_FOUND, TX_REUSED
  • DepositNotPending, TxHashAlreadySubmitted
User-facing (safe set)

From userFacingReason

  • "Transaction not found on chain"
  • "Transaction did not match your deposit"
  • "This transaction has already been used"
  • "This deposit is already confirmed."
  • Fallback: "This deposit could not be verified."
Rule: the resolver (rejectionReason, userFacingReason) → string returns ONLY allowed strings. Tests assert that no raw enum identifier appears in user copy.
§ 5 · Universal user contract

What the user must always know

Every Unit wallet UI must continuously expose six facts.

Source of funds — where the value originates.
Destination of funds — where the value lands.
Asset being moved — exact uppercase ticker.
Value being moved — executable, not display-rounded.
Network involved where applicable — exact chain.
Internal vs external — and which side is which.