Oracle3
Open-source trading engine and MCP server for prediction markets. Fee-aware no-arbitrage trading across related contracts, live on Kalshi, Polymarket and Solana or on paper.
Fundxtra is a Telegram-first rewards platform. Complete sponsored tasks, earn Naira rewards, refer friends, then withdraw as cash or redeem for airtime, data, Telegram Stars and Telegram Premium.
FinanceTypeScript · CSSGitHub @giftVisualsOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗A Telegram-first rewards platform. Users complete sponsored tasks, earn Naira, refer friends, and withdraw as cash or redeem for airtime, data, Telegram Stars and Telegram Premium.
Complete tasks. Earn rewards. Refer friends.
/app (opened from the Telegram bot)/adminfundxtra/
├─ apps/
│ ├─ api/ Express + TypeScript backend → Railway
│ └─ web/ Next.js frontend → Vercel
│ ├─ app/(marketing)/ public website
│ ├─ app/app/ Telegram Mini App
│ └─ app/admin/ admin console
├─ packages/
│ └─ shared/ types, zod schemas, design tokens, money helpers
├─ firebase/ Firestore rules, indexes, Storage rules
└─ docs/ launch, operations, architecture, data model, security, deployment
One shared package is the reason the three surfaces agree with each other: the API and both frontends compile against the same domain types, validate with the same zod schemas, and read colour from the same tokens.
npm ci
cp .env.example .env # then fill it in — see the file's own notes
npm run build:shared # the API and web app compile against this
npm run dev:api # http://localhost:8080
npm run dev:web # http://localhost:3000
GET http://localhost:8080/health reports exactly which configuration is
missing, so a half-configured environment tells you what to fix rather than
failing at the first request that needs a secret.
Set ALLOW_DEV_AUTH=true and send initData as dev:<telegramId>:<name>:<username>.
It is fenced three ways: the flag must be on, NODE_ENV must not be
production, no bot token may be configured, and it refuses to mint the primary
admin's id. /health warns loudly if it is ever enabled in production.
npm run seed --workspace @fundxtra/api
Creates settings, the primary admin, the reward catalogue and five campaigns across every verification method. It refuses to run against production, and it goes through the real services — so the ₦1,000 per-task cap applies to demo data too.
| Command | What it does |
|---|---|
npm run build | Build shared, then the API and the web app |
npm test | 145 tests across the shared package and the API |
npm run typecheck | Strict TypeScript across every workspace |
npm run lint | ESLint on the web app |
npm run seed | Seed development data |
Money is integer kobo, everywhere. Naira floats are never stored, summed or
compared. formatNaira() in the shared package is the only thing that turns an
amount into text. See packages/shared/src/money.ts.
The ledger is authoritative; the balance is a cache. A balance never moves
outside a Firestore transaction that also writes the immutable ledger row, and
every movement carries an idempotency key written with create() inside that
same transaction — so a retry or a genuine race reuses the original entry
rather than paying twice. Corrections are compensating REVERSAL rows, never
edits. auditUserBalance() recomputes from the ledger and is exposed to admins
for dispute investigation.
Telegram identity is the primary key. The user document id is the Telegram
id, which makes "one account per Telegram user" structural rather than enforced.
initData is verified server-side with the documented HMAC scheme before the
user object inside it is read at all.
Duplicate rewards are impossible by construction. A task reward is only ever
credited by a transaction that also creates taskCompletions/{userId}__{taskId}.
The id is derived from the pair, so a second create() fails and rolls the
credit back with it.
Campaign budgets cannot overspend. spentKobo counts approved completions
plus pending submissions, budget moves in the same transaction as the record
that justifies it, and a task closes itself when it can no longer fund another
reward. A test races five users for one funded reward: exactly one is paid.
Reward fulfilment is behind a provider interface. NasfamPay's public API is
still in development, so NasfamPayProvider contains no endpoints, no auth
scheme and no request bodies — only a precise description of what to implement
when the documentation lands. The default provider fails closed so a
misconfigured deployment cannot take money for undeliverable rewards.
| Document | Contents |
|---|---|
| docs/LAUNCH.md | Owner: what to do before going live or stepping back |
| docs/OPERATIONS.md | Daily work: hand this to whoever reviews and pays |
| docs/ARCHITECTURE.md | How the pieces fit, and why |
| docs/DATA_MODEL.md | Every collection, field and invariant |
| docs/SECURITY.md | Threat model and what defends against what |
| docs/DEPLOYMENT.md | Railway, Vercel, Firebase, custom domain |
| docs/PROVIDERS.md | Wiring NasfamPay when their API ships |
Built and working:
Waiting on an external dependency: