Разработка системы крипто-зарплаты (crypto payroll)

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1Все 1306 услуг
Разработка системы крипто-зарплаты (crypto payroll)
Сложный
от 2 недель до 3 месяцев
Часто задаваемые вопросы

Направления блокчейн-разработки

Этапы блокчейн-разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1311
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1222
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    922
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1151
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    614
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    887

Разработка системы крипто-зарплат (crypto payroll)

Ключевая проблема крипто-пейрола — это не технология, а операционная сложность: разные сотрудники хотят разные токены в разных сетях, налоговое законодательство требует фиксации рублёвого (или фиатного) эквивалента на момент выплаты, compliance требует KYC, а финансовый директор хочет планируемые расходы в стабильном выражении. Система должна решать все эти задачи одновременно — и делать это автоматически.

Самостоятельная разработка имеет смысл когда: команда > 20 человек, есть нестандартные требования к токенам/сетям, нужна интеграция с HR-системой или бухгалтерским учётом, или готовые решения (Request Finance, Superfluid, Deel Crypto) не закрывают специфику.

Архитектура системы

HR System / Manual Input
        ↓
Payroll Engine (расчёт, конвертация)
        ↓
Approval Workflow (multi-sig авторизация)
        ↓
Disbursement Module (батчевые выплаты)
        ↓
Accounting Module (налоговый учёт, отчёты)

Модель данных

interface Employee {
    id: string
    legalName: string
    taxId?: string        // для отчётности
    walletAddresses: {
        chain: string
        address: string
        verified: boolean // подтверждён через sign message
    }[]
    paymentPreferences: PaymentPreference[]
    kycStatus: 'pending' | 'approved' | 'rejected'
}

interface PaymentPreference {
    percentage: number        // % от зарплаты в этом токене
    token: string             // contract address
    chain: string
    minAmount?: Decimal       // минимум для выплаты (иначе накапливать)
}

interface PayrollRun {
    id: string
    periodStart: Date
    periodEnd: Date
    paymentDate: Date
    currency: 'USD' | 'EUR' | string   // base currency для расчёта
    employees: PayrollEntry[]
    status: 'draft' | 'approved' | 'processing' | 'completed' | 'failed'
    approvals: Approval[]
}

interface PayrollEntry {
    employeeId: string
    grossAmountFiat: Decimal    // в base currency
    deductions: Deduction[]
    netAmountFiat: Decimal
    payments: CryptoPayment[]  // разбивка по токенам/сетям
    exchangeRates: ExchangeRateSnapshot[]  // зафиксированные курсы
}

Расчёт выплат и конвертация курсов

Самый болезненный вопрос — какой курс использовать. Три варианта:

Spot rate на момент выплаты — самый простой. Работодатель берёт курс в момент отправки транзакции. Риск волатильности несёт сотрудник.

Фиксированный курс за N дней до выплаты — снижает волатильность, но требует advance planning и может расходиться с рынком на момент выплаты.

TWA (Time-Weighted Average) за расчётный период — стандарт в традиционных FX-расчётах, наиболее справедлив, но сложнее объяснить сотрудникам.

class ExchangeRateService {
    // Источники курсов с fallback
    private sources = [
        new ChainlinkPriceFeed(),  // on-chain, manipulation-resistant
        new CoinGeckoAPI(),        // CoinGecko с API key
        new BinanceAPI(),          // CEX spot price
    ]

    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}`)
        }

        // TWAP: усреднение по историческим ценам
        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 выплата каждому сотруднику отдельной транзакцией — это дорого. Батчевые выплаты через мультисенд контракт снижают стоимость в 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;   // address(0) для native ETH/BNB
        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
        )

        // Параллельно запускаем disbursement в каждой цепочке
        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.

Gnosis Safe (теперь 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' })

        // Кодируем вызов PayrollDispatcher.dispatchPayroll()
        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 с разбивкой по сотрудникам и периодам, совместимый с 1C или международными стандартами (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)

    // flowRate = wei/second
    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 — доход начисляется непрерывно.

Полная система с мультичейн поддержкой, Safe интеграцией, налоговым модулем и HR-интеграцией — от 3 до 6 недель разработки в зависимости от числа поддерживаемых сетей и требований к compliance.