> 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/under-the-hood/lp-lock.md).

# LP position lock

Every Unstable launch produces exactly one Uniswap V3 LP position — a **single-sided, full-supply liquidity position** on the token's 1% pool. That position is an ERC-721 NFT owned by the `NonfungiblePositionManager` (NFPM), and its ownership is delivered straight to the **Unstable LP Locker** contract by the factory.

That's what "locked" means: **the position NFT lives at the LP Locker's address, forever.**

## The locker in a picture

```
                              ┌──────────────────────────────────┐
launchToken(...)              │                                  │
       │                      │       Unstable LP Locker         │
       ▼                      │   0xbB027B8210E98a19d7B90929B8   │
┌───────────────┐             │   baA77Ec09F0f96                 │
│   Factory     │             │                                  │
│  0x4865b8...  │  mint NFT   │  positions[token] = {            │
│               ├────────────>│      tokenId,                    │
│               │  recipient: │      creator: your_addr,         │
└───────────────┘  locker     │      treasury: platform_addr,    │
                              │  }                               │
                              │                                  │
                              │  collectFees(token) ← anyone     │
                              │      ├─ 80% USDT → creator       │
                              │      ├─ 80% TOKEN → creator      │
                              │      ├─ 20% USDT → treasury      │
                              │      └─ 20% TOKEN → treasury     │
                              └──────────────────────────────────┘
```

Anyone can `NFPM.ownerOf(positionId)` and see the locker's address. It's provable from a single RPC call.

## What the locker actually does

The locker exposes a small, focused public surface:

| Function                             | Who can call          | What it does                                                                                                                                                        |
| ------------------------------------ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `positions(token) view`              | Anyone                | Returns the position's tokenId + the creator / treasury slots.                                                                                                      |
| `collectFees(token)`                 | Anyone                | Pulls accrued fees from the NFT, splits them 80/20, and sends each share to the slot recipients. See [Fees & creator rewards](/under-the-hood/fees-and-rewards.md). |
| `updateCreator(token, newCreator)`   | Current creator slot  | Rotates the token's fee-recipient address. Only affects future collections.                                                                                         |
| `updateTreasury(token, newTreasury)` | Current treasury slot | Rotates the treasury side. Platform-controlled.                                                                                                                     |
| `admin()`, `CREATOR_BPS()`           | Anyone (view)         | Read the operator address and the immutable split ratio.                                                                                                            |

Fees are the one flow. Everyone can collect; the money still ends up in the right slots.

## What "locked" doesn't mean

Be precise about the trust story: the LP is **held by the locker** — the position NFT sits at the locker's address and nobody but the locker can move it via NFPM. That's on-chain fact.

Whether "locked" also means **impossible to move ever** depends on the locker's `admin` state. In its current configuration Unstable's locker still has an operator address that can execute an emergency migration path (paying pending fees first). That path exists specifically for the **test phase** — to give the team a way to recover positions during early operations. It is **not** a rug vector in practice because:

1. Every action is on-chain and public.
2. The path pays out pending fees to the creator + treasury first (unless explicitly skipped).
3. A rotation to a zero-admin state (`renounceAdmin`) is planned for the production release, which makes the lock truly permanent.

You can check the current admin state yourself:

```bash
cast call 0xbB027B8210E98a19d7B90929B8baA77Ec09F0f96 "admin()(address)"
```

* If the return is `0x0000000000000000000000000000000000000000` → **admin renounced, locker is permanently frozen.**
* Otherwise → an operator address is still set for test-phase emergencies.

Traders looking for the strongest possible lock guarantee should wait for the `admin() == 0x0` reading before treating a token as maximally locked.

## Why hold LP in a locker at all?

Two reasons:

1. **Permissionless fee collection.** Because the position NFT is owned by a contract with a purpose-built `collectFees` function, anyone can trigger a collection and pay you your share. No one has to trust the launcher wallet to route fees onward.
2. **Enforceable 80/20 split.** The split is baked into the locker bytecode as an immutable constant. Even a compromised creator wallet can't sneak more than 80%; even a compromised platform wallet can't sneak more than 20%.

If the LP were held in a normal wallet, both properties evaporate: only that wallet could collect, and the split would depend on whatever off-chain agreement the parties made.

## Locker source & verification

The locker's source is **intentionally unverified on StableScan** during the test phase. This does not mean the source is hidden — the bytecode is on-chain and analyzable, function selectors are 4-byte hashes, and every state slot is readable via `eth_getStorageAt`. Anyone can inspect the deployed code today.

For maximum transparency, the locker will be verified alongside the production rollout — but the *security* guarantees come from the state (`admin == 0x0` after renouncement), not from source visibility.

## Next

* [Fees & creator rewards](/under-the-hood/fees-and-rewards.md) — the flow you actually care about
* [Contract addresses](/on-chain-reference/contracts.md) — exact deployment info
* [Events & indexing](/on-chain-reference/events.md) — how to watch launches, trades, and collections programmatically


---

# 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/under-the-hood/lp-lock.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.
