Разработка мобильного приложения для P2P-обмена криптовалюты
P2P-биржа — это не просто доска объявлений с ценами. Это система, в которой деньги и крипта должны переходить из рук в руки с минимальным доверием между сторонами. Ключевой механизм — escrow: криптовалюта продавца блокируется на смарт-контракте или кастодиальном кошельке до подтверждения получения фиатных денег. Если эту логику реализовать небрежно — либо продавец потеряет крипту без оплаты, либо покупатель заплатит и не получит ничего.
Escrow: смарт-контракт vs кастодиальный сервис
На выбор два подхода:
Смарт-контракт escrow (некастодиальный). Продавец депонирует крипту в контракт через approve() + deposit(). Покупатель переводит фиат любым способом → нажимает «подтвердить получение» → контракт вызывает release() и отправляет крипту покупателю. Если спор — арбитражный адрес может вызвать resolveDispute(winner).
// Упрощённая логика escrow на EVM-совместимой цепи
contract P2PEscrow {
enum Status { ACTIVE, RELEASED, REFUNDED, DISPUTED }
struct Trade {
address seller;
address buyer;
address token;
uint256 amount;
Status status;
}
mapping(uint256 => Trade) public trades;
address public arbiter;
function deposit(uint256 tradeId, address buyer, address token, uint256 amount) external {
IERC20(token).transferFrom(msg.sender, address(this), amount);
trades[tradeId] = Trade(msg.sender, buyer, token, amount, Status.ACTIVE);
}
function release(uint256 tradeId) external {
Trade storage t = trades[tradeId];
require(msg.sender == t.seller, "Only seller");
require(t.status == Status.ACTIVE);
t.status = Status.RELEASED;
IERC20(t.token).transfer(t.buyer, t.amount);
}
function dispute(uint256 tradeId) external {
Trade storage t = trades[tradeId];
require(msg.sender == t.buyer || msg.sender == t.seller);
t.status = Status.DISPUTED;
}
function resolveDispute(uint256 tradeId, address winner) external {
require(msg.sender == arbiter);
Trade storage t = trades[tradeId];
require(t.status == Status.DISPUTED);
IERC20(t.token).transfer(winner, t.amount);
}
}
Преимущество — decentralized, пользователи сами контролируют кошельки. Недостаток — gas fees на каждую операцию, сложность для новичков.
Кастодиальный escrow. Сервер хранит крипту на hot wallet. Быстрее, без газа, проще UX. Требует высоких стандартов безопасности: HSM для приватных ключей, мультисигнатурные кошельки (Gnosis Safe), cold/hot wallet разделение.
Мобильный клиент: архитектура и Web3
На iOS — web3.swift или кастомная интеграция через URLSession к JSON-RPC. На Android — web3j. Для кошелька пользователя — WalletConnect v2 (Sign SDK): позволяет подключить MetaMask, Trust Wallet, Rainbow и отправлять транзакции через deep link без хранения ключей в приложении.
// Подключение через WalletConnect v2 на iOS
import WalletConnectSign
class WalletService {
func connect() async throws {
let methods: Set<String> = ["eth_sendTransaction", "personal_sign"]
let chains = [Blockchain("eip155:1")!] // Ethereum mainnet
let namespaces: [String: ProposalNamespace] = [
"eip155": ProposalNamespace(
chains: chains,
methods: methods,
events: ["chainChanged", "accountsChanged"]
)
]
let uri = try await Sign.instance.connect(requiredNamespaces: namespaces)
// Открываем Deep Link к кошельку или показываем QR
await UIApplication.shared.open(uri.deepLink)
}
}
Лента ордеров и real-time обновления
Список ордеров на покупку/продажу должен обновляться в реальном времени — WebSocket от сервера. Новый ордер, изменение цены, закрытие сделки — всё через push по ws://. На клиенте URLSessionWebSocketTask (iOS) или OkHttp WebSocket (Android).
Фильтрация ордеров: валюта, способ оплаты (Tinkoff, Sberbank, СБП, наличные), диапазон суммы, рейтинг продавца. Рейтинговая система — обязательный элемент P2P. Без неё площадка не набирает доверие. Храним историю сделок и отзывы, рейтинг считаем на сервере.
Верификация пользователей (KYC)
Регуляторные требования для P2P-площадок: хотя бы базовый KYC (фото паспорта + selfie). На iOS — VisionKit документ-сканер, на Android — ML Kit Document Scanner. Проверку документов отдаём на Sum Sub, Veriff или Jumio через их мобильный SDK — самостоятельно реализовывать liveness detection нет смысла.
Лимиты по умолчанию для неверифицированных пользователей, повышение лимитов после KYC — стандартная схема.
Чат между трейдерами
Встроенный чат между покупателем и продавцом в рамках сделки — критичная функция. Без неё не решить спорные ситуации. Реализуем через Firebase Realtime Database или Stream Chat SDK — последний даёт готовый UI для iOS/Android, экономит 2–3 дня разработки. Сообщения шифруем end-to-end через libsignal если нужна дополнительная приватность.
Подтверждение оплаты фиата — скриншот из банка, загружаемый в чат. Хранится в Firebase Storage или S3 с presigned URL.
Безопасность
Rate limiting на эндпоинтах публикации ордеров — без него конкуренты зальют рынок мусорными ордерами. Anti-scam проверки: новый аккаунт не может сразу публиковать большие ордера. 2FA через TOTP (Google Authenticator) — обязательно для вывода средств. Биометрическая аутентификация через LocalAuthentication (iOS) / BiometricPrompt (Android) для подтверждения сделок.
Этапы работы
| Этап | Срок |
|---|---|
| Проектирование: escrow-механизм, архитектура | 1 неделя |
| Смарт-контракт + аудит (опционально) | 1–2 недели |
| Серверная часть (API, ордербук, escrow) | 2–3 недели |
| Мобильный клиент iOS + Android | 3–4 недели |
| KYC-интеграция, чат | 1 неделя |
| Тестирование, testnet/mainnet деплой | 1 неделя |
Итого: 8–12 недель в зависимости от типа escrow и набора функций. Стоимость рассчитывается индивидуально после анализа требований.







