BSKUSD
Pool v5.13.0 · staking v1.3.0 Network: … Contract: … Dashboard: Dune Updated: October 19, 2026

Start Here

BSKUSD is a dollar backed by a basket of stablecoins held in the contract: USDT, USDC, DAI and PYUSD. Any BSKUSD can be redeemed for any coin in the basket at any time.

sBSKUSD is staked BSKUSD. sBSKUSD holders receive 95% of the pool's fees. The term is 30 days.

Where the yield comes from

When stablecoin prices drift apart, bots swap through the pool and pay the 0.02% swap fee. That is the only source of yield: no emissions, no subsidies, no governance token.

30-day term

Leaving before 30 days returns only what you put in; the income stays in the vault for the remaining stakers.

The three main risks

  • One coin depegs. Up to 50% of the basket can end up in the coin that lost value.
  • An issuer blocks the pool's address. USDC, USDT and PYUSD can freeze an address — that coin's share is unavailable until it is rotated out.
  • A bug in the contract. The code is immutable: a bug cannot be fixed, only migrated away from. Worst case — total loss.

Details with numbers — in Risks.

What BSKUSD is not

  • not an algorithmic stablecoin — every BSKUSD is backed by coins held in the contract;
  • not an LP token exposed to volatile assets — the basket holds only dollar stablecoins;
  • not an emission token — new BSKUSD appear only against deposited coins and as fees.

Live numbers

TVL, daily volume and 30-day yield are on the Dune dashboard. Basket composition and rates are in the app.

Where next

2. How The Pool Works

The mechanics without reading code. Each topic: an explanation, the numbers, and a formula at the end for those who need it.

The basket

The basket holds 4 coins. Addresses and decimals are read from the contract:

IndexCoinAddressDecimalsStatus
Reading the contract…

Why these coins. They are the largest fiat-backed dollar stablecoins from different issuers (Circle, Tether, Paxos, Sky). A problem at one issuer affects only that issuer's share of the basket.

How a new coin is added. The administrator announces it (schedule_add_token); after 14 days there is a 14-day window to add it. The basket can hold up to 6 coins. Each new coin lowers the share cap: with 5 coins it is 40%.

Price and invariant

The swap rate follows from the pool's balances through the StableSwap formula — there is no oracle. While the coins are roughly equal, the rate is almost 1:1. The more uneven the basket, the cheaper the over-supplied coin becomes in the pool: that is how the pool pays bots to rebalance it.

How long the rate stays near 1:1 is set by the amplification A. Now A = … (ann = …). The higher A, the flatter the rate under imbalance.

Share of one coin in the basketIts rate to the othersDeviation from 1:1
Calculating…
Calculated with the contract's formula for the current A.

Invariant (as in _get_d): ann·Σx + D = ann·D + D^(n+1) / (n^n·Πx), where ann = A·n and x are balances in 18 decimals. The swap rate is the _get_y solution for the new balance.

Deposit (mint)

Deposit one coin (mint) or all coins in the pool's current proportion (mint_proportional). The deposit fee is 0%. You receive as much BSKUSD as the invariant D grows: almost 1:1 when the basket is even; under imbalance, depositing the over-supplied coin gives slightly less and the scarce coin slightly more.

Example: deposit $10,000 of one coin into a $1,000,000 poolBSKUSD received
Calculating…

Withdraw (burn)

Burn BSKUSD into one coin (burn) or into all coins proportionally (burn_proportional). The withdrawal fee is 0.02%.

  • A paused coin can still be withdrawn. A pause only closes deposits and swaps into that coin.
  • A coin that cannot be transferred (the issuer blocked the pool). Withdrawing into that coin reverts; other coins work. A proportional withdrawal goes through and the untransferred part is queued — collect it later with claim(token, to).

Swap (exchange)

Swapping one basket coin for another costs 0.02%. get_dy(i, j, dx) quotes it with the fee included. The contract requires the swap fee to be no higher than deposit plus withdrawal: otherwise a swap would cost more than "deposit one coin and withdraw another", and bots would route around it.

Share cap — the main protection

No coin may exceed 50% of the basket (cap = 2 ÷ number of coins, at most 60%). When a coin depegs, bots bring it into the pool and take the healthy ones. The cap stops this: no more than 50% of the bad coin can enter the basket, so at least half of the backing stays in other coins.

An operation that would push a coin past the cap reverts with error 15. Operations that reduce the imbalance always pass. Near the limit the app shows the maximum amount.

Slot floor

No coin may fall below 0.5% of the average share (D ÷ n × 0.5%). This keeps the pool's math away from division by near-zero and prevents fully draining one coin. Violation — error 16.

Where fees go

Fees do not stay in the pool as coins; they become BSKUSD:

  • swap — the pool mints new BSKUSD equal to the growth of D from the fee;
  • deposit and withdrawal — the fee is taken in BSKUSD from the operation's amount.

This BSKUSD is split at once: 95% to the sBSKUSD vault (…), 5% to System Revenue (…). If no vault is connected or it has no shares, the whole fee goes to System Revenue.

Virtual price

get_virtual_price() = D ÷ BSKUSD supply. It is the backing ratio: invariant dollars per 1 BSKUSD. It is at least 1 and barely moves. The swap fee is minted as new BSKUSD for the same growth of D, so virtual price does not show yield. Staking yield is measured by the growth of the sBSKUSD share price — see section 3.

3. Staking sBSKUSD

Three things to know before you deposit
  1. The term is 30 days. Leaving earlier returns only what you put in.
  2. The yield is not fixed. It depends on the pool's volume and can be zero.
  3. Transferring sBSKUSD restarts the receiver's term.

How to enter

  1. Let the vault spend BSKUSD: BSKUSD.approve(vault, amount).
  2. Deposit: deposit(amount, receiver). On the Staking page it is one button.

You get fewer sBSKUSD shares than the BSKUSD you deposit: the share price grows with every fee, so one share is worth more than 1 BSKUSD. There is no minimum. The very first deposit into the vault burns 10⁶ shares (10⁻¹² sBSKUSD) — a guard against rounding attacks.

How yield is calculated

Fees arrive in the vault as BSKUSD. The number of shares stays the same while the vault's BSKUSD grows — so each share's price rises (totalAssets ÷ totalSupply).

Yield ≈ staking share × pool fees per year ÷ BSKUSD staked

Example (a calculation, not a promise). A $5M pool with daily swaps of 150% of TVL ($7.5M) at 0.02%: $1,500 of fees a day. Stakers get 95% — $1,425 a day. With $4M staked that is ≈ 13% a year. A $10,000 position earns ≈ $107 in 30 days. At half the volume — half the yield.

Yield changes day to day because it depends on how many swaps happened. On a quiet day it can be close to zero.

Where to see the yield

On the dashboard — for 7 and 30 days. It is calculated from the share price: (price today ÷ price N days ago − 1) × 365 ÷ N. Past yield does not guarantee future yield.

The 30-day term

The term counts from the deposit. Leaving before it ends returns only the principal; the income your position earned stays in the vault and is shared by the remaining stakers. After the term the full share value is paid and no new term starts — you can leave at any time.

Example: 10,000 BSKUSD deposited, 100 BSKUSD earned over the periodYou receive
Leave on day 2010,000 BSKUSD
Leave on day 4010,100 BSKUSD

