A dollar account for people who support family across borders. Sign up with a passkey, hold AUSD on Monad, pay another member by @handle or pay a family member's UPI ID. Gullak pays every network fee.
Built for Monad Metropolis 2026 (Consumer Products & Payments).
Testnet demo. No real money moves. AUSD and CTK are Agora's test tokens on Monad testnet, rupee amounts are indicative, and the UPI payout is simulated.
| Home | Pay by @handle | Pay a UPI ID | Account |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
Screens from the recorded run on a real Android phone (published app, Monad testnet, 10 Oct 2026).
| Web app | https://gullak-family-money-app.replit.app |
| Android app (install page, APK, SHA-256) | https://gullak-family-money-app.replit.app/android |
| Demo video (1:59) | https://youtu.be/ykW18DHWzPQ |
Android: you need Android 9 or newer, a 64-bit ARM phone, Google Play services, a screen lock and a Google account.
- Open the install page on the phone and install the APK.
- Create my Gullak, then pick a name and @handle, then Create with passkey.
- Add money ($25).
- Send to an @handle (no passkey prompt inside the session budget).
- Send → Not on Gullak? Send to their UPI ID.
- Stateless test: Settings → Apps → Gullak → Storage → Clear data, reopen, then I already have one. The same account and balance come back.
Every receipt links to the transaction on the Monad testnet explorer. Shared daily limits protect the test gas budget, so if the app says it's paused, try again later.
| Step | On Monad testnet | Simulated |
|---|---|---|
| Passkey sign-up / sign-in | Mera passkey account (PRF-derived key, held only in app memory) | — |
| Add money | Desk swaps CTK → AUSD on Agora's Instant Settlement pair; the AUSD lands in the member's account | No card or bank deposit |
| Send to @handle | Direct AUSD transfer (EIP-3009), gas paid by Gullak. Not an Instant Settlement swap | — |
| Send to UPI | Member's AUSD goes to the desk, which swaps AUSD → CTK on the Instant Settlement pair | Rupee payout and INR amount |
Recorded on a real Android phone against the published app (10 Oct 2026), timed from the first frame of the landing screen, with idle time included:
- confirmed funding at 37.7 s
- first member-signed payment confirmed at 68.1 s
- after clearing app data, the restored account 8.9 s after tapping "I already have one"
flowchart TB
subgraph Phone["Member's phone"]
direction LR
PK["Passkey<br/>confirmed with the screen lock"]
APP["Gullak app (Android, web)<br/>account key in app memory only"]
PK -- "Mera: PRF output,<br/>one ceremony" --> APP
end
subgraph Server["Gullak API (Node, Express)"]
direction LR
RELAY["Gas relayer"]
DESK["Settlement desk<br/>approved swapper"]
DB[("PostgreSQL<br/>members, ledger")]
end
subgraph Chain["Monad testnet"]
direction LR
AUSD["AUSD token"]
PAIR["Agora Instant Settlement<br/>CTK/AUSD pair"]
end
APP -- "signed EIP-3009 authorization<br/>(Mera signing session)" --> RELAY
RELAY -- "transferWithAuthorization,<br/>Gullak pays gas" --> AUSD
DESK -- "Add money: CTK to AUSD<br/>Send to UPI: AUSD to CTK" --> PAIR
Members sign every transfer on their phone; the API relays it and pays the gas. An @handle payment moves AUSD straight from sender to recipient. The desk takes part only in Add money and Send to UPI.
Send to UPI, step by step:
sequenceDiagram
autonumber
actor M as Member (Gullak app)
participant API as Gullak API and desk
participant AUSD as AUSD contract
participant IS as Instant Settlement pair
Note over M: Mera session signs an EIP-3009 authorization:<br/>exact amount, payable only to the desk,<br/>10-minute expiry, one-time nonce
M->>API: Send to UPI request with the signed authorization
Note over API: Each desk transaction is written to the<br/>ledger before it is broadcast
API->>AUSD: transferWithAuthorization (member to desk)
AUSD-->>API: mined
API->>IS: getAmountsOut, then swapExactTokensForTokens (AUSD to CTK)
IS-->>API: mined
API-->>M: Receipt with a simulated UPI payout reference
Note over API,IS: If the swap fails, the desk sends the same AUSD back.<br/>The app shows refunded only after that transaction is mined.
- Mera (
@category-labs/mera) is the whole account layer: there is no seed phrase, extension, email or separate app password (the passkey is confirmed with the phone's screen lock). Inartifacts/gullak/lib/keys.ts:createPasskeyWithPrfOutputcreates the passkey and reads PRF in one ceremonycreateSecp256k1SigningSessionsigns without prompts inside a session that Gullak scopesgetPasskeyPrfOutputsigns in and recovers the account
- Agora AUSD is the balance and payment asset. Transfers use EIP-3009
transferWithAuthorization, so members never pay gas. - Agora Instant Settlement (CTK/AUSD pair) handles money in (Add money) and money out (Send to UPI / cash out) through a desk wallet that holds the approved-swapper role. Agora permits KYC-approved, whitelisted users to swap directly from their wallets; using a payout desk is Gullak's design choice.
Session scope. These limits are enforced by the app around the Mera session; they are not a cryptographic boundary.
- Only sign-in statements and AUSD transfers sign without a prompt, up to $200 per session.
- A larger send asks for the passkey again.
- The session locks after 10 minutes idle, 30 minutes total, 2 minutes in the background, or on Lock now.
Each transfer signature itself is bound to its exact recipient, amount, expiry and nonce. Session limits live in lib/gullak-core/src/policy.ts.
Contracts (Monad testnet, chain 10143):
- AUSD:
0xa9012a055bd4e0eDfF8Ce09f960291C09D5322dC - CTK:
0x7BEb5D9DB0d85cBEa543C04f0dE8c23c2176cd9D - Instant Settlement pair:
0x1Aa8958Aa34cEC8096EF4381cb335effe977b0ae
pnpm monorepo (Node 24, TypeScript):
| Path | What |
|---|---|
artifacts/gullak |
Expo / React Native app (Android and web); server/ serves the web build and the Android install page |
artifacts/api-server |
Express API: sign-in tokens, member directory, gasless relaying, Instant Settlement desk, crash-safe settlement ledger |
lib/gullak-core |
Shared chain config, contract ABIs, limits and session policy |
lib/db |
Drizzle schema (PostgreSQL) |
lib/api-spec, lib/api-zod, lib/api-client-react |
OpenAPI spec and generated Zod schemas / React Query client |
scripts |
Operator status and setup, API smoke test, headless web e2e (virtual PRF passkey), crash-recovery check, APK publishing |
You need Node 24, pnpm 10, PostgreSQL, and a Monad testnet wallet with a few test MON (from https://faucet.monad.xyz) to act as the relayer and settlement desk.
pnpm install
cp .env.example .env # fill in the values, then export them in your shell
pnpm --filter @workspace/db run push # create tables
pnpm --filter @workspace/scripts run operator # desk address, balances, gas runway
pnpm --filter @workspace/scripts run operator setup # one-time: Instant Settlement whitelist and approvals (spends test MON)
PORT=8080 pnpm --filter @workspace/api-server run dev # API (PORT is required)The app scripts are written for the Replit environment. Elsewhere:
- Web:
EXPO_PUBLIC_DOMAIN=<host serving /api> node artifacts/gullak/scripts/build.js --web-only, thenPORT=3999 node artifacts/gullak/server/serve.js. The web app and/apimust share one HTTPS host, because the passkey rpId is that host. - Android:
EXPO_PUBLIC_DOMAIN=<host> bash artifacts/gullak/scripts/build-android.sh. SetGULLAK_SIGNING_DIRto your own signing key, and put that key's SHA-256 inANDROID_CERT_SHA256so/.well-known/assetlinks.jsonlets the app use passkeys. Signing keys are not in this repository.
Checks: pnpm run typecheck. pnpm --filter @workspace/scripts run smoke with SMOKE_CHAIN=0 runs only the free checks; without it, the smoke test spends test MON.
- Testnet only. Test tokens, simulated UPI payout, indicative rupee rates.
- Tested on one real Android phone (Android 16), in Safari on macOS and in headless Chromium end-to-end tests. iOS is untested.
- Each member holds their own balance; there is no shared balance yet.
- The API runs as a single instance (in-memory rate limits and transaction queue).
- Gas sponsorship is capped at 60 transactions a day across all users.
- The funding and payout partners described in the write-up (licensed remittance and UPI partners, an Agora institutional account) do not exist yet.
MIT, see LICENSE.



