Module 06 — Staking (STASIS Vault)

The STASIS vault is a three-layer system: wrap STASIS into yield-bearing wSTASIS, lock it as collateral, borrow USDB against it. Your collateral earns yield at every layer — including while it backs a loan.

Prerequisites

  • Hold STASIS — buy it via trading, wrap=true on a buy makes this one tx
  • Wallet funded with USDB (→01), client initialized (→02)
  • Understand Stable+ ratchet mechanics — STASIS is the canonical Stable+ token

Next steps after staking


Why Stake

Platform trading fees flow automatically into the vault, increasing the wSTASIS:STASIS exchange rate over time. Every trade on the entire platform — not just STASIS trades — contributes to vault yield (because all factory tokens route through STASIS). When you unwrap, you receive more STASIS than you deposited.

The second reason: wSTASIS is collateral. Lock it, borrow USDB, deploy that capital into trades, markets, or more staking. The locked wSTASIS keeps earning while it backs the loan. Capital works twice simultaneously.

Phase 1 is the best entry window. Platform volume is growing, staking participation is still low, and the yield-per-token is at its highest point. As more participants stake, individual yield moderates. As volume increases, total yield grows. The equilibrium shifts over time — early stakers capture the most favorable ratio. Staking also accrues airdrop points daily.


How It Works

The vault is ERC4626 compliant. The wSTASIS:STASIS exchange rate strictly increases over time as fees accumulate. Three layers, each independent:

Layer 1 — Passive Yield (wrap / unwrap):

STASIS → staking.buy() → wSTASIS (yield-bearing, appreciates over time) wSTASIS → staking.sell() → STASIS (more than deposited)

Layer 2 — Collateral (lock / unlock):

wSTASIS → staking.lock() → Locked wSTASIS (still earning yield, immobile) Locked → staking.unlock() → wSTASIS (only after repaying any loan)

Layer 3 — Borrowing (borrow / repay):

Locked → staking.borrow(amount, days) → Liquid USDB USDB → staking.repay() → Loan cleared → can now unlock

Quick exit path: staking.sell(shares, claimUSDB=true) does atomic unwrap-to-USDB in one transaction. Skip the sell-STASIS step entirely.


Actions

Stake — client.staking.buy(stasisAmount)

Wraps STASIS into wSTASIS yield-bearing shares. Auto-approves STASIS to the vault. Earns airdrop points daily based on staked amount.

Pre-flight:

  1. Confirm STASIS balance >= amount (use balanceOf())
  2. Check minBuyAmount if relevant
  3. Preview conversion rate with convertToShares() first
// JS — stake 100 STASIS
const result = await client.staking.buy(parseUnits("100", 18));
console.log("Wrapped:", result.hash);
# Python — stake 100 STASIS
result = client.staking.buy(100 * 10**18)
print("Wrapped:", result["hash"])

Fee: 0% to wrap. The only real cost is the 0.5% swap fee + slippage when you bought STASIS in the first place.


Unstake — client.staking.sell(shares, claimUSDB?, minUSDB?)

Unwraps wSTASIS back to STASIS. You receive more STASIS than you staked (yield accrued in the rate).

ParamTypeDescription
sharesbigintwSTASIS shares to unwrap
claimUSDBbooleanAtomic unwrap-to-USDB in one tx. Default: false
minUSDBbigintSlippage floor if claimUSDB is true

Pre-flight — all three must be clear before calling sell():

  1. wSTASIS is NOT locked as collateral
  2. No active vault loan outstanding
  3. No resolver vote cooldown (24h lock applies after governance votes)

If any of these block you: repay the loan first (repay()), then unlock (unlock()), then sell.

// Standard unwrap
const sellResult = await client.staking.sell(shares);

// Atomic unwrap-to-USDB (single transaction)
const sellResult = await client.staking.sell(shares, true, minUSDB);

Staking Loan — Lock, Borrow, Manage, Repay

Vault loans differ from regular loans in one key way: collateral keeps earning yield while pledged. Fees are identical: 2% origination + 0.005%/day. There is one loan per wallet — no simultaneous second loan.

Full sub-flow:

Step 1 — Lock wSTASIS as collateral

// Convert STASIS amount to shares first — CRITICAL: lock() takes wSTASIS shares, not STASIS
const shares = await client.staking.convertToShares(parseUnits("100", 18));
const lockResult = await client.staking.lock(shares);

Critical: As yield accrues, the exchange rate diverges from 1:1. Always use convertToShares() to get the correct share count. Passing STASIS amounts directly to lock() will lock the wrong amount.

Step 2 — Borrow USDB against locked collateral

borrow() takes a STASIS-denominated amount (not wSTASIS shares). The contract converts internally using the current exchange rate.

Minimum duration: 10 days (hardcoded in contract). Take minimum and extend as needed.

// Borrow 50 STASIS worth of USDB for 30 days
const borrowResult = await client.staking.borrow(parseUnits("50", 18), 30n);
borrow_result = client.staking.borrow(50 * 10**18, 30)

