Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

141 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Shunt

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.

Shunt — Automated money routing

Stellar Soroban React PWA Tests

🌐 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.

Built real, not slideware

  • 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 → confirmed states. 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_key during 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.

Why people use it

Freelancers and overseas workers who invoice in dollars face three quiet leaks:

  1. 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.
  2. 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.
  3. 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

How Shunt differs from standard vaults (Vaquita, Piggy Wallet, Microvault)

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.

One app, the whole money loop

Animated loop: payment link and top-up in, one-tap split into four lanes, anchor cash-out

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.

How it works

Five steps: connect, set rules, income lands, one tap, auto-split

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.

How a real Indonesian / PH user actually onboards (honest)

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.

Live on testnet

Item Value
Vault contract (USDC) CDMFJZ6VRD2JEV7J2W7KMZZ3AXNSOST2C6L2KYRJAYIN7ULWJEOCWO5Bcurrent 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)

The app

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

Level 1 — White Belt (testnet proof)

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.

Level 2 — Blue Belt (multi-wallet + events)

Requirement Screenshot
Multi-Wallet Options
Showing Freighter, Albedo, xBull
Wallet options
Real-time Event Toast
Soroban split event detected
Event listening

Architecture

Animated architecture: payer, wallet, keeper, web app, vault, anchor

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. ShuntVault holds the Savings lane and enforces the lock on-chain; withdraw_savings answers 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 → confirmed states. 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_key during the lifetime of its persistent replay entry.

ShuntVault contract API

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.

Money in, money out (the anchor stack)

Both directions run on the standard Stellar anchor rails, implemented in web/src/lib/anchor.ts:

  1. SEP-1 — discover the anchor's endpoints from its stellar.toml.
  2. SEP-10 — prove wallet ownership by signing a challenge (no password, no account).
  3. 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 uses

Why 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.

Business model — service fees, never interest

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.

Quickstart

# 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 → send

No 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.

Repository layout

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

Honest limitations

  • One tap per income, by design. Soroban's require_auth wants 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 /trigger endpoint 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 and wrangler deploy to 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. init binds 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 __constructor that 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.

Roadmap

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

About

Financial autopilot for people who earn from abroad

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages