Product Timeline
Development phases and status. Updated June 2026 (v3.0 model reconciled).
Platform Core
✓ Done
- Core smart contracts (4 contracts — v3-11 absorbed PlatformEscrow; down from 6)
- SIWE authentication + JWT
- SumSub KYC integration + SBT minting
- Pool creation & management (admin)
- Investment (atomic deposit + LP mint, no separate escrow — v3-03 / v3-11)
- Investor portfolio view
- Redemption request flow (single-stage admin approve + PENDING_RESERVE — v3-04; pool_type removed v3-01)
- Fund management (funds, fund_members)
- Notification system (V1 — email + in-app; rebuilt on
notification_events/notifications/notification_deliveriesin v3-103, live SES bounce/complaint ingestion) - RBAC (Admin / Operator / Fund Manager)
- NAV oracle integrated into PlatformPool 🟠 PD1 (Decided)
▶ In Progress
- NAV update flow (admin panel)
- 24h timelock enforcement
- Portfolio NAV display (investor UI)
- Writedown UX (tone + transparency)
- Admin panel V2 cleanup
- Yield distribution flow (claim-based, MANUAL_CLAIM only)
- Pool lifecycle auto-transitions (scheduler)
▶ Post-maturity repayment — built, waiting on a manual deploy and two migrations
Written in code, not live: migrations 0189 / 0190 are not applied to dev and the API is a manual deploy:dev:api. The FE/BE legs need no contract change; the one contract item below is built and already on chain, waiting only for a pool to be created from the new factory.
- Wizard creates
FIXED_MATURITY+ epoch; plan columnsredemption_term_epochs·epoch_date_basis·epoch_roll_day(0189) 🔨 v3-132 - Deploy writes every cycle's funding date under a clock;
redemption_epochs.funding_daterecords what landed (0190); indexer fix 🔨 v3-133 - Funding-date reminder gated on unwritten cycles rather than
epoch_cycle_mode— ⚠️ one code seam still blocks it firing 🔨 v3-135 - Per-cycle confirm (
epoch_id) + a funding-date ordering guard in the endpoint (not in the contract) 🔨 v3-139 - Role grants follow the signer; bootstrap PAUSER handed over before it is taken away 🔴 v3-138
- ✅ Yield accrual ends at settlement, not at request (contract) — the last MVP item, and the one place the engine paid the wrong people on this product. Shipped 2026-08-20 and on chain 2026-08-21; new pools only, and no pool created from the new factory yet 🔧 v3-131
○ Planned
- Maturity anchored per investor (contract; out of MVP scope) 🔧 v3-131
over_funding_detectedcopy fix — the mail tells fund managers a leftover carries to the next cycle; it does not 🔴 v3-137- DocuSign term sheet integration 🟠 PD2
- Oracle fallback (PD4 — Decided: no fallback) 🟠 PD4
- KAIA mainnet dual-deploy
- Multi-sig admin controls (v3-37 shape decided: Admin 3-of-5, Pauser a separate 2-of-3)
Two entries left this list rather than shipping. "Email notification system" was a duplicate of the Done row above. "Reserve fund mechanics" (BD4) is resolved, not pending — R8 settled that the reserve is redemption liquidity and never absorbs loss, so there are no further mechanics to build:
updateNAV'sreserveConsumedis always 0 and the contract rejects anything else. First-loss is the Junior tranche or the manager's equity buffer.
❓ Open / TBD
- Secondary market / LP transfers 🟡 BD5
- Analytics dashboard
- Mobile app
Note: Multi-stablecoin (USDC/USDT/DAI, USD-backed) is supported per-pool (one recommended) — see 04-pool-models. KYC/KYB gating is live (per-pool, v3-10).
Joob Pool Integration (R21)
Joob (Grab JV) eNote Finance fund integration. Hybrid model: Joob API (fund financials) + On-chain (RPS token for investor positions).
Ref: Notion — Joob Pool Integration To Do | API Spec Doc
ℹ️ Part of this section is based on the March spec — the current SoT is Grab Joob API — Aset Integration (+ second-round request). Resolved after review (2026-06-16): ①
total_rni= gross confirmed — codeyield-distributions.post.create.tstakes gross input → computes net vianet_yield_fee_config(admin/perf fee) (if NULL, net=gross). Integration doc #7 is stale. One remaining line to confirm: whether rni is already net of Joob-side LOF/WHT (independent of the Aset fee layer). ② DPD = per-bucket (30/60/90) implementation is final for Joob (corrected below; ⚠️ superseded for the master route on 2026-08-19 — it serves 30/60 only and retired bucket 90 in favour of/risk/nonperforming, see Guest API surfaces) — only the denominator (active_loan_count/outstanding) is a second-round request. (The Aset-side ingest/data model is being generalized to dynamic, jurisdiction-defined buckets for non-Joob regimes — v3-59.)
✓ Done (Phase 1 — Spec)
- Joob API spec written + call completed (3 endpoints: Fund Summary, Fund History, DPD Risk)
- RPS token contract confirmed:
0x3f9c...1403(Kaia) - DB schema:
operating_currency,fx_ratecolumns added topools(schema.sql L322-323) - Admin API types:
operatingCurrency,fxRatemapping defined (admin-web/shared/api/pools.ts) total_rni= gross confirmed (mgmt/perf fee not applied,net interest = interest - LOF - WHT)- Investor data: not provided by Joob → replaced with on-chain
balanceOf+ Transfer event indexing - DPD: per-bucket (30/60/90) implementation (Joob
/risk/dpd/{bucket}per-bucket calls) — changed from the March "buckets not needed" plan. ⚠️ Fund route only as of 2026-08-19; the master route dropped bucket 90 (dpd-exclude-90) and keys its aggregate by month — Guest API surfaces.active_loan_count/outstanding denominator not included → second-round request
⚠️ The phase dates below are from the March plan and have lapsed
Phases 2–4 were scheduled for April/May 2026. Do not read the headings as current status. Where a line could be checked against the code in the 2026-08-06 pass it is marked ✅ or ⛔ below; the rest are not re-verified here, and the live status lives in the Notion SoT linked above rather than on this page.
▶ Phase 2 — DB & Backend (was ~4/1)
- ✅
pools.post.create.ts: acceptsoperating_currency,fx_rate - ✅
pools.patch.update.ts: both fields wired - Manual Joob Pool creation +
lp_token_address= RPS contract — not re-verified - ShardLab/Hashed deposit + manual
portfolio_positionscreation — not re-verified - Investability-state logic: non-investors CLOSED, investors ACTIVE (
lifecycle_status+ visibility) — not re-verified - Finalize pool values per the contract (lockup, penalty, min investment) — commercial, not code
○ Phase 3 — UI (was ~4/15)
- Admin
pool-form.tsx:operating_currency,fx_rateinput fields - Pool Detail
pool.$id.tsx: Fund Statistics card (FX bannerdropped — v3-24, USD-only, no investor FX disclosure) - Portfolio
portfolio.tsx: return % display + CLOSED pool button hide Pool card: operating currency tag(dropped —operating_currencybackend-only, v3-24)- Admin: Joob Pool dedicated management (fee tracking, DPD risk monitor)
- Net Yield calculation logic: Admin fee 1%/yr (quarterly) + Perf fee 20% (>15% hurdle, at maturity)
○ Phase 4 — API Integration (was early May)
- ✅ Scheduled fund-data sync exists (
fund-data.scheduler.sync) →external_pool_data_snapshots - ✅ TVL snapshot cron exists (
pools.scheduler.tvl-snapshot) →pool_tvl_history - ✅ On-chain LP
Transferindexing exists (onchain-indexer.scheduler) →portfolio_positions - Investor Position: on-chain
balanceOf+ Fund Summary hybrid — not re-verified
❓ Next Cycle
- Pool smart contract design/deployment
- API sync → on-chain transition
- IRR calculation (cashflow-based, Aset self-computed)
- Recovery Rate (NPL 0% — not needed yet)
- Per-loan detail data after eNote v2 update (April+)