Merge branch 'dev' into feature/close-mango-account

This commit is contained in:
Adrian Brzeziński 2023-01-13 17:33:50 +01:00
commit 3077f57c2f
21 changed files with 178 additions and 153 deletions

View File

@ -11,7 +11,6 @@ jobs:
format: format:
name: Format name: Format
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: (github.actor != 'dependabot[bot]')
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -31,7 +30,6 @@ jobs:
lint: lint:
name: Lint name: Lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: (github.actor != 'dependabot[bot]')
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -51,7 +49,6 @@ jobs:
unit-test: unit-test:
name: Unit Test name: Unit Test
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: (github.actor != 'dependabot[bot]')
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -71,7 +68,6 @@ jobs:
semgrep: semgrep:
name: Security Scan name: Security Scan
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: (github.actor != 'dependabot[bot]')
container: container:
image: returntocorp/semgrep image: returntocorp/semgrep
@ -80,6 +76,12 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Run semgrep - name: Run semgrep
run: semgrep ci run: semgrep ci --sarif --output=semgrep-results.sarif
env: env:
SEMGREP_RULES: p/typescript SEMGREP_RULES: p/typescript
- name: Upload output
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: semgrep-results.sarif

View File

@ -25,12 +25,11 @@ jobs:
trivy: trivy:
name: Dependency Scan name: Dependency Scan
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: (github.actor != 'dependabot[bot]')
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3
# Report all vulnerabilities in CI output # Report all vulnerabilities in security tab
- name: Report on all vulnerabilities - name: Report on all vulnerabilities
uses: aquasecurity/trivy-action@master uses: aquasecurity/trivy-action@master
with: with:
@ -38,7 +37,8 @@ jobs:
scan-ref: 'Cargo.lock' scan-ref: 'Cargo.lock'
ignore-unfixed: true ignore-unfixed: true
hide-progress: true hide-progress: true
format: 'table' format: 'sarif'
output: 'trivy-results.sarif'
# Fail the job on critical vulnerabiliies with fix available # Fail the job on critical vulnerabiliies with fix available
- name: Fail on critical vulnerabilities - name: Fail on critical vulnerabilities
@ -51,3 +51,9 @@ jobs:
format: 'table' format: 'table'
severity: 'CRITICAL' severity: 'CRITICAL'
exit-code: '1' exit-code: '1'
- name: Upload output
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'

View File

@ -11,12 +11,11 @@ jobs:
trivy: trivy:
name: Dependency Scan name: Dependency Scan
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: (github.actor != 'dependabot[bot]')
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3
# Report all vulnerabilities in CI output # Report all vulnerabilities in security tab
- name: Report on all vulnerabilities - name: Report on all vulnerabilities
uses: aquasecurity/trivy-action@master uses: aquasecurity/trivy-action@master
with: with:
@ -24,7 +23,8 @@ jobs:
scan-ref: 'yarn.lock' scan-ref: 'yarn.lock'
ignore-unfixed: true ignore-unfixed: true
hide-progress: true hide-progress: true
format: 'table' format: 'sarif'
output: 'trivy-results.sarif'
# Fail the job on critical vulnerabiliies with fix available # Fail the job on critical vulnerabiliies with fix available
- name: Fail on critical vulnerabilities - name: Fail on critical vulnerabilities
@ -37,3 +37,9 @@ jobs:
format: 'table' format: 'table'
severity: 'CRITICAL' severity: 'CRITICAL'
exit-code: '1' exit-code: '1'
- name: Upload output
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'

View File

