diff --git a/docs/base-chain/specs/reference/b20/constants-and-addresses.mdx b/docs/base-chain/specs/reference/b20/constants-and-addresses.mdx
index 65c57caed..8662b650b 100644
--- a/docs/base-chain/specs/reference/b20/constants-and-addresses.mdx
+++ b/docs/base-chain/specs/reference/b20/constants-and-addresses.mdx
@@ -76,6 +76,7 @@ Policy type bytes:
| Minimum Asset decimals | `6` |
| Maximum Asset decimals | `18` |
| Maximum supply cap / no-cap sentinel | `type(uint128).max` |
+| Maximum UI multiplier (`MAX_UI_MULTIPLIER`) | `type(uint128).max` |
| All features paused bitmask | `15` (`TRANSFER | MINT | BURN | SEIZE`) |
## Imports
diff --git a/docs/base-chain/specs/reference/b20/errors-and-events.mdx b/docs/base-chain/specs/reference/b20/errors-and-events.mdx
index d4888150c..055feaa50 100644
--- a/docs/base-chain/specs/reference/b20/errors-and-events.mdx
+++ b/docs/base-chain/specs/reference/b20/errors-and-events.mdx
@@ -50,7 +50,7 @@ description: "Reverse lookup B20 errors and events by selector or topic."
| error | `InvalidCurrency` | `0x997c1de8` | `IB20Factory` | The stablecoin `currency` was non-empty but contained a non-`A`-`Z` byte. |
| error | `InvalidDecimals` | `0xca950391` | `IB20Factory` | The asset `decimals` was outside the allowed inclusive range |
| error | `InvalidMetadataKey` | `0x86ea3abb` | `IB20Asset` | `updateExtraMetadata` was called with an empty `key`. |
-| error | `InvalidMultiplier` | `0x6f12f3dc` | `IB20Asset` | A multiplier setter (`updateUIMultiplier` or `updateMultiplier`) was called with a |
+| error | `InvalidMultiplier` | `0x6f12f3dc` | `IB20Asset` | A multiplier setter (`updateUIMultiplier` or the deprecated `updateMultiplier`) was called with a multiplier of zero or above the `type(uint128).max` overflow guard. |
| error | `InvalidReceiver` | `0x9cfea583` | `IB20` | The transfer's destination address is invalid (typically `address(0)`). |
| error | `InvalidSender` | `0x4c14f64c` | `IB20` | The transfer's source address is invalid (typically `address(0)`). |
| error | `InvalidSigner` | `0x7ba5ffb5` | `IB20` | ECDSA recovery on an EIP-2612 `permit` returned `signer`, which does not match the claimed `owner`. |
@@ -62,8 +62,8 @@ description: "Reverse lookup B20 errors and events by selector or topic."
| error | `LengthMismatch` | `0xab8b67c6` | `IB20Asset` | A batched function was called with parallel arrays of differing lengths. |
| event | `Memo` | `0x6989f5818dcfd11f8cd53b27c94cec33dae1589735f03e639cba54553a1825e8` | `IB20` | Emitted by `transferWithMemo`, `transferFromWithMemo`, `mintWithMemo`, and `burnWithMemo` |
| error | `MissingRequiredField` | `0x4a43ae87` | `IB20Factory` | A required string argument was the empty string. |
-| event | `MultiplierUpdated` | `0x4dbe4840d7465bd162f67814cea0b519567a2e0e578bcde61e7f4ced361e5a3d` | `IB20Asset` | Deprecated multiplier-change event emitted by `updateMultiplier` alongside `UIMultiplierUpdated`. |
-| event | `UIMultiplierUpdateCancelled` | `0x883856335ba5f60c18b9817c4505d3c7d3f6223dcf39516b30c508c46a5e1cad` | `IB20Asset` | A scheduled multiplier update was cancelled. |
+| event | `MultiplierUpdated` | `0x4dbe4840d7465bd162f67814cea0b519567a2e0e578bcde61e7f4ced361e5a3d` | `IB20Asset` | Deprecated multiplier-change event emitted by the instant setter (`updateMultiplier`) alongside `UIMultiplierUpdated` for backward compatibility with indexers on the legacy topic. The scheduled `updateUIMultiplier` emits only `UIMultiplierUpdated`. |
+| event | `UIMultiplierUpdateCancelled` | `0x883856335ba5f60c18b9817c4505d3c7d3f6223dcf39516b30c508c46a5e1cad` | `IB20Asset` | A scheduled multiplier update was cancelled. Emitted by `cancelUIMultiplierUpdate` and by the instant setter when it clears a live pending update. |
| event | `NameUpdated` | `0x74321da206c1b9fa34367f7ece59ca49371dcd13820b9a5c3767ae1ecceed51a` | `IB20` | Emitted by `updateName`. Carries the new name string. |
| error | `NonPayable` | `0x6fb1b0e9` | `IB20` | ETH was attached to a call targeting a nonpayable token selector. |
| error | `NonPayable` | `0x6fb1b0e9` | `IB20Factory` | ETH was attached to a call targeting a nonpayable factory selector. |
@@ -76,25 +76,4 @@ description: "Reverse lookup B20 errors and events by selector or topic."
| event | `PolicyAdminUpdated` | `0x98925cfb1bc09c5b43dd0dd56d3d95aa04fb3300927580cc588c3f5dd58c15e1` | `IPolicyRegistry` | The active admin changed. `newAdmin == address(0)` indicates renunciation; |
| event | `PolicyCreated` | `0xdc870ce85be577234b8548f42b93f84bbff6d0c1f38ee725c809c49932a13885` | `IPolicyRegistry` | A new policy was created. |
| error | `PolicyForbids` | `0xa43fec12` | `IB20` | A policy slot denied the operation. |
-| error | `PolicyNotFound` | `0xcccad523` | `IB20` | The provided policy ID does not exist in the policy registry. |
-| error | `PolicyNotFound` | `0x720caa4f` | `IPolicyRegistry` | The referenced policy ID does not exist. |
-| event | `PolicyUpdated` | `0x8b4790f7ff717fc8f60f07ae099e47ef318dc04b37ae98056b50a22b79056626` | `IB20` | Emitted by `updatePolicy` when a token's policy slot is changed. Initial slot assignment at |
-| event | `RoleAdminChanged` | `0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff` | `IB20` | Emitted by `setRoleAdmin` when the admin role for `role` changes. |
-| event | `RoleGranted` | `0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d` | `IB20` | Emitted when `account` is granted `role`. `sender` is the originating caller. |
-| event | `RoleRevoked` | `0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b` | `IB20` | Emitted when `role` is revoked from `account`. `sender` is the originating caller |
-| error | `UIMultiplierUpdateExists` | `0x4481a68e` | `IB20Asset` | `updateUIMultiplier` was called while a live pending update already exists |
-| event | `Seized` | `0xa9aec5d8b86e2fa2fd6ac3af62f2622e3dfdab1967d4cbbb56a5df7d74cb887c` | `IB20` | Emitted by `seizeWithMemo` in addition to `Transfer(from, to, amount)` (and the |
-| error | `StaticCallNotAllowed` | `0xbeaba5b7` | `IActivationRegistry` | A state-mutating entry point was invoked from a `STATICCALL` frame. |
-| error | `SupplyCapExceeded` | `0x4b344b11` | `IB20` | The mint would push `totalSupply` past the configured cap. |
-| event | `SupplyCapUpdated` | `0x6d14f44808ce024f263432bc38d019a9951fbe674e9898b54844dbc8dc09c23a` | `IB20` | Emitted by `updateSupplyCap`. |
-| event | `SymbolUpdated` | `0x64e8b5c6dcea43dd79766bb3b8af7c45968d12b68c960cf2da23856f34d598d4` | `IB20` | Emitted by `updateSymbol`. Carries the new symbol string. |
-| error | `TokenAlreadyExists` | `0x15ef3a57` | `IB20Factory` | A token already exists at the deterministic address derived from |
-| event | `Transfer` | `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` | `IB20` | ERC-20 transfer event. Emitted on every successful transfer (including memo'd variants), |
-| error | `Unauthorized` | `0x8e4a23d6` | `IActivationRegistry` | Caller is not the activation admin. |
-| error | `Unauthorized` | `0x82b42900` | `IB20` | Caller failed a positional authorization check that is not expressible as "missing role X". |
-| error | `Unauthorized` | `0x82b42900` | `IPolicyRegistry` | Caller is not the admin required by the attempted operation. |
-| event | `UIMultiplierUpdated` | `0x2205df4534432b2f60654a3fdb48737ffdaf3e9edb1a498bd985bc026b15b055` | `IB20Asset` | Emitted when the UI multiplier is updated. |
-| event | `Unpaused` | `0xdc6281474ea3dea2a856e225c7ba3edf427de9164495817c4d49a595e683fed4` | `IB20` | Emitted by `unpause`. `features` is the argument to the call (not the resulting paused state). |
-| error | `UnsupportedPolicyType` | `0xcdd98a4a` | `IB20` | `policyScope` is not a slot this token (or its variant) supports. |
-| error | `UnsupportedVersion` | `0xc0d8b4e0` | `IB20Factory` | The leading `version` byte in `params` does not match any known encoding for the requested variant. |
-| error | `ZeroAddress` | `0xd92e233d` | `IPolicyRegistry` | A required address argument was the zero address. |
+| error | `PolicyNotFound` | `0xcccad523
diff --git a/docs/base-chain/specs/reference/b20/index.mdx b/docs/base-chain/specs/reference/b20/index.mdx
index a76152704..cddc8d09c 100644
--- a/docs/base-chain/specs/reference/b20/index.mdx
+++ b/docs/base-chain/specs/reference/b20/index.mdx
@@ -192,7 +192,9 @@ Asset tokens add `OPERATOR_ROLE`, scaled UI balance support, scheduled and insta
#### Multiplier
-The multiplier is WAD-precision and scales UI balance reads while raw balances remain unchanged.
+The multiplier is WAD-precision and scales UI balance reads while raw balances remain unchanged. `toUIAmount(rawAmount)` / `fromUIAmount(uiAmount)` are the canonical ERC-8056 Conversion extension converters (`0x57854fc3`). The deprecated `toScaledBalance` / `toRawBalance` aliases are retained in `IB20Asset` for backward compatibility. `MAX_UI_MULTIPLIER()` exposes the `type(uint128).max` overflow guard.
+
+Multiplier updates are scheduled with `updateUIMultiplier(newMultiplier, effectiveAt)`. Only one pending update may exist at a time; a second call reverts `UIMultiplierUpdateExists`. Cancel with `cancelUIMultiplierUpdate()` (reverts `UIMultiplierUpdateDoesNotExist` when nothing is pending). The deprecated instant setter `updateMultiplier` is retained (dialable) for backward compatibility; it emits both the deprecated `MultiplierUpdated` event and the ERC-8056 `UIMultiplierUpdated` event. `OPERATOR_ROLE` gates `announce`, `updateUIMultiplier`, `cancelUIMultiplierUpdate`, and the deprecated `updateMultiplier`.
#### Announcements
diff --git a/docs/base-chain/specs/reference/b20/interfaces/IB20.mdx b/docs/base-chain/specs/reference/b20/interfaces/IB20.mdx
index 132933833..08d497006 100644
--- a/docs/base-chain/specs/reference/b20/interfaces/IB20.mdx
+++ b/docs/base-chain/specs/reference/b20/interfaces/IB20.mdx
@@ -76,40 +76,4 @@ description: "Generated B20 reference for IB20 functions, events, and errors."
| `RoleRevoked` | `0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b` | Emitted when `role` is revoked from `account`. `sender` is the originating caller |
| `RoleAdminChanged` | `0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff` | Emitted by `setRoleAdmin` when the admin role for `role` changes. |
| `LastAdminRenounced` | `0xe8d3a9872e7ca325571ff1e4c51ddd69090a0345240cc605ccde365ec867cc67` | Emitted by `renounceLastAdmin` in addition to the standard |
-| `Paused` | `0x43e072977b8112813d7c2aa0b63d3c121c1fe3e714e6d2eacb5735fe4027e976` | Emitted by `pause`. `features` is the argument to the call (not the resulting paused state). |
-| `Unpaused` | `0xdc6281474ea3dea2a856e225c7ba3edf427de9164495817c4d49a595e683fed4` | Emitted by `unpause`. `features` is the argument to the call (not the resulting paused state). |
-| `PolicyUpdated` | `0x8b4790f7ff717fc8f60f07ae099e47ef318dc04b37ae98056b50a22b79056626` | Emitted by `updatePolicy` when a token's policy slot is changed. Initial slot assignment at |
-| `SupplyCapUpdated` | `0x6d14f44808ce024f263432bc38d019a9951fbe674e9898b54844dbc8dc09c23a` | Emitted by `updateSupplyCap`. |
-| `ContractURIUpdated` | `0xa5d4097edda6d87cb9329af83fb3712ef77eeb13738ffe43cc35a4ce305ad962` | Emitted by `updateContractURI`. Per ERC-7572, parameterless: integrators re-fetch `contractURI()`. |
-| `NameUpdated` | `0x74321da206c1b9fa34367f7ece59ca49371dcd13820b9a5c3767ae1ecceed51a` | Emitted by `updateName`. Carries the new name string. |
-| `SymbolUpdated` | `0x64e8b5c6dcea43dd79766bb3b8af7c45968d12b68c960cf2da23856f34d598d4` | Emitted by `updateSymbol`. Carries the new symbol string. |
-| `EIP712DomainChanged` | `0x0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d31` | ERC-5267 domain-change signal. Emitted exactly once per successful `updateName` call, |
-
-## Errors
-
-| Error | Selector | Summary |
-|---|---|---|
-| `NonPayable` | `0x6fb1b0e9` | ETH was attached to a call targeting a nonpayable token selector. |
-| `AccessControlUnauthorizedAccount` | `0xe2517d3f` | `account` does not hold `neededRole`. |
-| `Unauthorized` | `0x82b42900` | Caller failed a positional authorization check that is not expressible as "missing role X". |
-| `ContractPaused` | `0xf9df5ac9` | The `PausableFeature` covering this operation is currently paused. |
-| `InsufficientAllowance` | `0x192b9e4e` | `spender`'s allowance is less than `needed` for the requested `transferFrom`. |
-| `InsufficientBalance` | `0xdb42144d` | `sender`'s balance is less than `needed` for the requested transfer or burn. |
-| `InvalidSender` | `0x4c14f64c` | The transfer's source address is invalid (typically `address(0)`). |
-| `InvalidReceiver` | `0x9cfea583` | The transfer's destination address is invalid (typically `address(0)`). |
-| `InvalidApprover` | `0x8bc146c4` | The approval's `owner` address is invalid (typically `address(0)`). |
-| `InvalidSpender` | `0x4e15efda` | The approval's `spender` address is invalid (typically `address(0)`). |
-| `InvalidAmount` | `0x2c5211c6` | An amount argument was zero where a non-zero value is required. Not used for ERC-20 amount arguments. |
-| `EmptyFeatureSet` | `0x4861ff45` | An empty array was passed to a function that requires at least one element. |
-| `InvalidSupplyCap` | `0x0a3780ce` | The proposed supply cap is outside the permitted range: below the current |
-| `SupplyCapExceeded` | `0x4b344b11` | The mint would push `totalSupply` past the configured cap. |
-| `PolicyForbids` | `0xa43fec12` | A policy slot denied the operation. |
-| `PolicyNotFound` | `0xcccad523` | The provided policy ID does not exist in the policy registry. |
-| `UnsupportedPolicyType` | `0xcdd98a4a` | `policyScope` is not a slot this token (or its variant) supports. |
-| `AccountNotSeizable` | `0x91dbbc8d` | `seizeWithMemo` was called against a `from` that is currently authorized under |
-| `AccountNotBlocked` | `0x64a5cb46` | The deprecated `burnBlocked` was called against a `from` that is currently authorized under |
-| `ExpiredSignature` | `0xbd2a913c` | An EIP-2612 `permit` was submitted with a `deadline` strictly less than `block.timestamp`. |
-| `InvalidSigner` | `0x7ba5ffb5` | ECDSA recovery on an EIP-2612 `permit` returned `signer`, which does not match the claimed `owner`. |
-| `LastAdminCannotRenounce` | `0x361513e7` | `renounceRole(DEFAULT_ADMIN_ROLE, ...)` was called by the sole remaining admin. |
-| `NotSoleAdmin` | `0x2a98e73b` | `renounceLastAdmin()` was called when other accounts also hold `DEFAULT_ADMIN_ROLE`. |
-| `AccessControlBadConfirmation` | `0x6697b232` | The `callerConfirmation` argument to `renounceRole` was not `msg.sender`. |
+| `Paused` | `0x43e072977b8
diff --git a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset.mdx b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset.mdx
index f48276cb0..ab80394d4 100644
--- a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset.mdx
+++ b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset.mdx
@@ -8,36 +8,36 @@ description: "Generated B20 reference for IB20Asset functions, events, and error
| Function | Selector | Summary |
|---|---|---|
-| [`OPERATOR_ROLE`](/base-chain/specs/reference/b20/interfaces/IB20Asset/OPERATOR_ROLE) | `0xf5b541a6` | Required to call `announce`, `updateUIMultiplier`, `cancelUIMultiplierUpdate`, and |
+| [`OPERATOR_ROLE`](/base-chain/specs/reference/b20/interfaces/IB20Asset/OPERATOR_ROLE) | `0xf5b541a6` | Required to call `announce`, `updateUIMultiplier`, `cancelUIMultiplierUpdate`, and the deprecated `updateMultiplier`. |
| [`WAD_PRECISION`](/base-chain/specs/reference/b20/interfaces/IB20Asset/WAD_PRECISION) | `0x664808a8` | Fixed-point precision used to scale `multiplier`. Equal to `1e18`. |
-| [`MAX_UI_MULTIPLIER`](/base-chain/specs/reference/b20/interfaces/IB20Asset/MAX_UI_MULTIPLIER) | `0x785c0cf0` | Maximum multiplier accepted by the setter functions. |
-| [`announce`](/base-chain/specs/reference/b20/interfaces/IB20Asset/announce) | `0x595135dd` | Posts a holder-impacting announcement and atomically dispatches each entry in |
+| [`MAX_UI_MULTIPLIER`](/base-chain/specs/reference/b20/interfaces/IB20Asset/MAX_UI_MULTIPLIER) | `0x785c0cf0` | Maximum multiplier accepted by the setter functions: `type(uint128).max`, the overflow guard. |
+| [`announce`](/base-chain/specs/reference/b20/interfaces/IB20Asset/announce) | `0x595135dd` | Posts a holder-impacting announcement and atomically dispatches each entry in `internalCalls`. |
| [`isAnnouncementIdUsed`](/base-chain/specs/reference/b20/interfaces/IB20Asset/isAnnouncementIdUsed) | `0xc0da474e` | Whether `id` has previously been consumed by `announce`. |
-| [`multiplier`](/base-chain/specs/reference/b20/interfaces/IB20Asset/multiplier) | `0x1b3ed722` | The current multiplier, scaled to `WAD_PRECISION`. Holder balances are stored |
-| [`toScaledBalance`](/base-chain/specs/reference/b20/interfaces/IB20Asset/toScaledBalance) | `0x04f04c99` | Converts a raw balance to its scaled view: `rawBalance * multiplier / WAD_PRECISION`. |
-| [`toRawBalance`](/base-chain/specs/reference/b20/interfaces/IB20Asset/toRawBalance) | `0x0ca06c44` | Converts a scaled balance back to its raw representation: |
+| [`multiplier`](/base-chain/specs/reference/b20/interfaces/IB20Asset/multiplier) | `0x1b3ed722` | The current multiplier, scaled to `WAD_PRECISION`. Holder balances are stored raw; multiply by this to derive the scaled view. |
+| [`toScaledBalance`](/base-chain/specs/reference/b20/interfaces/IB20Asset/toScaledBalance) | `0x04f04c99` | DEPRECATED. Converts a raw balance to its scaled view: `rawBalance * multiplier / WAD_PRECISION`. Retained for backward compatibility; prefer `toUIAmount`. |
+| [`toRawBalance`](/base-chain/specs/reference/b20/interfaces/IB20Asset/toRawBalance) | `0x0ca06c44` | DEPRECATED. Converts a scaled balance back to its raw representation: `scaledBalance * WAD_PRECISION / multiplier`. Retained for backward compatibility; prefer `fromUIAmount`. |
| [`scaledBalanceOf`](/base-chain/specs/reference/b20/interfaces/IB20Asset/scaledBalanceOf) | `0x1da24f3e` | Convenience for `toUIAmount(balanceOf(account))`. |
-| [`updateUIMultiplier`](/base-chain/specs/reference/b20/interfaces/IB20Asset/updateUIMultiplier) | `0x628e600f` | Schedules a UI-multiplier update to take effect at `effectiveAt`. |
-| [`cancelUIMultiplierUpdate`](/base-chain/specs/reference/b20/interfaces/IB20Asset/cancelUIMultiplierUpdate) | `0x2c97a0f0` | Cancels the single live pending update, restoring the no-pending state. |
-| [`updateMultiplier`](/base-chain/specs/reference/b20/interfaces/IB20Asset/updateMultiplier) | `0x5ffe6146` | Instant failsafe / emergency override — sets the current multiplier immediately and |
-| [`batchMint`](/base-chain/specs/reference/b20/interfaces/IB20Asset/batchMint) | `0x68573107` | Mints `amounts[i]` to `recipients[i]` in one call. All-or-nothing: any element |
-| [`extraMetadata`](/base-chain/specs/reference/b20/interfaces/IB20Asset/extraMetadata) | `0x4ddf9da0` | The value of the named metadata entry, or the empty string if not set. A |
-| [`updateExtraMetadata`](/base-chain/specs/reference/b20/interfaces/IB20Asset/updateExtraMetadata) | `0xb2851ef5` | Sets, updates, or removes an extra-metadata entry. An empty `value` removes the |
+| [`updateUIMultiplier`](/base-chain/specs/reference/b20/interfaces/IB20Asset/updateUIMultiplier) | `0x628e600f` | Schedules a UI-multiplier update to take effect at `effectiveAt`. Canonical path for corporate actions. |
+| [`cancelUIMultiplierUpdate`](/base-chain/specs/reference/b20/interfaces/IB20Asset/cancelUIMultiplierUpdate) | `0x2c97a0f0` | Cancels the single live pending update, restoring the no-pending state. Reverts `UIMultiplierUpdateDoesNotExist` when nothing is scheduled. |
+| [`updateMultiplier`](/base-chain/specs/reference/b20/interfaces/IB20Asset/updateMultiplier) | `0x5ffe6146` | DEPRECATED. Instant failsafe / emergency override — sets the current multiplier immediately and clears any live pending. Retained for backward compatibility; prefer `updateUIMultiplier`. |
+| [`batchMint`](/base-chain/specs/reference/b20/interfaces/IB20Asset/batchMint) | `0x68573107` | Mints `amounts[i]` to `recipients[i]` in one call. All-or-nothing: any element failure reverts the entire batch. |
+| [`extraMetadata`](/base-chain/specs/reference/b20/interfaces/IB20Asset/extraMetadata) | `0x4ddf9da0` | The value of the named metadata entry, or the empty string if not set. |
+| [`updateExtraMetadata`](/base-chain/specs/reference/b20/interfaces/IB20Asset/updateExtraMetadata) | `0xb2851ef5` | Sets, updates, or removes an extra-metadata entry. An empty `value` removes the entry. |
| [`uiMultiplier`](/base-chain/specs/reference/b20/interfaces/IB20Asset/uiMultiplier) | `0xa60bf13d` | Returns the current ERC-8056 UI multiplier. |
| [`newUIMultiplier`](/base-chain/specs/reference/b20/interfaces/IB20Asset/newUIMultiplier) | `0xdc767007` | Returns the pending UI multiplier. |
| [`effectiveAt`](/base-chain/specs/reference/b20/interfaces/IB20Asset/effectiveAt) | `0x97a4064f` | Returns the effective-at timestamp for the pending multiplier. |
| [`balanceOfUI`](/base-chain/specs/reference/b20/interfaces/IB20Asset/balanceOfUI) | `0x437a9958` | Returns an account's UI-adjusted balance. |
| [`totalSupplyUI`](/base-chain/specs/reference/b20/interfaces/IB20Asset/totalSupplyUI) | `0x9bea6429` | Returns the UI-adjusted total supply. |
-| [`toUIAmount`](/base-chain/specs/reference/b20/interfaces/IB20Asset/toUIAmount) | `0x3248d4ff` | Converts a raw amount to its UI representation. |
-| [`fromUIAmount`](/base-chain/specs/reference/b20/interfaces/IB20Asset/fromUIAmount) | `0x65cd9b3c` | Converts a UI amount to its raw representation. |
+| [`toUIAmount`](/base-chain/specs/reference/b20/interfaces/IB20Asset/toUIAmount) | `0x3248d4ff` | Converts a raw amount to its UI representation at the effective multiplier (ERC-8056 Conversion extension). |
+| [`fromUIAmount`](/base-chain/specs/reference/b20/interfaces/IB20Asset/fromUIAmount) | `0x65cd9b3c` | Converts a UI amount to its raw representation at the effective multiplier (ERC-8056 Conversion extension). |
## Events
| Event | Topic0 | Summary |
|---|---|---|
-| `UIMultiplierUpdated` | `0x2205df4534432b2f60654a3fdb48737ffdaf3e9edb1a498bd985bc026b15b055` | Emitted when the UI multiplier is updated. |
-| `MultiplierUpdated` | `0x4dbe4840d7465bd162f67814cea0b519567a2e0e578bcde61e7f4ced361e5a3d` | Deprecated multiplier-change event emitted by `updateMultiplier`. |
-| `UIMultiplierUpdateCancelled` | `0x883856335ba5f60c18b9817c4505d3c7d3f6223dcf39516b30c508c46a5e1cad` | A scheduled multiplier update was cancelled. |
+| `UIMultiplierUpdated` | `0x2205df4534432b2f60654a3fdb48737ffdaf3e9edb1a498bd985bc026b15b055` | Emitted on every multiplier change: by `updateUIMultiplier` (scheduled) and by `updateMultiplier` (instant). |
+| `MultiplierUpdated` | `0x4dbe4840d7465bd162f67814cea0b519567a2e0e578bcde61e7f4ced361e5a3d` | Deprecated multiplier-change event. Emitted by the instant setter (`updateMultiplier`) alongside `UIMultiplierUpdated` for backward compatibility; the scheduled `updateUIMultiplier` emits only `UIMultiplierUpdated`. |
+| `UIMultiplierUpdateCancelled` | `0x883856335ba5f60c18b9817c4505d3c7d3f6223dcf39516b30c508c46a5e1cad` | A scheduled multiplier update was cancelled. Emitted by `cancelUIMultiplierUpdate` and by `updateMultiplier` when it clears a live pending. |
| `ExtraMetadataUpdated` | `0xd7bb345be29e78d635203d40fe0567e7ef19d5cd5cc5fcd25f768b8063e82aa1` | Emitted by `updateExtraMetadata`. An empty `value` indicates removal. |
| `Announcement` | `0xccebf8218a62875909564adef86a6f4df81503cb617221e793357d62f8e813f7` | Emitted by `announce` to open an announcement bracket. |
| `EndAnnouncement` | `0x96d64dafe2c790596430196b982ad1da3221cb3b0f4e6e2df77f2e4f71a90037` | Emitted by `announce` to close the bracket opened by the paired `Announcement` with the same `id`. |
@@ -48,13 +48,13 @@ description: "Generated B20 reference for IB20Asset functions, events, and error
|---|---|---|
| `AnnouncementIdAlreadyUsed` | `0xd10b3c9e` | `announce` was called with an `id` that has already been consumed. |
| `InvalidMetadataKey` | `0x86ea3abb` | `updateExtraMetadata` was called with an empty `key`. |
-| `InvalidMultiplier` | `0x6f12f3dc` | A multiplier setter (`updateUIMultiplier` or `updateMultiplier`) was called with a |
-| `EffectiveAtInPast` | `0x14119cf6` | `updateUIMultiplier` was called with an `effectiveAt` that is not in the future |
-| `EffectiveAtTooFar` | `0x1ce214fa` | `updateUIMultiplier` was called with an `effectiveAt` above `type(uint64).max`, the |
-| `UIMultiplierUpdateExists` | `0x4481a68e` | `updateUIMultiplier` was called while a live pending update already exists |
-| `UIMultiplierUpdateDoesNotExist` | `0xa7d6a5ca` | `cancelUIMultiplierUpdate` was called when there is no live pending update |
+| `InvalidMultiplier` | `0x6f12f3dc` | A multiplier setter (`updateUIMultiplier` or the deprecated `updateMultiplier`) was called with a multiplier of zero or above `MAX_UI_MULTIPLIER`. |
+| `EffectiveAtInPast` | `0x14119cf6` | `updateUIMultiplier` was called with an `effectiveAt` that is not in the future (`effectiveAt <= block.timestamp`). |
+| `EffectiveAtTooFar` | `0x1ce214fa` | `updateUIMultiplier` was called with an `effectiveAt` above `type(uint64).max`. |
+| `UIMultiplierUpdateExists` | `0x4481a68e` | `updateUIMultiplier` was called while a live pending update already exists. The `effectiveAt` of the conflicting pending is included. |
+| `UIMultiplierUpdateDoesNotExist` | `0xa7d6a5ca` | `cancelUIMultiplierUpdate` was called when there is no live pending update. |
| `LengthMismatch` | `0xab8b67c6` | A batched function was called with parallel arrays of differing lengths. |
| `EmptyBatch` | `0xc2e5347d` | A batched function was called with empty arrays. |
| `AnnouncementInProgress` | `0x5c5f0829` | An inner call dispatched by `announce` tried to re-invoke `announce`. |
| `InternalCallMalformed` | `0x4e2f143e` | An inner call dispatched by `announce` was shorter than four bytes. |
-| `InternalCallFailed` | `0xb288a127` | An inner call dispatched by `announce` reverted with an ordinary revert; its reason is |
+| `InternalCallFailed` | `0xb288a127` | An inner call dispatched by `announce` reverted with an ordinary revert; its reason is forwarded. |
diff --git a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/MAX_UI_MULTIPLIER.mdx b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/MAX_UI_MULTIPLIER.mdx
index 84228fdd2..10e9f74bd 100644
--- a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/MAX_UI_MULTIPLIER.mdx
+++ b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/MAX_UI_MULTIPLIER.mdx
@@ -18,6 +18,8 @@ function MAX_UI_MULTIPLIER() external view returns (uint256);
Returns the maximum multiplier the setter functions accept: `type(uint128).max`.
+With token supply capped at `type(uint128).max`, a `uint128` multiplier keeps `balance * multiplier` inside `uint256`, so all balance-derived reads are overflow-safe. Both `updateUIMultiplier` and the deprecated `updateMultiplier` revert with `InvalidMultiplier` when `newMultiplier` exceeds this bound.
+
## Example
```solidity
diff --git a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/OPERATOR_ROLE.mdx b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/OPERATOR_ROLE.mdx
index eaa362ea6..18579a31a 100644
--- a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/OPERATOR_ROLE.mdx
+++ b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/OPERATOR_ROLE.mdx
@@ -18,7 +18,7 @@ function OPERATOR_ROLE() external view returns (bytes32);
## Description
-Required to call `announce`, `updateUIMultiplier`, `cancelUIMultiplierUpdate`, and
+Required to call `announce`, `updateUIMultiplier`, `cancelUIMultiplierUpdate`, and the deprecated
`updateMultiplier`. The metadata setters (`updateName`, `updateSymbol`,
`updateExtraMetadata`) are gated by the inherited `METADATA_ROLE` instead.
Return: Role constant.
diff --git a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/cancelUIMultiplierUpdate.mdx b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/cancelUIMultiplierUpdate.mdx
index 45a95c952..ea64f175e 100644
--- a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/cancelUIMultiplierUpdate.mdx
+++ b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/cancelUIMultiplierUpdate.mdx
@@ -20,8 +20,12 @@ function cancelUIMultiplierUpdate() external;
Cancels the single live pending update, restoring the no-pending state
(`effectiveAt` resets to 0).
-Dev: Reverts with `AccessControlUnauthorizedAccount` when the caller does not hold `OPERATOR_ROLE`.
-Dev: Reverts with `UIMultiplierUpdateDoesNotExist` when there is no live pending update.
+
+Reverts with `AccessControlUnauthorizedAccount` when the caller does not hold `OPERATOR_ROLE`.
+
+Reverts with `UIMultiplierUpdateDoesNotExist` when there is no live pending update.
+
+Emits `UIMultiplierUpdateCancelled(cancelledMultiplier, cancelledEffectiveAt)` on success.
## Access control
diff --git a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/fromUIAmount.mdx b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/fromUIAmount.mdx
index 4eccf97c5..33f7bc3d8 100644
--- a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/fromUIAmount.mdx
+++ b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/fromUIAmount.mdx
@@ -17,3 +17,24 @@ function fromUIAmount(uint256 uiAmount) external view returns (uint256);
## Description
Converts `uiAmount` to its raw token representation at the effective multiplier.
+
+Part of the ERC-8056 optional Conversion extension (`IScaledUIAmountConversion`, interface ID `0x57854fc3`). The inverse operation is `toUIAmount(rawAmount)`.
+
+Integer division truncates toward zero, so the round-trip `fromUIAmount(toUIAmount(x))` may return a value less than `x` by up to 1 wei when the multiplier does not evenly divide the amount.
+
+## Parameters
+
+| Name | Type | Description |
+|---|---|---|
+| `uiAmount` | `uint256` | UI (scaled) amount to convert back to raw. |
+
+## Returns
+
+| Name | Type | Description |
+|---|---|---|
+| _(unnamed)_ | `uint256` | Raw token amount at the effective multiplier: `uiAmount * WAD_PRECISION / multiplier`. |
+
+## Related
+
+- `toUIAmount` — the forward (raw → UI) converter.
+- `toRawBalance` — deprecated alias with identical behavior; retained in `IB20Asset` for backward compatibility.
diff --git a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/scaledBalanceOf.mdx b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/scaledBalanceOf.mdx
index 33fbf0048..d23ee6d9e 100644
--- a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/scaledBalanceOf.mdx
+++ b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/scaledBalanceOf.mdx
@@ -19,8 +19,12 @@ function scaledBalanceOf(address account) external view returns (uint256);
## Description
Convenience for `toUIAmount(balanceOf(account))`.
-Param: account Account whose scaled balance is being queried.
-Return: Scaled balance.
+
+| Parameter | Type | Description |
+|---|---|---|
+| `account` | `address` | Account whose scaled balance is being queried. |
+
+**Returns:** Scaled balance.
## Access control
diff --git a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/toScaledBalance.mdx b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/toScaledBalance.mdx
index 31669f2c0..1daa34e61 100644
--- a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/toScaledBalance.mdx
+++ b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/toScaledBalance.mdx
@@ -3,7 +3,9 @@ title: "IB20Asset.toScaledBalance"
description: "Generated B20 reference for toScaledBalance(uint256)."
---
-
+
+**Deprecated.** `toScaledBalance` is retained in `IB20Asset` for backward compatibility but is superseded by the ERC-8056 Conversion extension function `toUIAmount(uint256)`. Prefer `toUIAmount` in new integrations.
+
## Signature
@@ -18,13 +20,23 @@ function toScaledBalance(uint256 rawBalance) external view returns (uint256);
## Description
-Converts a raw balance to its scaled view: `rawBalance * multiplier / WAD_PRECISION`.
-Param: rawBalance Raw token amount to scale.
-Return: Scaled balance at the current multiplier.
+**DEPRECATED.** Converts a raw balance to its scaled view: `rawBalance * multiplier / WAD_PRECISION`. Retained (dialable) for backward compatibility as an alias of `toUIAmount`. Prefer the ERC-8056 Conversion extension `toUIAmount(uint256)` in new code.
+
+**Parameters**
+
+| Name | Type | Description |
+|---|---|---|
+| `rawBalance` | `uint256` | Raw token amount to scale. |
+
+**Returns**
+
+| Type | Description |
+|---|---|
+| `uint256` | Scaled balance at the current multiplier. |
## Access control
-Read-only or ERC-20-standard access rules unless the NatSpec states otherwise.
+Read-only; no role required.
## Policy interaction
@@ -32,6 +44,10 @@ No direct policy interaction.
## Example
-```solidity
-IB20Asset(target).toScaledBalance(arg0);
+```solidity Title Deprecated usage — prefer toUIAmount
+// Deprecated — retained for backward compatibility only.
+uint256 scaled = IB20Asset(target).toScaledBalance(rawBalance);
+
+// Preferred ERC-8056 canonical form:
+uint256 scaled = IB20Asset(target).toUIAmount(rawBalance);
```
diff --git a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/toUIAmount.mdx b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/toUIAmount.mdx
index 1a5e323b0..cc4e4ea10 100644
--- a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/toUIAmount.mdx
+++ b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/toUIAmount.mdx
@@ -17,3 +17,21 @@ function toUIAmount(uint256 rawAmount) external view returns (uint256);
## Description
Converts `rawAmount` to its UI representation at the effective multiplier.
+
+Part of the ERC-8056 optional Conversion extension (`IScaledUIAmountConversion`, interface ID `0x57854fc3`). The effective multiplier is the pending slot's value when a scheduled update is live; otherwise it is the current stored multiplier.
+
+The computation is `rawAmount * multiplier / WAD_PRECISION`, where `WAD_PRECISION` is `1e18`. Integer division truncates toward zero, so the round-trip `fromUIAmount(toUIAmount(x))` may return a value up to one ULP below `x`.
+
+The legacy `toScaledBalance(uint256)` is a deprecated alias with identical behavior, retained in `IB20Asset` for backward compatibility.
+
+## Parameters
+
+
+ Raw token amount to convert to its UI representation.
+
+
+## Returns
+
+| Name | Type | Description |
+|---|---|---|
+| _(unnamed)_ | `uint256` | UI amount at the effective multiplier. |
diff --git a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/updateMultiplier.mdx b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/updateMultiplier.mdx
index f9eecb2ed..3cbc20f10 100644
--- a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/updateMultiplier.mdx
+++ b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/updateMultiplier.mdx
@@ -18,12 +18,20 @@ function updateMultiplier(uint256 newMultiplier) external;
## Description
-DEPRECATED. Instant failsafe / emergency override — sets the current multiplier immediately and
-cancels any live pending update without a scheduling window. Emits both `MultiplierUpdated` and
-`UIMultiplierUpdated`. Prefer `updateUIMultiplier` for routine corporate actions.
-Dev: Reverts with `AccessControlUnauthorizedAccount` when the caller does not hold `OPERATOR_ROLE`.
-Dev: Reverts with `InvalidMultiplier` when `newMultiplier` is zero or above `type(uint128).max`.
-Param: newMultiplier New multiplier scaled to `WAD_PRECISION`; must be in `(0, type(uint128).max]`.
+
+`updateMultiplier` is deprecated. Prefer the scheduled `updateUIMultiplier` for routine corporate actions. This function is retained in `IB20Asset` (still dialable) for backward compatibility only.
+
+
+Instant failsafe / emergency override — sets the current multiplier immediately and cancels any live pending update without a scheduling window. Emits the deprecated `MultiplierUpdated(newMultiplier)` event alongside the ERC-8056 `UIMultiplierUpdated(oldMultiplier, newMultiplier, effectiveAtTimestamp)` so indexers watching the legacy topic continue to work through the transition. When it clears a live pending update, it also emits `UIMultiplierUpdateCancelled(cancelledMultiplier, cancelledEffectiveAt)` before the multiplier-change events.
+
+Reverts with `AccessControlUnauthorizedAccount` when the caller does not hold `OPERATOR_ROLE`.
+Reverts with `InvalidMultiplier` when `newMultiplier` is zero or above `type(uint128).max` (see `MAX_UI_MULTIPLIER()`).
+
+## Parameters
+
+| Parameter | Type | Description |
+|---|---|---|
+| `newMultiplier` | `uint256` | New multiplier scaled to `WAD_PRECISION`; must be in `(0, type(uint128).max]`. |
## Access control
diff --git a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/updateUIMultiplier.mdx b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/updateUIMultiplier.mdx
index 445f443ec..d28384adb 100644
--- a/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/updateUIMultiplier.mdx
+++ b/docs/base-chain/specs/reference/b20/interfaces/IB20Asset/updateUIMultiplier.mdx
@@ -18,26 +18,41 @@ function updateUIMultiplier(uint256 newMultiplier, uint256 effectiveAt) external
## Description
-Schedules a multiplier update to take effect at `effectiveAt` — the standard path
-for corporate actions (splits, reinvested dividends).
-Dev: Reverts with `AccessControlUnauthorizedAccount` when the caller does not hold `OPERATOR_ROLE`.
-Dev: Reverts with `InvalidMultiplier` when `newMultiplier` is zero or above `type(uint128).max`.
-Dev: Reverts with `EffectiveAtInPast` when `effectiveAt` is not in the future.
-Dev: Reverts with `EffectiveAtTooFar` when `effectiveAt` exceeds `type(uint64).max`.
-Dev: Reverts with `UIMultiplierUpdateExists` when a live pending update already exists.
-Param: newMultiplier New multiplier scaled to `WAD_PRECISION`.
-Param: effectiveAt Timestamp at which `newMultiplier` becomes effective; must be in the future.
+Schedules a UI-multiplier update to take effect at `effectiveAt` — the canonical path for corporate actions (splits, reinvested dividends). Evaluation is lazy: `multiplier()` / `uiMultiplier()` flip automatically once `block.timestamp` reaches `effectiveAt`. Only one pending update can be live at a time.
+
+## Parameters
+
+| Name | Type | Description |
+|---|---|---|
+| `newMultiplier` | `uint256` | New multiplier scaled to `WAD_PRECISION`. Must be non-zero and at most `MAX_UI_MULTIPLIER()` (`type(uint128).max`). |
+| `effectiveAt` | `uint256` | Timestamp at which `newMultiplier` becomes effective; must be strictly in the future and no greater than `type(uint64).max`. |
+
+## Revert conditions
+
+| Error | Condition |
+|---|---|
+| `AccessControlUnauthorizedAccount` | Caller does not hold `OPERATOR_ROLE`. |
+| `InvalidMultiplier` | `newMultiplier` is zero or above `type(uint128).max`. |
+| `EffectiveAtInPast` | `effectiveAt <= block.timestamp`. |
+| `EffectiveAtTooFar` | `effectiveAt > type(uint64).max`. |
+| `UIMultiplierUpdateExists` | A live pending update already exists. Cancel it first with `cancelUIMultiplierUpdate()` before scheduling a new one. |
## Access control
-`OPERATOR_ROLE` gates this Asset call.
+`OPERATOR_ROLE` gates this call.
-## Policy interaction
+## Events emitted
-No direct policy interaction.
+On success, emits `UIMultiplierUpdated(oldMultiplier, newMultiplier, effectiveAt)` once the scheduled update is stored. (The event fires at scheduling time; the multiplier itself flips lazily at `effectiveAt`.)
## Example
-```solidity
-IB20Asset(target).updateUIMultiplier(arg0, arg1);
+```solidity Title Schedule a 2:1 forward split
+bytes[] memory internalCalls = new bytes[](1);
+internalCalls[0] = abi.encodeCall(IB20Asset.updateUIMultiplier, (2e18, exDateTimestamp));
+
+IB20Asset(token).announce({
+ internalCalls: internalCalls,
+ disclosure: disclosureURI
+});
```