Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions docs/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ npx skills add base/base-skills
|Get Started/Get Funding:get-started/base-batches,get-started/base-ecosystem-fund,get-started/base-services-hub
|Get Started/References:get-started/base-chain,get-started/sdks-and-apis
|Build on Base/Overview:build-on-base/overview,build-on-base/test-on-vibenet,build-on-base/assign-user-attributes
|Build on Base/Integrate DeFi:build-on-base/integrate-defi/integrate-trading,build-on-base/integrate-defi/integrate-lending,build-on-base/integrate-defi/integrate-borrowing,build-on-base/integrate-defi/integrate-earn-product
|Build on Base/Integrate DeFi:build-on-base/integrate-defi/integrate-trading,build-on-base/integrate-defi/integrate-lending,build-on-base/integrate-defi/integrate-borrowing,build-on-base/integrate-defi/integrate-earn-product,build-on-base/integrate-defi/list-tokenized-stocks
|Build on Base/Tokenize Assets:build-on-base/issue-rwa/create-an-asset-token,build-on-base/issue-rwa/issue-units,build-on-base/issue-rwa/restrict-eligible-holders,build-on-base/issue-rwa/cancel-blocked-units,build-on-base/issue-rwa/announce-a-distribution,build-on-base/issue-rwa/apply-a-multiplier,build-on-base/issue-rwa/pause-transfers
|Build on Base/Issue Stablecoins:build-on-base/issue-stablecoins/issue-your-stablecoin,build-on-base/issue-stablecoins/mint-supply,build-on-base/issue-stablecoins/burn-supply,build-on-base/issue-stablecoins/restrict-who-can-hold,build-on-base/issue-stablecoins/block-an-account,build-on-base/issue-stablecoins/recover-funds,build-on-base/issue-stablecoins/pause-activity,build-on-base/issue-stablecoins/reconcile-with-memos
|Build on Base/Accept Payments/Take a Payment:build-on-base/accept-payments/request-a-payment,build-on-base/accept-payments/authorize-a-payment,build-on-base/accept-payments/capture-an-authorization,build-on-base/accept-payments/capture-a-partial-amount,build-on-base/accept-payments/void-an-authorization,build-on-base/accept-payments/charge-on-a-schedule
Expand All @@ -56,9 +56,8 @@ npx skills add base/base-skills
|Specifications/Specifications/Base Protocol/Execution:specifications/base-protocol/execution/l2-execution-engine,specifications/base-protocol/execution/precompiles,specifications/base-protocol/execution/predeploys,specifications/base-protocol/execution/preinstalls
|Specifications/Specifications/Base Protocol/Bridging:specifications/base-protocol/bridging/standard-bridges,specifications/base-protocol/bridging/deposits,specifications/base-protocol/bridging/withdrawals,specifications/base-protocol/bridging/cross-domain-messengers,specifications/base-protocol/bridging/base-solana-bridge
|Specifications/Specifications/Base Protocol/Proofs:specifications/base-protocol/proofs/overview,specifications/base-protocol/proofs/challenger,specifications/base-protocol/proofs/proposer,specifications/base-protocol/proofs/registrar,specifications/base-protocol/proofs/tee-prover,specifications/base-protocol/proofs/zk-prover,specifications/base-protocol/proofs/proof-contracts
|Specifications/Specifications/B20:specifications/b20/specification-overview,specifications/b20/tokenized-stocks-on-base,specifications/b20/changelog
|Specifications/Specifications/B20/Reference:specifications/b20/reference/constants-addresses,specifications/b20/reference/errors-events,specifications/b20/reference/invariants-tests
|Specifications/Specifications/B20/Reference/Interfaces:specifications/b20/reference/interfaces/i-activation-registry,specifications/b20/reference/interfaces/ib20,specifications/b20/reference/interfaces/ib20-asset,specifications/b20/reference/interfaces/ib20-factory,specifications/b20/reference/interfaces/ib20-stablecoin,specifications/b20/reference/interfaces/i-policy-registry
|Specifications/Specifications/B20:specifications/b20/specification-overview,specifications/b20/reference/constants-addresses,specifications/b20/reference/errors-events,specifications/b20/reference/invariants-tests,specifications/b20/changelog
|Specifications/Specifications/B20/Interfaces:specifications/b20/reference/interfaces/i-activation-registry,specifications/b20/reference/interfaces/ib20,specifications/b20/reference/interfaces/ib20-asset,specifications/b20/reference/interfaces/ib20-factory,specifications/b20/reference/interfaces/ib20-stablecoin,specifications/b20/reference/interfaces/i-policy-registry
|Specifications/Specifications/Transactions:specifications/transactions/transaction-ordering,specifications/transactions/transaction-finality,specifications/transactions/network-fees,specifications/transactions/throughput-and-limits,specifications/transactions/troubleshooting-transactions
|Specifications/Specifications/Builder Codes:specifications/builder-codes/overview,specifications/builder-codes/for-app-developers,specifications/builder-codes/for-wallet-developers,specifications/builder-codes/for-agent-developers
|Specifications/Reference:specifications/reference/base-contracts,specifications/reference/smart-contracts,specifications/reference/configuration,specifications/reference/glossary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ description: "The B20 seize surface at Cobalt and the deprecation of burnBlocked

