← back to blog

Setup guide: Proxy rotation strategy for 100 wallet operations

Setup guide: Proxy rotation strategy for 100 wallet operations

Running 100 wallets from one IP address is not a strategy, it’s a ban waiting to happen. Most airdrop programs, particularly EVM-based testnets and Sybil-sensitive campaigns, fingerprint wallet clusters by shared IP ranges. If ten of your wallets touch the same faucet from the same /24 subnet inside an hour, the risk engine flags the whole batch. I’ve watched operators lose hundreds of hours of farming work because they treated proxies as an afterthought.

This guide is for people already comfortable with multi-wallet setups who want to move from ad-hoc proxy use to a structured rotation system. you should already have wallet generation handled and a basic scripting environment. what we’re building here is the IP layer: a rotation strategy that assigns clean, distinct exit nodes to each wallet group, handles failures gracefully, and scales without requiring you to babysit it. by the end, your 100-wallet operation will have a documented IP assignment scheme, automated health checks, and a fallback rotation pool.

The outcome is deterministic IP isolation per wallet session. wallet A always exits through proxy slot A until you explicitly rotate it. wallet B through slot B. if a proxy slot dies, the system pulls from a warm standby pool rather than collapsing to your datacenter IP.

what you need

proxy infrastructure - a residential rotating proxy provider with sticky session support. i currently use Bright Data (formerly Luminati) for the sticky pool, around $15/GB for residential. Oxylabs and IPRoyal are viable alternatives at similar price points. - minimum 100 unique sticky session endpoints. most providers let you parameterise the session ID directly in the proxy username string. - optionally, a secondary datacenter pool for low-risk read operations (checking balances, querying explorers). these run around $2-4/GB from providers like Webshare or Proxy-Cheap.

local environment - python 3.10+ with requests, httpx, and pyyaml installed - a VPS or local machine with at least 2GB RAM (you’ll be holding 100 persistent sessions) - a proxy manager. i use mitmproxy for inspection during setup, then switch to a plain python rotation script for production. some operators use ProxyMesh or Goproxy for this layer but i find them overkill for sub-500 wallet setups.

accounts and config - provider API key or credential string - a wallets.yaml or similar file mapping wallet address to assigned proxy slot - a spreadsheet or database row tracking last-used IP per wallet (SQLite works fine)

rough cost at 100 wallets - residential proxies: $30-60/month depending on traffic volume - VPS: $5-10/month (a cheap DigitalOcean or Hetzner instance is enough) - total: under $80/month at this scale

step by step

step 1: understand sticky sessions and what you’re actually buying

Before touching any code, read your provider’s sticky session documentation carefully. HTTP proxy authentication works by embedding session parameters in the proxy username field. for Bright Data, the format looks like:

username: brd-customer-CUSTOMER_ID-zone-residential-session-SESSION_ID
password: YOUR_PASSWORD
host: brd.superproxy.io
port: 22225

the SESSION_ID string is what locks you to an exit node. you can set it to anything. i set it to a hash of the wallet address so the mapping is self-documenting. sticky sessions typically last 10-30 minutes depending on the provider’s terms. after expiry, the same session string may resolve to a different exit node, which is usually fine, as long as you’re not doing rapid successive requests that look like session hijacking to the target application.

if it breaks: session IDs with special characters sometimes get URL-encoded in transit. stick to alphanumeric strings only.

step 2: generate your session-to-wallet mapping

create a yaml file that maps each wallet address to a deterministic session ID:

import hashlib
import yaml

wallets = [
    "0xABCD...",  # repeat for all 100
]

mapping = {}
for wallet in wallets:
    session_id = hashlib.sha256(wallet.encode()).hexdigest()[:16]
    mapping[wallet] = {
        "session_id": session_id,
        "proxy_slot": f"brd-customer-CUSTOMER_ID-zone-residential-session-{session_id}",
        "status": "active"
    }

with open("wallet_proxy_map.yaml", "w") as f:
    yaml.dump(mapping, f)

