Skip to main content
The B20 native token standard ships with the Base Beryl upgrade. CDP SQL API indexes all B20-related events on Base Mainnet and Base Sepolia so you can query them with standard SQL—no custom indexer required.
B20 data is available once the Beryl upgrade activates on each network:
NetworkActivation
Base SepoliaJune 18, 2026
Base MainnetJune 25, 2026 at 18:00 UTC

Where B20 data lives

B20 events are decoded into the existing base.events table (or base_sepolia.events on testnet). Each row uses the same schema as other decoded logs: event_name, event_signature, parameters, address, block_timestamp, and more. Query B20 activity by filtering on:
  • event_signature — the canonical event ABI (preferred over event_name for performance; put this first in WHERE clauses for best query performance)
  • address — a specific B20 token contract, or the singleton B20 Factory / Policy Registry contract when querying factory or policy-registry events
For token-level events, filter on the token’s address once you know which B20 you are tracking. B20 token addresses are deterministic and share a recognizable prefix derived from the B20 address scheme.

Indexed event types

B20 token events

These events are emitted by individual B20 token precompiles:
EventSignature
TransferTransfer(address,address,uint256)
ApprovalApproval(address,address,uint256)
MemoMemo(address,bytes32)
BurnedBlockedBurnedBlocked(address,address,uint256)
RoleGrantedRoleGranted(bytes32,address,address)
RoleRevokedRoleRevoked(bytes32,address,address)
RoleAdminChangedRoleAdminChanged(bytes32,bytes32,bytes32)
LastAdminRenouncedLastAdminRenounced(address)
PausedPaused(address,uint8[])
UnpausedUnpaused(address,uint8[])
PolicyUpdatedPolicyUpdated(bytes32,uint64,uint64)
SupplyCapUpdatedSupplyCapUpdated(address,uint256,uint256)
ContractURIUpdatedContractURIUpdated()
NameUpdatedNameUpdated(address,string)
SymbolUpdatedSymbolUpdated(address,string)
EIP712DomainChangedEIP712DomainChanged()
Asset-variant tokens also emit:
EventSignature
MultiplierUpdatedMultiplierUpdated(uint256)
ExtraMetadataUpdatedExtraMetadataUpdated(string,string)
AnnouncementAnnouncement(address,string,string,string)
EndAnnouncementEndAnnouncement(string)

B20 Factory events

Token creation events are emitted by the singleton B20 Factory precompile:
EventSignature
B20CreatedB20Created(address,uint8,string,string,uint8,bytes)

Policy Registry events

B20 transfer policies are managed through the Policy Registry precompile at 0x8453000000000000000000000000000000000002. Query these events with that address and the matching event_signature:
EventSignature
PolicyCreatedPolicyCreated(uint64,address,uint8)
PolicyAdminStagedPolicyAdminStaged(uint64,address,address)
PolicyAdminUpdatedPolicyAdminUpdated(uint64,address,address)
AllowlistUpdatedAllowlistUpdated(uint64,address,bool,address[])
BlocklistUpdatedBlocklistUpdated(uint64,address,bool,address[])
For the full B20 interface specification, see the Base Standard Library.

Example queries

Try these in the SQL Playground before integrating programmatically.

Recent B20 token transfers

Replace {token_address} with the B20 token you are tracking:
SELECT
  block_timestamp,
  transaction_hash,
  parameters['from'] AS from_address,
  parameters['to'] AS to_address,
  parameters['value'] AS amount
FROM base.events
WHERE event_signature = 'Transfer(address,address,uint256)'
  AND address = '{token_address}'
  AND action = 'added'
ORDER BY block_timestamp DESC
LIMIT 100;

New B20 tokens created

Track deployments from the B20 Factory precompile at 0xB20f000000000000000000000000000000000000:
SELECT
  block_timestamp,
  transaction_hash,
  parameters['token'] AS token_address,
  parameters['name'] AS name,
  parameters['symbol'] AS symbol,
  parameters['decimals'] AS decimals
FROM base.events
WHERE event_signature = 'B20Created(address,uint8,string,string,uint8,bytes)'
  AND address = '0xB20f000000000000000000000000000000000000'
  AND action = 'added'
ORDER BY block_timestamp DESC
LIMIT 50;

Transfers with payment memos

B20 memo operations emit a Memo event immediately after the primary operation event. Join adjacent logs in the same transaction:
SELECT
  t.block_timestamp,
  t.transaction_hash,
  t.address AS token_address,
  t.parameters['from'] AS from_address,
  t.parameters['to'] AS to_address,
  t.parameters['value'] AS amount,
  m.parameters['memo'] AS memo
FROM base.events t
JOIN base.events m
  ON t.transaction_hash = m.transaction_hash
  AND m.address = t.address
  AND m.log_index = t.log_index + 1
WHERE t.event_signature = 'Transfer(address,address,uint256)'
  AND m.event_signature = 'Memo(address,bytes32)'
  AND t.address = '{token_address}'
  AND t.action = 'added'
  AND m.action = 'added'
ORDER BY t.block_timestamp DESC
LIMIT 100;

Policy and compliance activity

Monitor when an issuer updates transfer policies on a token:
SELECT
  block_timestamp,
  transaction_hash,
  address AS token_address,
  parameters['policyScope'] AS policy_scope,
  parameters['oldPolicyId'] AS old_policy_id,
  parameters['newPolicyId'] AS new_policy_id
FROM base.events
WHERE event_signature = 'PolicyUpdated(bytes32,uint64,uint64)'
  AND address = '{token_address}'
  AND action = 'added'
ORDER BY block_timestamp DESC
LIMIT 50;

Query tips

Follow the SQL API best practices when querying B20 data:
  1. Filter on indexed columns — use event_signature, address, and block_timestamp in your WHERE clause.
  2. Scope to active logs — add action = 'added' to exclude re-orged events, or aggregate by log_id if you need re-org-safe totals.
  3. Use network prefixes — query base_sepolia.events on testnet and base.events on mainnet.
  4. Join memos by log index — memo events follow their parent operation at log_index + 1 within the same transaction and contract (m.address = t.address).

Learn more