5.3 KiB
evelyn-liquidity-service Specification
Purpose
Realize Evelyn's manually funded EVE/SyrupUSDC concentrated liquidity into USDC payouts using one dedicated wallet and current on-chain state.
Requirements
Requirement: Owned positions qualify by their normalized upper boundary
The service SHALL discover positions owned by its wallet in its configured CLMM pool and withdraw positive liquidity only when the upper EVE/SyrupUSDC boundary U satisfies U <= P*(1-h/100). P SHALL come from a fresh on-chain pool read for each owned positive-liquidity position after NFT discovery and previous withdrawals have completed. The same state SHALL be used for that position's eligibility decision and withdrawal quote; an earlier position's price SHALL NOT be reused. Both orientations SHALL be normalized, and decisions SHALL use pool precision. Unusable P SHALL skip the remaining withdrawals in that iteration while allowing later steps.
Scenario: Inclusive threshold and upper boundary
- WHEN P is 15, h is 10 and positions span 13–13.5 and 13.5–14
- THEN only the first qualifies, including equality
Scenario: Reversed pool ordering
- WHEN mint A is SyrupUSDC and mint B is EVE
- THEN the inverted lower raw boundary determines the normalized upper price and the same eligibility rule applies
Scenario: Other or empty positions and falling market
- WHEN a position belongs to another wallet or pool, has zero liquidity, or its upper boundary exceeds the threshold after a price decline
- THEN it retains its state and the service neither withdraws it nor creates or refills positions
Scenario: Price declines during discovery or an earlier withdrawal
- WHEN a position qualifies before discovery or an earlier withdrawal, but its upper boundary exceeds the threshold at the new pool price
- THEN the service reads that new price before deciding and preserves the position's liquidity in either token orientation
Scenario: Pool read fails between positions
- WHEN an earlier position was withdrawn but the next current pool price is unavailable or unusable
- THEN no remaining position is withdrawn in that iteration and swap and payout still run on their independent balances
Requirement: Swap and payout use independent current balances
The service SHALL read SyrupUSDC at step 2 and USDC at step 3 and operate on the entire respective balance above its nonnegative reserve. Absent or at/below-reserve balances SHALL be skipped. Exact-input swap SHALL use explicit maximum slippage. SPL payout SHALL target the configured wallet owner with existing account-creation support. Amounts SHALL never round upward. EVE and reward tokens SHALL remain untouched by this pipeline.
Scenario: Nonzero reserves
- WHEN SyrupUSDC balance is 1.01 with reserve 0.01 and USDC balance is 2.5 with reserve 0.5
- THEN 1.00 SyrupUSDC is swapped and 2.0 USDC is sent
Scenario: Zero reserves and empty accounts
- WHEN reserves are zero
- THEN full positive balances are eligible, absent/zero balances are skipped and empty source accounts are not closed
Requirement: Failure recovery uses on-chain state
Each iteration SHALL attempt withdrawal, swap and payout independently in that order, isolating ordinary per-position failures. Subsequent iterations and restarts SHALL reread positions and balances without a persistent queue, attribution, pending-signature gate, immediate retries or replay. Logs SHALL identify operations, positions, amounts and returned signatures without signer secrets. Interruption SHALL stop work.
Scenario: Independent failures and restart
- WHEN withdrawal or swap fails or returns an unknown outcome
- THEN independent later work can proceed and the next iteration or restart acts on current state, skipping completed empty positions
Requirement: Configuration is validated before worker start
A dedicated version-1 runtime configuration SHALL validate wallet/signer binding, pool type/token identity, address syntax, 0<=h<100, positive fixed delay, nonnegative reserves with mint precision and explicit slippage limits. Currencies, mints and programs SHALL use canonical identity and chain metadata. The public example SHALL have zero reserves and SHALL never be a runtime fallback.
Scenario: Invalid input or missing deployment file
- WHEN configuration is invalid or only the example exists
- THEN startup fails before financial work
Requirement: Optional process owns a sequential worker
The Hub SHALL select evelyn.liquidity.prod through its existing catalogue and Registry, constructing deployment configuration and dedicated signer/swap dependencies only when selected. Existing selections and ordering SHALL be preserved. The domain interface SHALL expose no lifecycle operations. A single worker SHALL run the first and subsequent iterations identically, with a fixed delay after completion and ordinary shutdown interruption.
Scenario: Optional process is omitted
- WHEN the Hub plan omits evelyn.liquidity.prod
- THEN no liquidity configuration or dedicated signer is loaded and the checked-in Hub example activates no financial operation
Scenario: Slow iteration and shutdown
- WHEN an iteration exceeds the configured interval or shutdown interrupts it
- THEN no iterations overlap and interruption prevents further steps