this gives you a stable, reproducible mapping. if you re-run it tomorrow the same wallet always gets the same session string. keep this file out of version control.

if it breaks: if a wallet’s session keeps rotating despite the same ID, your provider may have a session cap per account. check your plan limits and contact support.

step 3: build a proxy dispatcher class

rather than configuring proxies inline per request, centralise them in a dispatcher:

import yaml
import requests

class ProxyDispatcher:
    def __init__(self, map_file="wallet_proxy_map.yaml"):
        with open(map_file) as f:
            self.mapping = yaml.safe_load(f)
        self.password = "YOUR_PASSWORD"
        self.host = "brd.superproxy.io"
        self.port = 22225

    def get_proxy(self, wallet_address):
        entry = self.mapping.get(wallet_address)
        if not entry or entry["status"] != "active":
            return self.get_fallback_proxy()
        username = entry["proxy_slot"]
        proxy_url = f"http://{username}:{self.password}@{self.host}:{self.port}"
        return {"http": proxy_url, "https": proxy_url}

    def get_fallback_proxy(self):
        # pull from your secondary datacenter pool
        return {"http": "http://dc_user:[email protected]:8080",
                "https": "http://dc_user:[email protected]:8080"}

dispatcher = ProxyDispatcher()

def make_request(wallet, url):
    proxies = dispatcher.get_proxy(wallet)
    return requests.get(url, proxies=proxies, timeout=15)

if it breaks: if you’re seeing ProxyError: Cannot connect to proxy, verify the proxy host and port directly with curl first: curl -x http://user:pass@host:port https://ipinfo.io/json.

step 4: run health checks before the session

a dead proxy slot costs you time during an operation. run a pre-flight check across all 100 slots before starting a farming run:

import concurrent.futures

def check_proxy(wallet, proxy_config):
    try:
        resp = requests.get(
            "https://ipinfo.io/json",
            proxies=proxy_config,
            timeout=10
        )
        data = resp.json()
        return wallet, data.get("ip"), True
    except Exception as e:
        return wallet, None, False

def preflight_check(dispatcher, wallets):
    results = {}
    with concurrent.futures.ThreadPoolExecutor(max_workers=20) as ex:
        futures = {
            ex.submit(check_proxy, w, dispatcher.get_proxy(w)): w
            for w in wallets
        }
        for future in concurrent.futures.as_completed(futures):
            wallet, ip, ok = future.result()
            results[wallet] = {"ip": ip, "ok": ok}
            if not ok:
                dispatcher.mapping[wallet]["status"] = "degraded"
    return results

log the results to a file. if more than 10% of slots fail the preflight, pause and investigate before running your operation. this saves you from submitting transactions that silently fall back to your real IP.

if it breaks: some providers block ipinfo.io. try https://api.ipify.org?format=json instead.

step 5: enforce IP uniqueness across the batch

after the preflight, verify that no two wallets resolved to the same exit IP:

from collections import Counter

ip_counts = Counter(v["ip"] for v in results.values() if v["ok"])
duplicates = {ip: count for ip, count in ip_counts.items() if count > 1}

if duplicates:
    print("WARNING: IP collisions detected:", duplicates)

if collisions appear, mark those wallets for manual re-assignment and rotate their session IDs before proceeding. one shared IP across two wallets is enough to create a linkability vector.

if it breaks: residential proxies in the same pool can occasionally resolve to the same exit node despite different session IDs. this is a provider-side issue. if it’s persistent, switch those wallets to a different zone or provider.

step 6: integrate with your farming script

once the dispatcher and health checks are working, integration is mechanical. wherever your existing script makes outbound requests, pass the proxy through the dispatcher:

wallets = list(dispatcher.mapping.keys())
for wallet in wallets:
    response = make_request(wallet, "https://target-protocol.xyz/api/faucet")
    # handle response

for async scripts using httpx, the pattern is the same, just pass proxies= to the AsyncClient. see the Python HTTPX proxy documentation for async-specific configuration.