Topping up

The start date is averaged by amount: new start = (P × start + X × now) ÷ (P + X), where P is the principal and X the top-up.

  • Position not yet matured. 10,000 on day 25, top up 10,000: the start moves from day 0 to day 12.5, unlock to day 42.5 — 17.5 days from now.
  • Matured position. It is pinned to "exactly matured": its value becomes the principal and start = now − 30 days. A top-up X to a position P delays unlock by X ÷ (P + X) × 30 days: an equal amount — 15 days.

Transferring sBSKUSD

sBSKUSD can be transferred. The matching part of the principal moves with the shares (the full value if the sender has matured). But the receiver's term for the incoming shares starts at the transfer. For trading sBSKUSD on a DEX: the buyer gets the position's principal and can take its income only after 30 days.

How to leave

  1. Check the position: position(owner) returns shares, value, principal, start date, unlock date, payout now and a "term complete" flag. preview_exit(owner, shares) gives the exact payout for the chosen shares.
  2. Leave: redeem(shares, receiver, owner) or withdraw(assets, receiver, owner).
Do not decide with previewRedeem

The standard ERC-4626 previewRedeem, previewWithdraw and convertToAssets do not know the owner. Before the term they overstate the payout (full value instead of the principal). Owner-specific numbers come from preview_exit, maxWithdraw and position.

On to stablecoins

After leaving, burn BSKUSD into any basket coin (0.02%) or into all of them proportionally. Full path "sBSKUSD → dollars": leave the vault (no fee) → leave the pool (0.02%).

What the vault does not have

  • no administrator and no pause — nobody can stop withdrawals or change the rules;
  • the term is set at deployment and never changes;
  • no support for fee-on-transfer or rebasing tokens (the vault works only with BSKUSD).

4. Economics And Governance

The answer to "who can change my terms, and how". Everything is published here: the completeness of this section is what makes the rules a commitment rather than an intention.

Fee split

Stakers 95%, system 5%. System Revenue: … (fixed in the contract forever). The system's share pays for audits, bug bounties and development.

The share ladder

A team commitment, not contract code

The contract allows a staking share from 5% to 95%, moving at most 10 points per 7 days. The ladder below is a narrower rule the team commits to.

StageConditionStakersSystem
0 — Launchfrom day one95%5%
1 — GrowthTVL ≥ $2M for 30 days in a row, yield ≥ 9%85%15%
2 — MaturityTVL ≥ $5M for 30 days, yield ≥ 8%75%25%
3 — ScaleTVL ≥ $10M for 30 days, yield ≥ 8%65%35%
4 — StabilityTVL ≥ $25M for 30 days, yield ≥ 7%55%45%
Limitnevernot below 50%not above 50%

Three rules:

  1. Only at a milestone. Average TVL at the milestone for 30 days in a row, and at least 4 weeks since the last change.
  2. Yield guarantee. The share drops only if the expected staker yield stays at or above 7% afterwards. Otherwise the step is postponed, and that is announced.
  3. Up is always allowed. If yield stays below 5% for two weeks, the staking share goes up one step.

Check it yourself: TVL and 30-day yield are on the dashboard; an announced split change is visible in the contract (pending_system_revenue_bp, pending_split_eta) and in the app under "Upcoming changes".

Fees

Now: deposit … · swap … · withdraw ….

Contract limits: each fee at most 0.06%; a swap never costs more than deposit plus withdrawal.

Team commitment

Deposits are always 0%. Swaps never above 0.04%. The swap fee moves to 0.03% when daily volume is steadily above 100% of TVL and more than half of the trades come from outside bots.

Timelocks

Every change is first announced in the contract, then waits, then has a window to be applied. If the window is missed, the change does not happen.

What changesNoticeWindowStep limitWhere to see it
Fees7 days14 days, anyone can applyeach ≤ 0.06%pending_fees()
Staking share7 days14 days, anyone≤ 10 points per step, system 5–95%pending_split_eta
Amplification A1 day2 days, administrator; then a 3-day rampat most ×2; steps 7 days apartpending_ann_eta
New coin14 days14 days, administratorup to 6 coinspending_token_eta
Coin rotationpause ≥ 7 days + 14 days14 days, anyonethe new coin is deposited in advance and visible in the contractrot_token(i), rot_eta(i)
Administratoruntil accepted—the new address must acceptpending_admin

All announced changes with dates are shown in the app, "Upcoming changes".

Roles

RoleWhoWhat it can do
admin… · …announce fees, split, A, a new coin; pause and unpause; run rotations; set the pauser; hand over the role
pauser…only pause a coin
System Revenue…only receives its share of fees; the address is immutable

The administrator can — with notice

  • change fees within 0.06%;
  • change the staking share in 10-point steps (5–95%);
  • change A at most ×2 per step;
  • add a coin (14 days);
  • replace a coin through rotation (pause ≥ 7 days + 14 days);
  • pause a coin immediately.

Can never

  • withdraw the pool's reserves;
  • block withdrawals (burn) — they work even when paused;
  • change the staking vault or the System Revenue address;
  • change the staking term;
  • take more than 95% of fees;
  • set a fee above 0.06%;
  • upgrade the code — there is no proxy.

Amplification

Now A = …. For a staker: a higher A gives a flatter rate, more volume and more fees — but in a depeg the bad coin fills the pool faster (up to the cap). ann range: 120 – 999,960, a multiple of 60; at most ×2 per step, no more than once in 7 days, with a 3-day ramp. A can change only when the basket is even (each coin 70–130% of the average share).

Change history

DateWhat changedWhyTransaction
No changes since launch yet. All contract events are on the contract page in the explorer.

5. Risks

Each risk in one format: what can happen → what the contract does → what the team does → what a staker loses in the worst case. No softening.

One coin depegs

What happensA coin loses its peg. Bots bring it into the pool and take the healthy coins. ContractThe share cap stops this at 50% of the basket. TeamThe pauser pauses the coin (deposits and swaps into it close), then a rotation to another stablecoin. Worst caseUp to 50% of the basket in a coin worth X. Coin falls to $0.50 → BSKUSD is ≈ 75% backed.

An issuer blocks the pool's address

What happensUSDT, USDC or PYUSD freezes the pool's address: the coin can no longer be transferred. ContractWithdrawals into other coins work. A proportional withdrawal passes; the blocked part is queued for claim. TeamRotate the frozen coin to another stablecoin. Worst caseThat coin's share (up to 50%) is frozen until rotation or unblocking.

A bug in the contract

What happensA vulnerability in the pool or the vault. ContractThe code is immutable: no proxy, no upgrades. A bug cannot be fixed — only migrated away from. TeamAudits, bug bounty, an incident plan (section 7). Worst caseTotal loss of funds.

Yield below expectations

What happensFew swaps — few fees. ContractThere is no minimum yield. TeamPer the share ladder: yield below 5% for two weeks → staking share goes up. Worst case0% yield, principal intact.

Early exit

What happensYou leave before 30 days. ContractReturns only the principal. Team— Worst caseThe period's income is lost.

Parameter changes by the administrator

What happensThe administrator raises fees, lowers the staking share, changes A or coins. ContractOnly with notice and within limits (section 4). Reserves cannot be taken and withdrawals cannot be blocked. TeamThe share ladder and fee commitments. Worst caseWithin the contract: a 5% staking share takes 9 steps of 7 days. A staker has time to leave.

