> For the complete documentation index, see [llms.txt](https://docs.unstable.run/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.unstable.run/on-chain-reference/verification.md).

# Verification

Every contract Unstable ships is intended to be **source-verified on** [**StableScan**](https://stablescan.xyz) — the Etherscan-family explorer for Stable mainnet.

Verification isn't a security feature (bytecode is always public) — it's a **readability** feature. A verified contract shows Solidity source alongside its ABI, so devs, traders, and bots can audit what they're interacting with in seconds instead of decompiling by hand.

## The trick: deterministic bytecode

Unstable's Solidity settings are pinned in `foundry.toml`:

```toml
solc = "0.8.26"
evm_version = "cancun"
optimizer = true
optimizer_runs = 200
via_ir = true
bytecode_hash = "none"
cbor_metadata = false
```

Setting `bytecode_hash = "none"` strips the source-metadata trailer that Solidity normally appends to bytecode. **Every launched `UnstableToken` therefore has identical runtime bytecode** — only the constructor arguments differ.

That gives us auto-verification for free.

## The auto-verify flow

| Step                                                              | Who does it                             |
| ----------------------------------------------------------------- | --------------------------------------- |
| 1. Verify the **Factory** on StableScan (via Etherscan V2 API)    | Unstable team, once                     |
| 2. Verify the **first UnstableToken** ever launched               | Unstable team, once                     |
| 3. Launch any new token via the app                               | You                                     |
| 4. StableScan detects the same bytecode as the verified reference | Automatic — matches on runtime bytecode |
| 5. New token shows up "Verified" on StableScan a few blocks later | Automatic                               |

You never touch a compiler. The result on the token's StableScan page is exactly the same as if you'd verified it yourself: source, ABI, decoded constructor args, everything.

## Verification status of the core contracts

| Contract             | Status                                                                                                                                             |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| **UnstableFactory**  | ✅ Verified. Compiler version, optimizer settings, and source are all public.                                                                       |
| **UnstableToken**    | Auto-matches the verified reference once StableScan indexes the first launch.                                                                      |
| **UnstableLPLocker** | Intentionally unverified during the test phase. Bytecode is on-chain and readable regardless — see [LP position lock](/under-the-hood/lp-lock.md). |

## Verifying manually

If StableScan hasn't picked up your token yet (which is rare, but can happen for the very first launch after a fresh deploy), you can trigger verification manually:

```bash
forge verify-contract \
  --verifier etherscan \
  --verifier-url "https://api.etherscan.io/v2/api?chainid=988" \
  --etherscan-api-key $ETHERSCAN_API_KEY \
  --num-of-optimizations 200 \
  --compiler-version 0.8.26 \
  --via-ir \
  --constructor-args <hex> \
  0xYOUR_TOKEN \
  src/UnstableToken.sol:UnstableToken
```

Where `<hex>` is the ABI-encoded constructor tuple `(name, symbol, supply, metadata)`. You can grab this from the deploy transaction's input data.

But again — you shouldn't need to. The auto-match is doing the work.

## Why not verify the LP Locker?

Source verification is a **UX signal**, not a security guarantee. Every function selector, storage slot, and state transition on the locker is discoverable via bytecode analysis in about five minutes — that data is on-chain and always will be.

During the test phase, the locker's source is intentionally left unverified. This does not:

* Hide the fact that there's an operator address (`admin()` is a public getter — anyone can read it).
* Hide the fee-split constant (`CREATOR_BPS()` is public).
* Hide the emergency-migration function (function selectors are discoverable).

The locker will be verified alongside the production rollout. Until then, everything meaningful about it is already public via `cast call`.

## Next

* [Contract addresses](/on-chain-reference/contracts.md) — the surface area to verify against
* [Events & indexing](/on-chain-reference/events.md) — what to watch off-chain


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.unstable.run/on-chain-reference/verification.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
