Self-Mine into Locked Liquidity
Enroll a wallet once, then point your miner's payout at it — and every block you mine is automatically zapped into the exchange's LIQUA/mUSDC AMM pool, with the resulting LP time-locked for you on a rolling term. It turns raw mining emission directly into deep, provable, locked liquidity. This is the hands-off cousin of Mining + ve-lock staking.
Real mining happens on the Liqua pool (Mining, :8030). This feature lives on
the orderbook-DEX (orderbook-dex/, a Hardhat EVM). A relayer mirrors your mined LIQUA onto
the exchange and the SelfMineLiquidity contract locks it as AMM liquidity. Run npm install
once in orderbook-dex/.
How it works
Three moving parts: you mine (any miner, paid to your address) · the relayer delivers that emission to the locker · the contract zaps it into the pool and locks the LP.
your wallet ──mines──▶ emission (LIQUA)
relayer (emitter) ──accrueFor(you, amount)──▶ SelfMineLiquidity
│ zap: swap ~half LIQUA → mUSDC at the live price
├─▶ addLiquidity → mint LP
└─▶ LOCK the LP for you · unlock = now + term (rolling)
The lock term is rolling: every accrual refreshes your unlock to now + term, so your
liquidity stays locked the full term ahead as long as you keep mining — the strongest proof-of-lock. Only you
can withdraw, and only after you stop and the term elapses. The relayer can deliver emission and nothing else — it can
never touch a miner's locked LP.
Quick start
From orderbook-dex/ — bring up the exchange, then the driver:
npm run chain # local EVM
npm run deploy:local # deploys the LIQUA/mUSDC pool + SelfMineLiquidity
npm run relayer # exchange + UI on :8080
npm run self-mine # the driver (watches the pool) · or --demo to self-drive
Then open localhost:8080/self-mine.html, connect your wallet, pick a term, and enroll. Keep mining to that same address (see Mining) and your locked liquidity grows every block.
Enroll & the rolling term
Enrolling just authorizes auto-locking — it moves no funds. You pick a rolling term between MIN_TERM
(1 day) and MAX_TERM (1460 days = 4 years, matching the ve-lock cap).
| Call | Who | Effect |
|---|---|---|
enroll(term) | you | opt in / start auto-locking with this rolling term |
setTerm(term) | you | change your term (applies to future accruals) |
disable() | you | stop auto-locking — freezes your unlock; never unlocks early |
accrueFor(miner, amount) | emitter only | deliver a block's emission → zap → lock; refreshes unlockAt |
withdraw() | you | after disable + term elapsed → returns your LP token |
The zap · single-sided, self-funded
Your emission is pure LIQUA, but an x·y=k pool needs both sides. The locker computes the optimal slice to swap (UniV2 0.30% closed form), swaps it for mUSDC at the live price, then adds both sides and mints LP. A clean invariant falls out:
The pool's LIQUA reserve grows by exactly the mined amount; the mUSDC reserve is borrowed for the swap and returned by the mint, so it nets out unchanged. You contribute value purely in LIQUA — no treasury drain — and the LP you hold is a real claim on the grown pool.
Withdraw
While enrolled, accruals keep pushing unlockAt forward, so you can't withdraw — that's the point. To
exit: disable() (freezes the unlock), wait out the term, then withdraw(). You receive the
InfinityPool LP token itself — burn it at the pool to redeem your share of LIQUA + mUSDC, or keep /
use it elsewhere (it's a real, transferable position).
The relayer
scripts/self-mine-relayer.js is the self-mining driver. It polls the live pool's per-miner
paid (the PPLNS reward, keyed by the wallet before the .worker suffix) and delivers each
enrolled miner's new emission via accrueFor.
npm run self-mine # watch the live pool (:8030) and lock enrolled miners' emission
node scripts/self-mine-relayer.js --demo # self-drive without a pool (fixed emission per enrolled miner)
node scripts/self-mine-relayer.js --once # one pass, then exit
node scripts/self-mine-relayer.js --miner 0x… --amount 25 # one manual delivery
The mined LIQUA lives on the molecular pool's chain; the exchange's LIQUA is a separate ERC-20. So — exactly like the wrapped-LIQUA bridge relayer — the driver is a trusted devnet authority: for every LIQUA you earn it delivers the same amount of exchange-LIQUA from a capped emission reserve. It conjures no value beyond that reserve and moves no user's funds. For a real launch, swap the reserve for a receipt-verifying mint (see the bridge relayer).
Contract & API
SelfMineLiquidity.sol holds the per-miner positions and does the
zap+lock. Read it (and drive enroll/withdraw) over the exchange on :8080:
| Read | Returns |
|---|---|
positionOf(addr) | enrolled · term · unlockAt · withdrawable · lp · liquaIn · accruals · secondsLeft |
page(start, n) | the proof-of-lock roll — miner · locked LP · unlock |
previewZap(amount) | the swap slice + mUSDC out for a given LIQUA amount |
totalLpLocked() · totalLiquaZapped() | aggregate locked LP · lifetime LIQUA self-mined |
The browser UI (frontend/self-mine.html, served at :8080/self-mine.html) renders all of this
— your position, the live pool reserves, and the full proof-of-lock list. See the
API reference for the service.
Verify it
npx hardhat test # 68 passing (12 self-mine + 56 existing)
# the self-mine suite proves: enroll · accrue→zap→LOCK · single-sided invariant ·
# rolling unlock · withdraw gated to disable+term · emitter-only · proof-of-lock page
Next: mine into it, stake & lock manually, or see the whole stack on the ecosystem map.