Key compromise

What happensAn attacker gets the admin or pauser key. ContractWith the admin key — whatever the admin can do, with the same timelocks. With the pauser key — only pausing a coin; withdrawals remain. TeamAdmin now: …. With a Safe multisig an attacker needs several keys. Worst caseInconvenience, not loss of reserves. The most dangerous path — rotating a coin into a fake one — is visible 21 days ahead (rot_token), enough time to leave.

Regulatory risk

What happensThe basket coins' issuers are regulated. Contract— TeamThe project gives no legal guarantees. Worst caseSee "An issuer blocks the pool's address".

Known limitations

What the contract deliberately does not do:

  • no oracle — the rate follows only from balances;
  • no automatic pause on a depeg — the pauser or administrator pauses;
  • no support for fee-on-transfer or rebasing tokens;
  • the vault's previewRedeem does not know the term and overstates the payout before it;
  • a coin cannot be removed from the basket — only replaced by rotation.

6. Developers And Bots

Everything here is copyable. Connect in an hour, without asking in chat.

Addresses

Network… · chain id …
BSKUSD pool (also the BSKUSD token)…
sBSKUSD vault…
admin…
pauser…
System Revenue…

Coins with indices and decimals — in The basket.

ABI

Full JSON: pool v5.13.0 · vault v1.3.0. Minimal swap ABI:

Swap ABI
[
  "function coins(uint256) view returns (address)",
  "function N_COINS() view returns (uint256)",
  "function balances(uint256) view returns (uint256)",
  "function get_dy(int128 i, int128 j, uint256 dx) view returns (uint256)",
  "function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) returns (uint256)",
  "function fees() view returns (uint256, uint256, uint256)",
  "function fee() view returns (uint256)",
  "function A() view returns (uint256)",
  "function paused(uint256) view returns (bool)"
]

StableSwap-compatible interface

Routers and bots that already work with StableSwap pools trade this pool without changes.

FunctionSame as StableSwapDifference
get_dy, exchangeyes, int128 indices—
coins, balances, N_COINSyesbalances are in each coin's own units
A, A_preciseyesA = ann ÷ n
feeyes, 10 decimalsthe swap fee; deposit and withdrawal are in fees()
get_virtual_priceyesD ÷ BSKUSD supply
add_liquidity / remove_liquiditynouse mint / burn and the proportional versions
LP tokenno separate oneBSKUSD is the LP token — the pool is the token

Quote and swap

Order: get_dy → min_dy with a tolerance → approve → exchange. Gas: 166–191k per swap, 111–134k per single-coin deposit or withdrawal, ≈ 245k for a basket deposit or withdrawal (measured on the USDT, USDC, PYUSD and DAI code, 4 coins).

Python · web3.py
from web3 import Web3
w3 = Web3(Web3.HTTPProvider(RPC_URL))
pool = w3.eth.contract(address=POOL, abi=SWAP_ABI)
erc20 = w3.eth.contract(address=pool.functions.coins(0).call(), abi=ERC20_ABI)

dx = 10_000 * 10**6                                  # 10,000 of coin 0 (6 decimals)
dy = pool.functions.get_dy(0, 1, dx).call()           # quote, fee included
min_dy = dy * 9_990 // 10_000                         # 0.1% tolerance

erc20.functions.approve(POOL, dx).transact({"from": ME})
pool.functions.exchange(0, 1, dx, min_dy).transact({"from": ME})
Solidity
interface IBasketPool {
    function get_dy(int128 i, int128 j, uint256 dx) external view returns (uint256);
    function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) external returns (uint256);
    function coins(uint256 i) external view returns (address);
}

function swap(IBasketPool pool, int128 i, int128 j, uint256 dx, uint256 slippageBp) external returns (uint256) {
    uint256 dy = pool.get_dy(i, j, dx);
    uint256 minDy = dy * (10_000 - slippageBp) / 10_000;
    IERC20(pool.coins(uint256(int256(i)))).approve(address(pool), dx);
    return pool.exchange(i, j, dx, minDy);
}

Slippage. The price is get_dy(i, j, dx) ÷ dx adjusted for decimals. Compare it with a quote for a small amount: the difference is the trade's price impact.

Deposit and withdraw

OperationQuoteCall
Deposit one coinquote_mint_net(i, amount)mint(i, amount, min_bsk)
Deposit the basketquote_mint_proportional(bsk)mint_proportional(amounts[6], min_bsk)
Withdraw one coinquote_burn(i, bsk)burn(i, bsk, min_out)
Withdraw the basketquote_burn_proportional(bsk)burn_proportional(bsk, min_out[6])
Collect a queued payoutclaimable(token, me)claim(token, to)

Quotes revert exactly where the operation would, with the same error code. Indices in mint/burn are uint256; arrays have 6 elements (pad with zeros).

Trade limits

  • Share cap (15). After a trade, x_i ÷ Σx ≤ cap for the coin whose share grows. Max dx for coin i: (cap × Σx − x_i) ÷ (1 − cap) in 18 decimals (ignoring the outgoing coin — for the exact value binary-search with get_dy).
  • Slot floor (16). Every coin after the operation > D ÷ n × 0.5%.
  • A swap cannot reduce D (31). A rounding guard: a swap that would shrink the invariant reverts.
  • Pause (23). A paused coin cannot be deposited or sold to the pool; it can be bought and withdrawn.

Error codes

A refused call reverts with Err(uint256), selector 0x39eabce6. The 10 most common first; the full list of every pool and vault code follows.

CodeWhyWhat to do
15The coin would exceed the share capReduce the amount or deposit the whole basket
16A coin would fall below the slot floorWithdraw less of that coin or proportionally
25Output below your minimumRefresh the quote, check the tolerance
23The coin is pausedPick another coin; withdrawing into it works
12Transferring the coin into the pool failedCheck approval and balance
14The coin cannot be sent from the poolWithdraw into another coin or proportionally (part goes to claim)
21The pool is not launched yetWait for launch
31The swap would reduce the invariantThe amount is too small or hit rounding — increase it
60A basket withdrawal would deliver under 99% of what is owedWithdraw less or coin by coin
72One coin of a proportional withdrawal is below its minimumUpdate min_out

All pool codes bskUSD v5.13.0

CodeWhat happenedWhereWhat to do

sBSKUSD vault codes v1.3.0

The vault uses the same Err(uint256) format, but its own numbering: code 2 in the vault is not code 2 in the pool. Check which contract the call went to.

CodeWhat happenedWhereWhat to do

Reading a code: revert data = 0x39eabce6 + the code as a 32-byte number. Example: 0x39eabce6…000f = 15. Code 65 is not used in v5.13.0.

Events

