Moro SDK · ResearchReport #3
Moro Swap · Reports · #1 · #2 · #3

Optimisation round 2: one shared memory for every SDK

@moromoro/moro-sdk 1.2.0 → 1.3.0 A/B measured 2026-09-13 HyperEVM · BNB Chain Redis Cloud shared cache credential removed in 1.3.5
TL;DR

1.3.0 ให้ทุก process ของ SDK แชร์สิ่งที่เรียนรู้ผ่าน Redis — pool ไหนไม่มี, pool ไหนว่างเปล่า, token มีกี่ทศนิยม — process ใหม่จึงเริ่มด้วยความรู้ของทุกคนก่อนหน้า ผล: call ลดอีก 25–30 % บน HyperEVM ตั้งแต่ quote แรก, request บน BNB ลด 20 % ราคาเท่าเดิม 0.00 bps ทั้ง 18 กรณี

Round 1 stopped asking about pools that do not exist. Round 2 adds two things: the SDK now notices pools that exist but are empty (a quarter of what was left on HyperEVM) and skips them for an hour, and every SDK process publishes what it learned to a shared Redis so the next process, on any machine, starts warm. Measured with the same A/B protocol against the frozen 1.2.0 build. Δ price 0.00 bps on all 18 cases.

−26 %
pool-state calls · HyperEVM, first quote of a fresh process
432 → 321
−26 %
bytes · HyperEVM
347 KB → 257 KB
−20 %
requests · BNB
46 → 37 over the workload
0.00
Δ price (bps), 18 / 18 cases
same route chosen every time
≈1.2 s
one-time cost per process
Redis connect + first sync

1 · Three versions, one trade (1 HYPE → USDT0, first quote of a fresh process)

v1.1.0 · npm
26 req · 1,217 calls
485 KB · 735 wasted
v1.2.0 · registry
2 req · 432 calls
347 KB · 111 to empty pools
v1.3.0 · shared cache
2 req · 321 calls
257 KB · 0 wasted
v1.1.0v1.2.0v1.3.0

2 · A/B: frozen 1.2.0 build vs 1.3.0, shared cache warmed by another process

chain · pairrequestsinner callsbytesΔ price
HyperEVM · HYPE → USDT02 → 2432 → 321 (−26 %)−26 %0.00 bps
HyperEVM · USDT0 → WHYPE2 → 2401 → 297 (−26 %)−26 %0.00 bps
HyperEVM · kHYPE → USDT03 → 2 (−33 %)568 → 396 (−30 %)−31 %0.00 bps
BNB · BNB → USDT5 → 4 (−20 %)1,351 → 1,190 (−12 %)−17 %0.00 bps
BNB · BUSD → USDT5 → 4 (−20 %)1,351 → 1,190 (−12 %)−17 %0.00 bps
BNB · ETH → CAKE5 → 4 (−20 %)1,351 → 1,190 (−12 %)−17 %0.00 bps

Same route chosen in every case. The first case of each run carries the one-time Redis connect + sync (~1.2 s), which shows up as +14–18 % wall time on that case only; every later quote is 4–31 % faster than 1.2.0.

3 · Why the cache holds facts, not pool state

Before designing the feature we measured the Redis instance from the SDK's point of view:

operationmeasuredconsequence
connect651 mspaid once per process; started in the constructor so the first quote rarely waits the full amount
PING round trip332 msa quote must never wait on Redis → sync once at start (bounded 2 s), then every 30 s in the background
300 KB SET + GET3,037 msslower than fetching the same pool state from the RPC (≈1.0 s) → pool state is not shared; only skip-lists and decimals (a few KB)
What is shared per chain: pools known to be missing (6 h TTL), pools known to be empty (1 h TTL), token decimals (permanent). Writes are batched and fire-and-forget; reads come from memory. A pool that gets liquidity reappears after its TTL.

4 · Trade-offs and what to fix before a public release

5 · Reproduce

# warm the shared cache from one process, then A/B a fresh process against the frozen 1.2.0 build
npx ts-node -T -O '{"module":"commonjs"}' benchmark/quote-quality.ts --chain hyperevm
npx ts-node -T -O '{"module":"commonjs"}' benchmark/ab-test.ts --chain hyperevm --a v1.2.0 --b dist --runs 2 --pause 15000
npx ts-node -T -O '{"module":"commonjs"}' benchmark/ab-test.ts --chain bsc      --a v1.2.0 --b dist --runs 2

Write-up: benchmark/rounds/2.md; raw samples: benchmark/results/2026-09-13-07-0*-round2-v1.3.0.json; code: src/services/sharedCache.ts — on korrio/moro-sdk-optimized. The npm package stays at 1.1.0 until the team publishes.

← Report #2 · All reports Report #3 · Optimisation round 2 · Moro SDK research