Phase 4 — Compare Pools
Add a yield scanner that checks all Cetus pools every 30 minutes. The agent reports which pools are earning the most so you can decide whether to move your funds.
Time: ~5 minutes | Requires: Phase 2 complete (Phase 3 optional)
The idea
Your agent is earning fees in one pool (SUI/USDC). But Cetus has 70+ pools. Some may be earning significantly more. This phase adds a scanner that periodically checks yield across all Cetus pools using DeFiLlama’s public API.
The scanner runs alongside your existing position management. It doesn’t move funds — it gives you data to decide.
New code: yield scanner
Add to agent.js:
import https from 'https';
const YIELD_SCAN_INTERVAL = 6; // every 6th cycle (30 min at 5-min intervals)
let cycleCount = 0;
async function fetchDefiLlamaYields() {
return new Promise((resolve, reject) => {
https.get('https://yields.llama.fi/pools', (res) => {
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => {
try { resolve(JSON.parse(data).data || []); }
catch (e) { reject(e); }
});
}).on('error', reject);
});
}
async function scanYields() {
try {
const allPools = await fetchDefiLlamaYields();
const suiPools = allPools.filter(p => p.chain === 'Sui');
// Top Cetus pools by APY
const cetusPools = suiPools
.filter(p => p.project === 'cetus-clmm')
.sort((a, b) => (b.apy || 0) - (a.apy || 0))
.slice(0, 10)
.map(p => ({
symbol: p.symbol,
apy: parseFloat((p.apy || 0).toFixed(2)),
tvl: Math.round(p.tvlUsd || 0),
}));
// Find our pool
const allCetus = suiPools.filter(p => p.project === 'cetus-clmm');
const ourPool = allCetus.find(p => (p.symbol || '').match(/USDC.*SUI|SUI.*USDC/i));
log('event', 'yield_scan', {
cetusTopPools: cetusPools,
currentPool: {
symbol: 'SUI/USDC',
apy: ourPool ? parseFloat((ourPool.apy || 0).toFixed(2)) : null,
tvl: ourPool ? Math.round(ourPool.tvlUsd || 0) : null,
rank: ourPool ? allCetus.sort((a, b) => (b.apy || 0) - (a.apy || 0)).indexOf(ourPool) + 1 : null,
},
scanTime: new Date().toISOString(),
});
log('info', 'Yield scan complete', { poolsFound: cetusPools.length });
} catch (err) {
log('warn', 'Yield scan failed', { error: err.message });
}
}Add to the main loop
Run the scan on startup and every 6th cycle:
// In runAgent(), before the main while loop:
await scanYields();
// Inside the while loop, after runCycle():
cycleCount++;
if (cycleCount % YIELD_SCAN_INTERVAL === 0) {
await scanYields();
}What it logs
Every 30 minutes, the agent logs a yield_scan event:
{
"message": "yield_scan",
"cetusTopPools": [
{ "symbol": "WAL-SUI", "apy": 131.7, "tvl": 116180 },
{ "symbol": "DEEP-SUI", "apy": 73.8, "tvl": 747154 },
{ "symbol": "CETUS-SUI", "apy": 34.1, "tvl": 1522870 }
],
"currentPool": { "symbol": "SUI/USDC", "apy": 24.3, "rank": 13 }
}Higher APY pools exist — but they often have higher risk (smaller TVL, newer tokens, more volatility). The data helps you make an informed decision.
Future: auto-migration
In a future version, the agent could automatically move funds to the best pool. This adds complexity (slippage, migration gas costs, risk scoring) but the monitoring groundwork is here.
Next step
Why limit yourself to one protocol? Phase 5 — Compare Protocols scans yield across all of Sui — lending protocols, other DEXes, and more.