Ramp status, July 29, 2026: Shunt's Stellar split and vault flows run on testnet. The SDF SEP-24 flow is a labeled Stellar testnet simulation. Provider sandboxes are shown separately. A route is called live only after a licensed provider returns the exact country, fiat, asset, network, direction, order status, and matching Stellar mainnet settlement.
🌐 Live app: shuntapp.xyz · testnet · connect Freighter and try the loop
(Includes 1-click testnet XLM/USDC funding directly on the Home screen)
Get paid in dollars. Keep them worth something. Never watch a month's income evaporate again.
Shunt is a financial autopilot for people who earn from abroad. The moment USDC lands in your Stellar wallet, one tap splits it by rules you set once: spending money stays liquid, an emergency buffer fills, savings get locked by code in hard value the rupiah can't erode, and — if you opt in — a slice is dollar-cost-averaged into an asset (XLM or gold). One tap per income, at the one moment discipline is easy: payday. (Detection is automatic; the money only ever moves when you sign — never hands-free.)
Shunt (electronics): a component that diverts current into parallel paths so no single path overloads. Shunt does the same for your income.
- 49 Soroban unit tests (split exactness, rounding, replay, timelock, penalty, savings goals, the unallocated-withdrawal guard, a per-user goal cap, authorization boundaries, and a solvency/conservation invariant) + a real-testnet end-to-end suite (Playwright, 41 specs across the whole loop; some auto-skip when the testnet DEX has no USDC liquidity that day) that friendbots a fresh account, buys real USDC on the DEX, and drives the real flow. No mocked Stellar network or contract interactions — signing is injected for headless execution, and everything after signing runs against live Stellar testnet services.
- Non-custodial by construction: the keeper holds zero keys; the Savings lane is held by contract code only its owner can withdraw (code custody, not third-party custody).
- Recoverable keeper lifecycle: detected inflows move through explicit
detected → prepared → confirmedstates. Preparing an unsigned XDR does not mark an inflow complete. Completion is recorded only after the keeper verifies the successful submitted transaction through Horizon. Failed or expired preparations remain rebuildable. - Two-layer replay protection: the keeper suppresses only chain-confirmed
inflows, while the contract independently rejects a repeated
inflow_keyduring the lifetime of its persistent replay entry. - Verifiable on-chain: every step of the split + savings-goals lifecycle is a clickable testnet hash (Live on testnet). Network for this submission is testnet only — no mainnet claims.
Freelancers and overseas workers who invoice in dollars face three quiet leaks:
- The single-balance trap. When $2,000 lands as one number, all of it feels spendable — and two weeks later it's gone. Savings become whatever's left over, which rounds to zero.
- Rupiah erosion. Money parked in IDR loses value year after year (~Rp18,000/USD and weakening). Saving in your local currency is running up a down escalator.
- No salary, no automation. Irregular income defeats every payroll-based savings tool. The only clean moment to set money aside is the instant it arrives — exactly the moment Shunt captures.
What you get is not "an app that splits money into pockets." It's four concrete outcomes:
| Outcome | How |
|---|---|
| 💵Savings that hold value | Kept in USDC, not IDR — your safety net stops shrinking |
| 🔒Savings you can't sabotage | Locked by a Soroban contract with a timelock, not by a label in an app. Early exit costs 10% — which goes toyour own buffer, not to us |
| 📈Optional investing that actually happens | If you opt in, a slice of each income is spot-converted (DCA) into XLM or gold the moment it lands — the strategy everyone knows and nobody sticks to. Separate from the safety net; set it to 0% and nothing else changes |
| 🔁One app for the whole loop | Money in, structured, and out to your bank — anchors and partners handle fiat; you never leave Shunt |
Standard vaults demand willpower. You receive money, open an app, and manually lock a portion away. This fails for freelancers with irregular income.
Shunt removes willpower. It operates as an income router, not a storage box. It sits at the entry point of your cashflow. The moment an invoice is paid or a client transfer lands, Shunt detects it. One tap routes the entire arrival into spending cash, an emergency buffer, and time-locked savings. It enforces financial discipline at the exact moment you get paid, before the money leaks into daily expenses.
| Direction | Feature | Status |
|---|---|---|
| In | Payment request links (SEP-7) — for crypto-capable clients, a link or QR removes the manual wallet-address and asset coordination; you get paid in USDC. Card checkout for non-crypto payers is on the roadmap | ✅ shipped (card checkout 🔜) |
| In | Add money (SEP-24 test deposit) — SDF test-anchor simulation for SEP-1/10/24; live providers appear only after exact-route approval | ✅ shipped as testnet simulation |
| Structure | One-tap split into Needs / Savings / Buffer — the three-lane allocation is atomic on-chain (Invest is a separate approved conversion) | ✅ shipped |
| Structure | Invest lane (optional) — spot DCA into your choice of XLM or TXAUM (Shunt's own testnet demo gold, standing in for Matrixdock's mainnet-only XAUm) via path payment after each split | ✅ shipped |
| Structure | In-app Convert — XLM ⇄ USDC swap on the Stellar DEX (live quote, slippage floor), no third party | ✅ shipped |
| Structure | Code-custody savings with timelock + penalty-to-your-buffer | ✅ shipped |
| Out | Cash-out (SEP-24 withdraw) — Needs lane to fiat via a licensed anchor's hosted flow, rate & fee shown first | ✅ shipped vs SDF test anchor; PHP (MoneyGram) is the production candidate, IDR the next corridor |
Shunt never touches fiat and never holds your keys — licensed anchors do fiat, your wallet and the vault contract do custody. That's what makes the loop possible without Shunt becoming a bank or a remittance company.
Honest market note: the value story is Indonesian rupiah erosion (our primary market), but the off-ramp that is live on Stellar today is PHP via MoneyGram — so the go-to-market is Philippines-first, Indonesia-next as the IDR corridor lands (IDRX or MoneyGram-Indonesia). We prove the engine + off-ramp mechanism live in an APAC country now; we don't claim a live rupiah cash-out we don't yet have. Detail in the anchor stack.
| Step | What happens under the hood | |
|---|---|---|
| 1 | Connect | Freighter browser wallet, one click. No app install, no sign-up, no custody. |
| 2 | Set rules | Sliders for Needs / Savings / Buffer / Invest + a savings timelock. Saved on-chain viaset_rules — the contract is the single source of truth. |
| 3 | Income lands | Via your payment link, a Top Up, or any direct USDC transfer. The keeper streams Horizon and detects it within seconds. |
| 4 | One tap | The keeper prepares an unsigneddistribute transaction. You review the exact breakdown and sign. Nothing moves without your signature. |
| 5 | Auto-split | The three-lane allocation is one atomic Soroban transaction: Needs & Buffer stay in your wallet, Savings moves into the vault and the timelock starts. If you enabled the optional Invest lane, its slice is spot-converted into your chosen asset (XLM or TXAUM) by a separate path payment you approve afterward — not part of the atomic split. Sub-cent fees, settled in seconds. |
Where each lane lives — and why:
| Lane | Lives in | Access | Purpose |
|---|---|---|---|
| 🟡Needs | Your wallet | Anytime | Daily spending; cash out to fiat through a supported Stellar anchor whenyou choose |
| 🟢Savings | The vault contract | After the timelock | Value-holding savings in USDC. Held by code — because a timelock in your own wallet would be fiction |
| 🔵Buffer | Your wallet | Instantly | Emergency fund — no lock, no penalty, no questions |
| 🟣Invest (optional) | Your wallet | Anytime | Opt-in growth slice — spot DCA (an asset purchase, not a yield product). Set it to 0% and Shunt's promise is unchanged. |
The value-preservation promise lives in Savings, not Invest. Savings is 100% USDC, held by code — that is the safety net that resists rupiah erosion. Invest is a separate, optional lane for users who explicitly want a growth slice; it is a spot asset purchase (bay'/DCA), never presented as safe or value-holding. In the current build the demo asset is XLM purely because it's the asset with real DEX liquidity on testnet — the intended long-term growth asset is allocated gold (a value-holding growth asset), with XLM as the testnet placeholder to prove the path-payment mechanism. Nothing in the safety net depends on Invest.
Early savings withdrawals are possible but cost a 10% penalty — which isn't lost: it's redirected into your Buffer credit inside the vault, withdrawable anytime. Discipline with a safety valve.
Shunt's engine assumes USDC is already on Stellar — getting a non-crypto worker to that point is the hard part, and we don't pretend it's solved. Here is the concrete, staged path with the honest status of each rung:
| User | How they get USDC on Stellar | Status |
|---|---|---|
| Wedge — crypto-aware freelancer / DAO contributor (the MVP's real target) | Already paid in USDC; connects Freighter directly | ✅ works today |
| Freelancer with a foreign client | Sends a Shunt payment link (SEP-7); for a crypto-capable client the link removes manual wallet-address and asset coordination, and USDC lands | ✅ shipped for crypto-capable clients · 🔜 card-paying clients via an on-ramp partner |
| Migrant worker, no crypto | SEP-24 Top Up — fiat in through a supported anchor's hosted flow, lands as USDC | ⚙️ mechanism shipped vs SDF test anchor · needs a live regional anchor + simpler-than-Freighter wallet |
Two gaps we name out loud instead of hiding: (1) a licensed regional fiat-in anchor (the same IDRX / Coins.ph partnership question as the off-ramp), and (2) self-custody UX — Freighter is too heavy for a first-time mainstream user, so passkey / smart-wallet onboarding is on the roadmap, not claimed today. The MVP deliberately proves the engine on the wedge; mainstream onboarding is the next validation step, not a finished feature.
| Item | Value |
|---|---|
| Vault contract (USDC) | CDMFJZ6VRD2JEV7J2W7KMZZ3AXNSOST2C6L2KYRJAYIN7ULWJEOCWO5B — current security-hardened deployment (supersedes CC7E…, the previous deployment; source-level fix for goal-vs-aggregate timelock + the unallocated-withdrawal guard). Earlier still: CB27… |
| Demo assets (TXAUM/TIDR/TPHP) | issuer GD3Y3DQEC6XIZME2PKSBKJ263E2UREV2WVSDJRKC3MJKBDU2RRM3IHZF — Shunt's own testnet issuance with real seeded liquidity (scripts/issue-demo-assets.mjs) |
| USDC SAC (testnet) | CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA |
| Keeper (Cloudflare Worker) | shunt-keeper.irhamtria.workers.dev |
The vault ran the complete lifecycle on-chain with real testnet USDC (acquired on the DEX via path payment), including the savings-goals feature — every hash below is clickable proof:
init (USDC SAC) ✓ contract initialized
set_rules 60/25/15, 1-day timelock ✓ stored on-chain
distribute 10 USDC ✓ split exactly 6 / 2.5 / 1.5, `split` event emitted
create_savings_goal "Emergency fund" 1.5 USDC ✓ drawn from unallocated, aggregate untouched
withdraw_from_goal 0.5 (still locked) ✓ paid 0.45 — 10% penalty → Buffer credit, goal decrements
rename_savings_goal → "Dana Darurat" ✓ cosmetic only, amount unchanged
delete_savings_goal ✓ 1.0 USDC principal released back to unallocated
Current deployment (CDMFJZ…) proof: deploy · init (USDC SAC). The hardening smoke test — set_rules 60/25/15, distribute 10 USDC → 6 / 2.5 / 1.5, a zero-lock goal that still incurs the 10% penalty under the active aggregate lock, and withdraw_savings(0.6) reverting #11 InsufficientUnallocated while withdraw_savings(0.5) succeeds — is visible in the contract's transaction history.
Historical proof (prior CC7E… deployment, kept for the record): deploy · init · set_rules · distribute · create_savings_goal · withdraw_from_goal · rename_savings_goal · delete_savings_goal
An earlier lifecycle proof (trustline, DEX purchase, basic split/withdraw) ran on the prior contract instance before the goals feature was added — same code path, same 7-decimal arithmetic, superseded by the deployment above.
New on the CC7E… instance (2026-07-16) — laddered timelocks + buffer threshold auto-refill:
set_rules 60/25/15, buffer_target 5 USDC ✓ stored on-chain
distribute 5 USDC, buffer_topup 2 USDC ✓ needs 1.8 / savings 0.75 / buffer 2.45 — exact, priority honored
create_savings_goal "Dana Darurat" 0.3 USDC, lock_secs=60 ✓ short ladder
create_savings_goal "Dana Haji" 0.3 USDC, lock_secs=63072000 ✓ long ladder (~2yr), same moment
withdraw_from_goal "Dana Darurat" after 70s real wait ✓ paid in full, penalty=0 — its own lock had elapsed
withdraw_from_goal "Dana Haji" same moment ✓ paid 90%, 10% penalty → Buffer — still locked, independently
Proof transactions: deploy · init · set_rules · distribute w/ buffer_topup · create_savings_goal (short) · create_savings_goal (long) · withdraw short (unlocked) · withdraw long (still locked)
Mobile-first (~390px column, PWA-installable), scaling to a desktop nav rail at ≥1024px.
![]() Onboarding |
![]() Connect wallet |
![]() Home |
![]() Configure Shunt |
![]() Auto-split confirm |
![]() Savings vault |
![]() Send & Pay |
![]() Activity |
![]() Settings |
All four requirements are live in the app: wallet connect, XLM balance fetched from Horizon (visible on Home with a Friendbot fund button for empty accounts), native XLM transfer from the Send & Pay screen, and the resulting hash with a Stellar Expert explorer link. The on-chain lifecycle proof in Live on testnet is independently verifiable on the explorer.
| Requirement | Screenshot |
|---|---|
| Multi-Wallet Options Showing Freighter, Albedo, xBull |
![]() |
| Real-time Event Toast Soroban split event detected |
![]() |
Three deliberate design principles:
- The keeper holds zero keys — and is now optional for detection. It only watches (Horizon payment stream, cursor-resumed reconnects) and prepares (unsigned XDR). Every fund movement requires your signature. Detection no longer depends on it at all: the app polls Horizon itself and flags un-split income client-side. The keeper's only remaining job is preparing the split XDR — stateless, replaceable, and open-API, so the in-app manual trigger does the identical thing and anyone can run their own. If it dies mid-demo, worst case is a short delay, never a fund risk.
- Savings must be held by code. A timelock on funds in your own wallet is theater — you could just transfer them out.
ShuntVaultholds the Savings lane and enforces the lock on-chain;withdraw_savingsanswers to your address and no one else's. Not third-party custody — code custody, owner-only. - Recoverable keeper lifecycle: detected inflows move through explicit
detected → prepared → confirmedstates. Preparing an unsigned XDR does not mark an inflow complete. Completion is recorded only after the keeper verifies the successful submitted transaction through Horizon. Failed or expired preparations remain rebuildable. - Two-layer replay protection: the keeper suppresses only chain-confirmed
inflows, while the contract independently rejects a repeated
inflow_keyduring the lifetime of its persistent replay entry.
| Function | Auth | Description |
|---|---|---|
init(token) |
— | One-time: binds the USDC SAC address. |
set_rules(user, needs_bps, savings_bps, buffer_bps, lock_secs, anchors, buffer_target) |
user | Split rules in basis points (must total 10,000) + off-ramp anchor allowlist + optional Buffer auto-refill target. |
distribute(user, amount, inflow_key, buffer_topup) |
user | Atomic split. buffer_topup is prioritized ahead of the normal bps split; dust from 7-decimal rounding lands in Needs. Replay-proof via inflow_key. |
deposit(user, amount) |
user | Voluntary top-up into the savings vault. |
withdraw_savings(user, amount) |
user | Free after the timelock; 10% penalty → Buffer credit before it. |
withdraw_buffer(user, amount) |
user | Withdraw Buffer credit — never locked. |
offramp(user, anchor, amount) |
user | Sends USDC only toallowlisted anchor addresses. |
create_savings_goal(user, label, initial_amount, lock_secs) |
user | Names a sub-allocation, drawn from the unallocated Savings pool, with its own laddered unlock date independent of the aggregate lock. No funds move — bookkeeping only. |
withdraw_from_goal(user, goal_id, amount) |
user | Same penalty/timelock as withdraw_savings, scoped to one goal's own unlock_at. |
rename_savings_goal(user, goal_id, new_label) |
user | Cosmetic — no balance change. |
delete_savings_goal(user, goal_id) |
user | Removes the goal; its principal simply becomes unallocated again. |
get_rules / get_savings / get_buffer_credit / get_lock_until |
— | Read-only views. |
get_savings_goals / get_unallocated_savings |
— | Read-only views for the goals feature. |
Errors are explicit (NotInitialized=1 … TooManyGoals=13); penalty and denominators are named constants (PENALTY_BPS = 1_000, BPS_DENOM = 10_000), not magic numbers. 49 unit tests cover the exact split, dust (no stroop lost, ever), replay rejection, rules validation, timelock behavior, the allowlist, the full goals lifecycle, threshold auto-refill priority, and independent per-goal unlock dates — plus a hardening set: the goal-vs-aggregate timelock rule (a goal can lock longer than the aggregate Savings lock but never shorter, so a zero-lock goal can't be an escape hatch around the timelock/penalty), the unallocated-withdrawal guard (generic withdraw_savings can only draw unallocated Savings; goal principal is reachable solely through withdraw_from_goal), zero-value goals rejected, a per-user goal cap (MAX_GOALS_PER_USER = 20, TooManyGoals), authorization boundaries (no account can withdraw another's Savings/Buffer, rewrite its rules, or create/rename/delete/withdraw its goals), input validation (zero/negative amounts rejected), init cannot be re-called, and a solvency/conservation invariant (the vault's token balance always covers the sum of every user's Savings + Buffer credit, and no user's goal allocations exceed their Savings). The Invest lane still does not touch this contract — the invest share stays wallet-side and converts via a separate classic path payment.
Both directions run on the standard Stellar anchor rails, implemented in web/src/lib/anchor.ts:
- SEP-1 — discover the anchor's endpoints from its
stellar.toml. - SEP-10 — prove wallet ownership by signing a challenge (no password, no account).
- SEP-24 — the anchor's hosted flow opens for KYC and bank details; Shunt polls the transaction status.
withdraw= cash-out,deposit= Top Up — same stack, mirrored.
Plus SEP-7 payment request links: a web+stellar:pay URI + QR any compatible wallet can open — the payee never explains crypto to a client again.
Provider rate and fee are shown only when a live provider quote exists. The SDF test-anchor simulation does not quote IDR or provider fees.
Pluggable to a real corridor — shown only after provider proof. The off-ramp architecture is generic SEP-24, but Shunt does not call a route live until the provider approves Shunt's domain/account, returns a usable flow, and the team reconciles a provider order with Stellar mainnet settlement. MoneyGram Ramps is the preferred Stellar-native cash candidate after allowlisting and Production Preview.
node scripts/verify-anchor.mjs stellar.moneygram.com
# Network: Public Global Stellar Network ; September 2015
# SEP-24: https://stellar.moneygram.com/stellaradapterservice/sep24
# ✓ real SEP-24 anchor. Set VITE_ANCHOR_HOME_DOMAIN=stellar.moneygram.com to route cash-out through it.
node scripts/verify-anchor.mjs testanchor.stellar.org # the SDF testnet anchor the demo usesWhy the demo uses the SDF test anchor: MoneyGram (and every regulated regional off-ramp) runs on mainnet only — no anchor in the ecosystem exposes a testnet SEP-24 endpoint except SDF's, so a testnet demo can only prove the mechanism there. That's a network limitation, not a missing integration: the exact same SEP-1/10/24 code resolves MoneyGram's real endpoints above.
| Corridor | Real, named target | Status |
|---|---|---|
| Cash route | MoneyGram Ramps — USDC cash-in/out at participating provider-returned locations | Pending allowlist, staging, and Production Preview evidence |
| 🇮🇩 IDR | IDRX — regulated, CertiK-audited Rupiah stablecoin | Roadmap target (idrx.co); Stellar availability still to confirm — not claimed as on Stellar |
Rupiah is the story; the Philippines is the live beachhead — we say so plainly. Our primary target market is Indonesia (the rupiah-erosion problem the whole product is built around), but the corridor that is live on Stellar today is PHP via MoneyGram — not IDR. There is no production IDR off-ramp on Stellar yet: IDRX (a regulated rupiah stablecoin) is the target asset but its Stellar availability is unconfirmed, and MoneyGram's Indonesia payout isn't a listed Stellar corridor. So the honest go-to-market is Philippines-first (the rail exists) with Indonesia next as the IDR corridor lands. We prove the engine and the off-ramp mechanism live in an APAC country now; we do not claim a live rupiah cash-out we don't have.
The shipped cash-out uses the anchor's standard SEP-24 hosted withdraw; the contract also ships a separate offramp() path gated by an on-chain anchor allowlist (unit-tested) for contract-enforced destination control, which a future release wires into the hosted flow. Settlement time is the anchor's (KYC involved) — Shunt reports it honestly instead of pretending it's instant.
Every revenue line is a transparent fee on a service the user wants: 0.4% on Needs-lane cash-out, a similar fee on Top Up and on Invest conversions. No lending, no yield products, no cut of your savings — by design, not by omission: interest-based yield would add unnecessary smart-contract risk. The 10% early-withdrawal penalty goes to your own buffer, not to us. Savings deposits and post-lock withdrawals are free, forever.
Shunt's own service fee is a blended ~0.29% of processed volume. That is Shunt's take, not the total landed cost — a fiat anchor charges its own fee on top, so end-to-end cost depends on the selected anchor and corridor and would be benchmarked before launch. A full illustrative model (ARPU, CAC, payback, LTV, break-even, and the assumptions that would break it) lives in docs/unit-economics.md.
# 1. Contracts — test & build (Rust + stellar CLI)
cd contracts/shunt-vault
cargo test # 49 tests
stellar contract build
# Deploy your own instance (or use the testnet one above)
stellar contract deploy --wasm target/wasm32v1-none/release/shunt_vault.wasm \
--source <IDENTITY> --network testnet
stellar contract invoke --id <CONTRACT_ID> --source <IDENTITY> --network testnet \
-- init --token CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA # USDC SAC (testnet), not the vault's own id
# 2. Keeper — inflow detection + tx preparation (Cloudflare Worker)
cd keeper
npm install
npx wrangler dev --local # http://localhost:8787
# Config lives in wrangler.toml (no .env file). Deploy with `npx wrangler deploy`.
# 3. Web app
cd web
cp .env.example .env # VITE_VAULT_CONTRACT_ID (+ anchor domain, keeper URL)
npm install && npm run dev # http://localhost:5173
# 4. End-to-end tests — REAL testnet, no mocks (see web/e2e/README.md)
npx playwright install chromium # once
npm run test:e2e # funds a throwaway account via Friendbot, buys real
# USDC on the DEX, then walks the whole loop:
# rules → split → vault & goals → anchor in/out → sendNo contract configured? The app runs in local demo mode — the full flow (connect → rules → simulated income → one-tap split → vault → cash-out) works with local state, so you can feel the product before touching a faucet. The "Simulate incoming income" button lives on the Configure Shunt page, in the "Test your rules" card that appears once rules are saved.
contracts/shunt-vault/ Soroban contract — split engine + savings vault (Rust)
web/ React + TypeScript app, mobile-first, PWA-ready (Vite)
keeper/ Cloudflare Worker — 1-min cron poll of Horizon, prepares distribute XDR
design/ Diagrams (animated SVG) + app screenshots
- One tap per income, by design. Soroban's
require_authwants a signature per invocation — and the Invest conversion is a second signature (a Soroban tx is single-operation by protocol). Never over-claimed as hands-free. - The keeper is centralized in this version — but it holds zero keys, income detection now runs client-side from Horizon (so the keeper isn't needed to notice income), and a manual trigger replaces its one remaining job. A single point of convenience, never of custody or fund safety.
- The keeper watches an explicit account list (
WATCH_ACCOUNTS), not every user automatically — its cron poll is demo-scoped. Per-user auto-detection at scale runs client-side today; a subscription/index model for the keeper is roadmap. - The keeper's
/triggerendpoint is unauthenticated by design — it only builds an unsigned XDR that is worthless without the owner's signature, so it is never a fund risk. It is now rate-limited per IP (isRateLimited, default 30/min) with an optional origin allowlist (ALLOWED_ORIGINS) so it can't be spammed into KV-write amplification (keeper/src/env.ts; set the env var andwrangler deployto activate on the live worker). - Anchor settlement is not instant — KYC is involved, and the UI says so instead of hiding it.
- The vault is unaudited and not upgradeable.
initbinds the token on first call; the current deployed instance (CDMFJZ…) is already initialized against the USDC SAC, so the "first caller could bind a fake token" grief window is closed for the live contract. The clean source-level fix — a Soroban__constructorthat binds the token atomically at deploy (no front-run window) plus an admin gate — is a pre-mainnet redeploy step, deliberately deferred so the current on-chain proof hashes stay valid. Keep real amounts trivial until an audit. - Off-ramp destination control: the shipped cash-out is the anchor's standard SEP-24 hosted withdraw; the contract's allowlisted
offramp()path exists and is unit-tested but is not yet wired into that hosted flow. - Replay-guard TTL (pre-production hardening). Each split writes a
Processed(inflow_key)entry that blocks re-processing the same inflow. Like all Soroban persistent state it carries a TTL (~30 days here) and isn't re-bumped, so a very old inflow key could eventually expire and, in principle, be re-processed. Re-processing still needs the owner's signature and can't move funds anywhere but per the rules, so it isn't a theft vector — but we do not claim permanent "one income, one split forever" replay protection. The production fix is a longer/renewed TTL or an archival index; deliberately deferred to avoid a redeploy that invalidates the current proof hashes. - Mainnet: all on-chain proof today is testnet (with real testnet USDC). A trivial mainnet split is a pre-launch step, not claimed as done.
| Next | Run Alchemy Pay/Banxa exact-route checks · complete MoneyGram Ramps allowlist and Production Preview · card checkout on payment links · anchor/provider status webhooks |
| Later | Session keys — truly hands-free splits · split + invest in one signature (AMM router) · deepen the gold (XAUm) invest path once mainnet DEX liquidity is live · native mobile · keeper decentralization |
⑃ money in · structured by code · money out — and the savings lane never lies to you










