Кейс: як ми вирішили проблему batch-виплат для стартапу на 30 осіб
Стартап із розподіленою командою хотів платити в USDC на Polygon, але кожна виплата вручну через мультисиг забирала години. Для команди з 30 осіб економія на газі при використанні батчевих виплат становить до $1500 на місяць. Батчеві виплати через мультисенд контракт знижують вартість у 3-5 разів. Самостійна розробка має сенс, коли в команді більше 20 осіб, є нестандартні вимоги до токенів або необхідність інтеграції з HR-системою. Готові рішення на кшталт Request Finance або Superfluid не завжди покривають специфіку, тому ми пропонуємо кастомну розробку під ключ.
Ми використовуємо перевірений стек: Solidity 0.8.x для смарт-контрактів, Foundry для тестування, TypeScript для бекенду, Safe SDK для мультисига. На рахунку — понад 10 проєктів з автоматизації виплат у криптовалюті, гарантуємо відповідність стандартам безпеки та compliance.
Як вибрати метод конвертації курсу?
Найболючіше питання — який курс використовувати. Три варіанти:
| Метод | Опис | Ризики | Застосовність |
|---|---|---|---|
| Spot rate на момент виплати | Курс біржі в момент відправлення транзакції | Волатильність на співробітнику | Простий, для частих виплат |
| Фіксований курс за N днів до виплати | Заморожується заздалегідь | Може відрізнятися від ринку | Планування бюджету |
| TWA (Time-Weighted Average) | Середнє за період | Складніший у розрахунках | Справедливий, для великих сум |
Spot rate на момент виплати — найпростіший. Роботодавець бере курс у момент відправлення транзакції. Ризик волатильності несе співробітник.
Фіксований курс за N днів до виплати — знижує волатильність, але вимагає advance planning і може розходитися з ринком на момент виплати.
TWA (Time-Weighted Average) за розрахунковий період — стандарт у традиційних FX-розрахунках, найбільш справедливий, але складніше пояснити співробітникам.
class ExchangeRateService { private sources = [ new ChainlinkPriceFeed(), new CoinGeckoAPI(), new BinanceAPI(), ] async getRate( fromCurrency: string, toCurrency: string, method: 'spot' | 'twap_7d' | 'twap_30d' = 'spot' ): Promise<{ rate: Decimal; source: string; timestamp: Date }> { if (method === 'spot') { for (const source of this.sources) { try { const rate = await source.getSpotRate(fromCurrency, toCurrency) return { rate, source: source.name, timestamp: new Date() } } catch (e) { console.warn(`${source.name} failed:`, e) } } throw new Error(`Cannot get spot rate for ${fromCurrency}/${toCurrency}`) } const days = method === 'twap_7d' ? 7 : 30 const historicalRates = await this.getHistoricalRates(fromCurrency, toCurrency, days) const avgRate = historicalRates.reduce((sum, r) => sum.plus(r), new Decimal(0)) .div(historicalRates.length) return { rate: avgRate, source: 'twap', timestamp: new Date() } } async snapshotForPayroll(run: PayrollRun): Promise<ExchangeRateSnapshot[]> { const tokens = new Set( run.employees.flatMap(e => e.payments.map(p => p.token)) ) const snapshots = await Promise.all( [...tokens].map(async (token) => { const rate = await this.getRate(run.currency, token, 'spot') return { token, ...rate, payrollRunId: run.id } }) ) await this.db.insertRateSnapshots(snapshots) return snapshots } } Чому батчеві виплати економлять газ?
Для Ethereum mainnet виплата кожному співробітнику окремою транзакцією — це дорого. Наприклад, для команди з 30 осіб економія на газі при використанні батчевих виплат може становити до $1500 на місяць. Батчеві виплати через мультисенд контракт знижують вартість у 3-5 разів:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract PayrollDispatcher is Ownable { event PaymentDispatched( bytes32 indexed payrollRunId, address indexed recipient, address indexed token, uint256 amount ); struct Payment { address recipient; address token; uint256 amount; } function dispatchPayroll( bytes32 payrollRunId, Payment[] calldata payments ) external onlyOwner { for (uint256 i = 0; i < payments.length; i++) { Payment calldata p = payments[i]; if (p.token == address(0)) { (bool success,) = p.recipient.call{value: p.amount}(""); require(success, "ETH transfer failed"); } else { require( IERC20(p.token).transferFrom(msg.sender, p.recipient, p.amount), "Token transfer failed" ); } emit PaymentDispatched(payrollRunId, p.recipient, p.token, p.amount); } } receive() external payable {} } Для стейблкоїнів (USDC, USDT) використовуємо transferFrom — джерело коштів залишається на multisig гаманці, контракт лише спрямовує виплати. Це важливо для безпеки: контракт не зберігає кошти.
Мультичейн disbursement
Якщо співробітники отримують зарплату в різних мережах — потрібен окремий disbursement модуль для кожної мережі. Паралельне виконання з агрегацією статусів:
class MultiChainDisbursementService { private dispatchers: Map<string, ChainDispatcher> async executePayrollRun(run: PayrollRun): Promise<DisbursementResult> { const byChain = groupBy( run.employees.flatMap(e => e.payments), p => p.chain ) const results = await Promise.allSettled( Object.entries(byChain).map(([chain, payments]) => this.dispatchers.get(chain)!.dispatch(run.id, payments) ) ) const failures = results.filter(r => r.status === 'rejected') if (failures.length > 0) { await this.handlePartialFailure(run.id, failures) } return this.aggregateResults(results) } } Multi-sig авторизація
Для фондів з AML-вимогами недостатньо одного підпису під виплатою. Стандартна схема: CFO + CEO + фінансовий директор, 2-of-3.
Safe{Wallet} — стандарт для мультисиг операцій. Інтеграція через Safe SDK:
import Safe, { EthersAdapter } from '@safe-global/protocol-kit' import SafeApiKit from '@safe-global/api-kit' class PayrollApprovalService { async proposePayrollTransaction( safeAddress: string, payrollData: PayrollRun, payments: BatchPayment[] ): Promise<string> { const safeSDK = await Safe.create({ ethAdapter, safeAddress }) const apiKit = new SafeApiKit({ txServiceUrl: 'https://safe-transaction-mainnet.safe.global' }) const data = payrollDispatcher.interface.encodeFunctionData( 'dispatchPayroll', [payrollData.id, payments] ) const safeTransaction = await safeSDK.createTransaction({ transactions: [{ to: PAYROLL_DISPATCHER_ADDRESS, data, value: '0' }] }) const safeTxHash = await safeSDK.getTransactionHash(safeTransaction) const senderSignature = await safeSDK.signTransactionHash(safeTxHash) await apiKit.proposeTransaction({ safeAddress, safeTransactionData: safeTransaction.data, safeTxHash, senderAddress: await signer.getAddress(), senderSignature: senderSignature.data, }) return safeTxHash } } Податковий облік та compliance
Кожна виплата має бути зафіксована з:
- Фіатним еквівалентом на момент виплати (для ПДФО/income tax)
- Джерелом курсу (для аудиту)
- Ідентифікатором транзакції on-chain
- Періодом, за який виплачено
CREATE TABLE payroll_transactions ( id BIGSERIAL PRIMARY KEY, payroll_run_id UUID NOT NULL REFERENCES payroll_runs(id), employee_id UUID NOT NULL REFERENCES employees(id), payment_date DATE NOT NULL, period_start DATE NOT NULL, period_end DATE NOT NULL, token_address VARCHAR(42) NOT NULL, token_symbol VARCHAR(20) NOT NULL, chain VARCHAR(50) NOT NULL, crypto_amount NUMERIC(36, 18) NOT NULL, tx_hash VARCHAR(66), fiat_currency VARCHAR(3) NOT NULL, fiat_amount NUMERIC(20, 2) NOT NULL, exchange_rate NUMERIC(20, 8) NOT NULL, rate_source VARCHAR(100) NOT NULL, rate_timestamp TIMESTAMPTZ NOT NULL, status VARCHAR(20) NOT NULL DEFAULT 'pending', confirmed_at TIMESTAMPTZ, block_number BIGINT ); Експорт для бухгалтерії: CSV з розбивкою по співробітниках і періодах, сумісний з 1С або міжнародними стандартами (IAS 19 для employee benefits). Зв'яжіться з нами — ми надамо шаблон експорту під вашу облікову систему.
Streaming payments: Superfluid інтеграція
Для DAOs і компаній з реально-часовим потоком зарплати — інтеграція з Superfluid Protocol. Замість періодичних виплат — безперервний потік токенів по секунді:
import { Framework } from '@superfluid-finance/sdk-core' async function createSalaryStream( employeeAddress: string, tokenAddress: string, monthlyAmountWei: bigint ): Promise<void> { const sf = await Framework.create({ chainId: 137, provider }) const superToken = await sf.loadSuperToken(tokenAddress) const flowRate = monthlyAmountWei / BigInt(30 * 24 * 3600) const createFlowOp = superToken.createFlow({ sender: companyAddress, receiver: employeeAddress, flowRate: flowRate.toString(), }) await createFlowOp.exec(signer) } Streaming payments знімають проблему періодичності та знижують операційне навантаження, але вимагають забезпечення ліквідності (sufficient buffer) і ускладнюють tax accounting — дохід нараховується безперервно.
Що входить в роботу
Розробка системи під ключ включає:
- Аудит поточних процесів виплат і вимог compliance
- Проектування архітектури та моделі даних
- Розробка смарт-контрактів і бекенду
- Інтеграція з мультисиг гаманцями (Safe) та оракулами (Chainlink)
- Налаштування податкового модуля та експорту в бухгалтерські системи
- Тестування (unit, integration, audit)
- Документація, навчання команди, підтримка після запуску
| Етап | Строк |
|---|---|
| Аналітика та проектування | 1–2 тижні |
| Розробка та тестування | 2–4 тижні |
| Інтеграція та деплой | 1 тиждень |
| Підтримка та доробки | за домовленістю |
Повна система з мультичейн підтримкою, Safe інтеграцією, податковим модулем та HR-інтеграцією — від 3 до 6 тижнів розробки залежно від кількості підтримуваних мереж та вимог до compliance. Вартість розраховується індивідуально після аудиту.
Якщо вам потрібна система крипто-зарплат під ключ, зв'яжіться з нами — ми оцінимо ваш проєкт і запропонуємо рішення. Наш досвід — понад 5 років у блокчейн-розробці, сертифіковані спеціалісти з Solidity та Rust, гарантія безпеки та відповідності регуляторам. Отримайте консультацію — обговоримо деталі вашого проєкту.







