Developer docs
Corporate actions
Splits, dividends and mergers.
When a company pays a dividend, splits its stock or merges, its ST0x tokens follow. Every stock comes as tStock, the issued token, and wtStock, an ERC-4626 wrapper that holds tStock (the two forms). This page explains what happens to tStock and wtStock in each case, and what your integration should do.
At a glance
| Action | tStock | wtStock | What to do |
|---|---|---|---|
| Dividend | Balances don’t change. Paid by claim; claiming isn’t live yet. | The ratio rises when the dividend reaches the wrapper. | Expect the share’s ex-dividend drop; allow for the delay before delivery. |
| Split | Balances change at the effective time. | Balances stay the same; the ratio changes. | Don’t cache balances across the effective time. |
| Merger or delisting | May be adjusted; redemption may pause, or the shares may be sold and the proceeds paid out. | The same, through the tStock it holds. | Review collateral settings for that token. |
| Name or ticker change | Balances and addresses don’t change. | Balances and addresses don’t change. | Refresh any metadata you cache. |
Dividends
Two dates matter. The record date is when the company checks who its shareholders are. The ex-date is the first day the share trades without the dividend, so its price usually drops by about the dividend that day.
wtStock. S01, the issuer, delivers dividends to each wrapper as tStock. No new wtStock is minted: each wtStock is simply worth more tStock, so convertToAssets(1e18) rises. Deliveries are made chain by chain, so the ratio can differ between chains. There is no separate event for a delivery: watch the wrapper’s tStock Transfer events or poll the ratio. Delivery follows S01 receiving the dividend, so it can come some days after the ex-date.
tStock. Balances don’t change. Distributions to tStock holders are paid separately for holders to claim, and claiming isn’t live yet.
If your contract holds tStock (a pool, vault or lending market), any distribution goes to the contract, not to your users. To pass dividends through without handling claims, hold wtStock instead.
Splits
A split is scheduled onchain before it happens, with its effective time set in the future, so you can see it coming and prepare. At the effective time, tStock balances change so that one tStock still equals one share. It happens without a transaction: balanceOf and totalSupply simply return post-split values, and each account’s stored balance is updated on its next transfer, emitting AccountMigrated.
- Pools and lending markets that track tStock balances internally will drift at the effective time. Hold wtStock to avoid it, and pause liquidations across the effective time to avoid false ones.
- Indexers that sum
Transferevents will diverge. Replay splits by theireffectiveTime, not the block they were scheduled in, skip actions that were cancelled, and useAccountMigratedto tell the rebase apart from transfers. - Oracles must switch to the post-split price at the same moment. See pricing guidance.
Mergers and delistings
If the company merges or is delisted, S01 may adjust the token so it stays equivalent to the share. Redemption for shares may be paused, or S01 may sell the shares and pay the proceeds to holders, less administration fees. Mergers aren’t an onchain action type today, so watch the company’s own announcements and review collateral settings for that token.
Name and ticker changes
Balances and addresses don’t change. Token metadata on this site is updated; refresh any metadata you cache.
Reading them onchain
Each tStock contract records its own corporate actions; there is no separate registry. Watch for CorporateActionScheduled and CorporateActionCancelled, and act on the onchain effectiveTime.
Contract reference
Interface: ABI.
- Scheduling (role-gated):
scheduleCorporateAction(bytes32 typeHash, uint64 effectiveTime, bytes parameters) returns (uint256 actionId)andcancelCorporateAction(uint256 actionId). The effective time must be in the future; only pending actions can be cancelled. - Views:
completedActionCount(),latestActionOfType,earliestActionOfType,nextOfType,prevOfType(each returns action id, type and effective time) andgetActionParameters(actionId). They take amaskover action types and a filter (0all,1completed,2pending), and return(type(uint256).max, 0, 0)when nothing matches. - Events:
CorporateActionScheduled(address indexed sender, uint256 indexed actionId, uint256 actionType, uint64 effectiveTime),CorporateActionCancelled(address indexed sender, uint256 indexed actionId),AccountMigrated(address indexed account, uint256 fromActionId, uint256 toActionId, uint256 oldBalance, uint256 newBalance), andReceiptAccountMigratedon the receipt contract (the ERC-1155 contract that holds each mint’s receipt). - Action types are bit flags:
1 << 1stock split (typeHash0x4548e57ae2f1604df75a3d17fecaff7dd11ad7a93d9f8a0dc05e7144f46f3f7c);1 << 2is reserved for dividends and can’t be scheduled today.scheduleCorporateActiontakes the typeHash; events and views report the bit flag. - Split parameters are
abi.encode(Float), a Rain decimal float: multiplier = coefficient × 10^exponent, with an int32 exponent in the top 4 bytes and an int224 coefficient below. A 2-for-1 split is0x00…02; a 1-for-10 reverse split is0xffffffff00…01. Compare values numerically.