At Cobalt, the base B20 surface gains a first-class seize operation. `seizeWithMemo(from, to,
amount, memo)` reassigns a holder's balance to a destination in one admin call, gated by a new
`SEIZE_ROLE`, a new `SEIZE` pause vector, and two new policy slots (`SEIZE_HOLDER_POLICY`,
`SEIZE_ROLE`, a new `SEIZE` pause vector, and two new policy slots (`SEIZE_EXEMPT_POLICY`,
`SEIZE_RECEIVER_POLICY`).

Nothing you call today breaks: every Beryl selector, event topic, and error keeps its exact 4-byte
Expand All @@ -23,7 +23,7 @@ To migrate, move administrative balance removal from `burnBlocked` to `seizeWith
treasury or self address, then call `burn` if you want the supply destroyed.

Seize is opt-in per token. The surface exists at Cobalt, but seize does nothing until the issuer
configures `SEIZE_HOLDER_POLICY`. With the slot unset (always-allow), no account is seizable, and
configures `SEIZE_EXEMPT_POLICY`. With the slot unset (always-allow), no account is seizable, and
every `seizeWithMemo` call reverts `AccountNotSeizable`. An issuer that never sets the policy has, in
effect, no seize capability on that token.

Expand All @@ -45,7 +45,7 @@ at Cobalt. Seize lives on the shared `IB20` surface, so it's identical across As
| `BURN_BLOCKED_ROLE()` `0x32ad9be8` | `BURN_BLOCKED_ROLE()` `0x32ad9be8` | carried over unchanged | Still gates `burnBlocked` only. |
| — | `seizeWithMemo(address,address,uint256,bytes32)` `0xf916d81b` | new | Admin balance reassignment. A transfer, not a burn. |
| — | `SEIZE_ROLE()` `0x3c7e9ba5` | new | Required to call `seizeWithMemo`. Value `keccak256("SEIZE_ROLE")` = `0x3469b8b0d89e9604f8510ed143f74a8336d22955d4f83e23bf53d9414e27f432`. |
| — | `SEIZE_HOLDER_POLICY()` `0xb279d311` | new | Policy slot checked against `from`. Value `keccak256("SEIZE_HOLDER_POLICY")` = `0x1497ab2b67ebb0a75dd9cdd6aec9f0e64620e6b87e911af7a088ac12e58d9ef2`. |
| — | `SEIZE_EXEMPT_POLICY()` `0xfeb346ec` | new | Policy slot checked against `from`. Value `keccak256("SEIZE_EXEMPT_POLICY")` = `0xedb5da348cfb67af08746d3afd1be81034b50d5c8576f31aff688f39dfd540ed`. |
| — | `SEIZE_RECEIVER_POLICY()` `0xb31da27f` | new | Policy slot checked against `to`. Value `keccak256("SEIZE_RECEIVER_POLICY")` = `0xbf15b19caf5c77422c038bc25f26b8b815c3a14f6d04c6616076b81bcfe07b3d`. |

### Events
Expand All @@ -60,7 +60,7 @@ at Cobalt. Seize lives on the shared `IB20` surface, so it's identical across As
| Beryl error (selector) | Cobalt (selector) | Status | Why |
| --- | --- | --- | --- |
| `AccountNotBlocked(address)` `0x64a5cb46` | unchanged | present on Beryl already | Thrown by `burnBlocked` when `from` is authorized under `TRANSFER_SENDER_POLICY` (that is, not blocked). |
| — | `AccountNotSeizable(address)` `0x91dbbc8d` | new | Thrown by `seizeWithMemo` when `from` is authorized under `SEIZE_HOLDER_POLICY` (that is, not seizable). |
| — | `AccountNotSeizable(address)` `0x91dbbc8d` | new | Thrown by `seizeWithMemo` when `from` is authorized under `SEIZE_EXEMPT_POLICY` (that is, not seizable). |

### Pause Features

Expand Down Expand Up @@ -90,9 +90,9 @@ Requirements and guards:
- **Pause**: `SEIZE` must not be paused, or the call reverts `ContractPaused(SEIZE)`.
- **Addresses**: `to != address(0)` and `from != to`, or the call reverts `InvalidReceiver`.
`from != address(0)`, or the call reverts `InvalidSender`.
- **Holder gate**: `from` must be blocked under `SEIZE_HOLDER_POLICY`, that is, not authorized by
- **Holder gate**: `from` must be blocked under `SEIZE_EXEMPT_POLICY`, that is, not authorized by
it, or the call reverts `AccountNotSeizable`. An unset slot reads as always-allow, so no account
is seizable until an issuer configures `SEIZE_HOLDER_POLICY`.
is seizable until an issuer configures `SEIZE_EXEMPT_POLICY`.
- **Destination gate**: `to` must be authorized under `SEIZE_RECEIVER_POLICY`, which mirrors
`MINT_RECEIVER_POLICY` and is always enforced. But an unset slot is always-allow, so a token can
seize to any destination (a treasury doesn't need to be allowlisted) until the slot is set.
Expand Down Expand Up @@ -124,7 +124,7 @@ untouched. `burnBlocked` is the burn: it sends to `address(0)` and reduces suppl
old burn-blocked outcome, seize to a treasury or self address, then call `burn`.

**Q: `seizeWithMemo` and `burnBlocked` both target "bad" accounts. Do they read the same set?**
No, and this is deliberate. `seizeWithMemo` reads `SEIZE_HOLDER_POLICY`. `burnBlocked` reads
No, and this is deliberate. `seizeWithMemo` reads `SEIZE_EXEMPT_POLICY`. `burnBlocked` reads
`TRANSFER_SENDER_POLICY`. A token can define a seizable set that's distinct from its
transfer-blocked set. In both cases, "eligible" means not authorized by the relevant policy, and an
unset policy (always-allow) means nobody is eligible.
Expand All @@ -138,14 +138,14 @@ No. `seizeWithMemo` requires `SEIZE_ROLE`. `burnBlocked` requires `BURN_BLOCKED_
doesn't grant the other.

**Q: I never configured the seize policies. What happens if I call `seizeWithMemo`?**
It reverts `AccountNotSeizable(from)` for every `from`, because an unset `SEIZE_HOLDER_POLICY` is
always-allow, so no account is seizable. You must configure `SEIZE_HOLDER_POLICY` to designate
It reverts `AccountNotSeizable(from)` for every `from`, because an unset `SEIZE_EXEMPT_POLICY` is
always-allow, so no account is seizable. You must configure `SEIZE_EXEMPT_POLICY` to designate
seizable holders before seize does anything. (Leaving `SEIZE_RECEIVER_POLICY` unset simply permits
any destination.)

**Q: Does seize consult the transfer policies or spend an allowance?**
No. It's an admin operation: it bypasses `TRANSFER_SENDER/RECEIVER/EXECUTOR_POLICY` and allowances,
and enforces only `SEIZE_HOLDER_POLICY` (on `from`) and `SEIZE_RECEIVER_POLICY` (on `to`).
and enforces only `SEIZE_EXEMPT_POLICY` (on `from`) and `SEIZE_RECEIVER_POLICY` (on `to`).

**Q: Is seize available on B20 Stablecoin as well as B20 Asset?**
Yes. It's defined on the shared `IB20` surface, so both variants expose the identical
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ that gates `createPolicy`, `updateAllowlist`, and others. There's no composite-s
flag. `compositePolicyChildIds`, `MIN_COMPOSITE_CHILD_POLICIES`, `MAX_COMPOSITE_CHILD_POLICIES`, and
`isAuthorized` on a composite ID are all always callable, whether or not the feature is active.

**Q: Can a B20 token's policy slot (for example, `TRANSFER_SENDER_POLICY` or `SEIZE_HOLDER_POLICY`)
**Q: Can a B20 token's policy slot (for example, `TRANSFER_SENDER_POLICY` or `SEIZE_EXEMPT_POLICY`)
reference a composite ID?**
Yes. B20 stores every policy slot as an opaque `uint64 policyId` and calls `isAuthorized`, so a
composite ID works exactly like a simple one, and no B20-side change was needed. As with any policy
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
---
title: "Tokenized Stocks on Base"
description: "Technical guide to integrating tokenized stocks on Base, including B20 contracts, multipliers, compliance policies, and price feeds."
title: "List Tokenized Stocks"
description: "Let users trade Coinbase-issued tokenized stocks on your app."
---

Tokenized Stocks on Base are built on the Base-native token standard, [B20](/build-on-base/issue-rwa/create-an-asset-token). B20 is an extension of the ERC-20 token standard and is intended to be asset-agnostic, with tokenized stocks being one of several possible use cases.

Product-specific details about Tokenized Stocks on Base can be found within [coinbase.com/tokenize](https://coinbase.com/tokenize).

## Token information and listings
## Token Information and Listings

Tokenized stocks launch similarly to any ERC-20 token: name, symbol, and icon come from the usual sources, along with a few notable B20 specifics. Standard ERC-20 methods and events are supported natively.

Expand All @@ -19,7 +19,7 @@ B20 specifics:
- Tokens should be identified by address rather than ticker or symbol. Metadata is mutable onchain and should be indexed accordingly.
- Discover new tokens by watching the [`B20Created`](/specifications/b20/reference/interfaces/ib20-factory) event.

## What B20 adds beyond ERC-20
## B20 Token Features

### Multipliers

Expand Down Expand Up @@ -72,19 +72,19 @@ Two design points:

**Admin actions:** admin operations and `updateMultiplier` ([`OPERATOR_ROLE`](/specifications/b20/reference/interfaces/ib20-asset/operator-role)) execute immediately when the role holder calls; the B20 standard has no built-in timelock. The `Announcement` and `EndAnnouncement` events are public notice, not an enforced delay. Any timelock or multisig is applied by the issuer at the governance layer.

### Extra metadata
### Extra Metadata

Issuers can store arbitrary key/value data onchain via [`extraMetadata(key)`](/specifications/b20/reference/interfaces/ib20-asset/extra-metadata) (for example, security identifiers such as ISIN and CUSIP).

### Name and symbol
### Name and Symbol

Name and symbol are updatable onchain ([`updateName`](/specifications/b20/reference/interfaces/ib20/update-name), [`updateSymbol`](/specifications/b20/reference/interfaces/ib20/update-symbol)), so the token can track offchain changes to the underlying without redeploying.

### Memos

[`transferWithMemo`](/specifications/b20/reference/interfaces/ib20/transfer-with-memo) and [`transferFromWithMemo`](/specifications/b20/reference/interfaces/ib20/transfer-from-with-memo) attach a `bytes32` reference to an individual transfer (emitted as a `Memo` event), for annotating transfers with offchain data for reconciliation and reporting.

### Supply cap
### Supply Cap

An optional supply cap bounds total supply, mitigating over-minting from operational errors or a compromise.

Expand All @@ -97,7 +97,7 @@ Holding and trading on the secondary market is permissionless. KYC only happens

**Security and audits:** tokenized stocks are B20 native precompiles, not separately deployed contracts, so there is no per-asset contract and no per-address verified contract on Basescan (precompiles hold no bytecode). B20 shipped in Base's Beryl upgrade on code audited by Base and Spearbit, with ongoing Cantina (smart contract) and HackerOne (offchain and infrastructure) bug-bounty coverage. Every token shares the same audited implementation.

## Price feeds
## Price Feeds

A tokenized stock's price is available from both onchain and offchain sources. In every case, the price is derived from the same relationship: the underlying equity's market price scaled by the token's multiplier.

Expand Down Expand Up @@ -156,13 +156,13 @@ Two common patterns are used to determine value:
- Directly reading the token's market price from a provider that tracks the B20 asset.
- Reading the underlying reference price and applying the multiplier calculation manually.

### Historical data
### Historical Data

For historical OHLC and time-series data, use market-data providers or query Chainlink round history by `roundId`.

Since prices are total-return (multiplier-adjusted), reconstruct the series consistently by applying the multiplier history ([`MultiplierUpdated`](/specifications/b20/reference/interfaces/ib20-asset) events, emitted by both scheduled and instant multiplier changes) if starting from raw share prices.

## Contract addresses
## Contract Addresses

| Ticker | Contract address |
|--------|------------------|
Expand All @@ -181,7 +181,7 @@ Since prices are total-return (multiplier-adjusted), reconstruct the series cons
| SPCXc | `0xb2000000000000000000007b9fcbd005511aCBd5` |
| TSLAc | `0xb2000000000000000000001e800a7f5189430cD0` |

## Additional resources
## Additional Resources

- [B20 Standard](/specifications/b20/specification-overview)
- [Base Standard Library](https://github.com/base/base-std/tree/main)
Expand Down
Loading
Loading