Contract d9d159816210ca2655944a398f20f1b297f2d8b6764925634a9e94ba91150745

← Back to Index πŸ“₯ Download WASM

Meta

cliver 27.0.0#5a7c5fe76530bf4248477ac812fc757146b98cc4
rssdkver 25.3.1#e50d95af029c83196dd122f0154bac3f1302394b
rsver 1.96.1

Instances

  • CAJKHGY3J2XSZHI3TFDFMXJ2GDFFUPUPPTUOP6UOBHSY6FW66J6YYBP7
  • CDWLAKWQ3OEIBRHNUN3KHS2WS7SCJF7RY372ZLUQFKJKU4H7XTJKKWTI

Interface

The Blend pool address (read-only view, handy for the frontend / dashboard).

fn pool(env: soroban_sdk::Env) -> soroban_sdk::Address
fn admin(env: soroban_sdk::Env) -> soroban_sdk::Address

Withdraw shares worth of underlying from Blend and send it to to. Returns underlying out.

fn redeem(env: soroban_sdk::Env, to: soroban_sdk::Address, shares: i128) -> i128

Pull amount USDC from from (the wrapper) and supply it to Blend. Returns shares minted.

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

Human-readable semver of the source build (informational; for verifiable identity use [Self::code_hash]).

fn version(env: soroban_sdk::Env) -> soroban_sdk::String
fn timelock(env: soroban_sdk::Env) -> u64

The live deployed WASM hash (32-byte SHA-256) of the running code β€” reflects the current build even across upgrades.

fn code_hash(env: soroban_sdk::Env) -> soroban_sdk::BytesN<32>

One-shot, admin-gated initialization.

  • admin β€” operational admin (pause/upgrade path; cannot move user funds).
  • wrapper β€” the Spield wrapper; the sole authorized caller of deposit/redeem.
  • pool β€” the Blend pool contract.
  • underlying β€” the asset SAC (USDC) to supply.
  • max_apr_bps β€” max allowed annual b_rate growth, in basis points (the sanity bound, pro-rated by elapsed time on each read). Set generously above Blend's real max borrow APR (e.g. 30_000 = 300%) so honest reads always pass while a wild read is still caught.
fn initialize(
    env: soroban_sdk::Env,
    wrapper: soroban_sdk::Address,
    pool: soroban_sdk::Address,
    underlying: soroban_sdk::Address,
    max_apr_bps: u32,
)
fn rate_bound(env: soroban_sdk::Env) -> (i128, u64, u32)

The underlying asset SAC.

fn underlying(env: soroban_sdk::Env) -> soroban_sdk::Address

Accept a pending admin proposal (step 2 of 2). Must be called by the proposed admin.

fn accept_admin(env: soroban_sdk::Env)

Live Blend b_rate (SCALAR_12), with the sanity bound applied and last_rate advanced.

fn current_rate(env: soroban_sdk::Env) -> i128

Where claimed BLND goes. Defaults to the admin until set.

fn emissions_to(env: soroban_sdk::Env) -> soroban_sdk::Address
fn set_timelock(env: soroban_sdk::Env, secs: u64)

