Locked liquidity on Uniswap V3
When a bonding curve hits its threshold, the buy that crosses it creates a Uniswap V3 pool on Robinhood Chain, puts the whole raise plus the reserved LP supply into one full-range position, and locks that position in a contract that cannot give it back. This page is the lifecycle, the contracts, and the three layers of proof.
What happens on-chain
VectrBondingCurve.buy() -- realQuoteReserves >= threshold (or curve sold out) --> _graduate()
|
v approve + migrate{value}(token, unsold + LP reserve, quoteAsset, raised)
VectrUniswapMigrator
| 1. pull both sides; native ETH -> WETH (V3 pools are ERC-20 only)
| 2. createAndInitializePoolIfNecessary(token, quote, tier, sqrt(raised / tokens))
| 3. if someone pre-created the pool at a bogus price: swap it back to ours
| 4. NonfungiblePositionManager.mint(full range, recipient = VectrLPLocker)
| 5. burn token dust, quote dust -> platform wallets
v
VectrLPLocker holds position NFT #n forever. Only exit: collect() -> LP fees -> platform walletsThe curve does not wait for a keeper or a multisig. Graduation is a branch inside the buy that crosses the line, so the pool exists in the same transaction as the last curve trade. After it, buy and sell on the curve revert and quotes return zero.
ETH-paired tokens graduate into a token/WETH pool. Stock-paired tokens graduate into a token/stock pool with no WETH involved; the LP fee then accrues in the stock token.
The addresses on Robinhood Chain
- VectrUniswapMigrator
- 0x384EEd2Ba540146FB09E4EE228B454091913F837 Creates the pool, mints the position, hands it to the locker
- VectrLPLocker
- 0xcf489e55a1167Cf883e0EE43D2354fdFc82b2B58 Holds every graduation position. No transfer, no decreaseLiquidity, no burn
- UniswapV3Factory
- 0x1f7d7550b1b028f7571e69a784071f0205fd2efa
- NonfungiblePositionManager
- 0x73991a25c818bf1f1128deaab1492d45638de0d3
- Pool fee tier
- 1.00%Accrues to the locked position; swept to platform wallets by collect()
No withdrawal path, by construction
VectrLPLocker owns every graduation position. It implements no transferFrom, approve, decreaseLiquidity or burn. A test reads the compiled ABI and fails the build if any of them appears. The one function that moves value is collect(tokenId), callable by anyone, which forwards accrued pool fees through the FeeCollector's platform split. Principal never leaves.
Three layers of tests
All in the public contracts repo. The numbers are the test counts at the time of writing; the suite is the source of truth.
- 1. Uniswap's own bytecode, locally
- 19 testsDeploys the artifacts from @uniswap/v3-core, v3-periphery and swap-router-contracts, then the Vectr stack on top. Pool creation, full migration to the wei, price continuity, locker ABI, griefed pools, stock-quoted pools, sell-out graduation, access control.
- 2. Robinhood Chain mainnet, forked
- 4 testsForks the chain in-process and points the migrator at the real Uniswap factory, position manager and WETH. Verified against those contracts, not ours.
- 3. Live
- demo-graduation.tsLaunches a throwaway token on the target network, buys past the line, then checks the result against Uniswap's getPool, ownerOf, positions, a router buy that must match the quoter, a router sell, and a fee sweep. Prints every transaction hash.
cd contracts/token-launchpad
npx hardhat test # layer 1
ROBINHOOD_FORK=1 npx hardhat test test/fork/robinhood-graduation.fork.test.ts # layer 2
FACTORY_ADDRESS=0x... SCALED=1 THRESHOLD=0.02 npx hardhat run scripts/demo-graduation.ts --network robinhood # layer 3Questions people ask
Can the team withdraw the liquidity after graduation?
No. The position NFT is owned by VectrLPLocker, whose compiled ABI exposes no transferFrom, approve, decreaseLiquidity or burn. The only function that moves value is collect(), which pays accrued pool fees to the platform wallets and cannot touch principal. A test reads the ABI and fails if any exit function appears.
What happens to the price at graduation?
The pool is initialised at exactly raised divided by tokens migrated, so the full-range mint absorbs both sides. With the production curve parameters that lands within about 2% of the curve's last spot price.
What if someone creates the pool first at a fake price?
Uniswap pool addresses are deterministic, so anyone can pre-create token/WETH at the graduation tier and initialise it anywhere. The migrator does not revert; it swaps against whatever is there, spending at most its own balance, until the price is back at target, then mints. Both the empty-pool and stray-liquidity cases are tested.
Where do trades go after graduation?
Through Uniswap's SwapRouter02, priced by QuoterV2. The token keeps its address and its Vectr page; only the venue changes. The pool's 1.00% LP fee accrues to the locked position and is swept to the platform wallets.
Keep going
- Launch a tokenThe curve that ends here starts with one transactionLaunch
- Security modelCustody, signing boundary, what the platform can and cannot doRead
- Contract registryEvery verified address on robin.etherscan.ioOpen
- Integrate VectrGraduated event, pool address, and how trades route afterRead docs
- Robinhood Chain for developersRPC, chain ID and the Uniswap V3 deploymentRead
- Contracts sourceThe migrator, the locker and the testsVectr git
Threshold and fee-tier values on this page come from GET /config at render time. Vectr is built on Robinhood Chain and uses the canonical Uniswap V3 deployment; it is not affiliated with Robinhood or Uniswap.