matter-labs / matter-labs/block-explorer

Base token is never added to the tokens DB on ZKsync OS chains

Open
#652 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
139
Forks
145
Avg merge
8h 3m
Merged PRs (30d)
3

Description

### Bug Report

#### Description

On ZKsync OS chains the base token never appears in the tokens DB, so it is missing from the token list and can never receive off-chain data (price, icon).

Root cause: the worker only creates the base token row when a contract exists at `0x800a`. On ZKsync OS there is no ERC-20-style contract there. The VM handles the base token as native account state and a system hook intercepts all calls to `0x800a`, reverting on everything except the withdraw selectors, so `name()/symbol()/decimals()` always revert.

- `addBaseToken()` (`packages/worker/src/token/token.service.ts:189`) requires an existing address row for `0x800a` to satisfy the Token entity's non-null `blockNumber`/`transactionHash`/`logIndex` (FKs to blocks/transactions), so it silently skips. The TODO on line 190 already notes this.
- The fallback path in `transaction.processor.ts:125` only fires when the data-fetcher emits a token with `l2Address == 0x800a`, which never happens without a deployment event.

This affects every ZKsync OS chain regardless of what `BASE_TOKEN_*` env vars are set to, since the config values are only written through the `0x800a` code paths.

Note: base token identity is available on-chain if wanted. On protocol v31 the L2 NativeTokenVault (`0x10004`) exposes `BASE_TOKEN_NAME()/BASE_TOKEN_SYMBOL()/BASE_TOKEN_DECIMALS()/BASE_TOKEN_ORIGIN_TOKEN()`. On v30.x, `NTV.WETH_TOKEN()` returns the wrapped base token, whose `l1Address()` getter holds the base token's L1 address.

#### Reproduction Steps

1. Run the explorer against any ZKsync OS chain with `BASE_TOKEN_*` env vars configured.
2. Query `/tokens` on the API.

#### Expected Behavior

The base token is listed with the configured (or on-chain) metadata and can be matched by the off-chain data updater.

#### Current Behavior

The base token row is never created. `addBaseToken()` is a silent no-op.

#### Possible Solution

Allow the base token row to exist without deployment provenance (e.g. nullable `blockNumber`/`transactionHash`/`logIndex` or a synthetic genesis anchor) and populate it from config and/or the NTV getters. Overlaps with the direction proposed in #455, related symptom in #403.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with addBaseToken() in packages/worker/src/token/token.service.ts and the fallback in packages/worker/src/transaction/transaction.processor.ts. Inspect the Token entity constraints and the direction in #455, then compare the v31 NativeTokenVault getters with the v30.x WETH_TOKEN path. Done means the configured or on-chain base token appears in /tokens and can receive off-chain metadata.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend, blockchain, database
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.