Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

rebalancing-bot

Keeps the rioswap (Uniswap v3 fork on Realio Network) tWBTC/tUSDC and tETH/tUSDC pools at the CoinGecko market price.

Every KEEPER_INTERVAL_MINUTES it:

  1. fetches BTC, ETH and USDC prices from CoinGecko (one request), target = base_usd / usdc_usd;
  2. reads each pool's slot0 and skips it if it's within KEEPER_DEVIATION_BPS of the target;
  3. otherwise swaps through the SwapRouter with exactInputSingle, sqrtPriceLimitX96 = the target price and amountIn = min(KEEPER_MAX_SWAP_USD worth, wallet balance).

The price limit does the sizing: the pool stops exactly at the target and the router only pulls the tokens actually used, so there's no liquidity math to get wrong. If the cap runs out first the price moves part-way and the next tick finishes the job.

Pairs live in src/config.ts (PAIRS); chain and contract addresses in src/chains.ts and deployments/.

Run

pnpm install
cp .env.example .env          # fill KEEPER_PRIVATE_KEY, keep KEEPER_DRY_RUN=true at first

pnpm once                     # one pass, then exit
pnpm start                    # loop in the foreground (Ctrl-C to stop after the current tick)

Run it in the background (settings from .env, logs in logs/):

pnpm keeper:start     # no-op if one is already running
pnpm keeper:status    # pid, uptime, swaps today, last log lines
pnpm keeper:restart   # e.g. after editing .env
pnpm keeper:stop      # finishes the current tick (incl. an in-flight swap) first

Restarts are safe: only one keeper can hold logs/keeper.lock (a stale lock from a killed process is taken over), a new run waits for any tx the previous run left pending, and the daily USD cap is rebuilt from logs/trades.jsonl instead of resetting.

Set KEEPER_DRY_RUN=false to actually trade. In dry-run it still reports deviation, the direction and size it would trade, and the simulated output (once the router has an allowance).

Wallet

The keeper wallet needs RIO for gas plus inventory on both sides: it sells tUSDC when the pool is under the market and tWBTC/tETH when it's over. On testnet the tokens have faucet() and an open mint(). Approvals to the router are sent automatically the first time a token is sold.

Safety limits

Env Default
KEEPER_DEVIATION_BPS 30 ignore smaller gaps (0.30%)
KEEPER_MAX_SWAP_USD 20000 max value sold per swap
KEEPER_MAX_DAILY_USD 500000 max value sold per UTC day (survives restarts via the trade log)
KEEPER_MAX_PRICE_AGE_SEC 600 skip stale CoinGecko data
KEEPER_MAX_PRICE_JUMP_PCT 15 a bigger tick-to-tick move waits one tick for confirmation

Test

pnpm test        # price math
pnpm typecheck

To try real swaps without touching testnet, fork it with anvil and point the keeper at it:

anvil --fork-url https://json-rpc.realiostage.network --chain-id 3300 --port 18545
# mint test tokens to anvil account 0 with `cast send <token> "mint(address,uint256)" ...`
KEEPER_RPC_URL=http://127.0.0.1:18545 KEEPER_DRY_RUN=false \
KEEPER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
pnpm once

The key above is anvil's well-known default account 0 — only ever use it against a local fork.

Secrets

All wallet keys and per-deployment settings live in .env (gitignored). Never commit .env or logs/ — the logs contain the operating wallet's address and trade history.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages