Contract c0cdeaf7c36a5268c7882ccda2aac8f7250eb525270c7b7bd0bf023337f30fb9

← Back to Index 📥 Download WASM

Meta

cliver 27.0.0#5a7c5fe76530bf4248477ac812fc757146b98cc4
rssdkver 25.3.1#e50d95af029c83196dd122f0154bac3f1302394b
rsver 1.96.1

Instances

  • CBBHJYH4I2IEJINCOAVUE3NRLVLMAXCYKKCCT3APV6D5KG32XJLG37WQ
  • CDNRQ4YLW4RA4LB4J4M5S3X4SEXXR3Z6TR7336VKOG3FPX3PBFAMVZ6P

Interface

Add PT coupon capacity: pull amount USDC, wrap to SR, strip into PT+YT held by the vault. Pure capacity — it creates no liability.

Admin-gated. v1's seed was permissionless, which is what turned a capacity limit into tofix.md #18's denial-of-service: anyone could prepend dust positions until the redeem walk exceeded the transaction budget and every receipt became unpayable. There is no walk here, but an open seed still lets a stranger write vault state for the price of a transaction, and nothing needs it to be open.

fn seed(env: soroban_sdk::Env, from: soroban_sdk::Address, amount: i128) -> i128
fn admin(env: soroban_sdk::Env) -> soroban_sdk::Address
fn pause(env: soroban_sdk::Env)

What amount USDC would earn: (payout, coupon, rate_bps). Read-only.

fn quote(env: soroban_sdk::Env, amount: i128) -> (i128, i128, u32)
fn stats(env: soroban_sdk::Env) -> SrVaultStats

Recover surplus inventory — seed capital and unneeded capacity — to to.

Liability-gated, which is tofix.md #22: v1 had no path at all, so seed capital and any over-provisioned inventory were one-way. This releases only PT face above every open payout, so it can never touch a receipt's backing. Admin only.

fn sweep(env: soroban_sdk::Env, to: soroban_sdk::Address, pt_amount: i128) -> i128

Redeem a matured receipt for its full promised payout.

O(1) — and that is the headline difference from v1. v1 walked a list of wrapper positions, redeeming each until the payout was met, at ~7 MB per position; five positions exhausted the mainnet transaction budget and a stranger could inflate the list at will (tofix.md #18). Here PT is fungible bearer, so the vault burns payout PT face in one redeem_py call. Cost does not depend on history, on how the inventory was assembled, or on anything an attacker controls.

fn redeem(env: soroban_sdk::Env, receipt_id: u64) -> i128

Lock a fixed rate. Pulls amount USDC, mints matching PT+YT into inventory, and issues a receipt promising principal + coupon at maturity.

The coupon is backed out of existing capacity: the deposit itself only creates PT equal to the principal, so the coupon must come from spare inventory. That is why the capacity check is the load-bearing line — it is what makes the promise solvent rather than hopeful.

fn deposit(env: soroban_sdk::Env, user: soroban_sdk::Address, amount: i128) -> u64

Claim the vault's YT yield and reinvest it as fresh PT capacity.

No maturity gate and no pruning, which is tofix.md #21. v1's harvest refused to run after maturity and pruned positions that still held live YT, so yield accrued before maturity became permanently unclaimable. Here the engine keeps pre-expiry yield claimable forever, and this simply collects it whenever it is called.

Returns (sr_claimed, py_minted). Reinvestment is skipped past expiry (the engine refuses mint_py then, correctly) — the claimed SR stays as vault inventory instead of reverting and throwing the claim away with it.

fn harvest(env: soroban_sdk::Env) -> (i128, i128)

What [Self::sweep_surplus] would release right now, without moving anything.

fn surplus(env: soroban_sdk::Env) -> (i128, i128, i128)
fn unpause(env: soroban_sdk::Env)
fn version(env: soroban_sdk::Env) -> soroban_sdk::String
fn maturity(env: soroban_sdk::Env) -> u64
fn pt_token(env: soroban_sdk::Env) -> soroban_sdk::Address
fn rate_bps(env: soroban_sdk::Env) -> u32
fn set_rate(env: soroban_sdk::Env, rate_bps: u32)
fn sr_token(env: soroban_sdk::Env) -> soroban_sdk::Address
fn timelock(env: soroban_sdk::Env) -> u64
fn code_hash(env: soroban_sdk::Env) -> soroban_sdk::BytesN<32>
fn is_paused(env: soroban_sdk::Env) -> bool

One-shot, admin-gated init.

Takes only the engine address. sr, pt, underlying and maturity are read back from it, so the tofix.md #24 class of mismatch — a vault wired to an asset its PT does not redeem into — cannot be constructed here.

fn initialize(
    env: soroban_sdk::Env,
    yield_contract: soroban_sdk::Address,
    rate_bps: u32,
    max_rate_bps: u32,
)
fn underlying(env: soroban_sdk::Env) -> soroban_sdk::Address
fn get_receipt(env: soroban_sdk::Env, receipt_id: u64) -> Receipt
fn accept_admin(env: soroban_sdk::Env)

Permissionless TTL keep-alive so a long-dated receipt cannot archive before it matures.

fn bump_receipt(env: soroban_sdk::Env, receipt_id: u64)
fn max_rate_bps(env: soroban_sdk::Env) -> u32
fn set_timelock(env: soroban_sdk::Env, secs: u64)
fn __constructor(env: soroban_sdk::Env, admin: soroban_sdk::Address)
fn apply_upgrade(env: soroban_sdk::Env)
fn pending_admin(env: soroban_sdk::Env) -> Option
fn propose_admin(env: soroban_sdk::Env, new_admin: soroban_sdk::Address)

Recover surplus SR, YT and USDC to to, at or after expiry (tofix.md #22).

sweep handles the PT leg. This handles everything else the vault ends up holding, which the PT-only sweep left permanently stranded — measured at 248.53 SR on a 20,000 USDC seed, about 1.2% of it, plus the USDC flooring remainder.

Why this is gated at expiry and sweep is not

PT face is directly comparable to a payout, so surplus PT can be identified — and released — at any time. The other three legs cannot:

  • YT is what earns the yield that funds future coupons. Before expiry it has real forward value that assert_solvent cannot see, because that invariant compares PT face against liability and says nothing about future capacity. A pre-expiry YT sweep would quietly degrade the vault's ability to meet later payouts while every check still passed.
  • SR resting in the vault before expiry is transient — harvest reinvests it in the same call. It only accumulates after expiry, when mint_py refus
fn sweep_surplus(env: soroban_sdk::Env, to: soroban_sdk::Address) -> (i128, i128, i128)

Flooring loss realized by partial redemptions across open receipts (anyfix.md F2).

fn total_residue(env: soroban_sdk::Env) -> i128
fn cancel_upgrade(env: soroban_sdk::Env)
fn yield_contract(env: soroban_sdk::Env) -> soroban_sdk::Address
fn pending_upgrade(env: soroban_sdk::Env) -> Option
fn total_liability(env: soroban_sdk::Env) -> i128

How much more USDC a receipt still needs before it can be paid. 0 = ready (or closed).

fn redeem_remaining(env: soroban_sdk::Env, receipt_id: u64) -> i128
fn schedule_upgrade(env: soroban_sdk::Env, wasm_hash: soroban_sdk::BytesN<32>) -> u64
fn cancel_admin_transfer(env: soroban_sdk::Env)

Imports

WebAssembly Text (WAT) ▶