WiftWiftConnect Wallet
DOCS

Wift technical reference.

Builder-facing documentation: the XRPL primitives Wift composes, the transaction sequences for each user operation, the math for NAV and YTM, the indexer REST API, the security model, and the mainnet roadmap. Start at the top if you're integrating; jump by section if you're debugging.

1 · Architecture overview.

Wift is a composition of five XRPL native primitives. There is no custom smart contract.

┌──────────────────────────────────────────────────────┐ │                       XRPL L1                        │ │                                                      │ │   SingleAssetVault   →   LoanBroker                  │ │   (XLS-65)               (XLS-66)                    │ │   shares as MPT          originates loans            │ │       │                                              │ │       │ share MPT                                    │ │       ▼                                              │ │   Wift Wrapper ←── 3-of-5 multisig                   │ │   pseudo-account    asfDisableMaster                 │ │       │                                              │ │       │ PT IOU / YT IOU                              │ │       ▼                                              │ │   Native XRPL DEX order book (OfferCreate)           │ │       │                                              │ │       ▼                                              │ │   Price discovery · Fixed rate lock · Credit curve   │ └──────────────────────────────────────────────────────┘

Every arrow above is a real XRPL transaction. No off-chain state, no oracle, no sidechain. The “contract” in Wift is the 3-of-5 multisig rule enforced by five independent signers.

2 · XRPL primitives used.

SpecRoleStatus on target
XLS-65 SingleAssetVaultunderlying yield sourcelive (rippleci/rippled)
XLS-66 LendingProtocolbroker originates loanslive
XLS-33 MPTvault shareslive
IOU trustlinesPT and YT tokenslive (P0.3 fallback path)
Native DEX (OfferCreate)PT/XRP and YT/XRP marketslive
SignerListSet3-of-5 wrapper multisiglive
Batchatomic split (optional)live on rippleci
XLS-101d SmartContractv2 trustless wrappernot yet upstream

The P0.3 preflight established that AMMCreate currently rejects MPT amounts with Amount can not be MPT. Wift therefore issues PT and YT as IOUs, not MPTs, so the native DEX can list them. Vault shares themselves stay MPT because they never touch the DEX — they're locked in the wrapper and burned at redemption.

3 · The wrapper pseudo-account.

The Wift wrapper is a standard AccountRoot created by the team:

  • A SignerListSet transaction installs five independent public keys with quorum 3.
  • An AccountSet transaction sets the asfDisableMaster flag. The master key is permanently disabled — the only way to authorise anything from this account is via 3-of-5 multisig.
  • The wrapper holds locked vault shares (MPT) for every active series and is the issuer of every PT and YT IOU.
  • Relayer policy (public, deterministic): sign nothing that would violate the invariant shares_locked == PT_supply == YT_supply. A relayer that signs a non-compliant op is removed from the signer list.

The wrapper address, signer list and quorum live in shared/config.yaml and are served via the indexer /wrapper endpoint.

4 · Series lifecycle.

A series is a {broker, maturity} pair. Each series has its own PT currency, YT currency, order book offers, and maturity timestamp. Setup sequence:

  1. VaultCreate by the broker owner. Asset is XRP for v1. Returns a vault pseudo-account and a ShareMPTID.
  2. LoanBrokerSet on the vault, withCoverRateMinimum in 1/10 bps (not plain bps — range 0..100000). Returns a LoanBroker object.
  3. The depositor VaultDeposits XRP into the vault and receives MPT shares.
  4. The depositor sends those shares to the Wift wrapper account via Payment.
  5. The wrapper multisig signs a Payment back to the depositor with PT IOU + YT IOU (equal amounts). Atomic via Batch if available, sequential + compensation otherwise.
  6. The depositor (or any other user) calls OfferCreate on the native DEX to seed the PT/XRP and YT/XRP order books.

All of the above is scripted in the seeder (backend/seeder/) and produces the live entries in shared/series_registry.json.

5 · The split operation.

The user-facing Mint flow:

1. User → Wrapper: Payment(share MPT, amount N) 2. Wrapper (multisig 3/5) → User: Payment(PT IOU, amount N) + Payment(YT IOU, amount N)

Steps 2a and 2b are wrapped in a Batch tx when the amendment is enabled, which gives atomic all-or-nothing semantics. When Batch is unavailable the relayer leader falls back to sequential submission with a compensation tx (a Payment(share → user) refund) if step 2b fails.

Post-op, the wrapper re-checks the invariant by reading its locked share balance and the twoIOUissuances' outstanding amounts. Mismatch triggers a loud alert and blocks further signing until reconciled.

6 · Trading on the native DEX order book.

Wift originally targeted the native XRPL AMM, but the Phase 0 preflight established that AMMCreate rejects MPT-typed amounts, and the upstream rippleci build also has rough edges around AMMCreate with fresh IOUs. The Phase 1 implementation switched to the native XRPL DEX order book via OfferCreate:

  • The depositor (“Alice” in the seeder) holds a large reserve of PT and YT and places resting sell offers at gradually walked prices. This is the market animator (Track E, see backend/arb_bot).
  • Buyers place matching OfferCreate or use pathfinding Payment to fill. Every fill is a real XRPL tx with a verifiable hash.
  • The indexer derives the spot PT price from the best ask at each ledger and inserts an amm_observations row (the table name pre-dates the pivot).
  • Prices are quoted in drops per token. 1 drop = 1e-6 XRP. A PT at 0.95 drops/PT with par at 1.00 implies a ~7% APR for a 90-day maturity.