To find your maximum borrow capacity from wSTASIS shares:

const wStasisShares = /* your locked balance */;
const stasisEquivalent = await client.staking.convertToAssets(wStasisShares);
// You can borrow up to stasisEquivalent (100% LTV — primary recommendation)
await client.staking.borrow(stasisEquivalent, 10n);

Borrowing at 100% LTV: Borrowing the full getAvailableStasis() amount is the primary recommended approach — it maximises deployed capital. However, when you borrow 100%, there is no collateral buffer remaining, so any future extendLoan() call must use payInUSDC: true since fees cannot be deducted from collateral. If you prefer to extend from collateral rather than paying in USDB, borrow ~98% of available capacity instead to retain a small buffer.

Fee: 2% flat origination + 0.005%/day interest (prepaid). USDB received = collateral value minus origination fee. Earns airdrop points at origination and daily while active.

One loan per wallet — the critical rule

StateWhat to call
No active loanborrow(amount, days)
Active loan existsaddToLoan(additionalAmount) — NOT borrow(). (The contract calls this increaseLoan internally; the SDK wraps it as addToLoan. Same pattern as hub increaseLoan.)
Need more timeextendLoan(daysToAdd, payInUSDC, refinance) — 400x cheaper than new loan

Calling borrow() when a loan already exists will revert with "Position active. Use increaseLoan". Check getUserStakeDetails() first.

Step 3 — Extend if needed

Extension costs only 0.005%/day — the same daily rate with no 2% origination fee. That makes it roughly 400x cheaper than closing and opening a new loan.

extendLoan takes three parameters: (daysToAdd, payInUSDC, refinance). The payInUSDC parameter is critical when collateral is fully pledged — if there is no collateral buffer to deduct fees from, you must pay the extension fee in USDB directly.

// Extend by 30 more days — pay fee in USDB (required when collateral is fully pledged)
const extendResult = await client.staking.extendLoan(30n, true, false);

Rule of thumb: take short initial durations (10-14 days), extend as needed. Prepaid interest is not refunded on early repayment.

Step 4 — Repay

Repays the vault loan in full. Auto-approves USDB. After repaying, collateral is released from the loan but remains locked — you must call unlock() separately.

const repayResult = await client.staking.repay();
repay_result = client.staking.repay()

Step 5 — Unlock collateral

After repaying, unlock the wSTASIS shares to make them liquid again.

const unlockResult = await client.staking.unlock(shares);

Pass shares as BigInt directly. Do NOT convert with Number() — large values lose precision.

Step 6 (if loan expired) — Settle expired position

If a vault loan expires without repayment, the loan expires and the position is closed by the protocol (time-based expiry — not price liquidation). Call settleLiquidation() to claim any surplus collateral value above the debt.

await client.staking.settleLiquidation();

Complete Example: Full Stake → Borrow → Repay → Exit

async function stakingOperations() {
  const client = await BasisClient.create({ privateKey: "0xYourPrivateKey..." });
  const { parseUnits } = require("viem");

  // 1. Wrap STASIS into wSTASIS
  await client.staking.buy(parseUnits("100", 18));

  // 2. Lock wSTASIS as collateral — always convert to shares first
  const shares = await client.staking.convertToShares(parseUnits("100", 18));
  await client.staking.lock(shares);

  // 3. Borrow USDB (amount in STASIS units, 18 decimals)
  await client.staking.borrow(parseUnits("50", 18), 30n);

  // 4. ... deploy borrowed USDB ...

  // 5. Repay the loan
  await client.staking.repay();

  // 6. Unlock collateral
  await client.staking.unlock(shares);

  // 7. Unwrap wSTASIS back to STASIS (receive more than deposited)
  await client.staking.sell(shares);
}
def staking_operations():
    client = BasisClient.create(private_key="0xYourPrivateKey...")

    client.staking.buy(100 * 10**18)

    shares = client.staking.convert_to_shares(100 * 10**18)
    client.staking.lock(int(shares))

    client.staking.borrow(50 * 10**18, 30)

    # ... deploy borrowed USDB ...

    client.staking.repay()
    client.staking.unlock(int(shares))
    client.staking.sell(int(shares))

Read Methods

getUserStakeDetails(user) — Full position breakdown

Returns the complete staking state for an address. Use this before any operation to check what's liquid, locked, and in use.

const [liquidShares, lockedShares, totalShares, totalAssetValue] =
  await client.staking.getUserStakeDetails(wallet);
FieldDescription
liquidShareswSTASIS that can be unlocked or transferred
lockedShareswSTASIS locked in vault (earning yield, immobile)
totalSharesliquidShares + lockedShares
totalAssetValueSTASIS equivalent of all shares (for display and collateral checks)

getAvailableStasis(user) — Available collateral

Returns STASIS available for new collateral pledges: total asset value minus what is already pledged to active loans.

const available = await client.staking.getAvailableStasis(wallet);
// Returns bigint in 18 decimals

