added partial liquidation
This commit is contained in:
parent
d6234ea4ee
commit
ccbe33d907
|
@ -104,6 +104,12 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "az"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822d7d63e0c0260a050f6b1f0d316f5c79b9eab830aca526ed904e1011bd64ca"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.56"
|
||||
|
@ -1068,14 +1074,51 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fixed"
|
||||
version = "0.5.7"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f32ca1abdbb21d63a3e02a658a9e3001b172f13c8b46724299e21190c5ee5041"
|
||||
checksum = "b3cd35dc49a38c999fb8bc36a8c8680ad97bf7b9b499d852b1d82e5dd09f73f9"
|
||||
dependencies = [
|
||||
"az",
|
||||
"half",
|
||||
"serde",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixed-macro"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f6b2cae66e4989f93364a38a59a12e1830afe3201c7c11e5ea8727534831fbe"
|
||||
dependencies = [
|
||||
"fixed",
|
||||
"fixed-macro-impl",
|
||||
"fixed-macro-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixed-macro-impl"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "787fa8e0bf88449e84799f4b440a15bd1958c4552a80abc568d5ba9e20a4283e"
|
||||
dependencies = [
|
||||
"fixed",
|
||||
"paste 1.0.5",
|
||||
"proc-macro-error",
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixed-macro-types"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c7241f3a037641b460153db21d5611c789e7e0504bf52e20a9b4bbe1d7cc00"
|
||||
dependencies = [
|
||||
"fixed",
|
||||
"fixed-macro-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.20"
|
||||
|
@ -1337,6 +1380,12 @@ dependencies = [
|
|||
"tracing-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3"
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.1.1"
|
||||
|
@ -1611,7 +1660,7 @@ checksum = "c502a5ff9dd2924f1ed32ba96e3b65735d837b4bfd978d3161b1702e66aca4b7"
|
|||
dependencies = [
|
||||
"jemalloc-sys",
|
||||
"libc",
|
||||
"paste",
|
||||
"paste 0.1.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1772,7 +1821,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mango"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bincode",
|
||||
|
@ -1780,6 +1829,7 @@ dependencies = [
|
|||
"byteorder",
|
||||
"enumflags2",
|
||||
"fixed",
|
||||
"fixed-macro",
|
||||
"flux-aggregator",
|
||||
"num-derive",
|
||||
"num_enum",
|
||||
|
@ -2243,6 +2293,12 @@ dependencies = [
|
|||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58"
|
||||
|
||||
[[package]]
|
||||
name = "paste-impl"
|
||||
version = "0.1.18"
|
||||
|
|
|
@ -13,11 +13,11 @@ path = "src/main.rs"
|
|||
[dependencies]
|
||||
anyhow = "1.0.36"
|
||||
clap = "3.0.0-beta.2"
|
||||
solana-client = "1.5.14"
|
||||
solana-cli = "1.5.16"
|
||||
solana-sdk = "1.5.16"
|
||||
solana-client = "~1.5"
|
||||
solana-cli = "~1.5"
|
||||
solana-sdk = "~1.5"
|
||||
mango = { version = "*", path = "../program", features=["no-entrypoint"] }
|
||||
spl-token = { version = "*", features=["no-entrypoint"] }
|
||||
spl-token = { version = "^3.1.0", features=["no-entrypoint"] }
|
||||
serde_json = "1.0.60"
|
||||
chrono = "*"
|
||||
common = { version = "*", path = "../common" }
|
||||
|
@ -26,4 +26,4 @@ serum_dex = { version = "^0.2", git = "https://github.com/project-serum/serum-de
|
|||
flux-aggregator = { version = "^0.1", git = "https://github.com/blockworks-foundation/solana-flux-aggregator.git", features=["program", "no-entrypoint"] }
|
||||
arrayref = "^0.3.6"
|
||||
|
||||
fixed = { version = "=0.5.7" }
|
||||
fixed = { version = "1.7.0" }
|
|
@ -8,10 +8,13 @@ fi
|
|||
|
||||
# deploy mango program and new mango group
|
||||
source ~/mango/cli/devnet.env $KEYPAIR
|
||||
solana config set --url $DEVNET_URL
|
||||
|
||||
cd ~/mango
|
||||
pushd program
|
||||
|
||||
# build bpf for devnet (just do cargo build-bpf for the mainnet version
|
||||
mkdir target/devnet
|
||||
cargo build-bpf --features devnet --bpf-out-dir target/devnet
|
||||
|
||||
# this will give a separate program id for devnet
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.4.7"
|
||||
|
@ -44,6 +46,12 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "az"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822d7d63e0c0260a050f6b1f0d316f5c79b9eab830aca526ed904e1011bd64ca"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.2"
|
||||
|
@ -290,14 +298,51 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fixed"
|
||||
version = "0.5.7"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f32ca1abdbb21d63a3e02a658a9e3001b172f13c8b46724299e21190c5ee5041"
|
||||
checksum = "b3cd35dc49a38c999fb8bc36a8c8680ad97bf7b9b499d852b1d82e5dd09f73f9"
|
||||
dependencies = [
|
||||
"az",
|
||||
"half",
|
||||
"serde",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixed-macro"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f6b2cae66e4989f93364a38a59a12e1830afe3201c7c11e5ea8727534831fbe"
|
||||
dependencies = [
|
||||
"fixed",
|
||||
"fixed-macro-impl",
|
||||
"fixed-macro-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixed-macro-impl"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "787fa8e0bf88449e84799f4b440a15bd1958c4552a80abc568d5ba9e20a4283e"
|
||||
dependencies = [
|
||||
"fixed",
|
||||
"paste",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixed-macro-types"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c7241f3a037641b460153db21d5611c789e7e0504bf52e20a9b4bbe1d7cc00"
|
||||
dependencies = [
|
||||
"fixed",
|
||||
"fixed-macro-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flux-aggregator"
|
||||
version = "0.1.0"
|
||||
|
@ -345,6 +390,12 @@ dependencies = [
|
|||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.9.1"
|
||||
|
@ -392,9 +443,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
|
||||
checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
|
@ -415,6 +466,7 @@ dependencies = [
|
|||
"byteorder",
|
||||
"enumflags2",
|
||||
"fixed",
|
||||
"fixed-macro",
|
||||
"flux-aggregator",
|
||||
"num-derive",
|
||||
"num_enum",
|
||||
|
@ -499,6 +551,12 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.1.3"
|
||||
|
@ -523,6 +581,30 @@ dependencies = [
|
|||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
|
@ -729,9 +811,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "solana-frozen-abi"
|
||||
version = "1.5.16"
|
||||
version = "1.5.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0acf010e4089c7027a65822c92a0c8c928f4ff9f8fa6fb9035b26bdb45c2730c"
|
||||
checksum = "c3f571559d39de6ff0bcad239541bce1272628ad6ce7a453b785dd769a9e4a30"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"bv",
|
||||
|
@ -749,9 +831,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "solana-frozen-abi-macro"
|
||||
version = "1.5.16"
|
||||
version = "1.5.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51e857abb4f59a4aacf2fb79b04edd295a801bccb46912de854f33d7d32e4f8c"
|
||||
checksum = "980db1fdc868336e4e00bc410e10cf4376060f2ea20e220cef75049b9d179450"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"proc-macro2",
|
||||
|
@ -762,9 +844,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "solana-logger"
|
||||
version = "1.5.16"
|
||||
version = "1.5.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a6b92c7d2abb55b5e4f66eef851ac877b5505d8f3198d872832b1d153562d04"
|
||||
checksum = "d2a89cdddcf35ef945aba5d4bb62e761c150fedecddb49e44b16ee673000e6aa"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"lazy_static",
|
||||
|
@ -773,9 +855,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "solana-program"
|
||||
version = "1.5.16"
|
||||
version = "1.5.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7247d5d6d4037064ee4aa65ee3abe7a1818ea6663710db3d2a65ffe72d830e3"
|
||||
checksum = "fd14a879d877f2712487109c1d2949a266837a250791ccf676ab606796715c61"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"borsh 0.8.2",
|
||||
|
@ -805,9 +887,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "solana-sdk-macro"
|
||||
version = "1.5.16"
|
||||
version = "1.5.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e9b3785480f2f1953b1d2962c00f4fa8a6b08461bbbb09aab9830030f90c9e7"
|
||||
checksum = "6d763cfa55a605a2e07326b9eafbb9a66227b441cb00db7c482b806e2b9768b4"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"proc-macro2",
|
||||
|
@ -844,9 +926,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.65"
|
||||
version = "1.0.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
|
||||
checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
@ -9,7 +9,7 @@ no-entrypoint = []
|
|||
devnet = []
|
||||
|
||||
[dependencies]
|
||||
solana-program = "=1.5.16"
|
||||
solana-program = "~1.5"
|
||||
spl-token = { version = "^3.0.0", features=["no-entrypoint"] }
|
||||
byteorder = "^1.3.4"
|
||||
arrayref = "^0.3.6"
|
||||
|
@ -25,7 +25,8 @@ serum_dex = { version = "^0.2", git = "https://github.com/project-serum/serum-de
|
|||
|
||||
num-derive = "^0.3.3"
|
||||
flux-aggregator = { version = "^0.1", git = "https://github.com/blockworks-foundation/solana-flux-aggregator.git", features=["program", "no-entrypoint"] }
|
||||
fixed = { version = "=0.5.7", features=["serde"] }
|
||||
fixed = { version = "1.7.0", features=["serde"] }
|
||||
fixed-macro = "1.1.1"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
|
|
@ -16,7 +16,6 @@ pub enum SourceFileId {
|
|||
Processor = 0,
|
||||
#[error("src/state.rs")]
|
||||
State = 1,
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
|
@ -47,7 +46,7 @@ pub enum MangoError {
|
|||
#[error(transparent)]
|
||||
ProgramError(#[from] ProgramError),
|
||||
#[error("{mango_error_code}; source: {source_file_id}:{line}")]
|
||||
MangoErrorCode { mango_error_code: MangoErrorCode, line: u32, source_file_id: SourceFileId}, // Just wraps MangoErrorCode into MangoError::MangoErrorCode
|
||||
MangoErrorCode { mango_error_code: MangoErrorCode, line: u32, source_file_id: SourceFileId},
|
||||
#[error(transparent)]
|
||||
AssertionError(#[from] AssertionError)
|
||||
}
|
||||
|
@ -55,8 +54,8 @@ pub enum MangoError {
|
|||
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, IntoPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum MangoErrorCode {
|
||||
#[error("MangoErrorCode::AboveBorrowLimit This transaction would exceed the borrow limit")]
|
||||
AboveBorrowLimit,
|
||||
#[error("MangoErrorCode::BorrowLimitExceeded This instruction would exceed the borrow limit")]
|
||||
BorrowLimitExceeded,
|
||||
#[error("MangoErrorCode::CollateralRatioLimit Your collateral ratio is below the minimum initial collateral ratio")]
|
||||
CollateralRatioLimit,
|
||||
#[error("MangoErrorCode::InsufficientFunds Quantity requested is above the available balance")]
|
||||
|
@ -73,8 +72,18 @@ pub enum MangoErrorCode {
|
|||
GroupNotRentExempt,
|
||||
#[error("MangoErrorCode::InvalidSignerKey")]
|
||||
InvalidSignerKey,
|
||||
#[error("MangoErrorCode::InvalidProgramId")]
|
||||
InvalidProgramId,
|
||||
#[error("MangoErrorCode::NotLiquidatable")]
|
||||
NotLiquidatable,
|
||||
#[error("MangoErrorCode::InvalidOpenOrdersAccount")]
|
||||
InvalidOpenOrdersAccount,
|
||||
#[error("MangoErrorCode::SignerNecessary")]
|
||||
SignerNecessary,
|
||||
#[error("MangoErrorCode::InvalidMangoVault")]
|
||||
InvalidMangoVault,
|
||||
|
||||
#[error("MangoErrorCode::Default")]
|
||||
#[error("MangoErrorCode::Default Check the source code for more info")]
|
||||
Default = u32::MAX_VALUE,
|
||||
}
|
||||
|
||||
|
@ -82,7 +91,11 @@ impl From<MangoError> for ProgramError {
|
|||
fn from(e: MangoError) -> ProgramError {
|
||||
match e {
|
||||
MangoError::ProgramError(pe) => pe,
|
||||
MangoError::MangoErrorCode { mango_error_code, line: _, source_file_id: _ } => ProgramError::Custom(mango_error_code.into()),
|
||||
MangoError::MangoErrorCode {
|
||||
mango_error_code,
|
||||
line: _,
|
||||
source_file_id: _
|
||||
} => ProgramError::Custom(mango_error_code.into()),
|
||||
MangoError::AssertionError(ae) => ProgramError::Custom(ae.into())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,25 +3,26 @@ use std::mem::size_of;
|
|||
|
||||
use arrayref::{array_ref, array_refs};
|
||||
use fixed::types::U64F64;
|
||||
use fixed_macro::types::U64F64;
|
||||
use flux_aggregator::borsh_state::InitBorshState;
|
||||
use serum_dex::matching::Side;
|
||||
use serum_dex::state::ToAlignedBytes;
|
||||
use solana_program::account_info::AccountInfo;
|
||||
use solana_program::clock::Clock;
|
||||
use solana_program::entrypoint::ProgramResult;
|
||||
use solana_program::instruction::{AccountMeta, Instruction};
|
||||
use solana_program::msg;
|
||||
use solana_program::program_error::ProgramError;
|
||||
use solana_program::program_pack::{IsInitialized, Pack};
|
||||
use solana_program::pubkey::Pubkey;
|
||||
use solana_program::rent::Rent;
|
||||
use solana_program::sysvar::{Sysvar};
|
||||
use solana_program::sysvar::Sysvar;
|
||||
use spl_token::state::{Account, Mint};
|
||||
|
||||
use crate::error::{check_assert, MangoResult, SourceFileId, MangoErrorCode, check_assert2};
|
||||
use crate::instruction::{MangoInstruction};
|
||||
use crate::state::{AccountFlag, check_open_orders, load_market_state, load_open_orders, Loadable, MangoGroup, MangoIndex, MarginAccount, NUM_MARKETS, NUM_TOKENS, MangoSrmAccount};
|
||||
use crate::error::{check_assert, check_assert2, MangoErrorCode, MangoResult, SourceFileId};
|
||||
use crate::instruction::MangoInstruction;
|
||||
use crate::state::{AccountFlag, check_open_orders, load_market_state, load_open_orders, Loadable, MangoGroup, MangoIndex, MangoSrmAccount, MarginAccount, NUM_MARKETS, NUM_TOKENS, ONE_U64F64, ZERO_U64F64, PARTIAL_LIQ_INCENTIVE};
|
||||
use crate::utils::{gen_signer_key, gen_signer_seeds};
|
||||
use solana_program::entrypoint::ProgramResult;
|
||||
|
||||
macro_rules! prog_assert {
|
||||
($cond:expr) => {
|
||||
|
@ -51,12 +52,14 @@ macro_rules! prog_assert_eq2 {
|
|||
|
||||
mod srm_token {
|
||||
use solana_program::declare_id;
|
||||
|
||||
#[cfg(feature = "devnet")]
|
||||
declare_id!("9FbAMDvXqNjPqZSYt4EWTguJuDrGkfvwr3gSFpiSbX9S");
|
||||
#[cfg(not(feature = "devnet"))]
|
||||
declare_id!("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt");
|
||||
}
|
||||
|
||||
pub const LIQ_MIN_COLL_RATIO: U64F64 = U64F64!(1.01);
|
||||
|
||||
pub struct Processor {}
|
||||
|
||||
|
@ -138,8 +141,8 @@ impl Processor {
|
|||
mango_group.vaults[i] = *vault_acc.key;
|
||||
mango_group.indexes[i] = MangoIndex {
|
||||
last_update: curr_ts,
|
||||
borrow: U64F64::from_num(1),
|
||||
deposit: U64F64::from_num(1) // Smallest unit of interest is 0.0001% or 0.000001
|
||||
borrow: ONE_U64F64,
|
||||
deposit: ONE_U64F64 // Smallest unit of interest is 0.0001% or 0.000001
|
||||
};
|
||||
mango_group.mint_decimals[i] = mint.decimals;
|
||||
}
|
||||
|
@ -440,8 +443,6 @@ impl Processor {
|
|||
clock_acc
|
||||
] = fixed_accs;
|
||||
|
||||
// margin ratio = equity / val(borrowed)
|
||||
// equity = val(positions) - val(borrowed) + val(collateral)
|
||||
prog_assert!(liqor_acc.is_signer)?;
|
||||
let mut mango_group = MangoGroup::load_mut_checked(
|
||||
mango_group_acc, program_id
|
||||
|
@ -459,10 +460,11 @@ impl Processor {
|
|||
|
||||
let prices = get_prices(&mango_group, oracle_accs)?;
|
||||
let coll_ratio = liqee_margin_account.get_collateral_ratio(
|
||||
&mango_group, &prices, open_orders_accs)?;
|
||||
&mango_group, &prices, open_orders_accs
|
||||
)?;
|
||||
|
||||
// No liquidations if account above maint collateral ratio
|
||||
prog_assert!(coll_ratio < mango_group.maint_coll_ratio)?;
|
||||
prog_assert2!(coll_ratio < mango_group.maint_coll_ratio, MangoErrorCode::NotLiquidatable)?;
|
||||
|
||||
// Settle borrows to see if it gets us above maint
|
||||
for i in 0..NUM_TOKENS {
|
||||
|
@ -470,21 +472,22 @@ impl Processor {
|
|||
settle_borrow_unchecked(&mut mango_group, &mut liqee_margin_account, i, native_borrow)?;
|
||||
}
|
||||
let coll_ratio = liqee_margin_account.get_collateral_ratio(
|
||||
&mango_group, &prices, open_orders_accs)?;
|
||||
&mango_group, &prices, open_orders_accs
|
||||
)?;
|
||||
if coll_ratio >= mango_group.maint_coll_ratio { // if account not liquidatable after settle borrow, then return
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
// TODO liquidator may forcefully SettleFunds and SettleBorrow on account with less than maint
|
||||
|
||||
if coll_ratio < U64F64::from_num(1) {
|
||||
if coll_ratio < ONE_U64F64 {
|
||||
let liabs = liqee_margin_account.get_total_liabs(&mango_group)?;
|
||||
let liabs_val = liqee_margin_account.get_liabs_val(&mango_group, &prices)?;
|
||||
let assets_val = liqee_margin_account.get_assets_val(&mango_group, &prices, open_orders_accs)?;
|
||||
|
||||
// reduction_val = amount of quote currency value to reduce liabilities by to get coll_ratio = 1.01
|
||||
let reduction_val = liabs_val
|
||||
.checked_sub(assets_val / U64F64::from_num(1.01)).unwrap();
|
||||
.checked_sub(assets_val / LIQ_MIN_COLL_RATIO).unwrap();
|
||||
|
||||
for i in 0..NUM_TOKENS {
|
||||
let proportion = U64F64::from_num(liabs[i])
|
||||
|
@ -1141,7 +1144,7 @@ impl Processor {
|
|||
|
||||
prog_assert!(!reduce_only)?; // Cannot borrow more in reduce only mode
|
||||
checked_add_borrow(&mut mango_group, &mut margin_account, out_token_i, rem_spend / out_index.borrow)?;
|
||||
prog_assert2!(margin_account.get_native_borrow(&out_index, out_token_i) <= mango_group.borrow_limits[out_token_i], MangoErrorCode::AboveBorrowLimit)?;
|
||||
prog_assert2!(margin_account.get_native_borrow(&out_index, out_token_i) <= mango_group.borrow_limits[out_token_i], MangoErrorCode::BorrowLimitExceeded)?;
|
||||
} else { // just spend user deposits
|
||||
let mango_spent = U64F64::from_num(total_out) / out_index.deposit;
|
||||
checked_sub_deposit(&mut mango_group, &mut margin_account, out_token_i, mango_spent)?;
|
||||
|
@ -1166,6 +1169,209 @@ impl Processor {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn partial_liquidate(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
deposit_quantities: [u64; NUM_TOKENS],
|
||||
max_deposit: u64
|
||||
) -> MangoResult<()> {
|
||||
|
||||
// Cancel as many orders as possible for the selected market
|
||||
// put account in liquidation mode
|
||||
// if account is_liquidating, then no new orders can be created until account gets above init_coll_ratio
|
||||
//
|
||||
|
||||
// cancel orders,
|
||||
// settle funds
|
||||
// settle borrows
|
||||
// allow liquidations up until the account gets above init collateral ratio
|
||||
// if account hits 0 deposits, socialize losses
|
||||
// offset borrows
|
||||
|
||||
const NUM_FIXED: usize = 14;
|
||||
// TODO make it so canceling orders feature is optional if no orders outstanding to cancel
|
||||
let accounts = array_ref![accounts, 0, NUM_FIXED + 2 * NUM_MARKETS + NUM_TOKENS];
|
||||
let (
|
||||
fixed_accs,
|
||||
open_orders_accs,
|
||||
oracle_accs,
|
||||
vault_accs,
|
||||
) = array_refs![accounts, NUM_FIXED, NUM_MARKETS, NUM_MARKETS, NUM_TOKENS];
|
||||
|
||||
let [
|
||||
mango_group_acc,
|
||||
liqor_acc,
|
||||
liqor_in_token_acc,
|
||||
liqor_out_token_acc,
|
||||
liqee_margin_account_acc,
|
||||
spot_market_acc,
|
||||
bids_acc,
|
||||
asks_acc,
|
||||
signer_acc,
|
||||
dex_event_queue_acc,
|
||||
dex_base_acc,
|
||||
dex_quote_acc,
|
||||
token_prog_acc,
|
||||
dex_prog_acc,
|
||||
] = fixed_accs;
|
||||
|
||||
prog_assert_eq2!(token_prog_acc.key, &spl_token::id(), MangoErrorCode::InvalidProgramId)?;
|
||||
prog_assert2!(liqor_acc.is_signer, MangoErrorCode::SignerNecessary)?;
|
||||
let mut mango_group = MangoGroup::load_mut_checked(
|
||||
mango_group_acc, program_id
|
||||
)?;
|
||||
prog_assert_eq2!(dex_prog_acc.key, &mango_group.dex_program_id, MangoErrorCode::InvalidProgramId)?;
|
||||
prog_assert_eq2!(signer_acc.key, &mango_group.signer_key, MangoErrorCode::InvalidSignerKey)?;
|
||||
|
||||
for i in 0..NUM_TOKENS {
|
||||
prog_assert_eq2!(&mango_group.vaults[i], vault_accs[i].key, MangoErrorCode::InvalidMangoVault)?;
|
||||
}
|
||||
|
||||
let mut liqee_margin_account = MarginAccount::load_mut_checked(
|
||||
program_id, liqee_margin_account_acc, mango_group_acc.key
|
||||
)?;
|
||||
|
||||
for i in 0..NUM_MARKETS {
|
||||
prog_assert_eq2!(open_orders_accs[i].key, &liqee_margin_account.open_orders[i],
|
||||
MangoErrorCode::InvalidOpenOrdersAccount)?;
|
||||
check_open_orders(&open_orders_accs[i], &mango_group.signer_key)?;
|
||||
}
|
||||
|
||||
let prices = get_prices(&mango_group, oracle_accs)?;
|
||||
let coll_ratio = liqee_margin_account.get_collateral_ratio(
|
||||
&mango_group, &prices, open_orders_accs
|
||||
)?;
|
||||
|
||||
// Only allow liquidations on accounts already being liquidated and below init or accounts below maint
|
||||
if liqee_margin_account.being_liquidated {
|
||||
if coll_ratio >= mango_group.init_coll_ratio {
|
||||
// TODO do same check in place_and_settle
|
||||
liqee_margin_account.being_liquidated = false;
|
||||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
prog_assert2!(coll_ratio < mango_group.maint_coll_ratio, MangoErrorCode::NotLiquidatable)?;
|
||||
}
|
||||
|
||||
// Force cancel some orders to recoup funds for liquidator to withdraw
|
||||
let market_index = mango_group.get_market_index(spot_market_acc.key).unwrap();
|
||||
let open_orders_acc = &open_orders_acc[market_index];
|
||||
let signers_seeds = gen_signer_seeds(&mango_group.signer_nonce, mango_group_acc.key);
|
||||
|
||||
cancel_all(open_orders_acc, dex_prog_acc, spot_market_acc, bids_acc, asks_acc, signer_acc,
|
||||
dex_event_queue_acc, dex_base_acc, dex_quote_acc,
|
||||
&vault_accs[market_index], &vault_accs[NUM_MARKETS],
|
||||
dex_signer_acc, token_prog_acc, &[&signers_seeds], 5)?;
|
||||
|
||||
for i in 0..NUM_TOKENS {
|
||||
settle_borrow_full_unchecked(&mut mango_group, &mut liqee_margin_account, i)?;
|
||||
}
|
||||
|
||||
// Check again to see if account still liquidatable
|
||||
let coll_ratio = liqee_margin_account.get_collateral_ratio(
|
||||
&mango_group, &prices, open_orders_accs
|
||||
)?;
|
||||
if liqee_margin_account.being_liquidated {
|
||||
if coll_ratio >= mango_group.init_coll_ratio {
|
||||
// TODO make sure liquidator knows why tx was success but he didn't receive any funds
|
||||
liqee_margin_account.being_liquidated = false;
|
||||
return Ok(());
|
||||
}
|
||||
} else if coll_ratio >= mango_group.maint_coll_ratio {
|
||||
return Ok(());
|
||||
} else {
|
||||
liqee_margin_account.being_liquidated = true;
|
||||
// TODO make it so you can't place orders when account is being liquidated
|
||||
// TODO set max orders allowed
|
||||
}
|
||||
|
||||
// Now try to liquidate
|
||||
let liqor_in_token_account = Account::unpack(&liqor_in_token_acc.try_borrow_data()?)?;
|
||||
let in_token_index = mango_group.get_token_index(&liqor_in_token_account.mint).unwrap();
|
||||
let liqor_out_token_account = Account::unpack(&liqor_out_token_acc.try_borrow_data()?)?;
|
||||
let out_token_index = mango_group.get_token_index(&liqor_out_token_account.mint).unwrap();
|
||||
prog_assert2!(in_token_index != out_token_index, MangoErrorCode::Default)?;
|
||||
|
||||
// Calculate maximum possible deposit amount
|
||||
let deficit_val = liqee_margin_account.get_partial_liq_deficit(
|
||||
&mango_group, &prices, open_orders_accs)?;
|
||||
|
||||
let out_withdrawable = liqee_margin_account.get_native_deposit(
|
||||
&mango_group.indexes[out_token_index], out_token_index);
|
||||
let val_out_withdrawable = U64F64::from_num(out_withdrawable)
|
||||
.checked_mul(prices[out_token_index]).unwrap();
|
||||
|
||||
// Can only deposit as much as it is possible to withdraw out_token
|
||||
let max_in_val = val_out_withdrawable / PARTIAL_LIQ_INCENTIVE;
|
||||
let max_in_val = if deficit_val < max_in_val {
|
||||
deficit_val
|
||||
} else {
|
||||
max_in_val
|
||||
};
|
||||
|
||||
// we know prices are not 0; if they are this will error;
|
||||
// TODO price could be very small
|
||||
// TODO verify all the rounding errors
|
||||
let max_in: U64F64 = max_in_val / prices[in_token_index];
|
||||
let max_in_token: u64 = max_in.checked_ceil().unwrap().to_num();
|
||||
let native_borrow = liqee_margin_account.get_native_borrow(
|
||||
&mango_group.indexes[in_token_index], in_token_index);
|
||||
// Can only deposit as much there is borrows to offset in in_token
|
||||
let in_quantity = std::cmp::min(std::cmp::min(max_in_token, native_borrow), max_deposit);
|
||||
|
||||
let deposit_instruction = spl_token::instruction::transfer(
|
||||
&spl_token::id(),
|
||||
liqor_in_token_acc.key,
|
||||
vault_accs[in_token_index].key,
|
||||
&liqor_acc.key, &[], in_quantity
|
||||
)?;
|
||||
let deposit_accs = [
|
||||
liqor_in_token_acc.clone(),
|
||||
vault_accs[in_token_index].clone(),
|
||||
liqor_acc.clone(),
|
||||
token_prog_acc.clone()
|
||||
];
|
||||
|
||||
solana_program::program::invoke_signed(&deposit_instruction, &deposit_accs, &[])?;
|
||||
let deposit: U64F64 = U64F64::from_num(in_quantity) / mango_group.indexes[in_token_index].borrow;
|
||||
checked_sub_borrow(&mut mango_group, &mut liqee_margin_account, in_token_index, deposit)?;
|
||||
|
||||
// Withdraw
|
||||
let in_val: U64F64 = U64F64::from_num(in_quantity) * prices[in_token_index];
|
||||
let out_val: U64F64 = in_val * PARTIAL_LIQ_INCENTIVE;
|
||||
let out_quantity: u64 = (out_val / prices[out_token_index]).checked_floor().unwrap().to_num();
|
||||
let withdraw_instruction = spl_token::instruction::transfer(
|
||||
&spl_token::ID,
|
||||
vault_accs[out_token_index].key,
|
||||
liqor_out_token_acc.key,
|
||||
signer_acc.key,
|
||||
&[],
|
||||
out_quantity
|
||||
)?;
|
||||
let withdraw_accs = [
|
||||
vault_accs[out_token_index].clone(),
|
||||
liqor_out_token_acc.clone(),
|
||||
signer_acc.clone(),
|
||||
token_prog_acc.clone()
|
||||
];
|
||||
|
||||
let signer_seeds = gen_signer_seeds(&mango_group.signer_nonce, mango_group_acc.key);
|
||||
solana_program::program::invoke_signed(&withdraw_instruction, &withdraw_accs, &[&signer_seeds])?;
|
||||
|
||||
let withdraw = U64F64::from_num(out_quantity) / mango_group.indexes[out_token_index].deposit;
|
||||
checked_sub_deposit(&mut mango_group, &mut liqee_margin_account, out_token_index, withdraw)?;
|
||||
|
||||
let coll_ratio = liqee_margin_account.get_collateral_ratio(&mango_group, &prices, open_orders_accs)?;
|
||||
|
||||
if coll_ratio >= mango_group.init_coll_ratio {
|
||||
// set margin account to no longer being liquidated
|
||||
liqee_margin_account.being_liquidated = false;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn process(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
|
@ -1387,8 +1593,8 @@ pub fn get_prices(
|
|||
mango_group: &MangoGroup,
|
||||
oracle_accs: &[AccountInfo]
|
||||
) -> MangoResult<[U64F64; NUM_TOKENS]> {
|
||||
let mut prices = [U64F64::from_num(0); NUM_TOKENS];
|
||||
prices[NUM_MARKETS] = U64F64::from_num(1); // quote currency is 1
|
||||
let mut prices = [ZERO_U64F64; NUM_TOKENS];
|
||||
prices[NUM_MARKETS] = ONE_U64F64; // quote currency is 1
|
||||
let quote_decimals: u8 = mango_group.mint_decimals[NUM_MARKETS];
|
||||
|
||||
for i in 0..NUM_MARKETS {
|
||||
|
@ -1411,7 +1617,7 @@ pub fn get_prices(
|
|||
Ok(prices)
|
||||
}
|
||||
|
||||
pub fn invoke_settle_funds<'a>(
|
||||
fn invoke_settle_funds<'a>(
|
||||
dex_prog_acc: &AccountInfo<'a>,
|
||||
spot_market_acc: &AccountInfo<'a>,
|
||||
open_orders_acc: &AccountInfo<'a>,
|
||||
|
@ -1456,7 +1662,7 @@ pub fn invoke_settle_funds<'a>(
|
|||
solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds)
|
||||
}
|
||||
|
||||
pub fn invoke_cancel_order<'a>(
|
||||
fn invoke_cancel_order<'a>(
|
||||
dex_prog_acc: &AccountInfo<'a>,
|
||||
spot_market_acc: &AccountInfo<'a>,
|
||||
bids_acc: &AccountInfo<'a>,
|
||||
|
@ -1492,3 +1698,78 @@ pub fn invoke_cancel_order<'a>(
|
|||
];
|
||||
solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds)
|
||||
}
|
||||
|
||||
fn cancel_all<'a>(
|
||||
open_orders_acc: &AccountInfo<'a>,
|
||||
dex_prog_acc: &AccountInfo<'a>,
|
||||
spot_market_acc: &AccountInfo<'a>,
|
||||
bids_acc: &AccountInfo<'a>,
|
||||
asks_acc: &AccountInfo<'a>,
|
||||
signer_acc: &AccountInfo<'a>,
|
||||
dex_event_queue_acc: &AccountInfo<'a>,
|
||||
dex_base_acc: &AccountInfo<'a>,
|
||||
dex_quote_acc: &AccountInfo<'a>,
|
||||
base_vault_acc: &AccountInfo<'a>,
|
||||
quote_vault_acc: &AccountInfo<'a>,
|
||||
dex_signer_acc: &AccountInfo<'a>,
|
||||
token_prog_acc: &AccountInfo<'a>,
|
||||
signers_seeds: &[&[&[u8]]],
|
||||
|
||||
mut limit: u32
|
||||
) -> MangoResult<()> {
|
||||
let open_orders = load_open_orders(open_orders_acc)?;
|
||||
let mut free_slot_bits = open_orders.free_slot_bits;
|
||||
limit = std::cmp::min(limit, free_slot_bits.count_zeros());
|
||||
if limit == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for j in 0..128 {
|
||||
let slot_is_free = (free_slot_bits & 1u128) != 0;
|
||||
free_slot_bits = free_slot_bits >> 1;
|
||||
if slot_is_free {
|
||||
continue
|
||||
}
|
||||
|
||||
let oid = open_orders.orders[j];
|
||||
|
||||
let cancel_instruction = serum_dex::instruction::MarketInstruction::CancelOrderV2(
|
||||
serum_dex::instruction::CancelOrderInstructionV2 {
|
||||
side: open_orders.slot_side(j as u8).unwrap(),
|
||||
order_id: oid
|
||||
}
|
||||
);
|
||||
invoke_cancel_order(
|
||||
dex_prog_acc,
|
||||
spot_market_acc,
|
||||
bids_acc,
|
||||
asks_acc,
|
||||
open_orders_acc,
|
||||
signer_acc,
|
||||
dex_event_queue_acc,
|
||||
cancel_instruction.pack(),
|
||||
signers_seeds
|
||||
)?;
|
||||
|
||||
limit -= 1;
|
||||
if limit == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
invoke_settle_funds(
|
||||
dex_prog_acc,
|
||||
spot_market_acc,
|
||||
open_orders_acc,
|
||||
signer_acc,
|
||||
dex_base_acc,
|
||||
dex_quote_acc,
|
||||
base_vault_acc,
|
||||
quote_vault_acc,
|
||||
dex_signer_acc,
|
||||
token_prog_acc,
|
||||
signers_seeds
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -11,6 +11,8 @@ use solana_program::clock::Clock;
|
|||
use solana_program::program_error::ProgramError;
|
||||
use solana_program::pubkey::Pubkey;
|
||||
|
||||
use fixed_macro::types::U64F64;
|
||||
|
||||
use crate::error::{AssertionError, check_assert, MangoResult, SourceFileId};
|
||||
|
||||
/// Initially launching with BTC/USDT, ETH/USDT
|
||||
|
@ -20,7 +22,14 @@ pub const MANGO_GROUP_PADDING: usize = 8 - (NUM_TOKENS + NUM_MARKETS) % 8;
|
|||
pub const MINUTE: u64 = 60;
|
||||
pub const HOUR: u64 = 3600;
|
||||
pub const DAY: u64 = 86400;
|
||||
pub const YEAR: u64 = 31536000;
|
||||
pub const YEAR: U64F64 = U64F64!(31536000);
|
||||
// pub const YEAR: u64 = 31536000;
|
||||
const OPTIMAL_UTIL: U64F64 = U64F64!(0.7);
|
||||
const OPTIMAL_R: U64F64 = U64F64!(3.17097919837645865e-09); // 10% APY -> 0.1 / YEAR
|
||||
const MAX_R: U64F64 = U64F64!(3.17097919837645865e-08); // max 100% APY -> 1 / YEAR
|
||||
pub const ONE_U64F64: U64F64 = U64F64!(1);
|
||||
pub const ZERO_U64F64: U64F64 = U64F64!(0);
|
||||
pub const PARTIAL_LIQ_INCENTIVE: U64F64 = U64F64!(1.05);
|
||||
|
||||
macro_rules! prog_assert {
|
||||
($cond:expr) => {
|
||||
|
@ -124,6 +133,8 @@ pub struct MangoGroup {
|
|||
}
|
||||
impl_loadable!(MangoGroup);
|
||||
|
||||
|
||||
|
||||
impl MangoGroup {
|
||||
pub fn load_mut_checked<'a>(
|
||||
account: &'a AccountInfo,
|
||||
|
@ -158,27 +169,23 @@ impl MangoGroup {
|
|||
}
|
||||
/// interest is in units per second (e.g. 0.01 => 1% interest per second)
|
||||
pub fn get_interest_rate(&self, token_index: usize) -> U64F64 {
|
||||
let optimal_util = U64F64::from_num(0.7);
|
||||
let optimal_r = U64F64::from_num(0.10) / U64F64::from_num(YEAR); // opt 10%
|
||||
let max_r = U64F64::from_num(1) / U64F64::from_num(YEAR); // max 100%
|
||||
let index: &MangoIndex = &self.indexes[token_index];
|
||||
let native_deposits = index.deposit * self.total_deposits[token_index];
|
||||
let native_borrows = index.borrow * self.total_borrows[token_index];
|
||||
if native_deposits <= native_borrows { // if deps == 0, this is always true
|
||||
return max_r; // kind of an error state
|
||||
return MAX_R; // kind of an error state
|
||||
}
|
||||
|
||||
let utilization = native_borrows / native_deposits;
|
||||
if utilization > optimal_util {
|
||||
let extra_util = utilization - optimal_util;
|
||||
let slope = (max_r - optimal_r) / (U64F64::from_num(1) - optimal_util);
|
||||
optimal_r + slope * extra_util
|
||||
if utilization > OPTIMAL_UTIL {
|
||||
let extra_util = utilization - OPTIMAL_UTIL;
|
||||
let slope = (MAX_R - OPTIMAL_R) / (ONE_U64F64 - OPTIMAL_UTIL);
|
||||
OPTIMAL_R + slope * extra_util
|
||||
} else {
|
||||
let slope = optimal_r / optimal_util;
|
||||
let slope = OPTIMAL_R / OPTIMAL_UTIL;
|
||||
slope * utilization
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_indexes(&mut self, clock: &Clock) -> MangoResult<()> {
|
||||
// TODO verify what happens if total_deposits < total_borrows
|
||||
// TODO verify what happens if total_deposits == 0 && total_borrows > 0
|
||||
|
@ -190,7 +197,7 @@ impl MangoGroup {
|
|||
for i in 0..NUM_TOKENS {
|
||||
let interest_rate = self.get_interest_rate(i);
|
||||
let index: &mut MangoIndex = &mut self.indexes[i];
|
||||
if index.last_update == curr_ts || self.total_deposits[i] == U64F64::from_num(0) {
|
||||
if index.last_update == curr_ts || self.total_deposits[i] == ZERO_U64F64 {
|
||||
// TODO is skipping when total_deposits == 0 correct move?
|
||||
continue;
|
||||
}
|
||||
|
@ -262,7 +269,8 @@ pub struct MarginAccount {
|
|||
|
||||
pub open_orders: [Pubkey; NUM_MARKETS], // owned by Mango
|
||||
|
||||
pub padding: [u8; 8] // padding to make compatible with previous MarginAccount size
|
||||
pub being_liquidated: bool,
|
||||
pub padding: [u8; 7] // padding to make compatible with previous MarginAccount size
|
||||
// TODO add has_borrows field for easy memcmp fetching
|
||||
}
|
||||
impl_loadable!(MarginAccount);
|
||||
|
@ -309,7 +317,7 @@ impl MarginAccount {
|
|||
let assets = self.get_assets_val(mango_group, prices, open_orders_accs)?;
|
||||
let liabs = self.get_liabs_val(mango_group, prices)?;
|
||||
if liabs > assets {
|
||||
Ok(U64F64::from_num(0))
|
||||
Ok(ZERO_U64F64)
|
||||
} else {
|
||||
Ok(assets - liabs)
|
||||
}
|
||||
|
@ -324,7 +332,7 @@ impl MarginAccount {
|
|||
// assets / liabs
|
||||
let assets = self.get_assets_val(mango_group, prices, open_orders_accs)?;
|
||||
let liabs = self.get_liabs_val(mango_group, prices)?;
|
||||
if liabs == U64F64::from_num(0) {
|
||||
if liabs == ZERO_U64F64 {
|
||||
Ok(U64F64::MAX)
|
||||
} else {
|
||||
Ok(assets / liabs)
|
||||
|
@ -372,7 +380,7 @@ impl MarginAccount {
|
|||
) -> MangoResult<U64F64> {
|
||||
// TODO weight collateral differently
|
||||
// equity = val(deposits) + val(positions) + val(open_orders) - val(borrows)
|
||||
let mut assets: U64F64 = U64F64::from_num(0);
|
||||
let mut assets: U64F64 = ZERO_U64F64;
|
||||
for i in 0..NUM_MARKETS { // Add up all the value in open orders
|
||||
// TODO check open orders details
|
||||
if *open_orders_accs[i].key == Pubkey::default() {
|
||||
|
@ -401,7 +409,7 @@ impl MarginAccount {
|
|||
mango_group: &MangoGroup,
|
||||
prices: &[U64F64; NUM_TOKENS],
|
||||
) -> MangoResult<U64F64> {
|
||||
let mut liabs: U64F64 = U64F64::from_num(0);
|
||||
let mut liabs: U64F64 = ZERO_U64F64;
|
||||
for i in 0..NUM_TOKENS {
|
||||
let index: &MangoIndex = &mango_group.indexes[i];
|
||||
let native_borrows = index.borrow * self.borrows[i];
|
||||
|
@ -419,12 +427,30 @@ impl MarginAccount {
|
|||
let assets = self.get_assets_val(mango_group, prices, open_orders_accs)?;
|
||||
let liabs = self.get_liabs_val(mango_group, prices)?;
|
||||
|
||||
if liabs == U64F64::from_num(0) || assets >= liabs * mango_group.init_coll_ratio {
|
||||
if liabs == ZERO_U64F64 || assets >= liabs * mango_group.init_coll_ratio {
|
||||
Ok(0)
|
||||
} else {
|
||||
Ok((liabs * mango_group.init_coll_ratio - assets).to_num())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_partial_liq_deficit(
|
||||
&self,
|
||||
mango_group: &MangoGroup,
|
||||
prices: &[U64F64; NUM_TOKENS],
|
||||
open_orders_accs: &[AccountInfo; NUM_MARKETS]
|
||||
) -> MangoResult<U64F64> {
|
||||
let assets = self.get_assets_val(mango_group, prices, open_orders_accs)?;
|
||||
let liabs = self.get_liabs_val(mango_group, prices)?;
|
||||
|
||||
if liabs == ZERO_U64F64 || assets >= liabs * mango_group.init_coll_ratio {
|
||||
Ok(ZERO_U64F64)
|
||||
} else {
|
||||
// TODO make this checked
|
||||
Ok((liabs * mango_group.init_coll_ratio - assets) / (mango_group.init_coll_ratio - PARTIAL_LIQ_INCENTIVE))
|
||||
}
|
||||
|
||||
}
|
||||
pub fn get_native_borrow(&self, index: &MangoIndex, token_i: usize) -> u64 {
|
||||
(self.borrows[token_i] * index.borrow).to_num()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue