Skip to Content
RecipesCetus Yield Agent (Sui)

Cetus Yield Agent on Sui

Build a Node.js agent that deposits funds into trading pools on Cetus Protocol (Sui’s largest DEX) and earns a share of every trade. With no private key in your .env.

The recipe is split into five phases. Each phase builds on the previous one. You can stop at any phase and have a working agent.

PhaseWhat it doesTimeRisk level
1. Monitor a PoolWatch pool prices, detect when positions would need repositioning10 minNone (read-only)
2. Earn FeesOpen a position, earn fees, auto-reposition when price moves15 minReal funds at risk
3. Adaptive StrategyAuto-adjust earning zone width based on market volatility5 minSame as Phase 2
4. Compare PoolsScan all Cetus pools and rank by return5 minNone (monitoring)
5. Watch the Sui yield landscapeSee where your Cetus position sits in the broader Sui DeFi landscape5 minNone (monitoring)

What you need

  • Node.js 20+
  • WaaP CLI (npm install -g @human.tech/waap-cli@latest)
  • A WaaP account with SUI for gas. Phase 1 is read-only, so run it on whichever network you intend to trade on — the .env below ships NETWORK=mainnet, and Cetus pool IDs and coin types differ per network, so a Phase 1 run on testnet does not tell you a mainnet pool resolves. If you do start on testnet, set NETWORK=testnet and swap CETUS_POOL_ID for a testnet pool; the ID below is mainnet SUI/USDC.

Project setup

This is shared across all phases:

mkdir cetus-yield-agent && cd cetus-yield-agent npm init -y npm pkg set type=module npm install @cetusprotocol/cetus-sui-clmm-sdk @mysten/sui@^1 bn.js dotenv tslib npm install -g @human.tech/waap-cli@latest

Both pins are load-bearing — do not drop them.

@mysten/sui@^1 — the Cetus CLMM SDK targets the 1.x client API, but declares its peer as >=1.1.2, so an unpinned install pulls 2.x, which removed SuiClient and getFullnodeUrl from @mysten/sui/client. The agent then fails at its first import.

tslib — required by @syntsugar/cc-graph (a transitive dependency of the Cetus SDK) but not declared by it, so npm does not install it for you.

Create a WaaP wallet

waap-cli signup --email youremail+cetus-agent@example.com --password 'YourSecurePassword!' waap-cli whoami # note your Sui address — fund it with SUI # Signing calls below pass --chain sui:mainnet (or sui:testnet) explicitly.

Funding tip: Send native SUI from an exchange (Coinbase, Binance, etc.) directly to your Sui address. Do not bridge ETH. The Sui Bridge creates wrapped ETH, not native SUI, and you need SUI for gas. Reserve at least 0.2 SUI for transaction fees.

Testnet tip: The Sui testnet faucet rate-limits aggressively from VPS and cloud IPs. Use a browser-based faucet if the API faucet fails.

Configuration

Create a .env file. You’ll add to this as you progress through phases:

# Pool (SUI/USDC on Cetus — get pool IDs from app.cetus.zone) CETUS_POOL_ID=0xb8d7d9e66a60c239e7a60110efcf8de6c705580ed924d0dde141f4a0e2c90105 # Agent mode: "monitor" (Phase 1) or "active" (Phase 2+). # Documentation only — the code in these phases does not read it. Which phase you are on is # decided by what runAgent() calls, not by this value. Kept so your .env records your intent. AGENT_MODE=monitor # Strategy REBALANCE_THRESHOLD_TICKS=100 POSITION_RANGE_TICKS=200 CHECK_INTERVAL_MS=300000 # Network NETWORK=mainnet # Sui RPC. REQUIRED — set it. JSON-RPC is deprecated on Mysten's public fullnodes, which is # what @mysten/sui reaches for by default, so balance and object reads fail without this. # The code falls back to the Mysten fullnode if you leave it unset; that fallback is the # broken path, not a working default. Treat an unset SUI_RPC as a misconfiguration. SUI_RPC=https://sui-rpc.publicnode.com

Security model

Every transaction goes through WaaP CLI. The signing key stays inside WaaP’s enclave, so the agent never holds a key at all, and each transaction is separately authorized by the Policy Engine.

LayerWhat it does
SigningThe signature is produced in secure hardware on WaaP’s infrastructure, gated by security policies
Daily limitThe point where you get asked. It reads the day’s running total, not a single transaction: below it — and exactly on it — the agent acts alone; only once a payment would take the total past it are you asked. It never halts the account. Approving one transaction does not clear the condition: while the day’s total stays above the limit, later priced requests keep asking
Your approvalYou answer once, via Telegram or email, and the transaction goes through
No .env secretsNo private key in environment variables or code

Now pick a phase and start building.

Last updated on