if it breaks: websocket connections do not inherit HTTP proxy settings by default. if your target protocol uses websockets for wallet interaction, you need a separate ws proxy configuration. this is a common source of IP leaks.

step 7: log and persist IP assignments

write each wallet’s resolved IP and operation timestamp to SQLite after each run. this lets you audit the operation, check for drift in sticky session assignments, and spot if a provider is recycling IPs faster than advertised:

import sqlite3, datetime

conn = sqlite3.connect("proxy_log.db")
conn.execute("""
    CREATE TABLE IF NOT EXISTS ip_log (
        wallet TEXT,
        ip TEXT,
        timestamp TEXT,
        success INTEGER
    )
""")

for wallet, info in results.items():
    conn.execute("INSERT INTO ip_log VALUES (?, ?, ?, ?)",
        (wallet, info["ip"], datetime.datetime.utcnow().isoformat(), int(info["ok"])))
conn.commit()

step 8: schedule automatic rotation

every 2-3 days, rotate the session IDs for wallets that have completed their current protocol interaction. this prevents long-term IP fingerprinting even within a provider’s pool:

import random, string

def rotate_session(wallet, mapping):
    new_id = ''.join(random.choices(string.ascii_lowercase + string.digits, k=16))
    mapping[wallet]["session_id"] = new_id
    mapping[wallet]["proxy_slot"] = f"brd-customer-CUSTOMER_ID-zone-residential-session-{new_id}"
    return new_id

do not rotate mid-operation. rotate only between protocol interactions when wallet identity continuity doesn’t matter.

common pitfalls

using the same proxy pool for all protocols. different campaigns have different risk tolerances. mixing high-value mainnet interactions with testnet faucet claims in the same session pool is unnecessary risk. keep separate pools and mappings per protocol.

ignoring the subnet, not just the IP. two IPs that look different may share a /24 or /16 subnet. some Sybil detection systems flag at the subnet level, not the individual IP. check ipinfo.io’s org field in your preflight results. if multiple wallet slots resolve to the same ASN block, investigate.

trusting provider uptime without monitoring. residential proxy providers have outages. if you start a 100-wallet run at 2am without a pre-flight check, you may complete the entire run over your server’s real IP after a silent proxy failure. always run preflight checks. always.

websocket IP leaks. as mentioned in step 6, websocket connections bypass standard HTTP proxy settings in most frameworks. protocols that use ws:// for wallet interactions will leak your real IP unless explicitly configured. this is covered in more depth at antidetectreview.org’s multi-wallet proxy guide.

not rotating after a wallet is flagged. if a wallet address gets Sybil-flagged, immediately retire its proxy slot. the IP is now associated with a flagged address in that protocol’s data. continuing to use it for other wallets contaminates them.

scaling this

at 10 wallets, a single residential provider plan and a manual yaml mapping is fine. no dispatcher needed, you can just hardcode session IDs.

at 100 wallets, the setup above is the right level. the dispatcher class, automated health checks, and SQLite logging become necessary. you’ll spend $50-80/month on residential proxies.

at 1000 wallets, this architecture still works but needs a few additions. first, you need multiple provider accounts or zones, because a single provider account with 1000 sticky sessions may hit API rate limits or raise flags on the provider’s side. second, health check parallelism needs tuning, running 1000 concurrent health checks will exhaust most VPS network buffers. batch them in groups of 50. third, consider a dedicated proxy rotation layer like Goproxy or a commercial proxy gateway that handles failover internally. at this scale the per-GB cost also changes, negotiate a dedicated residential pool directly with providers.

the HTTP/1.1 proxy authentication standard is worth reading if you want to understand what’s actually happening at the protocol level when you authenticate through a proxy. knowing this helps when debugging unusual proxy errors that your provider’s support team can’t explain.

where to go next

Written by Xavier Fok

disclosure: this article may contain affiliate links. if you buy through them we may earn a commission at no extra cost to you. verdicts are independent of payouts. last reviewed by Xavier Fok on 2026-05-19.

need infra for this today?