EventFields
TokenExchangebuyer, sold_id, tokens_sold, bought_id, tokens_bought, fee_bsk
Mintuser, token_in_idx, token_in_raw, bsk_gross, bsk_fee, bsk_net
MintProportionaluser, bsk_net, bsk_fee
Burnuser, token_out_idx, bsk_in, bsk_fee, bsk_effective, token_out_raw
BurnProportionaluser, bsk_in, bsk_fee
ClaimQueued / Claimedtoken, funder, amount_raw
FeesScheduled / FeesApplied / FeesCancelledmint_bp, swap_bp, burn_bp, eta
SplitScheduled / SplitApplied / SplitCancellednew_system_revenue_bp, eta / old, new / cancelled_bp
AnnChangeScheduled / AnnChanged / AnnChangeCancellednew_ann, eta / old_ann, new_ann
AddTokenScheduled / TokenAdded / AddTokenCancelledtoken, amount_raw, eta / index, bsk_net, ann
TokenPaused / TokenUnpausedindex
RotationFunded / RotationScheduled / RotationExecutedindex, new_token, amount_raw, eta / old_token, old_raw, new_raw, old_sent, surplus_sent
RotationCancelled / RotationReclaimedindex, token, funder, returned
AdminProposed / AdminChanged / PauserSet / VaultSetrole addresses; VaultSet — staking_vault, system_revenue_bp
Vault: Deposit / WithdrawERC-4626 standard
Vault: Exitowner, receiver, shares, assets, forfeited, matured — how much income was left in the vault on an early exit

The sBSKUSD vault and ERC-4626

Non-standard behaviour
  • previewRedeem, previewWithdraw, convertToAssets do not know the owner and show the full price before the term. Use preview_exit(owner, shares), maxWithdraw(owner), position(owner).
  • maxRedeem(owner) = 0 for an unmatured position with no principal.
  • A transfer restarts the receiver's term. For lending markets and protocols like Pendle: shares taken as collateral or wrapped are under a 30-day term from the transfer, and an early exit returns only the principal.

Adapters

A DefiLlama adapter (TVL and yield) and an example for aggregator routers are in the repository.

Source code

Code is on GitHub, version tags v5.13.0 / v1.3.0. Vyper 0.4.3, evm-version prague; the pool uses optimize codesize. To verify bytecode: vyper -f bytecode_runtime bskUSD_v5.13.0.vy and compare it with the code at the contract address.

7. Security

AuditsReports will be published in full: who, when, which commit, a findings table with severity and status (fixed / accepted as a risk — with an explanation).
Bug bountyA program on Immunefi: payouts by tier, scope — both contracts.
ImmutabilityNo proxies, no upgrades. Fixed forever: the System Revenue address, the vault (once connected), the staking term, fee limits (0.06%) and split limits (5–95%).
Keysadmin — …; pauser — a separate key for instant pauses. Key holders are listed by role.
Admin powersSee "Can / can never".
Incident planThe pauser pauses a coin within minutes of a depeg or a block. Status is published in the official channels. What a staker can do alone: leave the vault and burn BSKUSD into healthy coins — this always works.
Vulnerability contactemail and PGP key — to be published

FAQ

What backs BSKUSD and where can I check it?

The basket coins held in the pool contract. Read the balances directly with balances(i) or in the app. → The basket

Where does the yield come from if there is no token?

From swap fees paid by bots that rebalance prices. No emissions. → Yield

Why was the yield 14% yesterday and 6% today?

Income depends on daily volume: many swaps on a volatile day, few on a quiet one. Look at the 30-day yield. → Yield

What happens if I leave on day 20?

You get your principal; the 20 days of income stay with the other stakers. → Term

I topped up — why did my unlock date move?

The start date is averaged by amount: a top-up is new money with its own term. An equal amount on day 25 moves the unlock to day 42.5. → Topping up

Can I sell sBSKUSD on a DEX? What does the buyer get?

Yes. The buyer gets the principal, and their term starts at the transfer. → Transfers

What if USDT or PYUSD blocks the pool?

That coin can no longer be withdrawn; other coins work. Its share is frozen until rotation. → Risks

What happens if one coin depegs? How much can I lose?

No more than that coin's share, which the 50% cap limits. A coin at $0.50 → backing ≈ 75%. → Risks

Can the admin take the money or stop withdrawals?

No. There is no function to withdraw reserves, and withdrawals work even when paused. → Roles

How fast can fees and the staking share change? How do I know in advance?

No sooner than 7 days after the announcement. Announcements are visible in the contract and in the app under "Upcoming changes". → Timelocks

Why does previewRedeem show more than I receive?

It does not know the owner and shows the full price. Before the term you receive only the principal — use preview_exit. → How to leave

How do I get USDC back instead of BSKUSD?

Leave the vault, then burn BSKUSD into USDC (0.02%). → Withdraw

What is claim and when do I need it?

If a coin could not be sent to you on withdrawal, it waits in a queue. Collect it with claim(token, to) or the button in the app. → Withdraw

Who audited it?

Reports are published in full in Security.

Is there a governance token or an airdrop?

No, and none is planned.

Why is depositing free but withdrawing is not?

Deposits add reserves and benefit every holder. The withdrawal fee keeps "deposit + withdraw" from undercutting the swap fee. → Swap

How do I connect a bot?

Addresses, a minimal ABI and a swap example are in section 6.

Addresses And Links

BSKUSD pool…
sBSKUSD vault…
System Revenue…
DashboardDune
Source codeGitHub
Auditreport
Пул v5.13.0 · стейкинг v1.3.0 Сеть: … Контракт: … Дашборд: Dune Обновлено: 19 октября 2026

Начало

BSKUSD — доллар, обеспеченный корзиной стейблкоинов, которые лежат в контракте: USDT, USDC, DAI и PYUSD. Любой BSKUSD можно в любой момент обменять на любую из монет корзины.

sBSKUSD — стейкинг BSKUSD. Держателям sBSKUSD идёт 95% комиссий пула. Срок — 30 дней.

Откуда доход

Когда курсы стейблкоинов на рынке расходятся, боты обменивают монеты через пул и платят комиссию обмена 0,02%. Это единственный источник дохода: эмиссии, субсидий и токена управления нет.

Срок 30 дней

Выход раньше 30 дней возвращает только вложенное; доход остаётся в вейлте и достаётся остальным стейкерам.

Три главных риска

  • Депег одной монеты. До 50% корзины может оказаться в подешевевшей монете.
  • Блокировка адреса пула эмитентом. USDC, USDT и PYUSD могут заморозить адрес — доля этой монеты будет недоступна до ротации.
  • Ошибка в контракте. Код неизменяем: найденную ошибку нельзя исправить, только мигрировать. В худшем случае — полная потеря.

Подробно, с числами — в разделе «Риски».

Чем BSKUSD не является

  • не алгоритмический стейблкоин — каждый BSKUSD обеспечен монетами, лежащими в контракте;
  • не LP-токен с непостоянными потерями в волатильных активах — в корзине только долларовые стейблкоины;
  • не токен с эмиссией — новые BSKUSD появляются только под внесённые монеты и как комиссия.

Текущие цифры

TVL, оборот за день и доходность за 30 дней — на дашборде Dune. Состав корзины и курс — в приложении.

Куда дальше

2. Как работает пул

Механика без чтения кода. В каждой теме — объяснение, числа и, в конце, формула для тех, кому она нужна.

Корзина

Сейчас в корзине 4 монеты. Адреса и decimals читаются из контракта:

ИндексМонетаАдресDecimalsСтатус
Читаем контракт…

Почему эти монеты. Это крупнейшие долларовые стейблкоины с обеспечением у разных эмитентов (Circle, Tether, Paxos, Sky). Проблема одного эмитента касается только его доли в корзине.

