Program Upgrade 0.1.11
Upgrade to SDK 2.8.0 before September 4, 2026 — banks moving to the new oracle setups will not decode on older SDKs
Upgrade to @0dotxyz/p0-ts-sdk@^2.8.0 before Friday, September 4, 2026.
From that date banks start moving to the new 0.1.11 oracle setups. SDK 2.7.x
and older throw while decoding any such bank, which fails Project0Client.initialize
and every bank read — not just actions on that bank. The upgrade is additive: no code
changes required.
TL;DR: program 0.1.11 adds nine oracle setups that do not depend on Switchboard — Kamino Scope feeds, and exchange-rate pricing for mSOL, SPL/Sanctum LSTs and Exponent PTs. Existing instructions and account layouts are untouched. What breaks is decoding: older SDKs don't know the new enum values, so one migrated bank stops them loading banks at all. SDK >= 2.8.0 decodes and prices every setup, includes the extra accounts in health checks, and is padded so future setups degrade gracefully instead of throwing.
What changes
- Nine new
OracleSetupvariants (18–26):Scope,PythMSOL,KaminoMSOL,JuplendMSOL,PythLST,KaminoLST,JuplendLST,PTPyth,PTFixed. How each one prices is on Oracles. BankConfig.scope_entry_index(u16) replaces two padding bytes. Same size, no other layout change.- Every existing instruction keeps its accounts and arguments. Two admin instructions are added (
lending_pool_configure_bank_oracle_scope,lending_pool_set_oracle_price), replacinglending_pool_set_fixed_oracle_price. - New error codes
6136–6139and6800–6803;6132renamed toUseSetOraclePrice. See Errors.
The breaking change
A bank's oracle setup is a one-byte enum and Anchor resolves it against the IDL. The IDL in SDK <= 2.7.4 lists 18 variants, so a setup byte of 18 or higher makes the coder throw:
TypeError: Cannot read properties of null (reading 'property')Project0Client.initialize decodes every bank in the group, so a single migrated bank breaks initialization for everyone on an older SDK. This affects reads, and it is triggered by the first bank migration — not by the program deploy.
What you must do
Using Project0Client or the SDK builders — upgrade. Nothing else. initialize passes the new pricing options through, computeHealthAccountMetas appends the extra accounts, and unknown future setups parse to OracleSetup.Unknown (zero price) instead of throwing.
Calling fetchOracleData directly — pass the two new, optional option blocks, or banks on the new setups price at zero with a warning:
const { bankOraclePriceMap } = await fetchOracleData(banks, {
pythOpts: { mode: "on-chain", connection },
swbOpts: { mode: "on-chain", connection },
scopeOpts: { mode: "on-chain", connection },
oracleMultiplierOpts: { mode: "on-chain", connection },
});The exchange rate is baked into the price: an mSOL bank's OraclePrice is mSOL/USD, matching what the program caches on the bank. Venue receipt-token rates stay in assetShareValueMultiplierByBank, as before. See Banks & Prices.
Hand-rolling remainingAccounts — the new setups need their pricing account after the oracle: oracleKeys[1] for PythMSOL / PythLST / PTPyth, oracleKeys[2] for the Kamino and JupLend variants. Scope and PTFixed keep the [bank, oracleKeys[0]] shape. Prefer computeHealthAccountMetas.
Decoding accounts yourself — use the SDK's bundled 0.1.11 IDL, passed through new Program(...). Do not fetch the IDL from chain; the on-chain IDL account is not kept current.
Serving prices or multipliers from your own API — return prices the way the program caches them (rate included, venue rate excluded). In API mode the SDK only rejects non-numeric multipliers, so your endpoint must return program-valid rates.
Testing on staging
getConfig("staging-mainnet-clone") already runs 0.1.11 with one bank per new family:
| Bank | Setup |
|---|---|
Dt8xUxXxUgVpg74ke5WB4XBogmv1E4TM7zRfwEnbm3SF | wSOL · Scope |
Bf2QXbRZPGtDHvd4AVoFDb4jNjMSDjsPGDaboSHkzE21 | mSOL · PythMSOL |
ZEK4wkNUMbU2ALzKSfb888yZwugypJY466snSj6CuK6 | jitoSOL · PythLST |
4jNGCy6SvEY2itfCrvTGQC65mKHcwZgoahiZjtvmBizK | PT-hyUSD · PTFixed |
7Np6qLQg691RUM64S4J63Py7dRNGMKho3Fh9UU5Q9YZw | PT-hyloSOL · PTPyth |
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
TypeError: Cannot read properties of null (reading 'property') on initialize or any bank decode | SDK <= 2.7.4 meeting a 0.1.11 bank | Upgrade to >= 2.8.0 |
Banks priced at 0 plus a no scopeOpts / no oracleMultiplierOpts warning | Direct fetchOracleData call without the new options | Pass both options |
WrongNumberOfOracleAccounts / WrongOracleAccountKeys on borrow or withdraw | Hand-built remainingAccounts missing the pricing account | Use computeHealthAccountMetas |
ScopeStalePrice (6802) or StakePoolStale (6139) | Feed entry or stake pool not refreshed | Wait; the SDK prices the bank at zero meanwhile |