convertToShares(assets) — STASIS → wSTASIS preview

Given a STASIS amount, returns how many wSTASIS shares you would receive. Use before calling buy() to preview the conversion, and before lock() to get the correct share count.

const shares = await client.staking.convertToShares(parseUnits("100", 18));

convertToAssets(shares) — wSTASIS → STASIS preview

Given wSTASIS shares, returns the equivalent STASIS amount. Use to check how much STASIS your locked position represents — needed to determine max borrow capacity.

const stasisEquivalent = await client.staking.convertToAssets(shares);

totalAssets() — Vault total

Returns total STASIS held by the vault across all stakers (available + pledged as collateral). Useful for gauging vault participation and yield dilution.

const total = await client.staking.totalAssets();

When and How Much to Stake

The question is not whether to stake — it is how much, given what you plan to do next.

Recommended starting split: 30–50% of STASIS holdings staked, rest liquid.

SituationAdjustment
Lots of attractive trades and new marketsKeep more liquid
Platform is quiet, capital sitting idleStake more
Want to borrow meaningfullyStake enough that the borrowable amount is worth the 2% origination fee
First time stakingStart smaller, verify the full cycle before committing large amounts

Phase 1 note: Staking participation is low relative to growing platform volume. The yield-per-STASIS is at its highest. This window closes as more participants stake.

Break-even consideration: Round-trip fees are ~1% (0.5% buy + 0.5% sell on STASIS, plus slippage both ways). A $100 position needs $1+ in yield before it is profitable. Vault staking is a days-to-weeks position, not hours.

// Estimate your round-trip break-even before staking
const entryAmount = parseUnits("1000", 18);
const entryPreview = await client.trading.getAmountsOut(entryAmount, [USDB, MAINTOKEN]);
const entryCost = entryAmount - entryPreview;
const roundTripCost = entryCost * 2n;
// Your vault position needs to earn more than roundTripCost in yield to be profitable

Fees

ActionFee
Wrap (buy)0% — lossless
Unwrap (sell)0% — lossless
Entry (buy STASIS)0.5% swap fee + slippage
Exit (sell STASIS)0.5% swap fee + slippage
Full round-trip~1% raw fees + variable slippage both ways
Lock / unlock0% (gas only)
Vault loan origination2% flat
Vault loan interest0.005% per day (prepaid, no refund on early repayment)
Loan extension0.005% per day — no origination fee

Vault yield is variable. No fixed APY exists. Yield depends on total platform trading volume and the percentage of STASIS supply currently staked. Both variables change continuously.


Errors

ErrorTriggered byFix
"Below min buy"buy() with too small an amountIncrease stake amount
"Insufficient locked balance"lock() operationsLock more wSTASIS first
"Cannot withdraw: Collateral in use"sell() while wSTASIS is lockedRepay vault loan → unlock() → then sell()
"Position active. Use increaseLoan"borrow() when loan already existsUse addToLoan() to add collateral to existing loan
"Insufficient collateral value"borrow() or addToLoan()Stake more STASIS, then lock more wSTASIS
"Duration too short"addToLoan() when loan has < 10 days remainingCall extendLoan() first — see Module 05 §Recovery Flows

For the full alphabetical error index across all modules, see Module 18 — SDK Reference.


Pitfalls

  • Staking for hours: Round-trip fees require yield to cover them. Think days minimum, not hours.
  • Passing STASIS amounts to lock(): lock() takes wSTASIS shares. Once the exchange rate diverges from 1:1 (which it will), this locks the wrong amount. Always call convertToShares() first.
  • Not checking hasActiveLoan before borrow(): One loan per wallet. Call getUserStakeDetails() first. If lockedShares > 0 and a loan is active, use addToLoan().
  • Re-originating instead of extending: Each new loan costs 2% origination. Extension costs 0.005%/day. Take a short loan, extend as needed — do not close and re-open.
  • Letting the loan expire without claiming: On expiry (time-based, not price-based), remaining collateral surplus above the debt does not auto-return. You must call settleLiquidation() to claim it.
  • Not calculating break-even: Use getAmountsOut() to preview actual swap costs before entering. Factor in size and planned hold duration.

What Next

Staking is Path A in the stacking strategies guide — the foundation layer that everything else builds on.

After staking:

  • Borrow against wSTASIS to get liquid USDB → Lending
  • Buy more tokens with borrowed USDB → Trading
  • Create a new token → Token Creation
  • Bet on prediction markets → Predictions
  • See Path A in the full stacking strategies context → Strategy & Stacking

The core compound loop:

Buy STASIS → stake (wrap) → lock → borrow USDB → reinvest ↑ | └──── yield appreciates wSTASIS ────────┘ extend loan → extract more → repeat

Your wSTASIS earns from every trade on the platform. Your borrowed USDB earns from wherever you deploy it. Both run simultaneously. When the wSTASIS appreciation exceeds your loan value, refinance — extract more capital without closing the position.


See Also