Total shares this strategy holds in Blend (the wrapper's whole position).

fn total_shares(env: soroban_sdk::Env) -> i128

Atomic deploy-time constructor (no deploy→init front-run). Binds admin the moment the strategy exists; the remaining [Self::initialize] is then gated to this admin.

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

Propose a new admin (step 1 of 2). Current admin authorizes; the proposed admin must then call accept_admin to take control.

fn propose_admin(env: soroban_sdk::Env, new_admin: soroban_sdk::Address)
fn cancel_upgrade(env: soroban_sdk::Env)

Underlying value of shares at the live rate.

fn position_value(env: soroban_sdk::Env, shares: i128) -> i128

Claim accrued BLND to [Self::emissions_to]. Permissionless.

Returns the amount claimed β€” 0 when there is nothing, which is not an error and must not panic: a keeper calls this on a schedule and an empty claim is the normal case.

BLND is not re-supplied into Blend, and that is deliberate rather than lazy. SR is minted one-for-one with the b_tokens Blend returns, and its exchange rate is Blend's own b_rate β€” not position / supply. Re-supplying would therefore mint b_tokens that no SR is entitled to: b_rate would not move, no redemption could reach the extra value, and Sr::realizable_rate would start reporting above Sr::exchange_rate β€” a number users could see and never realise. Routing BLND to the treasury keeps every SR invariant exactly as it is.

fn claim_emissions(env: soroban_sdk::Env) -> i128
fn pending_upgrade(env: soroban_sdk::Env) -> Option

Widen (or tighten) the max annual b_rate growth, in basis points (the bound is then pro-rated by elapsed time on each read β€” see check_rate_bound_timed). Admin only.

This is the safety valve for the soft-brick risk: if Blend's real b_rate ever rises faster than the configured annual ceiling, every current_rate read would otherwise panic and freeze the whole protocol (no claims/redeems/mints/solvency reads). The admin can raise the ceiling to unstick it without a redeploy. last_rate/last_ts are preserved.

Intentionally immediate (not timelocked): it is a liveness safety valve that can only widen tolerance on an already-trusted, monotonic Blend rate β€” it can never mint value or move funds. Raising it does not bypass any solvency check; the wrapper still asserts backing >= principal against Blend's real position on every mutation.

fn set_max_apr_bps(env: soroban_sdk::Env, max_apr_bps: u32)

The recovery valve for a b_rate DECREASE. Lowers the stored last_rate high-water mark to the pool's live b_rate, re-stamping last_ts to now. Admin only. Returns the floor in effect after the call.

check_rate_bound_timed rejects current < last outright, because Blend documents b_rate as monotonic non-decreasing. If Blend ever socialises bad debt and the rate dips by even one stroop, that guard sits under current_rate, which sits under every wrapper entry point β€” mint, claim_yield, redeem_pt (even at maturity), combine_and_redeem, position_value and solvency all revert RateOutOfBounds. Only transfer_position survives (it never reads the rate), so a position could be moved but never exited, and the freeze lasts until Blend's rate climbs back above the high-water mark β€” with no admin action, timelock, or upgrade able to shorten it.

[Self::set_max_apr_bps] is not a substitute: it widens the upper ceiling, and this failure is the lower monotonicity guard. Wideni

fn reset_rate_floor(env: soroban_sdk::Env) -> i128

Schedule a contract upgrade to wasm_hash, applyable after the timelock. Returns the eta.

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

Admin-only. The destination is fixed precisely so that [Self::claim_emissions] can be open to anyone without letting the caller choose where the money lands.

fn set_emissions_to(env: soroban_sdk::Env, to: soroban_sdk::Address)

Withdraw exactly amount underlying from Blend and send it to to. Returns shares burned.

fn redeem_underlying(
    env: soroban_sdk::Env,
    to: soroban_sdk::Address,
    amount: i128,
) -> i128

The current b_rate sanity bound: (last_rate, last_ts, max_apr_bps). View for monitoring β€” lets ops watch the last observed rate/time and the configured annual-growth ceiling. Underlying the pool can actually pay out right now (tofix.md #20).

A withdrawal does not fail because the protocol is insolvent β€” it fails because borrowers have taken the supply and the pool has nothing on hand. Nothing on chain surfaced that in advance, so an exit either worked or reverted with no way to find out first, and no way to take a smaller amount that would have succeeded.

The bound is the pool's own token balance minus backstop_credit: a lending pool cannot hand out what it does not hold, and part of what it holds is already owed to the backstop.

Still an upper bound, but a tight one. Touching the pool accrues a little more backstop_credit, so by the time a withdrawal is evaluated the true limit has moved a hair below what was read. Measured at 0.001% on a mainnet-parameter pool aged six month

fn available_liquidity(env: soroban_sdk::Env) -> i128

BLND accrued to this strategy and not yet claimed. Pure. 0 when the pool has no emissions configured for our supply side, which is the case on mainnet today.

fn claimable_emissions(env: soroban_sdk::Env) -> i128

Cancel a pending admin proposal. Current admin only.

fn cancel_admin_transfer(env: soroban_sdk::Env)

Loss accounting. What the whole Blend position is really worth right now β€” live b_rate, no monotonicity guard, no write.

[Self::current_rate] refuses a fallen rate, which freezes every deposit, sync and redemption until [Self::reset_rate_floor]. That is the right safety behaviour and the wrong behaviour for a question a user is entitled to an answer to during the freeze: how much money actually exists? This reads the venue and reports it, unguarded.

It is therefore the only rate path here that can report a number LOWER than the stored high-water mark. Never route a deposit or a redemption through it β€” the guard exists for a reason. Sr::realizable_rate composes it into the per-share figure a UI should quote.

fn position_value_unguarded(env: soroban_sdk::Env) -> i128

Imports

WebAssembly Text (WAT) β–Ά