From b40eb5466f96f45d97e6d666c88f7f6f2edbbc9c Mon Sep 17 00:00:00 2001 From: nimcon <32712736+nimcon@users.noreply.github.com> Date: Fri, 17 Jul 2026 22:02:53 +0100 Subject: [PATCH] Make wallet key_count configurable via global KEY_COUNT env Every bot derives key_count synthetic keys (wallet addresses) and sends them on each request; the node scans them all, so the default 500 over a wallet with address history can hit the per-wallet coin-fetch limit or time out. Add a global KEY_COUNT env var (default 500, unchanged) so keepers can lower it (e.g. 1-20) when funds live on early derivation indexes. Applied to every bot that builds a CircuitRPCClient. Addresses keeper-bots#1 (issue 2). Issue 1 (fee_per_cost) was already fixed. Issue 3 (KeyError 'expired') is not a current-code bug: SurplusAuctionCoin.expired is a required field the list endpoint always sets, so no bot-side guard is needed. --- .env.example | 2 ++ keeper_bots/announcer_configure_bot.py | 2 +- keeper_bots/announcer_penalize_bot.py | 2 +- keeper_bots/announcer_rewards_bot.py | 2 +- keeper_bots/announcer_update_bot.py | 2 +- keeper_bots/bad_debt_recovery_bot.py | 2 +- keeper_bots/governance_implement_bot.py | 2 +- keeper_bots/governance_veto_bot.py | 2 +- keeper_bots/liquidation_bid_bot.py | 2 +- keeper_bots/liquidation_start_bot.py | 2 +- keeper_bots/oracle_update_bot.py | 2 +- keeper_bots/recharge_bid_bot.py | 2 +- keeper_bots/recharge_start_settle_bot.py | 2 +- keeper_bots/savings_bot.py | 2 +- keeper_bots/stability_fee_transfer_bot.py | 2 +- keeper_bots/statutes_update_bot.py | 2 +- keeper_bots/surplus_bid_bot.py | 2 +- keeper_bots/surplus_start_settle_bot.py | 2 +- keeper_bots/treasury_rebalance_bot.py | 2 +- 19 files changed, 20 insertions(+), 18 deletions(-) diff --git a/.env.example b/.env.example index 36ee154..95a0f2b 100644 --- a/.env.example +++ b/.env.example @@ -19,6 +19,8 @@ OKX_API_LIVE_TRADING_KEY= # <<>> OKX_API_LIVE_TRADING_SECRET= # <<>> OKX_API_LIVE_TRADING_PASSPHRASE= # <<>> FEE_PER_COST="fast" +# Number of wallet addresses (synthetic keys) each bot derives and scans for coins. Keepers usually hold CRT/XCH on the first indexes, so a low count (eg 1-20) is enough and avoids scanning many empty addresses (which can trip the node's per-wallet coin-fetch limit or time out). blank = 500 +KEY_COUNT= OKX_URL=wss://ws.okx.com:8443/ws/v5/public # Base URL for OKX v5 API # Bot specific env vars diff --git a/keeper_bots/announcer_configure_bot.py b/keeper_bots/announcer_configure_bot.py index e661a91..12a20f1 100644 --- a/keeper_bots/announcer_configure_bot.py +++ b/keeper_bots/announcer_configure_bot.py @@ -63,7 +63,7 @@ if not private_key: raise ValueError("No master private key found") -rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost) +rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500"))) async def run_announcer(): diff --git a/keeper_bots/announcer_penalize_bot.py b/keeper_bots/announcer_penalize_bot.py index 01b6acb..2e9a97e 100644 --- a/keeper_bots/announcer_penalize_bot.py +++ b/keeper_bots/announcer_penalize_bot.py @@ -40,7 +40,7 @@ if not private_key: raise ValueError("No master private key found") -rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost) +rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500"))) async def penalize_announcer(announcer_name, rpc_client): diff --git a/keeper_bots/announcer_rewards_bot.py b/keeper_bots/announcer_rewards_bot.py index 1ae8d7e..738d1b2 100644 --- a/keeper_bots/announcer_rewards_bot.py +++ b/keeper_bots/announcer_rewards_bot.py @@ -55,7 +55,7 @@ elif TARGET_PUZZLE_HASH == "": TARGET_PUZZLE_HASH = None -rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost) +rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500"))) async def run_announcer_rewards_bot(): diff --git a/keeper_bots/announcer_update_bot.py b/keeper_bots/announcer_update_bot.py index 91926a2..854fc01 100644 --- a/keeper_bots/announcer_update_bot.py +++ b/keeper_bots/announcer_update_bot.py @@ -74,7 +74,7 @@ async def run_announcer(): UPDATE_THRESHOLD_BPS_ADJ = UPDATE_THRESHOLD_BPS # setting default value log.info("Set default adjusted update threshold [bps]: %s", UPDATE_THRESHOLD_BPS_ADJ) - rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost) + rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500"))) if "testnet" in rpc_url or "localhost" in rpc_url: sym = "XRP-USDT" sym_gate = "XRP_USDT" # Gate.io uses underscore diff --git a/keeper_bots/bad_debt_recovery_bot.py b/keeper_bots/bad_debt_recovery_bot.py index 7685a15..c9b0b2f 100644 --- a/keeper_bots/bad_debt_recovery_bot.py +++ b/keeper_bots/bad_debt_recovery_bot.py @@ -45,7 +45,7 @@ log.error("No master private key found") raise ValueError("No master private key found") -rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost) +rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500"))) async def run_bad_debt_recovery_bot(): diff --git a/keeper_bots/governance_implement_bot.py b/keeper_bots/governance_implement_bot.py index f2304e5..800b0c5 100644 --- a/keeper_bots/governance_implement_bot.py +++ b/keeper_bots/governance_implement_bot.py @@ -46,7 +46,7 @@ async def run_governance_implement_bot(): if not private_key: raise ValueError("No master private key found") - rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost) + rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500"))) try: while True: diff --git a/keeper_bots/governance_veto_bot.py b/keeper_bots/governance_veto_bot.py index 4e60631..22eeb59 100644 --- a/keeper_bots/governance_veto_bot.py +++ b/keeper_bots/governance_veto_bot.py @@ -48,7 +48,7 @@ async def run_governance_veto_bot(): if not args.private_key: raise ValueError("No private key provided") - rpc_client = CircuitRPCClient(args.rpc_url, args.private_key) + rpc_client = CircuitRPCClient(args.rpc_url, args.private_key, key_count=int(os.getenv("KEY_COUNT", "500"))) while True: diff --git a/keeper_bots/liquidation_bid_bot.py b/keeper_bots/liquidation_bid_bot.py index 3bed0e4..c9fc707 100644 --- a/keeper_bots/liquidation_bid_bot.py +++ b/keeper_bots/liquidation_bid_bot.py @@ -95,7 +95,7 @@ class OrderRejectedError(Exception): log.error("No master private key found") raise ValueError("No master private key found") -rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost) +rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500"))) def get_okx_symbols(base_symbol, quote_symbol): diff --git a/keeper_bots/liquidation_start_bot.py b/keeper_bots/liquidation_start_bot.py index 386d5c5..18a44fe 100644 --- a/keeper_bots/liquidation_start_bot.py +++ b/keeper_bots/liquidation_start_bot.py @@ -60,7 +60,7 @@ ) raise -rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost) +rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500"))) async def start_liquidation(vault_name, initiator_puzzle_hash, rpc_client): diff --git a/keeper_bots/oracle_update_bot.py b/keeper_bots/oracle_update_bot.py index 7dd1905..f7951db 100644 --- a/keeper_bots/oracle_update_bot.py +++ b/keeper_bots/oracle_update_bot.py @@ -64,7 +64,7 @@ async def run_oracle(): raise ValueError("No private key provided") rpc_client = CircuitRPCClient( - args.rpc_url, args.private_key, args.add_sig_data, fee_per_cost=args.fee_per_cost + args.rpc_url, args.private_key, args.add_sig_data, fee_per_cost=args.fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500")) ) while True: # update oracle diff --git a/keeper_bots/recharge_bid_bot.py b/keeper_bots/recharge_bid_bot.py index 7782767..a6980a9 100644 --- a/keeper_bots/recharge_bid_bot.py +++ b/keeper_bots/recharge_bid_bot.py @@ -142,7 +142,7 @@ def _env(name: str) -> str | None: "RECHARGE_BID_STARTING_CRT_PRICE must be <= RECHARGE_BID_MAX_CRT_PRICE" ) -rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost) +rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500"))) # Puzzle hashes controlled by us, used to detect when we are already the leading bidder. my_puzzle_hashes = { diff --git a/keeper_bots/recharge_start_settle_bot.py b/keeper_bots/recharge_start_settle_bot.py index d484b2d..e6d3d62 100644 --- a/keeper_bots/recharge_start_settle_bot.py +++ b/keeper_bots/recharge_start_settle_bot.py @@ -58,7 +58,7 @@ async def run_recharge_start_settle_bot(): if not args.private_key: raise ValueError("No private key provided") - rpc_client = CircuitRPCClient(args.rpc_url, args.private_key) + rpc_client = CircuitRPCClient(args.rpc_url, args.private_key, key_count=int(os.getenv("KEY_COUNT", "500"))) while True: diff --git a/keeper_bots/savings_bot.py b/keeper_bots/savings_bot.py index 6a065f4..34f6851 100644 --- a/keeper_bots/savings_bot.py +++ b/keeper_bots/savings_bot.py @@ -45,7 +45,7 @@ log.error("No master private key found") raise ValueError("No master private key found") -rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost) +rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500"))) async def run_savings_job(): diff --git a/keeper_bots/stability_fee_transfer_bot.py b/keeper_bots/stability_fee_transfer_bot.py index d57bb46..5b57bd4 100644 --- a/keeper_bots/stability_fee_transfer_bot.py +++ b/keeper_bots/stability_fee_transfer_bot.py @@ -52,7 +52,7 @@ async def run_stability_fee_transfer_bot(): - rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost) + rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500"))) while True: # get vaults diff --git a/keeper_bots/statutes_update_bot.py b/keeper_bots/statutes_update_bot.py index fa77326..581e01c 100644 --- a/keeper_bots/statutes_update_bot.py +++ b/keeper_bots/statutes_update_bot.py @@ -65,7 +65,7 @@ async def run_statutes(): if not args.private_key: raise ValueError("No private key provided") - rpc_client = CircuitRPCClient(args.rpc_url, args.private_key, args.add_sig_data, fee_per_cost=args.fee_per_cost) + rpc_client = CircuitRPCClient(args.rpc_url, args.private_key, args.add_sig_data, fee_per_cost=args.fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500"))) while True: # Update Statutes price log.info("Updating Statutes Price") diff --git a/keeper_bots/surplus_bid_bot.py b/keeper_bots/surplus_bid_bot.py index e0ffa10..caf7aff 100644 --- a/keeper_bots/surplus_bid_bot.py +++ b/keeper_bots/surplus_bid_bot.py @@ -133,7 +133,7 @@ def _env(name: str) -> str | None: "SURPLUS_BID_STARTING_CRT_PRICE must be >= SURPLUS_BID_MIN_CRT_PRICE" ) -rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost) +rpc_client = CircuitRPCClient(rpc_url, private_key, add_sig_data, fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500"))) # Puzzle hashes controlled by us, used to detect when we are already the leading bidder. my_puzzle_hashes = { diff --git a/keeper_bots/surplus_start_settle_bot.py b/keeper_bots/surplus_start_settle_bot.py index 1d549bd..47db6ca 100644 --- a/keeper_bots/surplus_start_settle_bot.py +++ b/keeper_bots/surplus_start_settle_bot.py @@ -82,7 +82,7 @@ async def run_surplus_start_settle_bot(): raise ValueError("No private key provided") rpc_client = CircuitRPCClient( - args.rpc_url, args.private_key, args.add_sig_data, args.fee_per_cost + args.rpc_url, args.private_key, args.add_sig_data, args.fee_per_cost, key_count=int(os.getenv("KEY_COUNT", "500")) ) while True: diff --git a/keeper_bots/treasury_rebalance_bot.py b/keeper_bots/treasury_rebalance_bot.py index 3ceff70..d97420e 100644 --- a/keeper_bots/treasury_rebalance_bot.py +++ b/keeper_bots/treasury_rebalance_bot.py @@ -37,7 +37,7 @@ async def run_bot(): "--private-key", "-p", type=str, default=os.environ.get("PRIVATE_KEY"), help="Private key for your coins" ) args = parser.parse_args() - rpc_client = CircuitRPCClient(args.base_url, args.private_key) + rpc_client = CircuitRPCClient(args.base_url, args.private_key, key_count=int(os.getenv("KEY_COUNT", "500"))) while True: