Розробка системи управління кошельками для airdrop-фарминга
Airdrop-фарминг у 2024-2025 — це професійна діяльність з сотнями кошельків, систематичними on-chain транзакціями й роботою з десятками протоколів одночасно. Ручне управління не масштабується: занадто багато повторюючихся операцій, занадто висок ризик помилок, занадто складно відслідковувати прогрес по кожному кошельку. Система автоматизації — обов'язковий інструмент для серйозного фармера.
Що таке професійний airdrop-фарминг
Аналіз крупних airdrop-ів (Arbitrum, Optimism, ZkSync, LayerZero, EigenLayer) показує паттерни, які були награджені: регулярна активність протягом багатьох місяців, різноманітність протоколів, нативні транзакції (не просто bridging), утримання токенів, участь у governance. Система повинна автоматизувати саме ці паттерни, зберігаючи органічність активності.
Архітектура системи
Ієрархія кошельків
Професійний фармер працює з кількома рівнями ключів:
Master Wallet — холодний кошелек (Ledger/Trezor або air-gapped машина). Зберігає основний капітал. Ніколи не використовується безпосередньо у протоколах.
Fund Wallets (2-5 штук) — проміжні кошельки для розподілу. Отримують ETH/USDC від master, розподіляють по farming wallets.
Farming Wallets (50-500 штук) — робочі кошельки, що безпосередньо взаємодіють із протоколами. Кожен генерується як окремий HD-шлях від однієї або кількох seed фраз.
Master Wallet
↓ (manual transfers)
Fund Wallets [1-5]
↓ (automated distribution)
Farming Wallets [50-500]
↓ (automated interactions)
DeFi Protocols
Важливо: farming wallets не повинні мати прямих on-chain зв'язків з master wallet. Ланцюг fund wallet → farming wallet з різними часовими інтервалами зменшує кореляцію.
Генерація й зберігання ключів
Все farming wallets генеруються детерміновано з seed фраз по BIP44:
import { HDNodeWallet, Mnemonic } from "ethers";
function generateFarmingWallets(
mnemonic: string,
count: number,
startIndex: number = 0
): WalletInfo[] {
const masterNode = HDNodeWallet.fromMnemonic(
Mnemonic.fromPhrase(mnemonic)
).derivePath("m/44'/60'/0'/0");
return Array.from({ length: count }, (_, i) => {
const wallet = masterNode.deriveChild(startIndex + i);
return {
index: startIndex + i,
address: wallet.address,
privateKey: wallet.privateKey,
derivationPath: `m/44'/60'/0'/0/${startIndex + i}`,
};
});
}
Зберігання. Ніколи не зберігаємо private keys у открытому вигляді. Варіанти:
- Шифрування через AES-256-GCM з паролем (KDF: Argon2id)
- Зберігання лише seed phrase + on-demand деривація
- HashiCorp Vault для командного використання
База даних кошельків й активності
CREATE TABLE wallets (
id SERIAL PRIMARY KEY,
address VARCHAR(42) UNIQUE NOT NULL,
derivation_path VARCHAR(64),
wallet_group VARCHAR(64), -- для групування
created_at TIMESTAMPTZ DEFAULT NOW(),
last_active_at TIMESTAMPTZ,
total_gas_spent NUMERIC(30, 18) DEFAULT 0,
notes TEXT,
tags TEXT[]
);
CREATE TABLE protocol_interactions (
id BIGSERIAL PRIMARY KEY,
wallet_id INTEGER REFERENCES wallets(id),
protocol VARCHAR(128) NOT NULL,
chain_id INTEGER NOT NULL,
tx_hash VARCHAR(66),
action_type VARCHAR(64), -- swap, bridge, stake, lp, vote
amount NUMERIC(30, 18),
gas_used NUMERIC(30, 18),
executed_at TIMESTAMPTZ DEFAULT NOW(),
status VARCHAR(16) DEFAULT 'pending',
metadata JSONB
);
CREATE TABLE farming_tasks (
id BIGSERIAL PRIMARY KEY,
wallet_id INTEGER REFERENCES wallets(id),
task_type VARCHAR(128) NOT NULL,
protocol VARCHAR(128) NOT NULL,
chain_id INTEGER NOT NULL,
parameters JSONB NOT NULL,
scheduled_at TIMESTAMPTZ,
executed_at TIMESTAMPTZ,
status VARCHAR(16) DEFAULT 'pending',
retry_count INTEGER DEFAULT 0,
error_message TEXT
);
Автоматизація взаємодій
Task Runner
Система виконання задач повинна імітувати людське поведінку: випадкові затримки між транзакціями, варіативне час суток, різні gas prices.
class FarmingTaskRunner {
async executeTask(task: FarmingTask): Promise<TxReceipt> {
const wallet = await this.walletManager.getWallet(task.walletId);
const provider = this.getProvider(task.chainId);
// Випадкова затримка 30с - 5 хв перед транзакцією
const delay = randomBetween(30_000, 300_000);
await sleep(delay);
// Випадкова варіація gas price на ±10%
const gasPrice = await this.getGasWithVariance(provider, 0.1);
const handler = this.handlers.get(task.taskType);
if (!handler) throw new Error(`Unknown task type: ${task.taskType}`);
return handler.execute(wallet, task.parameters, { gasPrice });
}
private async getGasWithVariance(provider: Provider, variance: number) {
const feeData = await provider.getFeeData();
const base = feeData.maxFeePerGas!;
const multiplier = 1 + (Math.random() * 2 - 1) * variance;
return base * BigInt(Math.round(multiplier * 100)) / 100n;
}
}
Protocol Handlers
Для кожного протоколу — окремий handler:
// Приклад: Uniswap V3 swap handler
class UniswapV3SwapHandler implements ProtocolHandler {
async execute(
wallet: Wallet,
params: SwapParams,
options: ExecutionOptions
): Promise<TxReceipt> {
const router = new Contract(UNISWAP_V3_ROUTER, ROUTER_ABI, wallet);
const deadline = Math.floor(Date.now() / 1000) + 1800; // 30 хв
const tx = await router.exactInputSingle({
tokenIn: params.tokenIn,
tokenOut: params.tokenOut,
fee: params.fee, // 500, 3000, 10000
recipient: wallet.address,
deadline,
amountIn: params.amountIn,
amountOutMinimum: params.minAmountOut,
sqrtPriceLimitX96: 0,
}, {
maxFeePerGas: options.gasPrice,
maxPriorityFeePerGas: options.maxPriorityFeePerGas,
});
return tx.wait();
}
}
Аналогічні handlers створюються для: Curve, AAVE, GMX, Stargate, Wormhole/LayerZero bridge, Pendle, різних lending протоколів.
Планировщик задач
Задачи планюються з урахуванням: мінімального інтервалу між транзакціями на одному кошельку, часових окон активності, залежностей (спочатку отримати токени, потім stake).
class TaskScheduler {
async scheduleForWallet(walletId: number, plan: FarmingPlan) {
const tasks: ScheduledTask[] = [];
let currentTime = plan.startTime;
for (const action of plan.actions) {
// Випадковий сдвиг до ±20% від planned interval
const variance = action.interval * 0.2;
const jitter = (Math.random() * 2 - 1) * variance;
currentTime = new Date(currentTime.getTime() + action.interval + jitter);
tasks.push({
walletId,
taskType: action.type,
protocol: action.protocol,
chainId: action.chainId,
parameters: action.params,
scheduledAt: currentTime,
});
}
await this.db.farmingTasks.bulkInsert(tasks);
}
}
Моніторинг й аналітика
Dashboard метрик
Для кожного кошелька система повинна показувати:
- On-chain активність по протоколам (з датами першої/останньої транзакції)
- Потрачений gas (у USD)
- Поточні позиції (LP, стейкинг, lending)
- Score по відомим метриках (об'єм, кількість транзакцій, унікальні протоколи, дні активності)
- Поточний баланс по цепям
interface WalletStats {
address: string;
totalTxCount: number;
activeDays: number; // унікальних днів з транзакціями
uniqueProtocols: number;
totalVolumeUSD: number;
totalGasSpentUSD: number;
chainActivity: Record<number, ChainActivity>;
protocolActivity: ProtocolActivity[];
estimatedAirdropScore: Record<string, number>; // project -> estimated score
}
Оцінка airdrop eligibility
Для кожного відстеженого проекту — набір on-chain критеріїв з вагами. Система автоматично розраховує поточний score кожного кошелька й видає рекомендації що ще потрібно зробити.
Anti-sybil захист
Сучасні airdrop-системи (EigenLayer, Wormhole) активно борються з sybil-атаками. Система повинна враховувати:
Унікальність активності. Не копіювати паттерни між кошельками. Різні суми, різні протоколи, різні часові паттерни.
IP ротація. Кожен кошелек або група кошельків працює через окремий proxy/VPN. Загальний IP = сильний sybil-сигнал.
Source of Funds. Ланцюг фінансування не повинен простежуватися до одного джерела. CEX withdrawals на різні кошельки — добре. Прямий переводить з одного кошелька на 100 — погано.
Age of Wallet. Старі кошельки цінуються більше. Система повинна створювати кошельки заблаговременно й давати їм "історію" до цільового дедлайна.
Газ й економіка
При роботі з 200 кошельками, 3-5 транзакціями в день на кошелек — важна газова оптимізація:
- Транзакції на L2 (Arbitrum, Base, Optimism) у 10-50x дешевше mainnet
- Batching: якщо протокол підтримує multicall — об'єднувати операції
- Gas price monitoring: транзакції у періоди низького gas (ніч UTC)
- Автоматичний розрахунок мінімального балансу ETH на кожному кошельку
Стек
| Компонент | Технологія |
|---|---|
| Backend | Node.js + TypeScript, Fastify |
| Task queue | Bull + Redis |
| Database | PostgreSQL + TimescaleDB |
| Blockchain | ethers.js v6, viem |
| RPC | Alchemy, Infura (з failover) |
| Proxy | SOCKS5 ротація (Bright Data, Oxylabs) |
| Frontend | React + TanStack Query |
| Monitoring | Grafana + Prometheus |
Сроки
- MVP (генерація кошельків, базові handlers для 3-5 протоколів, dashboard): 4-6 тижнів
- Production (20+ handlers, планировщик, analytics, anti-sybil): 10-14 тижнів
- Підтримка й оновлення під нові протоколи: ongoing







