Finna
Crypto-native money: wallets, swaps, lending.
Led the React Native app on a Redux Toolkit + TanStack Query architecture with per-domain service layers: a multi-currency wallet (crypto, NGN, USD), lending, P2P requests and bill payments.
- role
- Lead mobile engineer
- year
- 2025 — 2026
- platform
- iOS · Android
- live
- finnahq.com ↗
- stack
- React NativeRedux ToolkitTanStack QueryWebAuthnSentry



$ ls ./screens
10 screens · scroll →The problem
Finna is a crypto-native finance app: hold stablecoins, spend in naira, borrow against what you hold. The product is only as good as its edges — the moment a payment fails because the money sits in the wrong currency, users stop trusting the whole thing.
What I built
I led the React Native app alongside product, backend and QA, on a Redux Toolkit + TanStack Query architecture with per-domain service layers.
- A multi-currency wallet — crypto, NGN and USD — with on/off-ramp, crypto send and receive, currency conversion and virtual bank accounts.
- A just-in-time swap. If a payment would fail because the NGN balance is short but the user holds USDT, the app quotes and executes the conversion for just the shortfall, then completes the payment — one confirmation, not three screens.
- Crypto-backed lending with a live loan-health view.
- Recurring P2P payment requests, and merchant bill payments with real-time operator detection from the phone number.
- Authentication in layers — transaction PIN, TOTP 2FA and WebAuthn passkeys.
async function payBill(bill: Bill, amount: Naira) {
const shortfall = amount - balances.NGN;
if (shortfall > 0) {
const quote = await swaps.quote({ from: "USDT", to: "NGN", amount: shortfall });
await swaps.execute(quote, { idempotencyKey: bill.paymentId });
}
return bills.pay(bill, amount, { idempotencyKey: bill.paymentId });
}Reusing the payment's idempotency key for the swap is the important line: retry the whole flow and you get the same swap, not a second one.
Outcome
- Payments that used to fail on a currency mismatch now go through in a single confirmation.
- Three authentication factors, with passkeys removing most PIN fatigue.
- One architecture across wallet, lending and payments, so features land in a known shape.






