# Discover v4 pools

A token is a Signal v4 launch when a reviewed Signal factory bore it. A ticker, a picture, an API search hit or a pool that merely contains the token proves nothing.

## The birth events

Every launch emits one `Launched` from its factory. Release 4.2 also emits `Details` in the same transaction.

```solidity
event Launched(
    bytes32 indexed id,          // the Uniswap v4 pool id
    address indexed token,
    address indexed creator,     // the launching wallet
    address quote,               // the pair asset
    bool rewards,                // true: a holders token
    uint16 poolFeeBps,
    uint16 buyTaxBps,
    uint16 sellTaxBps,
    uint16 protocolBps,
    Split split,                 // (creator, holders, liquidity, burn, floor), bps
    uint256 firstBuyTokens,      // tokens the launcher's first buy received, 0 if none
    Blocks blocks,               // the launch's optional rules
    Leg[] legs,                  // named co-recipients of the creator side
    Module module,
    uint128 liqBatchQuote
);

event Details(address indexed token, bytes32 metaHash, string uri);
```

| Event | Topic 0 |
| --- | --- |
| `Launched` (4.2 and 4.1) | `0x8fd460cf6081c16be4921e6d01164cb0745944b824325879617eefd6a81b3f7b` |
| `Details` (4.2) | `0x4b87591452f11d5711de01c570b9a9519aa41e8dccd0e5878dc6c53c4eeb4514` |
| `Launched` (release 2) | `0x8a27775651889aee0c899890c76e303ec5efd6b0a63392cecd6a040572142e56` |

Release 2's `Launched` is the same event without the last two fields (`module`, `liqBatchQuote`), so its topic differs.

Decode with the [factory ABI](v4-deployments.md#interfaces); the struct layouts are in it. Scan only the factory addresses in the [deployment record](v4-deployments.md), from each one's first block. Use bounded block ranges, keep a cursor and backfill what you miss. Some public HyperEVM RPC endpoints return an empty result, not an error, for a log range they consider too wide: page in small ranges and confirm a known launch appears before trusting an empty answer.

The event is a trigger. The authority is the hook's own record, read back at a pinned block.

### Another route: the PoolManager

Every pool is created through the PoolManager, so its `Initialize` log names the pool's hook. Filtering `Initialize` by `hooks` in Signal's hook list finds the same pools without a factory ABI. A new Signal hook means a new address to add to that list.

## Confirm the identity at one block

1. `factory.poolOf(token)` returns a non-zero pool id, and `factory.isSignalToken(token)` is true.
2. `hook.terms(id).token` is the token, and `hook.terms(id).quote` is the pair asset you expect.
3. `hook.poolKey(id)` returns `fee = 0`, `tickSpacing = 200`, `hooks` = that hook, and the two currencies are the token and the pair asset in address order.
4. `keccak256(abi.encode(currency0, currency1, fee, tickSpacing, hooks))` equals the pool id.
5. `factory.hook()` is the hook and `hook.factory()` is the factory.
6. On release 4.2, the token's code is the EIP-1167 minimal clone of the plain implementation, or of the holders implementation when `terms.rewards` is true.

The [read-only example](v4-example.md) performs these checks.

## Token facts

| Fact | Where to read it |
| --- | --- |
| Supply and decimals | `totalSupply()` is 1,000,000,000 × 10^18; `decimals()` is 18 |
| Holders token or plain | `rewardsEnabled()`, or `terms.rewards` |
| Pair asset | `terms.quote`; a holders token also exposes `rewardAsset()` |
| Launcher | `Launched.creator`, and `hook.creatorOf(id)` |
| Launch time | `terms.launchTs` (unix seconds) |
| Start price | `terms.startTp`, a tick: price in pair-asset units per token = 1.0001^startTp, before decimals |

## Names can change

A release 4.1 or 4.2 token is a plain ERC-20 with one unusual power: its launcher (`identityOwner()`) can change the token's `name` and `symbol` with `setIdentity`, at most once every 24 hours. The token emits `IdentitySet(string name, string symbol)`, and `bornName()` and `bornSymbol()` keep what it was launched as. The address, the pool and every rule stay the same. Release 2 tokens do not have this: their name and symbol are fixed and these calls revert.

Index a token by address. Refresh the name and ticker on `IdentitySet`. Treat a ticker match as nothing more than a ticker match.

## Words and pictures

`contractURI()` on a 4.2 token returns `https://signal.family/api/meta/0x<token>`, an [ERC-7572](https://eips.ethereum.org/EIPS/eip-7572) document: `name`, `symbol`, `description`, `image`, `website`, `external_link`, `twitter`, `telegram`. The token stores none of it. The factory's `Details` event carries the `uri` the launcher supplied (on current launches a `https://signal.family/m/<hash>` address) and `metaHash = keccak256(bytes(uri))`, the hash of that address string. It records which address the token was launched with. It does not commit to the document's contents, which Signal's server supplies.

All of it is display content supplied by a launcher. Never let it choose a spender, an RPC host, a route or a transaction recipient.

## API-assisted discovery

| Read | Use |
| --- | --- |
| `/api/born?every=1` | Every launch, newest first, in pages. A v4 row has `launch_venue: "v4"` and `pad_addr` = its factory |
| `/api/token/<address>` | The token record with `v4_launch`: pool id, pool key, terms as read at the birth block, and cached hook state |
| `/api/config` | Which factory is open, and the admitted pair assets |

These are indexed views with their own freshness. See the [public data API](api.md). Rebuild durable history from chain logs when your product needs completeness.
