Event-driven rebalance keeper for automated index rebalancing on Arbitrum. Listens for on-chain RebalanceIntentCreated events, computes optimal swap paths across DAO-registered DEX pools, and submits rebalance() transactions.
Part of the BLOKC Solver Network — a permissionless, zero-barrier solver marketplace where anyone can run an instance and compete for execution quality.
npm install
npm run build
# Dry-run (no transactions)
npm start
# With signing (submits rebalance transactions)
PRIVATE_KEY=0x... npm startRebalanceIntentCreated event
→ Resolve prices (IndexComponentRegistry)
→ Compute deltas (current vs target allocation)
→ Build pool graph (LiquidityPoolRegistry)
→ DFS path finding (multi-hop, same-DEX per step)
→ Multi-hop quoting (DexFacet.quoteExactInput)
→ Proportional matching (deficit-share split)
→ Wait 1 block (IntentBlockDelayNotPassed)
→ Submit rebalance(steps) transaction
src/
index.ts Entry point — WSS event loop + tx submission
types.ts TypeScript types, interfaces, ABI constants
config/
dex-ids.ts DEX identifier hashes + lookup helpers
contracts/
garden.ts GardenClient — rebalance(), encodeRebalance()
registry.ts LiquidityPoolRegistryClient — pool graph
dex-facet.ts DexFacetClient — on-chain swap quoting
solver/
event-listener.ts RebalanceEventListener — WSS subscriptions
intent-processor.ts processRebalanceIntent — pricing, paths, quotes, matching
All via environment variables:
| Variable | Default | Description |
|---|---|---|
PRIVATE_KEY |
(none) | Signer key. If unset, runs dry-run (no txs submitted) |
RPC_URL |
Alchemy Arbitrum | HTTP RPC for reads |
WSS_URL |
Alchemy Arbitrum WSS | WebSocket for event subscriptions |
GARDEN_FACTORY |
0xA6c5... |
GardenFactory address on Arbitrum |
The reference solver uses DFS path finding + DexFacet quoting + proportional matching. You can replace this with any strategy — the relay contract only validates that the output is a well-formed SwapStep[] using DAO-registered pools and DEXs.
To implement a custom strategy, modify src/solver/intent-processor.ts or write your own and swap the import in src/index.ts. Your function must:
- Accept
(IntentEvent, PathFinderConfig, JsonRpcProvider) - Return
Promise<ProcessedIntent>with a validSwapStepData[] - Source all pools from
LiquidityPoolRegistry - Source all prices from
IndexComponentRegistry - Use only
dexIdvalues that map to registered DEXs inFacetRegistry
Competing strategies are compared by the relay's _pickBest() function, which ranks by lowest totalAmountIn. Better strategies win more rebalances.