# ERC-8463: Pool Liquidity Locks

> Robinhood Chain testnet (46630). Test tokens, no value. Reference contracts not audited. These are drafts under review, not standards.

A draft under review on ethereum/ERCs. One interface for any contract that locks pool liquidity (v2 pool tokens, v3 and v4 positions).

Status: Testnet only.

- Pull request: https://github.com/ethereum/ERCs/pull/2107
- Text pinned at the pull request's head commit d9e55a3349d4f001aff09e5911d71d2390406979 (ERCS/erc-8463.md, CC0): https://github.com/priors-agents/ERCs/blob/d9e55a3349d4f001aff09e5911d71d2390406979/ERCS/erc-8463.md
- Discussion: https://ethereum-magicians.org/t/erc-8463-liquidity-locks/30028
- Reference implementation: https://github.com/priors-agents/erc-liquidity-locks/tree/6db5a5171798d1069f08499a8160ea4e7d9beaf0 (commit 6db5a5171798d1069f08499a8160ea4e7d9beaf0)
- This page: https://lab.priors.trade/erc/8463

## Abstract

This proposal defines an interface for a contract that holds pool liquidity under locks: a locker. A lock is either a quantity of fungible pool tokens, an [ERC-20](https://eips.ethereum.org/EIPS/eip-20) token whose balance is a share of a pool, or one position held as an [ERC-721](https://eips.ethereum.org/EIPS/eip-721) token of a position manager. Each lock names its pool, the position, the liquidity locked, the time it unlocks or that it never does, the account that receives the liquidity at release, and the account paid the position's fees meanwhile. A locker lists its locks by pool and sums them per pool into permanent and timed liquidity with the earliest unlock time, so scanners, launchpads and lenders read any conforming locker with one integration. Which lockers to count stays the reader's choice; the interface makes that choice checkable against what the locker holds.

## Specification headings

1. Interface
2. Locks
3. Creating locks
4. Holding
5. Extending
6. Releasing
7. Fees
8. Reading
9. Detector inputs

## At Priors

Nothing at Priors runs this draft. Its reference contracts go on the testnet only.

## Try it on testnet (46630)

Every action is prepared as an unsigned transaction { chainId: 46630, to, data, value }, signed by your own wallet or testnet key. Test tokens have no value.

Contracts:

- liquidityLocker: 0xf161B0d86746fAf7C88C4B3Cc560f7025e0423e9 (https://explorer.testnet.chain.robinhood.com/address/0xf161B0d86746fAf7C88C4B3Cc560f7025e0423e9)
- positionManager: 0x94781fB93f69ed3cA208f294D1d0A25476367E6e (https://explorer.testnet.chain.robinhood.com/address/0x94781fB93f69ed3cA208f294D1d0A25476367E6e)
- poolFactory: 0x2B60aB8ABfD1661fcF86c803cff19Edbd694D708 (https://explorer.testnet.chain.robinhood.com/address/0x2B60aB8ABfD1661fcF86c803cff19Edbd694D708)

Launch a token: ERC-8462's `launch` creates a test token, seeds its pool against the Lab Test Dollar, locks the liquidity (ERC-8463), declares the launch (ERC-8462) and registers the creator fee stream (ERC-8459), in one transaction. Read each back with the reads below and on the ERC-8462, ERC-8463 and ERC-8459 pages. Every token launched on the lab is a visitor's test token, not verified: anyone can launch one on the lab, and the lab vouches for none.

Actions:

- `create_pool_token`: Create a pool token of your own (LabPoolToken: its whole supply minted once to you, no fee, no setting). Who signs: anyone (its first holder) Params: `token_b` (The pool's other token (any token address, such as one you launched), address), `token_a` (The pool's first token (empty: the lab's test dollar), address, optional, default (the lab's)), `supply` (How many pool tokens, in base units (18 decimals: 1000000000000000000 is one), uint, optional, default 1000000000000000000000).
- `approve_pool_tokens`: Let the locker take pool tokens. Who signs: the holder Params: `pool_token` (The pool token (one of your own, or a launch's after its release), address), `amount` (How many, in base units, uint), `contract` (Your own locker's address (empty: the lab's shared one), address, optional).
- `lock_pool_tokens`: Lock pool tokens. Who signs: the holder Params: `pool_token` (The pool token, address), `amount` (How many, in base units, uint), `unlock_at` (Until (unix seconds, +7d, permanent), time), `beneficiary` (Who receives them at release, address), `contract` (Your own locker's address (empty: the lab's shared one), address, optional).
- `mint_position`: Mint a mock position (the reference's MockPositionManager; its pool follows from its tokens and fee). Who signs: anyone Params: `to` (Who owns it, address), `token0` (The first token, address), `token1` (The second token, address), `fee` (The fee tier, uint, optional, default 3000), `liquidity` (Its liquidity, uint).
- `approve_position`: Let the locker take a position. Who signs: the position's owner Params: `token_id` (The position, uint), `contract` (Your own locker's address (empty: the lab's shared one), address, optional).
- `lock_position`: Lock a position. Who signs: the position's owner Params: `token_id` (The position, uint), `unlock_at` (Until (unix seconds, +7d, permanent), time), `beneficiary` (Who receives it at release, address), `fee_recipient` (Who is paid its fees meanwhile, address), `contract` (Your own locker's address (empty: the lab's shared one), address, optional).
- `extend_lock`: Extend a lock. Who signs: the lock's beneficiary Params: `lock_id` (The lock, uint), `unlock_at` (The new, later unlock time, time), `contract` (Your own locker's address (empty: the lab's shared one), address, optional).
- `release_lock`: Release a lock that has lapsed. Who signs: anyone, at or after its unlock time Params: `lock_id` (The lock, uint), `contract` (Your own locker's address (empty: the lab's shared one), address, optional).
- `collect_fees`: Collect a locked position's fees. Who signs: anyone (they go to the fee recipient) Params: `lock_id` (The lock, uint), `contract` (Your own locker's address (empty: the lab's shared one), address, optional).
- `accrue_fees`: Credit fees to a mock position. Who signs: anyone (a mock) Params: `token_id` (The position, uint), `owed0` (Fees in token0, uint), `owed1` (Fees in token1, uint).

Reads:

- `lock`: One lock. Params: `lock_id` (The lock, uint), `contract` (Your own locker's address (empty: the lab's shared one), address, optional).
- `locked_liquidity`: A pool's locked liquidity, and for a pool token how much of its supply that is. Params: `pool` (The pool, address), `pool_id` (Its id in a singleton manager (empty: none), bytes32, optional, default 0x0000000000000000000000000000000000000000000000000000000000000000), `contract` (Your own locker's address (empty: the lab's shared one), address, optional).
- `pool_of`: The pool of two tokens and a fee, as the lab's pool factory computes it (no one can set or move it). Params: `token0` (One token, address), `token1` (The other token, address), `fee` (The fee tier, uint, optional, default 3000).
- `position`: A mock position: its owner, tokens, fee, liquidity and pool; and the id the next mint gets. Params: `token_id` (The position (empty: only the next id), uint, optional).
- `locks_of_pool`: A pool's locks. Params: `pool` (The pool, address), `pool_id` (Its id (empty: none), bytes32, optional, default 0x0000000000000000000000000000000000000000000000000000000000000000), `start` (From, uint, optional, default 0), `limit` (At most, uint, optional, default 20), `contract` (Your own locker's address (empty: the lab's shared one), address, optional).

Deploy your own:

- `locker`: Your own LiquidityLocker over a position manager. Params: `position_manager` (The position manager (empty: the lab's mock), address, optional, default (the lab's)).

## With an agent

- MCP (Streamable HTTP): https://lab.priors.trade/mcp. Tools for this draft: `lab_erc(8463)`, `lab_setup(address)`, `lab_read(8463, read, params)`, `lab_prepare(8463, action, params)`, `lab_deploy_prepare(8463, deploy, params)`, `lab_check_contract(8463, chain, address)`, `lab_feedback_draft(8463, note, txHash?)`.
- HTTP: https://lab.priors.trade/openapi.json describes GET https://lab.priors.trade/api/lab/erc/8463, /api/lab/read/8463/{read}, /api/lab/prepare/8463/{action}, /api/lab/deploy/8463/{deploy}, /api/lab/check/8463/{chain}/{address} and /api/lab/setup/{address}.

A prompt to give your agent:

```text
Use the Priors lab on Robinhood Chain testnet (chain id 46630), where every token is a test token of no value. Its MCP server is https://lab.priors.trade/mcp and this draft's page is https://lab.priors.trade/erc/8463.md. Try ERC-8463, Pool Liquidity Locks (a draft under review). Start with lab_setup for my testnet address to see my test ETH, test dollars and identities, then create a pool token of your own (labpooltoken: its whole supply minted once to you, no fee, no setting), then let the locker take pool tokens, then lock pool tokens, then mint a mock position (the reference's mockpositionmanager; its pool follows from its tokens and fee), then let the locker take a position, then lock a position with lab_prepare(8463, <action>, params). Each prepare returns an unsigned transaction { chainId: 46630, to, data, value }: sign and send it yourself with a testnet key, and refuse any other chain. Never ask me for a key. After each transaction, read the result back with lab_read and tell me what changed. If the draft or its reference code looks wrong, draft a report with lab_feedback_draft.
```

## Check a contract

Any address on testnet or mainnet: supportsInterface(0x15d36c4a) and the views, read only (`lab_check_contract`, or GET https://lab.priors.trade/api/lab/check/8463/{chain}/{address}).

## Feedback

The discussion of the text belongs in its thread: https://ethereum-magicians.org/t/erc-8463-liquidity-locks/30028. A bug in the reference implementation goes to its repository's issues: https://github.com/priors-agents/erc-liquidity-locks/issues (a new one: https://github.com/priors-agents/erc-liquidity-locks/issues/new). The text under review: https://github.com/ethereum/ERCs/pull/2107/files. `lab_feedback_draft` writes the report; the lab posts nothing for anyone.