@ -1,42 +1,55 @@
# Mango v4 Program Change Log # Mango v4 Program Change Log
Update this for each mainnet deployment. Update this for each program release and mainnet deployment.
## not on mainnet ## not on mainnet
## mainnet ## mainnet
Jan 5, 2023 Central European Standard Time ### v0.2.0, 2023-1-13
Deployment: Jan 13, 2023 at 11:31:05 Central European Standard Time, https://explorer.solana.com/tx/4yGRUk6QwntvC4umECDPDZJNcbevSJ1fdZi75Mz9rGa9SHKzUtjMF3V5FCTkzBZqAETQTccqv63BYw6yX8JNxiur
- Add an optional security authority with the ability to halt a group or
temporarily freeze user accounts.
- Extend perp pnl settle limits to apply to realized pnl
- Rename perp_liq_bankruptcy to perp_liq_quote_and_bankruptcy and extend it to
cover taking over the liqee's negative pnl while the settle limits and perp
settle health allow it.
- Perp bankruptcy is now allowed when settling is impossible, even when there are
spot assets remaining.
### Jan 5, 2023 Central European Standard Time
- Change max staleness slots from -1 to 600 for trustless token registering - Change max staleness slots from -1 to 600 for trustless token registering
Jan 4, 2023 Central European Standard Time ### Jan 4, 2023 Central European Standard Time
- Reduce only mode for tokens, and perp markets - Reduce only mode for tokens, and perp markets
- Perp settlement applies no loan origination fee - Perp settlement applies no loan origination fee
Dec 16, 2022 at 16:40 Central European Standard Time ### Dec 16, 2022 at 16:40 Central European Standard Time
Oct 8, 2022 at 14:38:31 Central European Summer Time ### Oct 8, 2022 at 14:38:31 Central European Summer Time
https://explorer.solana.com/tx/3m8EDohkgwJZyiwpGXztBWARWQVxyhnSNDVuH467D7FPS2wxJerr79HhdhDEed5hpConHgGsKHvxtW1HJP6GixX9 https://explorer.solana.com/tx/3m8EDohkgwJZyiwpGXztBWARWQVxyhnSNDVuH467D7FPS2wxJerr79HhdhDEed5hpConHgGsKHvxtW1HJP6GixX9
Oct 8, 2022 at 14:38:31 Central European Summer Time ### Oct 8, 2022 at 14:38:31 Central European Summer Time
https://explorer.solana.com/tx/3m8EDohkgwJZyiwpGXztBWARWQVxyhnSNDVuH467D7FPS2wxJerr79HhdhDEed5hpConHgGsKHvxtW1HJP6GixX9 https://explorer.solana.com/tx/3m8EDohkgwJZyiwpGXztBWARWQVxyhnSNDVuH467D7FPS2wxJerr79HhdhDEed5hpConHgGsKHvxtW1HJP6GixX9
- New ix `TokenDepositIntoExisting` - New ix `TokenDepositIntoExisting`
Sep 1, 2022 at 10:24:35 Central European Summer Time ### Sep 1, 2022 at 10:24:35 Central European Summer Time
https://explorer.solana.com/tx/3NnX13A3QwsREKKKo3iYR4jqgoongpCjdhhXuJ3y5iP6FwfPcNieVop623tpgPbyreC7m7KtphwdWdoHYE5YC394 https://explorer.solana.com/tx/3NnX13A3QwsREKKKo3iYR4jqgoongpCjdhhXuJ3y5iP6FwfPcNieVop623tpgPbyreC7m7KtphwdWdoHYE5YC394
- Add HealthRegionBegin, -End instructions - Add HealthRegionBegin, -End instructions
- Add explicit "oracle" account argument for TokenDeposit and TokenWithdraw instructions - Add explicit "oracle" account argument for TokenDeposit and TokenWithdraw instructions
Aug 20, 2022 at 19:58:29 Central European Summer Time ### Aug 20, 2022 at 19:58:29 Central European Summer Time
https://explorer.solana.com/tx/3R4frko1AekQKJmmQ5T6k3mdXF9uZVHTR7oocdspTPsc82xX7qrbgnG61r28UdhCxsjMxtQHgBqMc37FSvoHQfCN https://explorer.solana.com/tx/3R4frko1AekQKJmmQ5T6k3mdXF9uZVHTR7oocdspTPsc82xX7qrbgnG61r28UdhCxsjMxtQHgBqMc37FSvoHQfCN
- loan fee logging for off-chain services - loan fee logging for off-chain services
Aug 18, 2022 at 17:17:40 Central European Summer Time ### Aug 18, 2022 at 17:17:40 Central European Summer Time
https://explorer.solana.com/tx/4Xnyswcwx98y6khw8ptNVmdhQZwJjuNy2BvmQg2pJayoThFiw8kmS2ecRAg5cg2DncvW3NQgn2vtP8mCUtv6Q1yB https://explorer.solana.com/tx/4Xnyswcwx98y6khw8ptNVmdhQZwJjuNy2BvmQg2pJayoThFiw8kmS2ecRAg5cg2DncvW3NQgn2vtP8mCUtv6Q1yB
- liq_token_bankruptcy: removed liab_token_index argument - liq_token_bankruptcy: removed liab_token_index argument
@ -82,13 +95,13 @@ https://explorer.solana.com/tx/4Xnyswcwx98y6khw8ptNVmdhQZwJjuNy2BvmQg2pJayoThFiw
marginTrade takes inputMintPk and outputMintPk instead of inputToken and outputToken marginTrade takes inputMintPk and outputMintPk instead of inputToken and outputToken
marginTrade takes flashLoanType as an argument marginTrade takes flashLoanType as an argument
Aug 8, 2022 at 18:56:04 Central European Summer Time ### Aug 8, 2022 at 18:56:04 Central European Summer Time
https://explorer.solana.com/tx/yjZggRTrcDNquMkftNvBKLv77Dk4xp5yQPYXgN3qvBHTBWWJVhLPGHxqpGwosmEq3j8byHZMa13oxLLerBWUdgW https://explorer.solana.com/tx/yjZggRTrcDNquMkftNvBKLv77Dk4xp5yQPYXgN3qvBHTBWWJVhLPGHxqpGwosmEq3j8byHZMa13oxLLerBWUdgW
- improved logging for off chain services - improved logging for off chain services
- `AccountCreate` ix takes explicit input for sizes of various features - `AccountCreate` ix takes explicit input for sizes of various features
Aug 4, 2022 at 09:30:00 Central European Summer Time ### Aug 4, 2022 at 09:30:00 Central European Summer Time
ts/client changes ts/client changes
@ -114,7 +127,7 @@ New features
- `TokenRegistration` and `TokenRegisterTrustless` ixs dont take a bank_num anymore, hardcoded to 0. - `TokenRegistration` and `TokenRegisterTrustless` ixs dont take a bank_num anymore, hardcoded to 0.
- Enforced a minimum maximum rate of 50% so that rates don't fall so low that they cannot recover. - Enforced a minimum maximum rate of 50% so that rates don't fall so low that they cannot recover.
Jul 14, 2022 at 09:33:52 Central European Summer Time ### Jul 14, 2022 at 09:33:52 Central European Summer Time
https://explorer.solana.com/tx/vZ5hP1vGp37fgzBfG9nb4nfA5ZdmYgk8meq53YPR4ReFxrcTwBUxTYBQUgnfAnq9u5fH36S3QTfb9mVkBXt5A6C https://explorer.solana.com/tx/vZ5hP1vGp37fgzBfG9nb4nfA5ZdmYgk8meq53YPR4ReFxrcTwBUxTYBQUgnfAnq9u5fH36S3QTfb9mVkBXt5A6C
- Account data was rearranged to put fields that are often used with gPA first - Account data was rearranged to put fields that are often used with gPA first

