A different kind of position.
Sprag is a prototype for collateral-backed credit that buys a project token and uses a repayment ladder to reduce the USDG debt when eligible token sales succeed.
This site is a working local simulation, not a deployed lending protocol. No smart contracts, real lending pools, live token quotes, or wallet balances are represented by the mock database. No private key or RPC access is needed to explore it.
The mechanism
PLEDGE — Tokenized stock or ETH you already hold. Nothing is sold. The scaffold uses WETH as the ETH collateral asset. A future native-ETH deposit flow must explicitly wrap ETH and account for gas.
ENTER — An isolated lending market lends USDG against the collateral. That USDG is routed through WETH into the project token and deposited into a vault assigned to the user.
EXIT — The user configures a ladder. When a token-price target is reached, a successful execution sells enough tokens to fund the chosen USDG repayment and an execution allowance. If liquidity or permissions prevent a fill, the rung stays unfilled.
The intended buy route is USDG → WETH → TOKEN. Repayment sales reverse it: TOKEN → WETH → USDG. Both modeled hops use the 10,000 fee tier, or 1% per hop. The net fee retention is 0.99 × 0.99 = 0.9801, before price impact and slippage.
What can liquidate the position?
The health calculation uses collateral value and USDG debt, not the token purchased with the loan.
collateral value = collateral units × collateral oracle price
LTV = current USDG debt / collateral value
health factor = collateral value × LLTV / current USDG debt
collateral liquidation price = current USDG debt / (collateral units × LLTV)
These displayed USD formulas assume USDG is worth $1. A real implementation must use the actual collateral/loan oracle ratio, token decimals, protocol debt shares, rounding, and market liquidation rules.
The equity fixtures use 63% LLTV; WETH uses 77% LLTV. The default borrowing target is 32.5%, inside the requested 30–35% range. These fixture parameters are not claims about available Morpho deployments. Real Morpho markets require governance-enabled parameters; read the actual deployed market LLTV rather than rounding it or assuming the custom fixture is supported.
The UI conservatively flags a health factor of 1 or below as liquidatable. It does not execute mock liquidations. The exact real-contract boundary and any liquidation incentives must be read from verified contract logic.
A token-price crash leaves the USDG debt intact. A collateral-price decline reduces the collateral health factor. Interest increases the debt and pushes up the collateral liquidation price. These independent effects can be tested in the position’s Scenario Lab.
How the ladder repays
The default ladder has two rungs:
- At 1.5× effective entry price, repay 30% of the original USDG principal.
- At 2.0× effective entry price, repay all remaining USDG debt, including accrued interest.
The effective entry price is original borrowed USDG divided by tokens actually received after modeled buy friction. It is not the pre-swap spot price. Intermediate rungs may be added, with strictly increasing targets and partial repayments totaling less than 100% of original principal. The final rung always repays the remainder.
The simulator solves for the smallest gross token sale that covers a repayment after both reverse-route fees, price impact, slippage, and a $0.25 execution allowance. It does not blindly sell a fixed percentage of the token balance. A price gap can make several rungs eligible; an explicit mock execution processes eligible rungs sequentially in one database transaction. If a required fill is infeasible, that simulated execution rolls back without claiming a repayment.
A reached target alone is not an executed rung. Pausing auto-repay stops ladder execution but does not pause interest or liquidation risk. At zero debt all further scheduled sales stop, even if token prices keep rising.
The four preview numbers
Tokens you receive: the conservative token output after the modeled two-hop buy and chosen slippage tolerance.
Your collateral liquidation price: the price of NVDA, TSLA, SPY, or WETH at which the current collateral/debt ratio reaches the modeled liquidation boundary. It is not a token stop loss.
Interest per day: first-day USDG interest at the displayed mock APR. It is an estimate, not a fixed-rate offer.
Token break-even price: a debt-cover price. It solves for the token price at which a reverse sale of the current tokens would cover current debt and modeled sell friction. It excludes opportunity cost, taxes, and collateral investment performance. It is not a promise of profit. Interest, depth changes, and partial repayments change this line. An impossible fill is shown as not coverable, never as an infinite or fabricated quote.
Credit capacity
A token’s credit ceiling is based on the USD-equivalent value of modeled executable WETH-side depth. It is not total two-sided pool TVL and not nominal position-manager liquidity.
per-position cap = WETH-side executable depth × 2%
aggregate cap = WETH-side executable depth × 10%
reserved = sum of original borrowing notionals for positions with debt > 0
remaining = max(0, aggregate cap − reserved)
max next position = min(per-position cap, remaining)
The reservation model is intentionally conservative: partial repayments do not free capacity. A reservation is released only when the position has no debt. Interest does not create a second origination reservation. New borrowing also needs enough USDG lending liquidity and must remain strictly below collateral LLTV.
The server rechecks all of these constraints inside the opening transaction. Concurrent requests cannot rely on a stale client meter. Per-position caps can be split across positions or wallets; they are not a Sybil defense. The aggregate cap remains necessary. Oracle manipulation, LP withdrawal, and correlated borrowing require further production controls.
What FREE CARRY means
FREE CARRY means the position has zero USDG debt and the collateral is available to withdraw. Remaining tokens stay in the user’s modeled vault. If the collateral is withdrawn, the position becomes CLOSED while preserving its debt-free receipt and token balance.
It does not mean free money, a guaranteed residual value, or a profitable investment. Remaining tokens can still lose all their value. The Share button generates a 1200 × 630 PNG containing a visible demo disclosure. The same image endpoint is used for Open Graph metadata.
Risk disclosure
- Your USDG debt does not shrink if the token falls.
- Your collateral can still be liquidated if the collateral price falls or interest accrues.
- The token issuer can pause transfers, block addresses, or force-burn stock tokens.
- Execution depends on liquidity. A ladder target is not a guaranteed fill.
Issuer terms vary by instrument. Production integrations must verify issuer controls, transfer eligibility, oracle freshness, stock-market hours, corporate actions, depeg exposure, and collateral valuation gaps. Smart-contract, bridge, sequencer, MEV, rounding, permission, and liquidity risks are additional concerns. A user-owned vault is an architectural intention until audited contracts actually enforce it.
What the mock does—and does not do
The deterministic seed creates four collateral markets, eight positions, two debt-free outcomes, and illustrative price history. Five fixtures belong to the demo account; other accounts’ fixtures can only be inspected through the UI. Newly opened demo positions also belong to the demo account.
All position changes persist in SQLite. A fixed scenario clock starts at the configured MOCK_START_TIME; the +1 day interest control advances it. Prices do not automatically drift with wall-clock time. UI data refreshes periodically, but these are simulated snapshots, not live market feeds. Quote expiry uses real wall-clock time.
The swap model uses two virtual constant-product reserve approximations to demonstrate fee, impact, and slippage effects. It is not Uniswap V3 tick-accurate pricing. The WETH-side depth is an explicit fixture assumption. Production must obtain executable route quotes from verified pool/quoter contracts and calculate depth using the actual concentrated-liquidity curve.
Interest is simple between saved debt snapshots. Real lending integrations must read protocol debt shares and the current borrow index. USDG is assumed to be worth $1. The $0.25 execution allowance is a mock modeling assumption, not a gas quote. Numbers use JavaScript floating point and SQLite Float for presentation simulation only; real financial state requires scaled integers or exact decimal arithmetic.
Manual mock repayments use simulated external USDG without reading a funded wallet balance. Scenario Lab changes are shared in the local demo database. There is no live trading, real collateral custody, or real signature collection.
From mock to on-chain
The composition root is lib/adapters/index.ts. It selects implementations for ILendingAdapter, ISwapAdapter, and IVaultAdapter using NEXT_PUBLIC_ADAPTER_MODE=mock|onchain.
The on-chain classes intentionally throw ADAPTER_NOT_CONFIGURED. They contain no fabricated product ABI. Setting the environment variable does not secretly fall back to mock balances and does not make the protocol live. Demo mutation endpoints refuse to operate in on-chain mode. Wallet connection is isolated to on-chain mode; connecting a wallet alone does not authorize a backend mutation.
Before real execution, implement verified deployments, asset decimals, wallet ownership/authentication, strict network checks, issuer restrictions, oracle freshness, market LLTV, real debt accounting, executable route quotes, minOut/deadlines, capacity enforcement, and atomic pledge/borrow/swap/vault operations. Enforce owner permissions and stop-at-zero invariants in audited contracts, not just the database.
Network constants in lib/chain.ts were supplied in the product brief. TOKEN, USDG, and Sprag deployment addresses are deliberately blank. Stock-token addresses and the token identifier in the seed are mock fixtures. Do not promote them into production configuration. Rebuild after changing public environment variables.
The indexer uses viem getLogs only when configured with an explicit on-chain contract and start block. It records raw logs and a cursor without inventing a decoder or inferring positions. A short confirmed overlap can be replayed; deep-reorg recovery and authoritative state reconciliation remain integration work.
The keeper is hard-coded DRY RUN ONLY. It reports eligible repayments, but never constructs a wallet client, reads a private key, sends a transaction, or mutates a position. Setting its dry-run environment variable to false makes it refuse startup. Real keeper execution must be a separate, reviewed implementation.
API & local workflow
GET /api/stats
GET /api/markets
GET /api/tokens/[address]/capacity
GET /api/positions?owner=0x...
GET /api/positions/[id]
POST /api/positions/simulate
GET /api/board?sort=size&direction=desc
The capacity endpoint returns token metadata, the capacity calculation, and price snapshots together. Additional mock-only endpoints create positions, update ladders, toggle auto-repay, simulate fills, repay, withdraw, or change the scenario. The full API contract and payload examples are in the repository README.
npm install
npm run dev
# Unit tests, type check, and production build
npm run check
# Inspect the seeded database or restore the initial scenario
npm run db:studio
npm run db:reset
# Standalone workers; neither sends transactions
npm run indexer -- --once
npm run keeper -- --once
Primary integration references
Use canonical documentation and verified deployment artifacts—not the mock implementation—as the authority when wiring real contracts.