Как добавляется новая монета. Администратор объявляет её (schedule_add_token) — через 14 дней у него есть 14 дней, чтобы её добавить. Всего в корзине может быть до 6 монет. С каждой новой монетой потолок доли снижается: при 5 монетах — 40%.

Курс и инвариант

Курс обмена следует из балансов пула по формуле StableSwap — оракула нет. Пока монеты в корзине примерно поровну, курс почти 1:1. Чем сильнее перекос, тем дешевле в пуле монета, которой слишком много: так пул платит ботам за то, чтобы они возвращали баланс.

Насколько курс держится у 1:1, задаёт амплификация A. Сейчас A = … (ann = …). Чем выше A, тем дольше курс остаётся почти ровным при перекосе.

Доля одной монеты в корзинеЕё курс к остальнымОтклонение от 1:1
Считаем…
Рассчитано по формуле контракта для текущего A.

Формула инварианта (как в _get_d): ann·Σx + D = ann·D + D^(n+1) / (n^n·Πx), где ann = A·n, x — балансы в 18 знаках. Курс обмена — решение _get_y для нового баланса.

Вход (mint)

Внести можно одну монету (mint) или все монеты в текущей пропорции пула (mint_proportional). Комиссия входа сейчас 0%. За монеты вы получаете столько BSKUSD, на сколько вырос инвариант D: при ровной корзине это почти 1:1, при перекосе вход «лишней» монетой даёт немного меньше, а недостающей — немного больше.

Пример: вносим $10 000 одной монетой в пул на $1 000 000Получим BSKUSD
Считаем…

Выход (burn)

Сжечь BSKUSD можно в одну монету (burn) или во все сразу пропорционально (burn_proportional). Комиссия выхода сейчас 0,02%.

  • Монета на паузе — выход в неё работает. Пауза закрывает только вход и обмен в эту монету.
  • Монета не переводится (адрес пула заблокирован эмитентом). Выход в одну эту монету откатится; выход в другие монеты работает. Пропорциональный выход проходит, а непереведённая часть ставится в очередь — её можно забрать позже через claim(token, to).

Обмен (exchange)

Обмен одной монеты корзины на другую стоит 0,02%. Котировку даёт get_dy(i, j, dx), комиссия в ней уже учтена. Контракт требует, чтобы комиссия обмена была не больше, чем вход плюс выход: иначе обмен был бы дороже пути «внести одну монету и сразу вывести другую», и боты шли бы в обход.

Потолок доли — главная защита

Ни одна монета не может занять больше 50% корзины (потолок = 2 ÷ число монет, не выше 60%). Когда монета теряет привязку, боты несут её в пул и забирают здоровые. Потолок останавливает этот процесс: дальше 50% плохой монеты в корзину не попадёт, и половина обеспечения гарантированно остаётся в других монетах.

Операция, после которой доля монеты превысила бы потолок, откатывается с ошибкой 15. Операции, которые уменьшают перекос, проходят всегда. Около границы максимальную сумму показывает приложение.

Минимум слота

Ни одна монета не может опуститься ниже 0,5% средней доли (D ÷ n × 0,5%). Это защищает математику пула от деления на почти ноль и не даёт полностью вычерпать одну монету. Нарушение — ошибка 16.

Куда идут комиссии

Комиссии не остаются в пуле в виде монет, а превращаются в BSKUSD:

  • обмен — пул выпускает новые BSKUSD ровно на величину прироста D от комиссии;
  • вход и выход — комиссия удерживается в BSKUSD из суммы операции.

Эти BSKUSD сразу делятся: 95% — в вейлт sBSKUSD (…), 5% — на адрес System Revenue (…). Если вейлт не подключён или в нём нет ни одной доли, вся комиссия идёт System Revenue.

Virtual price

get_virtual_price() = D ÷ выпуск BSKUSD. Это коэффициент обеспечения: сколько «долларов инварианта» приходится на 1 BSKUSD. Он не меньше 1 и почти не меняется. Комиссия обмена выпускается новыми BSKUSD на тот же прирост D, поэтому virtual price не показывает доход. Доход стейкера считается по росту цены доли sBSKUSD — см. раздел 3.

3. Стейкинг sBSKUSD

Три вещи, которые нужно знать до депозита
  1. Срок 30 дней. Выход раньше возвращает только вложенное.
  2. Доходность не фиксирована. Она зависит от оборота пула и бывает нулевой.
  3. Перевод sBSKUSD начинает срок получателя заново.

Как войти

  1. Разрешите вейлту списать BSKUSD: BSKUSD.approve(vault, amount).
  2. Внесите: deposit(amount, receiver). На странице «Стейкинг» это одна кнопка.

Долей sBSKUSD вы получите меньше, чем внесли BSKUSD: цена доли растёт с каждой комиссией, поэтому одна доля стоит больше 1 BSKUSD. Минимальной суммы нет. Самый первый депозит в вейлт сжигает 10⁶ долей (10⁻¹² sBSKUSD) — это защита от атаки на округление.

Как считается доход

Комиссии приходят в вейлт как BSKUSD. Число долей не меняется, а BSKUSD в вейлте становится больше — поэтому растёт цена каждой доли (totalAssets ÷ totalSupply).

Доходность ≈ доля стейкинга × комиссии пула за год ÷ BSKUSD в стейкинге

Пример (расчёт, не обещание). Пул $5 млн, обмены за день — 150% TVL (то есть $7,5 млн), комиссия 0,02%: комиссии $1 500 в день. Стейкерам 95% — $1 425 в день. Если застейкано $4 млн, это ≈ 13% годовых. Позиция $10 000 за 30 дней принесёт ≈ $107. При вдвое меньшем обороте — вдвое меньше.

Доходность меняется день ко дню, потому что зависит от того, сколько обменов было сделано. В спокойный день она может быть близка к нулю.

Где смотреть доходность

На дашборде — за 7 и 30 дней. Считается по росту цены доли: (цена сегодня ÷ цена N дней назад − 1) × 365 ÷ N. Прошлая доходность не гарантирует будущую.

Срок 30 дней

Срок отсчитывается от депозита. Выход раньше срока возвращает только вложенное (principal); доход, накопленный позицией, остаётся в вейлте и делится между остальными стейкерами. После срока выплачивается полная стоимость доли, и новый срок не начинается — можно выйти в любой момент.

Пример: внесли 10 000 BSKUSD, доход за период — 100 BSKUSDПолучите
Вышли на 20-й день10 000 BSKUSD
Вышли на 40-й день10 100 BSKUSD

Довнесение

Дата старта усредняется по сумме: новый старт = (P × старт + X × сейчас) ÷ (P + X), где P — вложенное, X — довнесённое.

  • Позиция ещё не созрела. Было 10 000 на 25-й день, довнесли 10 000: старт сдвигается с 0 на 12,5 дня, разблокировка — на 42,5-й день, то есть через 17,5 дня.
  • Позиция созрела. Она фиксируется как «ровно созревшая»: стоимость становится вложенным, старт = сейчас − 30 дней. Довнесение X к позиции P сдвигает разблокировку на X ÷ (P + X) × 30 дней: равная сумма — через 15 дней.

Перевод sBSKUSD

sBSKUSD можно переводить. Вместе с долями переходит соответствующая часть вложенного (если отправитель уже прошёл срок — полная стоимость). Но срок получателя для полученных долей начинается с момента перевода. Следствие для торговли sBSKUSD на DEX: покупатель получает тело позиции, а доход с неё сможет забрать только через 30 дней.

