P2P Crypto Exchange Mobile App Development
P2P exchange is not just a bulletin board with prices. It's a system where money and crypto change hands with minimal trust between parties. Key mechanism — escrow: seller's crypto locked on smart contract or custodial wallet until fiat receipt confirmation. Implement this carelessly — either seller loses crypto without payment or buyer pays and gets nothing.
Escrow: Smart Contract vs Custodial Service
Two approaches to choose:
Smart contract escrow (non-custodial). Seller deposits crypto in contract via approve() + deposit(). Buyer transfers fiat any way → clicks "confirm receipt" → contract calls release() and sends crypto to buyer. If dispute — arbitrator can call resolveDispute(winner).
// Simplified escrow logic on EVM-compatible chain
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);
}
}
Advantage — decentralized, users control wallets. Disadvantage — gas fees per operation, complexity for newcomers.
Custodial escrow. Server holds crypto on hot wallet. Faster, no gas, simpler UX. Requires high security standards: HSM for private keys, multi-sig wallets (Gnosis Safe), cold/hot wallet separation.
Mobile Client: Architecture and Web3
On iOS — web3.swift or custom integration via URLSession to JSON-RPC. On Android — web3j. For user wallet — WalletConnect v2 (Sign SDK): allows connecting MetaMask, Trust Wallet, Rainbow and sending transactions via deep link without storing keys in app.
// WalletConnect v2 connection on 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)
// Open Deep Link to wallet or show QR
await UIApplication.shared.open(uri.deepLink)
}
}
Order Feed and Real-time Updates
Buy/sell order list must update in real time — WebSocket from server. New order, price change, trade close — all via WebSocket. On client URLSessionWebSocketTask (iOS) or OkHttp WebSocket (Android).
Order filtering: currency, payment method (bank transfer, cash), amount range, seller rating. Rating system — mandatory element for P2P. Without it platform doesn't gain trust. Store transaction history and reviews, calculate rating on server.
User Verification (KYC)
Regulatory requirements for P2P: at least basic KYC (passport photo + selfie). On iOS — VisionKit document scanner, on Android — ML Kit Document Scanner. Offload document checks to Sum Sub, Veriff or Jumio via their mobile SDK — no point building liveness detection yourself.
Default limits for unverified users, raised after KYC — standard scheme.
Trader Chat
Built-in chat between buyer and seller within trade — critical function. Without it impossible to resolve disputes. Implement via Firebase Realtime Database or Stream Chat SDK — latter provides ready UI for iOS/Android, saves 2–3 days development. Encrypt messages end-to-end via libsignal if extra privacy needed.
Fiat payment confirmation — bank screenshot, uploaded to chat. Stored in Firebase Storage or S3 with presigned URL.
Security
Rate limiting on order publishing endpoints — without it competitors flood market with junk orders. Anti-scam checks: new account can't immediately publish huge orders. 2FA via TOTP (Google Authenticator) — mandatory for withdrawals. Biometric auth via LocalAuthentication (iOS) / BiometricPrompt (Android) for trade confirmation.
Work Timeline
| Stage | Duration |
|---|---|
| Design: escrow mechanism, architecture | 1 week |
| Smart contract + audit (optional) | 1–2 weeks |
| Server layer (API, orderbook, escrow) | 2–3 weeks |
| Mobile client iOS + Android | 3–4 weeks |
| KYC integration, chat | 1 week |
| Testing, testnet/mainnet deploy | 1 week |
Total: 8–12 weeks depending on escrow type and feature set. Cost calculated individually after requirements analysis.







