Files
com_r35157_nenjim-hubd-impl…/docs/EvelynLiquidityService.md
T

8.0 KiB
Raw Blame History

Evelyn liquidity proceeds

com.r35157.evelyn.service.liquidity.EvelynLiquidityService is a domain-only Nenjim component. impl.ref.EvelynLiquidityServiceImpl additionally implements NenjimProcess; NenjimHub owns startup. The optional process ID is evelyn.liquidity.prod.

The owner creates/funds EVE/SyrupUSDC CLMM positions manually (for example, 10 EVE each) using the dedicated liquidity wallet. This service withdraws, converts and pays proceeds; it never creates, refills, reranges, closes or burns positions, NFTs or source token accounts. A falling price leaves nonqualifying positions intact, including positions whose inventory has returned to EVE.

Deployment

Copy conf/evelyn-liquidity.conf.example to conf/evelyn-liquidity.conf and replace every placeholder. The local runtime file is intentionally ignored by Git. Both begin with FORMAT_VERSION=1; the example is never loaded as a fallback. Unknown, duplicate and missing settings fail validation.

Setting Contract
LIQUIDITY_WALLET Dedicated public Solana wallet address
SIGNER_KEY_NAME Existing external jup key name controlling exactly that address
CLMM_POOL Existing EVE/SyrupUSDC Raydium CLMM pool address
HARVEST_DISTANCE_PERCENT 0 <= h < 100; 10 means ten percent
ITERATION_INTERVAL_SECONDS Positive integer delay after an iteration completes; example 300
USDC_RECIPIENT Recipient wallet owner address, not a token account; must differ from the liquidity wallet
MINIMUM_SYRUPUSDC_RESERVE Nonnegative SyrupUSDC amount; example 0
MINIMUM_USDC_RESERVE Nonnegative USDC amount; example 0
MAXIMUM_SWAP_SLIPPAGE_BPS Explicit Jupiter limit in [0,10000] basis points
MAXIMUM_WITHDRAWAL_SLIPPAGE_BPS Explicit CLMM limit in [0,10000) basis points

The existing SolanaWallet implementation checks the external jup version and key/address binding during construction. No key material belongs in these files. Fund the wallet with SOL for fees and any destination token-account rent. Reserve amounts must be exactly representable at the corresponding mint's precision; 0.01 SyrupUSDC and 0.5 USDC are permitted operating choices. No hidden positive reserve is added.

Only after configuring and funding the wallet, explicitly add evelyn.liquidity.prod to the existing [AUTO_START] section of private conf/NenjimHub.conf. Keep Registry first and Journal second, with no blank line inside the active section. Preserve all existing process selections and their order. This process requires no Ticker, Evelyn status, JavaFX or burner process. The checked-in Hub example continues to select only Registry and Journal.

Deployment configuration and the dedicated signer/wallet, Jupiter and direct Raydium dependencies are constructed only when the selected entry is reached. Registry IDs are solana.wallet.evelyn-liquidity-prod, jupiter.swap.evelyn-liquidity-prod, raydium.service.evelyn-liquidity-prod and evelyn.liquidity.prod. Jupiter signs with this wallet. Currency/mint identities come from CIS; token programs and precision come from chain metadata.

Iteration and recovery

A single worker runs immediately on startup and then with fixed delay after completion. Every iteration follows the same three independent steps:

  1. Read current on-chain pool state in SyrupUSDC per EVE. For each owned, positive-liquidity position in the configured pool, withdraw complete liquidity when its normalized upper boundary satisfies U <= P * (1 - h/100). Equality qualifies. Both token orientations use exact squared Q64.64 comparisons, without display-price rounding. At P=15, h=10, 13–13.5 qualifies and 13.5–14 does not. Withdrawals retain the position and NFT, and return pool-token fees to the same wallet.
  2. Read current SyrupUSDC balance and swap the full balance above its reserve into USDC through the confirmed exact-input Jupiter operation.
  3. Read current USDC balance and send the full balance above its reserve to the recipient owner, creating its ATA at the sender's expense if needed. The transfer submits once and is awaited at CONFIRMED.

Missing/zero balances and balances equal to their reserves are skipped. Amounts are rounded down to mint precision. An unusable positive market price skips withdrawals while retaining steps 2 and 3. EVE returned as principal/fees and other reward tokens remain in the wallet and never enter the conversion/payout pipeline. All available SyrupUSDC/USDC is eligible, including manual deposits.

An ordinary position failure does not block other readable positions. An ordinary step failure does not block later independent steps. Logs identify steps, position NFTs, liquidity/token amounts and returned signatures. Unknown outcomes are logged with signatures when available. Subsequent iterations and restarts reread chain state; there is no service journal, attribution, pending signature gate, immediate retry or transaction replay. Empty positions are skipped and can be manually reused. Shutdown interrupts the current operation and prevents following steps; the reference implementation can also be closed by its local owner through AutoCloseable.

Withdrawal support

The transaction follows the official decrease_liquidity_v2 accounts and decrease/minimum-output behavior, also checked against the official SDK encoder. Withdrawal and closure are separate actions in Raydium's liquidity documentation.

Raydium validates pool/personal-position discriminators, the owned NFT holding, current complete liquidity, mint precision, vaults and tick arrays before signing. Missing destination ATAs are created idempotently in the same transaction, which requests a 600,000 compute-unit limit. The bitmap extension and initialized reward triplets are included when required. The integer principal math matches Raydium's tick algorithm. Minimum principal amounts are floored after applying explicit withdrawal slippage. An amount too small to protect at least one raw unit is rejected. No withdrawal always substitutes zero for both minimums.

The current EVE mint uses Token-2022 metadata pointer/token metadata extensions; SyrupUSDC uses legacy SPL. Read-only mainnet inspection on 2026-10-04 found the EVE/SyrupUSDC pool EpZXeeShz64DK8HfKnjWPTkmhN7dZe77SjvzNDX8CARq with decimals 8/6, tick spacing 60 and no initialized rewards. Deployment still requires an explicit pool setting and repeats validation. Mint close-authority and metadata/ group extensions are supported; other transfer-affecting extensions, including transfer fees/hooks, fail before signing. The withdrawal encoder supports legacy transactions fitting Solana's packet limit and rejects larger account sets.

Offline verification

The Gradle JUnit fixtures exercise exact threshold equality, inversion, raw principal amounts, owner/pool filtering, reserves, independent failures, restart recovery and shutdown. Captured serialized transactions verify account order, full liquidity, minimum output, NFT retention, bitmap/reward accounts and one submission/confirmation attempt. All financial dependencies are controlled; no verification submits live withdrawals, swaps or transfers.

./gradlew compileJava compileTestJava test \
  --tests '*RaydiumClmm*Test' --tests '*EvelynLiquidityServiceImplTest' \
  --tests '*NenjimHubLiquidityConfigurationTest'
openspec validate 89-add-evelyn-liquidity-service --strict
git diff --check

Stop the process/JVM and remove its explicit Hub selection to disable operation. Existing positions and wallet balances remain the recovery state.