# Guide: The Viewer's Own Wallet and Transfer Histories

**Goal:** show the person viewing your app their own balance, token balance, ENS name or identicon, and a list of
recent transfers, without making the app look different to different wallets.

A resolver's arguments are sealed into your app's content hash when you register it. Your users' addresses are not
known then, so an ordinary slot cannot read "the connected wallet". ChainRender has two kinds of slot for this. A
ChainRender viewer fills both of them in the browser, above the on-chain floor (⚙).

## A read of the viewer's wallet

Write `"$viewer"` as the account argument, and leave out `resolver` and `arg`:

```json
{ "type": "slot", "bind": "erc20balance", "argValues": { "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", "account": "$viewer" } }
{ "type": "image", "bind": "gidenticon", "argValues": { "account": "$viewer" }, "alt": "Your identicon" }
```

| Kind | Node | Args |
|---|---|---|
| `balance`, `balanceWei` | slot | `account` |
| `erc20balance`, `erc20balanceRaw` | slot | `token`, `account` |
| `ensName` | slot | `who` |
| `identicon`, `gidenticon` | image | `account` |

No other kind can read the viewer's address (there is no viewer portfolio total).

**What happens:**

1. The builder compiles the slot as a client slot whose arg is the text `cr:viewer;token=0x…;account=$viewer`
   (`viewerReadArg`). The on-chain render shows its fallback text, "Connect your wallet to see this", to everyone.
   That text is the floor.
2. In the viewer, a bar says what the app can show and that the person's address goes to the page's RPC endpoints
   to read it (at least two of them where the chain lists two, because the reads are cross-checked). Nothing is read until the person chooses **Show my wallet's data**. The choice is remembered for that
   app on that device until they choose **Stop showing my data**.
3. The viewer then calls **this chain's** published resolver for the kind (from `chains.json`) with their address,
   and puts the result in the slot as text, or as a validated image. An address the app supplies is never used as
   the resolver. `ensName` is filled only where the chain's `EnsRecordResolver` reads the ENS registry.

The address is never written into the app, the link or the provenance export. It can never decide what the app
shows or does: `"$viewer"` in an action, a signature or a condition is a review error.

## A transfer history

```json
{ "type": "slot", "bind": "transfers",
  "argValues": { "kind": "token-transfers", "account": "$viewer", "token": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", "blocks": "5000", "limit": "20" } }
```

- **`kind`**: `token-transfers`, `erc20-transfers`, `nft-transfers` or `native-transfers`.
- **`account` and `token`:** `account` is `"$viewer"` or an address; `token` is an address. Give at least one of the
  two. A chain-wide history is mostly other people's spam.
- **`blocks`:** 1..45000 (default 5000).
- **`limit`:** 1..50 (default 20).

The viewer reads the chain's logs with paged `eth_getLogs` and states the block window it actually read. Say next to
the table that it covers recent blocks, not all time.

The logs are read the way every value the viewer shows is read (docs/179 §14.11): each
page must come back the same from two of the chain's endpoints, at one block both already have. The caption names the
source, for example "Source: 2 independent endpoints agreed at block N", or "one public endpoint is known for this
chain: not cross-checked". If the endpoints disagree, no row is shown: the slot keeps its fallback and says why. The
builder's preview reads its one configured RPC and says so.

A history is where an attacker can write straight into your page: anyone can emit `Transfer` logs to an address. So
the viewer:

- **Hides zero-value and dust transfers** (an incoming amount below 0.0001 of a token) and counts them. A "Show them" button reveals them, flagged.
- **Flags look-alike addresses:** a counterparty with the same first four and last four hex digits as another address
  in view.
- **Marks tokens your app did not name** as unverified, with their contract address.
- **Shows every address in full,** never shortened.

## Grade

Both are ⚙ above the floor. `grade()` lists `viewer-read` and `transfer-history` in `aboveFloor.kinds`, and the
review reports the app as ⚙ over a floor that grades A, B or C. Report it as ⚙, never as the floor's letter.

## Previewing in the builder

**Preview on-chain floor** and **Render deployed** fill these slots the way the viewer will. If you have connected a
wallet in the builder, they use it. Otherwise they use a sample address, and every filled slot carries a
*sample address* tag. The design-time preview marks them ⚙.

See **[Wallet Connection & Signing](./wallet-and-signing.md)** for actions, and **[Live Data & Events](./live-data-and-events.md)**
for fixed-address reads.