Как выйти

  1. Посмотрите позицию: position(owner) возвращает доли, стоимость, вложенное, дату старта, дату разблокировки, выплату сейчас и признак «срок прошёл». preview_exit(owner, shares) — точная выплата за выбранные доли.
  2. Выйдите: redeem(shares, receiver, owner) или withdraw(assets, receiver, owner).
Не используйте previewRedeem для решения о выходе

Стандартные previewRedeem, previewWithdraw и convertToAssets по стандарту ERC-4626 не знают владельца. До срока они завышают выплату (показывают полную стоимость вместо вложенного). Точные числа для владельца дают preview_exit, maxWithdraw и position.

Дальше в стейблкоины

После выхода BSKUSD можно сжечь в любую монету корзины (0,02%) или во все пропорционально. Полный путь «sBSKUSD → доллары»: выход из вейлта (без комиссии) → выход из пула (0,02%).

Чего в вейлте нет

  • нет администратора и паузы — никто не может остановить выход или изменить правила;
  • срок задан при развёртывании и не меняется;
  • не поддерживаются токены с комиссией за перевод и rebasing-токены (вейлт работает только с BSKUSD).

4. Экономика и управление

Ответ на вопрос «кто и как может изменить мои условия». Здесь опубликовано всё: именно полнота этого раздела делает правила обязательством, а не намерением.

Распределение комиссий

Стейкингу — 95%, системе — 5%. System Revenue: … (адрес зашит в контракт навсегда). Доля системы идёт на аудиты, bug bounty и разработку.

Лестница долей

Обязательство команды, не код контракта

Контракт разрешает долю стейкинга от 5% до 95% с шагом не больше 10% за 7 дней. Лестница ниже — более узкое правило, которое команда обязуется соблюдать.

ЭтапУсловие переходаСтейкингуСистеме
0 — Запускс первого дня95%5%
1 — РостTVL ≥ $2 млн 30 дней подряд, доходность ≥ 9%85%15%
2 — ЗрелостьTVL ≥ $5 млн 30 дней, доходность ≥ 8%75%25%
3 — МасштабTVL ≥ $10 млн 30 дней, доходность ≥ 8%65%35%
4 — УстойчивостьTVL ≥ $25 млн 30 дней, доходность ≥ 7%55%45%
Пределникогдане ниже 50%не выше 50%

Три правила:

  1. Переход только по вехе. Средний TVL на уровне вехи 30 дней подряд, и с прошлого изменения прошло не меньше 4 недель.
  2. Гарантия доходности. Доля снижается, только если после снижения расчётная доходность стейкера остаётся не ниже 7%. Иначе переход откладывается, и об этом объявляется.
  3. Вверх — всегда можно. Если доходность ниже 5% две недели, доля стейкинга повышается на шаг.

Как проверить самому: TVL и доходность за 30 дней — на дашборде; объявленное изменение доли видно в контракте (pending_system_revenue_bp, pending_split_eta) и в приложении в блоке «События и сроки».

Комиссии

Сейчас: вход … · обмен … · выход ….

Пределы контракта: каждая комиссия не выше 0,06%; обмен не дороже входа плюс выхода.

Обязательство команды

Вход — 0% всегда. Обмен — не выше 0,04%. Шаг обмена до 0,03% — когда оборот за день стабильно выше 100% TVL и больше половины сделок делают внешние боты.

Таймлоки

Каждое изменение сначала объявляется в контракте, затем ждёт, затем есть окно, чтобы его применить. Если окно пропущено, изменение не вступает.

Что меняетсяУведомлениеОкноПредел шагаГде видно
Комиссии7 дней14 дней, применить может любойкаждая ≤ 0,06%pending_fees()
Доля стейкинга7 дней14 дней, любой≤ 10 п.п. за шаг, система 5–95%pending_split_eta
Амплификация A1 день2 дня, администратор; затем плавный переход 3 дняне больше чем вдвое; шаги через 7 днейpending_ann_eta
Новая монета14 дней14 дней, администратордо 6 монетpending_token_eta
Ротация монетыпауза ≥ 7 дней + 14 дней14 дней, любойновая монета вносится заранее и видна в контрактеrot_token(i), rot_eta(i)
Администратордо принятия—новый адрес должен сам принять праваpending_admin

Все объявленные изменения с датами показывает приложение, блок «События и сроки».

Роли

РольКтоЧто может
admin… · …объявлять комиссии, долю, A, новую монету; ставить и снимать паузу; проводить ротацию; назначать pauser; передать права
pauser…только поставить монету на паузу
System Revenue…только получать свою долю комиссий; адрес неизменяем

Администратор может — с уведомлением

  • менять комиссии в пределах 0,06%;
  • менять долю стейкинга шагами по 10 п.п. (5–95%);
  • менять A не больше чем вдвое за шаг;
  • добавить монету (14 дней);
  • заменить монету через ротацию (пауза ≥ 7 дней + 14 дней);
  • сразу поставить монету на паузу.

Не может никогда

  • вывести резервы пула;
  • запретить выход (burn) — он работает и при паузе;
  • сменить вейлт стейкинга и адрес System Revenue;
  • изменить срок стейкинга;
  • забрать больше 95% комиссий;
  • поставить комиссию выше 0,06%;
  • обновить код — прокси нет.

Амплификация

Сейчас A = …. Для стейкера: чем выше A, тем ровнее курс, тем больше оборот и комиссии — но при депеге плохая монета набирается в пул быстрее (до потолка доли). Диапазон ann: 120 – 999 960, кратно 60; шаг не больше чем вдвое, не чаще раза в 7 дней, переход плавный за 3 дня. Менять A можно, только когда корзина ровная (каждая монета 70–130% средней доли).

История изменений

ДатаЧто измененоПочемуТранзакция
Изменений после запуска пока не было. Все события контракта — на странице контракта в обозревателе.

5. Риски

Каждый риск — в одном формате: что может случиться → что делает контракт → что делает команда → что потеряет стейкер в худшем случае. Без смягчений.

Депег одной монеты

Что случитсяМонета теряет привязку. Боты несут её в пул и забирают здоровые монеты. КонтрактПотолок доли останавливает это на 50% корзины. Командаpauser ставит монету на паузу (вход и обмен в неё закрываются), дальше — ротация на другой стейблкоин. Худший случайДо 50% корзины в монете, которая стоит X. Монета упала до $0,50 → BSKUSD обеспечен на ≈ 75%.

Блокировка адреса пула эмитентом

Что случитсяUSDT, USDC или PYUSD замораживают адрес пула: монета перестаёт переводиться. КонтрактВыход в другие монеты работает. Пропорциональный выход проходит, заблокированная часть ставится в очередь на claim. КомандаРотация замороженной монеты на другой стейблкоин. Худший случайДоля этой монеты (до 50%) заморожена до ротации или разблокировки.

Ошибка в контракте

Что случитсяУязвимость в коде пула или вейлта. КонтрактКод неизменяем: прокси и обновлений нет. Найденную ошибку нельзя исправить — только мигрировать на новый контракт. КомандаАудиты, bug bounty, план на инцидент (раздел 7). Худший случайПолная потеря средств.

Доходность ниже ожиданий