7 · Redemption at maturity.

Once maturity_unix ≤ now, the wrapper opens the redemption window. The multisig signs payouts according to which legs the user holds:

User holdsPer-unit payoutMath
PT + YT (pair)1 share returned per unitinvariant-neutral
PT onlyXRPmin(1, NAV_T)
YT onlyXRPmax(0, NAV_T − 1)

NAV_T is read from the vault via the vault_info RPC after the broker collects all LoanPay transactions due at maturity. The wrapper burns the incoming PT and/or YT IOUs and emits the matching Payment to the user.

8 · NAV and YTM math.

NAV per share (XLS-65)

NAV_per_share = (Vault.AssetsTotal − Vault.LossUnrealized) / MPTokenIssuance(ShareMPTID).OutstandingAmount

AssetsTotal is the full accrued value of the vault including scheduled interest. LossUnrealized is moved only by LoanManage (impair / unimpair / default). On deposit (mint), LossUnrealized is not subtracted — the formula above applies to redemption only.

Implied YTM from PT price

YTM = (1 / PT_price)^(365 / days_to_maturity) − 1

PT_price is expressed in the underlying unit such that PT redeems to 1 unit at par (e.g. drops/PT with par = 1 drop/PT). The formula annualises the implied discount rate. Used by the dashboard credit curve and by GET /curve.

Cover rate (XLS-66)

required_cover = DebtTotal × CoverRateMinimum / 1_000_000 (CoverRateMinimum unit is 1/10 basis points, range 0..100000)

On LoanSet the ledger rejects origination with tecINSUFFICIENT_FUNDS ifCoverAvailable < required_cover. When cover is below the floor, broker feePaid is automatically redirected to the cover pool until the floor is refilled.

9 · Indexer REST API.

The Track C indexer exposes FastAPI at http://localhost:8000 by default (CORS wide-open). Read-only endpoints:

GET /health                            # liveness probe GET /wrapper                           # wrapper multisig + signer list GET /series                            # all active series with joined live state GET /series/{id}                        # one series, full detail GET /curve                             # credit curve (one point per series) GET /observations/{id}?side=PT&limit=100 # time-series for the price chart GET /holders/{id}?limit=20              # top-N holders of PT/YT

Response shapes mirror shared/series_registry.json for static fields and the indexer Postgres schema for live state (see backend/indexer/schema.sql). All decimals are returned as floats; all timestamps as ISO-8601.

10 · Security model.

Trust assumption (v1)

Three honest relayers out of five. Each relayer runs a watcher that refuses to sign any operation that would violate the wrapper invariant. The master key of the wrapper account is disabled (asfDisableMaster), so no key can bypass the quorum.

Adversary scope

  • A single malicious relayer cannot mint unbacked PT or YT — its partial is useless without 2 others.
  • Three colluding relayers can mint unbacked tokens. The economic deterrent is the public signer list and social slashing at the protocol level. This is an explicit trust assumption, not a theorem.
  • The wrapper cannot create shares out of thin air — the MPT-backed vault share is the only thing the invariant checks against.

v2 trustless path

When XLS-101d SmartContract lands upstream, the wrapper becomes a ContractCall. The invariant becomes a hard ledger rule, trust assumption drops to zero. Existing PT and YT holders are unaffected — the wrapper account simply becomes contract-controlled instead of multisig-controlled.

11 · Error codes and edge cases.

  • tecINSUFFICIENT_FUNDS on LoanSet— the broker's cover pool is below DebtTotal × CoverRateMinimum. Deposit more cover before originating.
  • temINVALID on LoanBrokerSet — check that fee-rate fields are within documented ranges. ManagementFeeRate, CoverRateLiquidation, and CoverRateMinimum are all in 1/10 bps and are immutable after creation.
  • Amount can not be MPT on AMMCreate — the documented P0.3 failure. Use IOUs for PT/YT.
  • Invariant drift detected by the indexer — the affected series is flagged status = 'degraded' and a row is inserted in invariant_violations. The relayer leader stops signing for that series until a human reconciles.
  • Late LoanPay at maturity — extra interest is added to Vault.AssetsTotal and flows to YT holders via a higher NAV_T.
  • LoanManage tfLoanImpair mid-series — Vault.LossUnrealized is incremented and NAV drops immediately. PT and YT prices re-quote on the next indexer poll cycle.

12 · Roadmap.

  • Hackathon (April 2026) — v1 wrapper, 3 live series (safe / medium / risky), live credit curve, full Mint / Redeem / Trade / Portfolio flow on local standalone rippled.
  • Post-hackathon Q2 — switch to public devnet once XLS-66 lands there, add one real broker integration, open the relayer set to three external operators.
  • Q3 — migrate to ContractCall once XLS-101d is live upstream. Wrapper becomes trustless. No breaking change for PT/YT holders.
  • Q4 — YT stream (continuous distributions on every LoanPay), multi-asset vault support, cross-series portfolio risk dashboard.