Program Upgrade 0.1.10
What the marginfi 0.1.9 → 0.1.10 program upgrade means for SDK integrators
Completed. Mainnet flipped to program 0.1.10 on 2026-08-25 15:00 UTC. SDK
2.6.x and older break on flash loans, health simulation and account
transfers. The next upgrade, 0.1.11, is documented on
Program Upgrade 0.1.11 and raises the
minimum SDK to 2.8.0.
TL;DR: program 0.1.10 inserts required accounts into six instructions. That is a positional wire break in both directions, so a single SDK build cannot be sent to both programs unchanged. SDK >= 2.7.0 builds 0.1.10-style and, for the three affected instructions it actually uses, removes the inserted account again while the target program still runs 0.1.9. The switch is a per-program-id timestamp baked into the SDK — no RPC call, no caching. Upgrade the SDK any time before the flip with zero code changes.
Deployments
| Program | Program ID | Group | Status |
|---|---|---|---|
| 0.1.9 | MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA | 4qp6Fx6tnZkY5Wropq9wUYgtFxXKwE6viZxFHg3rdAG8 | mainnet production until the flip |
| 0.1.10 | stag8sTKds2h4KzjUw3zKTsxbqvT4XKHdaR9X9E6Rct | FCPfpHA69EbS8f9KKSreTRkXbzFpunsKuYf5qNmnJjpo | staging since 2026-08-03; mainnet after |
Use getConfig("staging") (or "staging-mainnet-clone" for a production-like bank set) to test against 0.1.10 today.
What changes in the program
- Per-bank oracle circuit breaker — a bank whose price moves more than a configured threshold in a window temporarily halts risk-increasing operations (borrow, withdraw, liquidate). New
OperationalState.CircuitBrokenbank state, which the SDK parses instead of throwing. - Same-asset e-mode — banks sharing a mint and oracle family (e.g. Kamino SOL, JupLend SOL, P0 SOL) can be placed in same-asset e-mode for higher leverage. New
SameAssetEmodeRegistryaccount per group. - Configurable fees — per-liability-bank liquidation fees and a configurable account-transfer fee in
FeeState. - Account resizes —
MarginfiGroupgrows 1,056 → 9,248 bytes andFeeState256 → 512 bytes (reserved padding, layouts are prefix-identical). Expect a short outage right after the mainnet deploy while accounts are resized. - Oracle fix — Switchboard feeds no longer use
std_dev;oracle_max_confidenceconfigures a static confidence spread instead.
Full details: UPGRADE-0.1.10.md in the SDK repo.
The breaking change: inserted accounts
Solana instructions carry accounts as an ordered, unnamed array. Inserting a required account mid-list shifts every later index, so the six instructions below break in both directions (old layout → new program and new layout → old program):
| Instruction | Inserted account | Position | SDK handles it |
|---|---|---|---|
lending_account_end_flashloan | group | before authority (displaces the signer) | ✅ makeEndFlashLoanIx |
lending_account_pulse_health | group | after marginfi_account | ✅ makePulseHealthIx |
transfer_to_new_account | fee_state | before system_program | ✅ makeAccountTransferToNewAccountIx |
transfer_to_new_account_pda | fee_state | before system_program | — no SDK builder |
lending_account_start_liquidation | group | after liquidation_record | — no SDK builder |
lending_account_end_liquidation | group (+ optional trailing fee_payer) | after liquidation_record | — no SDK builder |
Everything else survives: deposit / withdraw / borrow / repay / account create & close are unchanged, account decoding works across versions (layouts are prefix-identical), and admin instructions that only gained trailing Option args are tolerated by 0.1.9.
How the SDK handles it
SDK 2.7.0–2.7.3 carried a per-program-id timestamp switch (MARGINFI_V0_1_10_ACTIVATION / isMarginfiV0110Live) so one build could talk to both programs around the flip: makeEndFlashLoanIx, makePulseHealthIx and makeAccountTransferToNewAccountIx built the 0.1.10 layout and spliced the inserted account out while the target program still ran 0.1.9. The switch was removed in 2.7.4 once the upgrade was final; the SDK now emits the 0.1.10 layout unconditionally, and those exports no longer exist.
What you must do
Using the SDK's builders (Layers 2–4):
- Upgrade to
@0dotxyz/p0-ts-sdk@^2.7.0before 2026-08-25 15:00 UTC. No code changes. - Optionally test against
getConfig("staging"), which already runs 0.1.10.
Hand-rolling any of the six instructions (raw program.methods.*() calls, the /instructions subpath, or your own Borsh encoding) — the SDK cannot intercept those:
- Add the inserted account at the positions in the table above, and gate on
isMarginfiV0110Live(programId)if you need to keep sending to 0.1.9 until the flip. end_liquidationgains an optional trailingfee_payerwritable signer; when omitted,liquidation_receiverpays the flat fee as before.- Don't send 0.1.9-encoded admin instructions to 0.1.10: shorter args make the new program read garbage for the appended options.
Decoding accounts yourself: nothing breaks — but a Bank in CircuitBroken state only decodes with the 0.1.10 IDL bundled in SDK >= 2.7.0.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
AnchorError caused by account: group. AccountNotEnoughKeys on a loop/swap | 0.1.9-style end_flashloan sent to a 0.1.10 program | Upgrade SDK to >= 2.7.0 |
Same error from simulateBundle health simulation | 0.1.9-style pulse_health | Upgrade SDK to >= 2.7.0 |
Signer / system_program mismatch on flash loans or account transfer before the flip | 0.1.10 layout sent to 0.1.9 (hand-rolled, or wrong timestamp) | Use the SDK builders, or gate on isMarginfiV0110Live |