Что случитсяМало обменов — мало комиссий. КонтрактМинимальной доходности нет. КомандаПо лестнице долей: доходность ниже 5% две недели → доля стейкинга вверх. Худший случайДоход 0%, вложенное сохранено.

Ранний выход

Что случитсяВы выходите раньше 30 дней. КонтрактВозвращает только вложенное. Команда— Худший случайПотеря дохода за период.

Изменение параметров администратором

Что случитсяАдминистратор поднимает комиссии, снижает долю стейкинга, меняет A или монеты. КонтрактВсё — только с уведомлением и в пределах (раздел 4). Забрать резервы или запретить выход нельзя. КомандаЛестница долей и обязательства по комиссиям. Худший случайВ пределах контракта: доля стейкинга 5% — через 9 шагов по 7 дней. Стейкер успевает выйти.

Компрометация ключей

Что случитсяЗлоумышленник получает ключ admin или pauser. КонтрактС ключом admin — то же, что может админ, с теми же таймлоками. С ключом pauser — только пауза монеты; выход остаётся. КомандаAdmin сейчас: …. Права у мультиподписи Safe — злоумышленнику нужно несколько ключей. Худший случайНеудобство, не потеря резервов. Самое опасное — ротация монеты на ненастоящую: её видно за 21 день (rot_token), и этого хватает, чтобы выйти.

Регуляторный риск

Что случитсяЭмитенты монет корзины подчиняются регуляторам. Контракт— КомандаПроект не даёт юридических гарантий. Худший случайСм. «Блокировка адреса пула эмитентом».

Известные ограничения

Что контракт намеренно не делает:

  • нет оракула — курс следует только из балансов;
  • нет автоматической паузы при депеге — паузу ставит pauser или администратор;
  • не поддерживаются токены с комиссией за перевод и rebasing-токены;
  • previewRedeem вейлта не знает про срок и до срока завышает выплату;
  • монету нельзя удалить из корзины — только заменить ротацией.

6. Для разработчиков и ботов

Всё здесь можно скопировать. Подключиться — за час, без вопросов в чат.

Адреса

Сеть… · chain id …
Пул BSKUSD (это же токен BSKUSD)…
Вейлт sBSKUSD…
admin…
pauser…
System Revenue…

Монеты с индексами и decimals — в таблице «Корзина».

ABI

Полный JSON: пул v5.13.0 · вейлт v1.3.0. Минимальный ABI для свопа:

ABI для свопа
[
  "function coins(uint256) view returns (address)",
  "function N_COINS() view returns (uint256)",
  "function balances(uint256) view returns (uint256)",
  "function get_dy(int128 i, int128 j, uint256 dx) view returns (uint256)",
  "function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) returns (uint256)",
  "function fees() view returns (uint256, uint256, uint256)",
  "function fee() view returns (uint256)",
  "function A() view returns (uint256)",
  "function paused(uint256) view returns (bool)"
]

Совместимый интерфейс StableSwap

Роутеры и боты, которые умеют работать с пулами StableSwap, торгуют этим пулом без доработок.

ФункцияКак в StableSwapОтличие
get_dy, exchangeда, индексы int128—
coins, balances, N_COINSдаbalances — в единицах каждой монеты
A, A_preciseдаA = ann ÷ n
feeда, 10 знаковэто комиссия обмена; вход и выход — в fees()
get_virtual_priceдаD ÷ выпуск BSKUSD
add_liquidity / remove_liquidityнетвместо них mint / burn и пропорциональные версии
LP-токеннет отдельногоBSKUSD и есть LP-токен — пул сам является токеном

Котировка и своп

Порядок: get_dy → min_dy с допуском → approve → exchange. Газ: 166–191 тыс. на обмен, 111–134 тыс. на вход или выход одной монетой, ≈ 245 тыс. на вход или выход корзиной (замер на коде USDT, USDC, PYUSD и DAI, 4 монеты).

Python · web3.py
from web3 import Web3
w3 = Web3(Web3.HTTPProvider(RPC_URL))
pool = w3.eth.contract(address=POOL, abi=SWAP_ABI)
erc20 = w3.eth.contract(address=pool.functions.coins(0).call(), abi=ERC20_ABI)

dx = 10_000 * 10**6                                  # 10 000 монеты 0 (6 знаков)
dy = pool.functions.get_dy(0, 1, dx).call()           # котировка с комиссией
min_dy = dy * 9_990 // 10_000                         # допуск 0,1%

erc20.functions.approve(POOL, dx).transact({"from": ME})
pool.functions.exchange(0, 1, dx, min_dy).transact({"from": ME})
Solidity
interface IBasketPool {
    function get_dy(int128 i, int128 j, uint256 dx) external view returns (uint256);
    function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) external returns (uint256);
    function coins(uint256 i) external view returns (address);
}

function swap(IBasketPool pool, int128 i, int128 j, uint256 dx, uint256 slippageBp) external returns (uint256) {
    uint256 dy = pool.get_dy(i, j, dx);
    uint256 minDy = dy * (10_000 - slippageBp) / 10_000;
    IERC20(pool.coins(uint256(int256(i)))).approve(address(pool), dx);
    return pool.exchange(i, j, dx, minDy);
}

Проскальзывание. Цена — это get_dy(i, j, dx) ÷ dx с поправкой на decimals. Сравните её с котировкой на малой сумме: разница и есть влияние сделки на цену.

Вход и выход

ОперацияКотировкаВызов
Внести одну монетуquote_mint_net(i, amount)mint(i, amount, min_bsk)
Внести корзинуquote_mint_proportional(bsk)mint_proportional(amounts[6], min_bsk)
Вывести одну монетуquote_burn(i, bsk)burn(i, bsk, min_out)
Вывести корзинуquote_burn_proportional(bsk)burn_proportional(bsk, min_out[6])
Забрать выплату из очередиclaimable(token, me)claim(token, to)

Котировки откатываются ровно там же, где откатилась бы сама операция, — с тем же кодом ошибки. Индексы в mint/burn — uint256, массивы — на 6 элементов (лишние нули).

Ограничения сделки

  • Потолок доли (15). После обмена x_i ÷ Σx ≤ cap для монеты, доля которой растёт. Максимальный dx для монеты i: (cap × Σx − x_i) ÷ (1 − cap) в 18 знаках (без учёта уходящей монеты — точное значение ищите бинарным поиском по get_dy).
  • Минимум слота (16). Каждая монета после операции > D ÷ n × 0,5%.
  • Обмен не уменьшает D (31). Защита от округлений: обмен, после которого инвариант стал бы меньше, откатывается.
  • Пауза (23). В монету на паузе нельзя вносить и её нельзя продавать пулу; покупать и выводить можно.

Коды ошибок

Отклонённый вызов откатывается с Err(uint256), селектор 0x39eabce6. Сначала — 10 самых частых; ниже — полный список всех кодов пула и вейлта.

КодПочемуЧто делать
15Монета превысит потолок долиУменьшить сумму или внести «Всей корзиной»
16Монета опустится ниже минимума слотаВывести меньше этой монеты или пропорционально
25Получится меньше вашего минимумаОбновить котировку, проверить допуск
23Монета на паузеВыбрать другую монету; выход в неё работает
12Перевод монеты в пул не прошёлПроверить approve и баланс
14Монета не переводится из пулаВывести в другую монету или пропорционально (часть — в claim)
21Пул ещё не запущенДождаться запуска
31Обмен уменьшил бы инвариантСумма слишком мала или упёрлась в округление — увеличить
60Вывод корзиной доставит меньше 99% причитающегосяВывести меньшую сумму или по одной монете
72Одна из монет пропорционального вывода ниже минимумаОбновить min_out

