Olive Docs
Smart Contract

Smart Contract Fix Plan

Smart Contract Fix Plan

This is the implementation order for cleaning up the smart contract accounting model.

Status:

Implemented on 2026-04-23.

The main decision is:

Use USD-only collateral state.

That means collateral is a risk and margin value, not a payout asset selector.

Core Rules

Collateral should be tracked as:

collateral_usd

Collateral deposits should:

  1. Convert the deposited token amount to USD using the oracle.
  2. Transfer the deposited token into the matching custody.
  3. Increase that custody token_owned.
  4. Increase position collateral_usd.
  5. Not track separate per-position SOL and USDC collateral buckets.

Collateral withdrawals should:

  1. Convert the requested withdrawal token amount to USD using the oracle.
  2. Check the position remains healthy after reducing collateral_usd.
  3. Check the requested payout custody has enough free liquidity.
  4. Transfer the requested token to the user.
  5. Decrease that custody token_owned.
  6. Decrease position collateral_usd.

Close and liquidation logic should treat collateral as:

margin math only

Collateral should not decide liquidation payout asset.

For liquidation:

Long liquidation pays from locked SOL.
Short liquidation pays from locked USDC.

Implementation Order

  1. Convert collateral model to USD-only.
  2. Fix open position initialization around collateral_usd.
  3. Fix add collateral.
  4. Fix remove collateral.
  5. Fix direct close.
  6. Fix limit close and cancel refunds.
  7. Fix TP/SL execution.
  8. Fix liquidation.
  9. Fix auto-exercise immediate payout.
  10. Sync IDL, backend, frontend, and docs.

Implemented Behavior

The final implementation keeps legacy collateral_custody and collateral_amount fields for account-layout compatibility, but they are no longer the economic source of truth.

Rules now enforced:

  1. collateral_usd is the margin source of truth for perps and expiry futures.
  2. Collateral deposits convert the deposited token amount to USD using the oracle.
  3. Collateral withdrawals convert the requested withdrawal token to USD, check post-withdraw health, and require free liquidity in the receive custody.
  4. Market opens check free backing liquidity before locking.
  5. Limit placements do not check backing liquidity because no lock is created.
  6. Limit executions check free backing liquidity immediately before locking.
  7. Same-asset closes and settlements can pay from released locked backing, bounded by the released locked amount.
  8. Cross-asset closes and settlements require free liquidity in the payout custody.
  9. Liquidations pay from locked backing: long pays SOL and short pays USDC.
  10. Auto-exercise immediately transfers profit from locked backing and releases the lock.

Step 1: Convert Collateral Model To USD-Only

Goal:

collateral_usd is the source of truth for position collateral.

Edits:

  1. Stop using collateral_custody as a payout selector.
  2. Stop using collateral_amount as the economic collateral source of truth.
  3. Keep collateral_usd as the value used for margin, leverage, liquidation, PnL, and health checks.
  4. Decide whether collateral_custody and collateral_amount are removed from account state or kept temporarily for backward compatibility.

Risk:

Removing account fields changes the Anchor account layout and requires IDL/backend/frontend sync.

Step 2: Fix Open Position Initialization

Open perp and open future should:

  1. Convert the initial collateral deposit into USD.
  2. Store that value in collateral_usd.
  3. Transfer the deposited asset into its custody.
  4. Increase the deposited asset custody token_owned.
  5. Lock backing based on side, not collateral asset.

Perp and future backing:

Long = lock SOL
Short = lock USDC

Step 3: Fix Add Collateral

Add collateral should:

  1. Accept SOL or USDC.
  2. Convert the added token amount to USD.
  3. Transfer the added token into the matching custody.
  4. Increase that custody token_owned.
  5. Increase collateral_usd.
  6. Recalculate leverage and liquidation price.

It should not:

normalize the added token into the original collateral asset

Step 4: Fix Remove Collateral

Remove collateral should:

  1. Accept a requested withdrawal asset, SOL or USDC.
  2. Convert the requested withdrawal amount into USD.
  3. Check that collateral_usd - withdrawal_usd keeps the position healthy.
  4. Check the receive custody has free liquidity:
receive_custody.token_owned - receive_custody.token_locked >= withdrawal_tokens
  1. Transfer the requested token to the user.
  2. Decrease receive custody token_owned.
  3. Decrease position collateral_usd.

Step 5: Fix Direct Close

Direct close includes:

close_option.rs
close_future.rs
close_perp_position.rs

Rules:

  1. Same-asset payout can use locked backing.
  2. Same-asset payout must be bounded by released locked amount.
  3. Cross-asset payout must use free liquidity.
  4. Token transfer must subtract token_owned from the custody that actually paid.

Step 6: Fix Limit Close And Cancel Refunds

Limit close execution should use the same payout rules as direct close.

Cancel/refund paths should:

  1. Not use locked backing unless the refund is explicitly from locked backing.
  2. Use reserved-premium or reserved-collateral accounting if such reserve exists.
  3. Otherwise require free liquidity before refund transfer.
  4. Subtract token_owned from the custody that actually paid.

Step 7: Fix TP/SL Execution

TP/SL creation and updates do not need payout checks.

TP/SL execution should use the same payout rules as direct close:

  1. Same-asset payout bounded by released locked amount.
  2. Cross-asset payout backed by free liquidity.
  3. Exact paying custody token_owned subtraction.

Step 8: Fix Liquidation

Liquidation should not pay from collateral.

Liquidation payout asset should be based on locked backing:

Long = SOL payout from locked SOL
Short = USDC payout from locked USDC

Rules:

  1. Calculate liquidation payout.
  2. Require payout is bounded by locked backing released.
  3. Transfer from locked backing custody.
  4. Subtract payout from locked backing custody token_owned.
  5. Release locked backing from token_locked.
  6. Do not use collateral_custody as payout source.

Step 9: Fix Auto-Exercise Immediate Payout

Auto-exercise should immediately transfer profit.

Rules:

  1. Call auto-exercise pays SOL from locked SOL.
  2. Put auto-exercise pays USDC from locked USDC.
  3. Require locked custody has enough locked backing.
  4. Require profit payout is bounded by unlock amount.
  5. Transfer profit.
  6. Subtract transferred profit from locked custody token_owned.
  7. Subtract unlock amount from locked custody token_locked.
  8. Mark the option exercised or invalid.

There should be no claim-recording model.

Step 10: Sync IDL, Backend, Frontend, And Docs

After smart contract account or instruction changes:

  1. Run anchor build.
  2. Sync IDL to backend and frontend.
  3. Update backend indexers and API models.
  4. Update frontend transaction builders.
  5. Update frontend order boxes and position views.
  6. Update docs to match the final implementation.

On this page