announce emits Announcement before the inner calls and EndAnnouncement after, giving indexers a reliable bracket for every announced change.
Real-world asset (RWA) tokenization is one of many use cases for the B20 Asset standard. The examples on this page use a stock token for illustration; the same flows apply to other asset types.Tokenized securities examples shown for illustration. Base is a general-purpose blockchain; issuance and compliance are the responsibility of the issuer under applicable law.
Demo
New to B20? See the B20 Token Standard for the concepts and a full launch walkthrough. These samples target
base-std@be6d045, viem@2.55.11, and Base Foundry v1.1.1.How Announcements Work
announce takes internalCalls, a single-use id, a description, and a uri.
internalCalls: ABI-encoded calldata blobs targeting this asset. Each blob must be at least 4 bytes. Pass an empty array for a notice with no onchain effect.id: chosen by the caller and consumed on success. Reuse revertsAnnouncementIdAlreadyUsed. After success,isAnnouncementIdUsed(id)returnstrue.descriptionanduri: operator-supplied strings. The asset does not verify them.
Announcement(caller, id, description, uri), runs the inner calls atomically, then emits EndAnnouncement(id). If any inner call fails, the whole transaction reverts. Nesting announce inside an inner call reverts AnnouncementInProgress.
The caller must hold OPERATOR_ROLE. Any other caller reverts AccessControlUnauthorizedAccount. Inner calls keep their own role gates. If an inner call needs MINT_ROLE or BURN_ROLE, grant those to the operator as well.
Announce and Distribute the Stock Dividend
OPERATOR_ROLE and MINT_ROLE. Recipients must pass MINT_RECEIVER_POLICY. MINT must not be paused. On success the asset emits Announcement, then one Transfer(address(0), recipient, amount) per recipient, then EndAnnouncement.
On success, the unique announcement
id is marked used and the batch mint executes between Announcement and EndAnnouncement.This example issues additional shares. It does not distribute a cash dividend. A reinvested dividend that only rescales displayed balances is a multiplier update, covered below and in Apply a Multiplier.
Announce Other Changes
The same bracket discloses any operator-driven change. Each scenario below lists the roles the operator needs and the events the asset emits.Multiplier Update
WrapupdateUIMultiplier(newMultiplier, effectiveAt). A 2-for-1 split uses 2e18. A reverse split uses a value below 1e18. The operator needs OPERATOR_ROLE only.
Announce a multiplier update
Announcement, UIMultiplierUpdated, then EndAnnouncement. UIMultiplierUpdated means the schedule was recorded, not that the multiplier is already active. See Apply a Multiplier for the full schedule, cancel, and override flow.
To replace a live pending update, cancel and reschedule in one announce:
Cancel and reschedule in one announcement
Treasury Burn
WrapburnWithMemo(amount, memo). The call burns the operator’s own balance. The operator needs OPERATOR_ROLE and BURN_ROLE. BURN must not be paused.
Announce a treasury burn
Announcement, Transfer(operator, address(0), amount), Memo, then EndAnnouncement. totalSupply decreases.
Notice With No Onchain Effect
Pass an emptyinternalCalls array. The operator needs OPERATOR_ROLE only. The asset emits Announcement then EndAnnouncement with nothing between them. The id is still consumed.
Notice only
Common Errors
Typical inner causes of
InternalCallFailed: missing MINT_ROLE or BURN_ROLE, paused MINT or BURN, UIMultiplierUpdateExists, PolicyForbids, SupplyCapExceeded, InsufficientBalance. A Solidity Panic (for example overflow) propagates raw and is not wrapped as InternalCallFailed.
See Also
Issue Shares
Mint asset units to holders.