Все коды пула bskUSD v5.13.0

КодЧто случилосьГдеЧто делать

Коды вейлта sBSKUSD v1.3.0

Вейлт использует тот же формат Err(uint256), но свою нумерацию: код 2 вейлта — не код 2 пула. Смотрите, в какой контракт шёл вызов.

КодЧто случилосьГдеЧто делать

Как прочитать код: данные отката = 0x39eabce6 + код 32-байтным числом. Пример: 0x39eabce6…000f = 15. Код 65 в v5.13.0 не используется.

События

СобытиеПоля
TokenExchangebuyer, sold_id, tokens_sold, bought_id, tokens_bought, fee_bsk
Mintuser, token_in_idx, token_in_raw, bsk_gross, bsk_fee, bsk_net
MintProportionaluser, bsk_net, bsk_fee
Burnuser, token_out_idx, bsk_in, bsk_fee, bsk_effective, token_out_raw
BurnProportionaluser, bsk_in, bsk_fee
ClaimQueued / Claimedtoken, funder, amount_raw
FeesScheduled / FeesApplied / FeesCancelledmint_bp, swap_bp, burn_bp, eta
SplitScheduled / SplitApplied / SplitCancellednew_system_revenue_bp, eta / old, new / cancelled_bp
AnnChangeScheduled / AnnChanged / AnnChangeCancellednew_ann, eta / old_ann, new_ann
AddTokenScheduled / TokenAdded / AddTokenCancelledtoken, amount_raw, eta / index, bsk_net, ann
TokenPaused / TokenUnpausedindex
RotationFunded / RotationScheduled / RotationExecutedindex, new_token, amount_raw, eta / old_token, old_raw, new_raw, old_sent, surplus_sent
RotationCancelled / RotationReclaimedindex, token, funder, returned
AdminProposed / AdminChanged / PauserSet / VaultSetадреса ролей; VaultSet — staking_vault, system_revenue_bp
Вейлт: Deposit / Withdrawстандарт ERC-4626
Вейлт: Exitowner, receiver, shares, assets, forfeited, matured — сколько дохода оставлено в вейлте при раннем выходе

Вейлт sBSKUSD и стандарт ERC-4626

Нестандартное поведение
  • previewRedeem, previewWithdraw, convertToAssets не знают владельца и до срока показывают полную цену. Используйте preview_exit(owner, shares), maxWithdraw(owner), position(owner).
  • maxRedeem(owner) = 0 для несозревшей позиции без вложенного (например, доли получены переводом и тут же заблокированы).
  • Перевод начинает срок получателя заново. Для лендингов и протоколов вроде Pendle: доли, принятые в залог или обёртку, будут под сроком 30 дней с момента перевода, а досрочный выход вернёт только вложенное.

Адаптеры

Адаптер для DefiLlama (TVL и доходность) и пример для роутеров агрегаторов — в репозитории.

Исходники

Код — в GitHub, тег версии v5.13.0 / v1.3.0. Компилятор Vyper 0.4.3, evm-version prague; пул — optimize codesize. Чтобы сверить байткод: vyper -f bytecode_runtime bskUSD_v5.13.0.vy и сравните с кодом по адресу контракта.

7. Безопасность

АудитыОтчёты будут опубликованы целиком: кто, когда, какой коммит, таблица находок с серьёзностью и статусом (исправлено / принято как риск — с объяснением).
Bug bountyПрограмма на Immunefi: выплаты по уровням, скоуп — оба контракта.
НеизменяемостьКонтракты без прокси и обновлений. Навсегда зафиксированы: адрес System Revenue, вейлт (после подключения), срок стейкинга, пределы комиссий (0,06%) и доли (5–95%).
Ключиadmin — …; pauser — отдельный ключ для мгновенной паузы. Держатели ключей — по ролям.
Полномочия админаСм. «Может / не может никогда».
План на инцидентPauser ставит монету на паузу в течение минут после депега или блокировки. Статус публикуется в официальных каналах. Что стейкер может сделать сам: выйти из вейлта и сжечь BSKUSD в здоровые монеты — это работает всегда.
Контакт для уязвимостейпочта и PGP-ключ — будут опубликованы

FAQ

Чем обеспечен BSKUSD и где это проверить?

Монетами корзины, которые лежат в контракте пула. Балансы читаются напрямую: balances(i), или в приложении. → Корзина

Откуда доход, если нет токена?

Из комиссий обмена, которые платят боты, выравнивающие курсы. Эмиссии нет. → Как считается доход

Почему доходность вчера была 14%, а сегодня 6%?

Доход зависит от оборота за день: в волатильный день обменов много, в спокойный — мало. Смотрите доходность за 30 дней. → Доход

Что будет, если я выйду на 20-й день?

Получите вложенное; доход за 20 дней останется остальным стейкерам. → Срок

Я довнёс — почему сдвинулась дата разблокировки?

Дата старта усредняется по сумме: довнесение — это новые деньги со своим сроком. Равная сумма на 25-й день сдвигает разблокировку на 42,5-й день. → Довнесение

Можно ли продать sBSKUSD на DEX? Что получит покупатель?

Можно. Покупатель получит тело позиции, а срок для него начнётся с момента перевода. → Перевод

Что будет, если USDT или PYUSD заблокирует пул?

Эта монета перестанет выводиться; выход в другие монеты работает. Доля монеты заморожена до ротации. → Риски

Что будет при депеге одной монеты? Сколько я потеряю?

Не больше доли этой монеты, а она ограничена потолком 50%. Монета по $0,50 → обеспечение ≈ 75%. → Риски

Может ли админ забрать деньги или остановить вывод?

Нет. Функции вывода резервов нет, выход работает даже при паузе. → Роли

Как быстро могут измениться комиссии и доля стейкинга? Как узнать заранее?

Не раньше чем через 7 дней после объявления. Объявленное видно в контракте и в приложении, блок «События и сроки». → Таймлоки

Почему previewRedeem показывает больше, чем я получаю?

Он не знает владельца и показывает полную цену. До срока вы получите только вложенное — смотрите preview_exit. → Как выйти

Как получить обратно USDC, а не BSKUSD?

Выйти из вейлта, затем сжечь BSKUSD в USDC (0,02%). → Выход

Что такое claim и когда он нужен?

Если монету не удалось перевести вам при выходе, она ждёт в очереди. Забрать — claim(token, to) или кнопкой в приложении. → Выход

Кто аудировал?

Отчёты публикуются в разделе «Безопасность» целиком.

Есть ли токен управления или airdrop?

Нет, и не планируется.

Почему вход бесплатный, а выход платный?

Вход пополняет резервы и выгоден всем держателям. Комиссия выхода делает невыгодным обход комиссии обмена через «вход + выход». → Обмен

Как подключить бота?

Адреса, минимальный ABI и пример свопа — в разделе 6.

Адреса и ссылки

Пул BSKUSD…
Вейлт sBSKUSD…
System Revenue…
ДашбордDune
ИсходникиGitHub
Аудитотчёт