8
Cargo.lock generated
View File

@ -1094,7 +1094,7 @@ dependencies = [
[[package]] [[package]]
name = "cli" name = "cli"
version = "0.1.0" version = "0.3.0"
dependencies = [ dependencies = [
"anchor-client", "anchor-client",
"anchor-lang", "anchor-lang",
@ -1118,7 +1118,7 @@ dependencies = [
[[package]] [[package]]
name = "client" name = "client"
version = "0.1.0" version = "0.3.0"
dependencies = [ dependencies = [
"anchor-client", "anchor-client",
"anchor-lang", "anchor-lang",
@ -2846,7 +2846,7 @@ dependencies = [
[[package]] [[package]]
name = "keeper" name = "keeper"
version = "0.1.0" version = "0.3.0"
dependencies = [ dependencies = [
"anchor-client", "anchor-client",
"anchor-lang", "anchor-lang",
@ -3121,7 +3121,7 @@ dependencies = [
[[package]] [[package]]
name = "mango-v4" name = "mango-v4"
version = "0.1.0" version = "0.3.0"
dependencies = [ dependencies = [
"anchor-lang", "anchor-lang",
"anchor-spl", "anchor-spl",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "cli" name = "cli"
version = "0.1.0" version = "0.3.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -1,6 +1,6 @@
[package] [package]
name = "client" name = "client"
version = "0.1.0" version = "0.3.0"
edition = "2021" edition = "2021"
[lib] [lib]

View File

@ -1,6 +1,6 @@
[package] [package]
name = "keeper" name = "keeper"
version = "0.1.0" version = "0.3.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mango-v4" name = "mango-v4"
version = "0.1.0" version = "0.3.0"
description = "Created with Anchor" description = "Created with Anchor"
edition = "2021" edition = "2021"

View File

@ -537,21 +537,6 @@ impl HealthCache {
self.has_spot_borrows() || perp_borrows self.has_spot_borrows() || perp_borrows
} }
pub fn has_liquidatable_spot_or_perp_base(&self) -> bool {
let spot_liquidatable = self.has_spot_assets();
let serum3_cancelable = self.has_serum3_open_orders_funds();
let perp_liquidatable = self.perp_infos.iter().any(|p| {
// can use perp_liq_base_position
p.base_lots != 0
// can use perp_liq_force_cancel_orders
|| p.has_open_orders
// A remaining quote position can be reduced with perp_settle_pnl and that can improve health.
// However, since it's not guaranteed that there is a counterparty, a positive perp quote position
// does not prevent bankruptcy.
});
spot_liquidatable || serum3_cancelable || perp_liquidatable
}
pub(crate) fn compute_serum3_reservations( pub(crate) fn compute_serum3_reservations(
&self, &self,
health_type: HealthType, health_type: HealthType,

View File

@ -1,11 +1,11 @@
use fixed::types::I80F48; use fixed::types::I80F48;
pub trait ClampedToNum { pub trait ClampToInt {
fn clamp_to_i64(&self) -> i64; fn clamp_to_i64(&self) -> i64;
fn clamp_to_u64(&self) -> u64; fn clamp_to_u64(&self) -> u64;
} }
impl ClampedToNum for I80F48 { impl ClampToInt for I80F48 {
fn clamp_to_i64(&self) -> i64 { fn clamp_to_i64(&self) -> i64 {
if *self <= i64::MIN { if *self <= i64::MIN {
i64::MIN i64::MIN
@ -27,7 +27,7 @@ impl ClampedToNum for I80F48 {
} }
} }
impl ClampedToNum for f64 { impl ClampToInt for f64 {
fn clamp_to_i64(&self) -> i64 { fn clamp_to_i64(&self) -> i64 {
if *self <= i64::MIN as f64 { if *self <= i64::MIN as f64 {
i64::MIN i64::MIN
@ -49,7 +49,7 @@ impl ClampedToNum for f64 {
} }
} }
impl ClampedToNum for u64 { impl ClampToInt for u64 {
fn clamp_to_i64(&self) -> i64 { fn clamp_to_i64(&self) -> i64 {
if *self >= i64::MAX as u64 { if *self >= i64::MAX as u64 {
i64::MAX i64::MAX

View File

@ -71,25 +71,9 @@ pub fn perp_liq_base_position(
let liqee_init_health = liqee_health_cache.health(HealthType::Init); let liqee_init_health = liqee_health_cache.health(HealthType::Init);
liqee_health_cache.require_after_phase1_liquidation()?; liqee_health_cache.require_after_phase1_liquidation()?;
// Once maint_health falls below 0, we want to start liquidating, if !liqee.check_liquidatable(&liqee_health_cache)? {
// we want to allow liquidation to continue until init_health is positive,
// to prevent constant oscillation between the two states
if liqee.being_liquidated() {
if liqee
.fixed
.maybe_recover_from_being_liquidated(liqee_init_health)
{
msg!("Liqee init_health above zero");
return Ok(()); return Ok(());
} }
} else {
let maint_health = liqee_health_cache.health(HealthType::Maint);
require!(
maint_health < I80F48::ZERO,
MangoError::HealthMustBeNegative
);
liqee.fixed.set_being_liquidated(true);
}
let mut perp_market = ctx.accounts.perp_market.load_mut()?; let mut perp_market = ctx.accounts.perp_market.load_mut()?;
let perp_market_index = perp_market.perp_market_index; let perp_market_index = perp_market.perp_market_index;

View File

@ -1,5 +1,4 @@
use anchor_lang::prelude::*; use anchor_lang::prelude::*;
use fixed::types::I80F48;
use crate::error::*; use crate::error::*;
use crate::health::*; use crate::health::*;
@ -47,22 +46,20 @@ pub fn perp_liq_force_cancel_orders(
let health_cache = let health_cache =
new_health_cache(&account.borrow(), &retriever).context("create health cache")?; new_health_cache(&account.borrow(), &retriever).context("create health cache")?;
if account.being_liquidated() {
let init_health = health_cache.health(HealthType::Init);
if account
.fixed
.maybe_recover_from_being_liquidated(init_health)
{ {
msg!("Liqee init_health above zero"); let result = account.check_liquidatable(&health_cache);
if account.fixed.is_operational() {
if !result? {
return Ok(()); return Ok(());
} }
} else { } else {
let maint_health = health_cache.health(HealthType::Maint); // Frozen accounts can always have their orders cancelled
require!( if let Err(Error::AnchorError(ref inner)) = result {
maint_health < I80F48::ZERO, if inner.error_code_number != MangoError::HealthMustBeNegative as u32 {
MangoError::HealthMustBeNegative result?;
); }
account.fixed.set_being_liquidated(true); }
}
} }
health_cache health_cache

View File

@ -118,25 +118,9 @@ pub fn perp_liq_quote_and_bankruptcy(
let liqee_settle_health = liqee_health_cache.perp_settle_health(); let liqee_settle_health = liqee_health_cache.perp_settle_health();
liqee_health_cache.require_after_phase2_liquidation()?; liqee_health_cache.require_after_phase2_liquidation()?;
// Once maint_health falls below 0, we want to start liquidating, if !liqee.check_liquidatable(&liqee_health_cache)? {
// we want to allow liquidation to continue until init_health is positive,
// to prevent constant oscillation between the two states
if liqee.being_liquidated() {
if liqee
.fixed
.maybe_recover_from_being_liquidated(liqee_init_health)
{
msg!("Liqee init_health above zero");
return Ok(()); return Ok(());
} }
} else {
let maint_health = liqee_health_cache.health(HealthType::Maint);
require!(
maint_health < I80F48::ZERO,
MangoError::HealthMustBeNegative
);
liqee.fixed.set_being_liquidated(true);
}
// check positions exist/create them, done early for nicer error messages // check positions exist/create them, done early for nicer error messages
{ {

View File

@ -1,6 +1,5 @@
use anchor_lang::prelude::*; use anchor_lang::prelude::*;
use anchor_spl::token::{Token, TokenAccount}; use anchor_spl::token::{Token, TokenAccount};
use fixed::types::I80F48;
use crate::error::*; use crate::error::*;
use crate::health::*; use crate::health::*;
@ -126,22 +125,21 @@ pub fn serum3_liq_force_cancel_orders(
let health_cache = let health_cache =
new_health_cache(&account.borrow(), &retriever).context("create health cache")?; new_health_cache(&account.borrow(), &retriever).context("create health cache")?;
if account.being_liquidated() {
let init_health = health_cache.health(HealthType::Init);
if account
.fixed
.maybe_recover_from_being_liquidated(init_health)
{ {
msg!("Liqee init_health above zero"); let result = account.check_liquidatable(&health_cache);
if account.fixed.is_operational() {
if !result? {
return Ok(()); return Ok(());
} }
} else { } else {
let maint_health = health_cache.health(HealthType::Maint); // Frozen accounts can always have their orders cancelled
require!( if let Err(Error::AnchorError(ref inner)) = result {
maint_health < I80F48::ZERO, if inner.error_code_number != MangoError::HealthMustBeNegative as u32 {
MangoError::HealthMustBeNegative // propagate all unexpected errors
); result?;
account.fixed.set_being_liquidated(true); }
}
}
} }
health_cache health_cache

View File

@ -69,22 +69,9 @@ pub fn token_liq_with_token(
let init_health = liqee_health_cache.health(HealthType::Init); let init_health = liqee_health_cache.health(HealthType::Init);
liqee_health_cache.require_after_phase1_liquidation()?; liqee_health_cache.require_after_phase1_liquidation()?;
// Once maint_health falls below 0, we want to start liquidating, if !liqee.check_liquidatable(&liqee_health_cache)? {
// we want to allow liquidation to continue until init_health is positive,
// to prevent constant oscillation between the two states
if liqee.being_liquidated() {
if liqee.fixed.maybe_recover_from_being_liquidated(init_health) {
msg!("Liqee init_health above zero");
return Ok(()); return Ok(());
} }
} else {
let maint_health = liqee_health_cache.health(HealthType::Maint);
require!(
maint_health < I80F48::ZERO,
MangoError::HealthMustBeNegative
);
liqee.fixed.set_being_liquidated(true);
}
// //
// Transfer some liab_token from liqor to liqee and // Transfer some liab_token from liqor to liqee and

View File

@ -86,7 +86,7 @@ pub struct MangoAccount {
/// Init health as calculated during HealthReginBegin, rounded up. /// Init health as calculated during HealthReginBegin, rounded up.
pub health_region_begin_init_health: i64, pub health_region_begin_init_health: i64,
pub frozen_until: i64, pub frozen_until: u64,
pub reserved: [u8; 232], pub reserved: [u8; 232],
@ -968,6 +968,30 @@ impl<
Ok(()) Ok(())
} }
pub fn check_liquidatable(&mut self, health_cache: &HealthCache) -> Result<bool> {
// Once maint_health falls below 0, we want to start liquidating,
// we want to allow liquidation to continue until init_health is positive,
// to prevent constant oscillation between the two states
if self.being_liquidated() {
let init_health = health_cache.health(HealthType::Init);
if self
.fixed_mut()
.maybe_recover_from_being_liquidated(init_health)
{
msg!("Liqee init_health above zero");
return Ok(false);
}
} else {
let maint_health = health_cache.health(HealthType::Maint);
require!(
maint_health < I80F48::ZERO,
MangoError::HealthMustBeNegative
);
self.fixed_mut().set_being_liquidated(true);
}
Ok(true)
}
// writes length of tokens vec at appropriate offset so that borsh can infer the vector length // writes length of tokens vec at appropriate offset so that borsh can infer the vector length
// length used is that present in the header // length used is that present in the header
fn write_token_length(&mut self) { fn write_token_length(&mut self) {

View File

@ -6,7 +6,7 @@ use static_assertions::const_assert_eq;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::mem::size_of; use std::mem::size_of;
use crate::i80f48::ClampedToNum; use crate::i80f48::ClampToInt;
use crate::state::*; use crate::state::*;
pub const FREE_ORDER_SLOT: PerpMarketIndex = PerpMarketIndex::MAX; pub const FREE_ORDER_SLOT: PerpMarketIndex = PerpMarketIndex::MAX;

View File

@ -58,7 +58,7 @@ import {
} from './utils'; } from './utils';
import { sendTransaction } from './utils/rpc'; import { sendTransaction } from './utils/rpc';
enum AccountRetriever { export enum AccountRetriever {
Scanning, Scanning,
Fixed, Fixed,
} }
@ -2657,9 +2657,7 @@ export class MangoClient {
); );
} }
/// private public buildHealthRemainingAccounts(
private buildHealthRemainingAccounts(
retriever: AccountRetriever, retriever: AccountRetriever,
group: Group, group: Group,
mangoAccounts: MangoAccount[], mangoAccounts: MangoAccount[],
@ -2699,12 +2697,12 @@ export class MangoClient {
const tokenPositionIndices = mangoAccount.tokens.map((t) => t.tokenIndex); const tokenPositionIndices = mangoAccount.tokens.map((t) => t.tokenIndex);
for (const bank of banks) { for (const bank of banks) {
const tokenPositionExists = const tokenPositionExists =
tokenPositionIndices.indexOf(bank.tokenIndex) > 0; tokenPositionIndices.indexOf(bank.tokenIndex) > -1;
if (!tokenPositionExists) { if (!tokenPositionExists) {
const inactiveTokenPosition = tokenPositionIndices.findIndex( const inactiveTokenPosition = tokenPositionIndices.findIndex(
(index) => index === TokenPosition.TokenIndexUnset, (index) => index === TokenPosition.TokenIndexUnset,
); );
if (inactiveTokenPosition) { if (inactiveTokenPosition != -1) {
tokenPositionIndices[inactiveTokenPosition] = bank.tokenIndex; tokenPositionIndices[inactiveTokenPosition] = bank.tokenIndex;
} }
} }
@ -2724,12 +2722,12 @@ export class MangoClient {
const perpPositionIndices = mangoAccount.perps.map((p) => p.marketIndex); const perpPositionIndices = mangoAccount.perps.map((p) => p.marketIndex);
for (const perpMarket of perpMarkets) { for (const perpMarket of perpMarkets) {
const perpPositionExists = const perpPositionExists =
perpPositionIndices.indexOf(perpMarket.perpMarketIndex) > 0; perpPositionIndices.indexOf(perpMarket.perpMarketIndex) > -1;
if (!perpPositionExists) { if (!perpPositionExists) {
const inactivePerpPosition = perpPositionIndices.find( const inactivePerpPosition = perpPositionIndices.findIndex(
(perpIdx) => perpIdx === PerpPosition.PerpMarketIndexUnset, (perpIdx) => perpIdx === PerpPosition.PerpMarketIndexUnset,
); );
if (inactivePerpPosition) { if (inactivePerpPosition != -1) {
perpPositionIndices[inactivePerpPosition] = perpPositionIndices[inactivePerpPosition] =
perpMarket.perpMarketIndex; perpMarket.perpMarketIndex;
} }
@ -2753,15 +2751,16 @@ export class MangoClient {
const ooPositionExists = const ooPositionExists =
serumPositionIndices.findIndex( serumPositionIndices.findIndex(
(i) => i.marketIndex === serum3Market.marketIndex, (i) => i.marketIndex === serum3Market.marketIndex,
) > 0; ) > -1;
if (!ooPositionExists) { if (!ooPositionExists) {
const inactiveSerumPosition = serumPositionIndices.find( const inactiveSerumPosition = serumPositionIndices.findIndex(
(serumPos) => (serumPos) =>
serumPos.marketIndex === Serum3Orders.Serum3MarketIndexUnset, serumPos.marketIndex === Serum3Orders.Serum3MarketIndexUnset,
); );
if (inactiveSerumPosition) { if (inactiveSerumPosition != -1) {
inactiveSerumPosition.marketIndex = serum3Market.marketIndex; serumPositionIndices[inactiveSerumPosition].marketIndex =
inactiveSerumPosition.openOrders = openOrderPk; serum3Market.marketIndex;
serumPositionIndices[inactiveSerumPosition].openOrders = openOrderPk;
} }
} }
} }

View File

@ -1,5 +1,5 @@
export type MangoV4 = { export type MangoV4 = {
"version": "0.1.0", "version": "0.2.0",
"name": "mango_v4", "name": "mango_v4",
"instructions": [ "instructions": [
{ {
@ -4030,7 +4030,7 @@ export type MangoV4 = {
}, },
{ {
"name": "frozenUntil", "name": "frozenUntil",
"type": "i64" "type": "u64"
}, },
{ {
"name": "reserved", "name": "reserved",
@ -7717,7 +7717,7 @@ export type MangoV4 = {
}; };
export const IDL: MangoV4 = { export const IDL: MangoV4 = {
"version": "0.1.0", "version": "0.2.0",
"name": "mango_v4", "name": "mango_v4",
"instructions": [ "instructions": [
{ {
@ -11748,7 +11748,7 @@ export const IDL: MangoV4 = {
}, },
{ {
"name": "frozenUntil", "name": "frozenUntil",
"type": "i64" "type": "u64"
}, },
{ {
"name": "reserved", "name": "reserved",

View File

@ -509,6 +509,45 @@ async function makePerpMarketReduceOnly() {
); );
} }
async function makePerpMarketUntrusted() {
const result = await buildAdminClient();
const client = result[0];
const admin = result[1];
const creator = result[2];
const group = await client.getGroupForCreator(creator.publicKey, GROUP_NUM);
const perpMarket = group.getPerpMarketByName('BTC-PERP');
await client.perpEditMarket(
group,
perpMarket.perpMarketIndex,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
false,
null,
null,
null,
null,
null,
null,
null,
null,
null,
);
}
async function createAndPopulateAlt() { async function createAndPopulateAlt() {
const result = await buildAdminClient(); const result = await buildAdminClient();
const client = result[0]; const client = result[0];
@ -669,6 +708,7 @@ async function main() {
try { try {
// await registerPerpMarkets(); // await registerPerpMarkets();
// await makePerpMarketReduceOnly(); // await makePerpMarketReduceOnly();
// await makePerpMarketUntrusted();
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }