Merge remote-tracking branch 'origin/serge/boost-liquidator' into finn/updateDockerBoostFiles
This commit is contained in:
commit
615b5f3f26
|
@ -33,7 +33,7 @@ env:
|
|||
CARGO_TERM_COLOR: always
|
||||
SOLANA_VERSION: '1.16.14'
|
||||
RUST_TOOLCHAIN: '1.69.0'
|
||||
LOG_PROGRAM: '4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg'
|
||||
LOG_PROGRAM: 'zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25'
|
||||
|
||||
jobs:
|
||||
format:
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
exclude = ["programs/margin-trade"]
|
||||
|
||||
[programs.localnet]
|
||||
mango_v4 = "4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg"
|
||||
mango_v4 = "zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25"
|
||||
|
||||
[programs.devnet]
|
||||
mango_v4 = "4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg"
|
||||
mango_v4 = "zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25"
|
||||
|
||||
[features]
|
||||
seeds = true
|
||||
|
|
66
CHANGELOG.md
66
CHANGELOG.md
|
@ -4,13 +4,75 @@ Update this for each program release and mainnet deployment.
|
|||
|
||||
## not on mainnet
|
||||
|
||||
### v0.23.0, 2024-3-
|
||||
|
||||
- Allow disabling asset liquidations for tokens (#867)
|
||||
|
||||
This allows listing tokens that have no reliable oracle. Those tokens could be
|
||||
traded through mango but can't be borrowed, can't have asset weight and can't
|
||||
even be liquidated.
|
||||
|
||||
- Add configurable collateral fees for tokens (#868, #880, #894)
|
||||
|
||||
Collateral fees allow the DAO to regularly charge users for using particular
|
||||
types of collateral to back their liabilities.
|
||||
|
||||
- Add force_withdraw token state (#884)
|
||||
|
||||
There already is a force_close_borrows state, but for a full delisting user
|
||||
deposits need to be removed too. In force_withdraw, user deposits can be
|
||||
permissionlessly withdrawn to their owners' token accounts.
|
||||
|
||||
- Flash loan: Add a "swap without flash loan fees" option (#882)
|
||||
- Cleanup, tests and minor (#878, #875, #854, #838, #895)
|
||||
|
||||
## mainnet
|
||||
|
||||
### v0.21.2, 2024-1-
|
||||
### v0.22.0, 2024-3-3
|
||||
|
||||
Deployment: Mar 3, 2024 at 23:52:08 Central European Standard Time, https://explorer.solana.com/tx/3MpEMU12Pv7RpSnwfShoM9sbyr41KAEeJFCVx9ypkq8nuK8Q5vm7CRLkdhH3u91yQ4k44a32armZHaoYguX6NqsY
|
||||
|
||||
- Perp: Allow reusing your own perp order slots immediately (#817)
|
||||
|
||||
Previously users who placed a lot of perp orders and used time-in-force needed
|
||||
to wait for out-event cranking if their perp order before reusing an order
|
||||
slot. Now perp order slots can be reused even when the out-event is still on
|
||||
the event queue.
|
||||
|
||||
- Introduce fallback oracles (#790, #813)
|
||||
|
||||
Fallback oracles can be used when the primary oracle is stale or not confident.
|
||||
These oracles need to configured by the DAO to be usable by clients.
|
||||
|
||||
Fallback oracles may be based on Orca in addition to the other supported types.
|
||||
|
||||
- Add serum3_cancel_by_client_order_id instruction (#798)
|
||||
|
||||
Can now cancel by client order id and not just the order id.
|
||||
|
||||
- Add configurable platform liquidation fees for tokens and perps (#849, #858)
|
||||
- Delegates can now withdraw small token amounts to the owner's ata (#820)
|
||||
- Custom allocator to allow larger heap use if needed (#801)
|
||||
- Optimize compute use in token_deposit instruction (#786)
|
||||
- Disable support for v1 and v2 mango accounts (#783)
|
||||
- Cleanups, logging and tests (#819, #799, #818, #823, #834, #828, #833)
|
||||
|
||||
### v0.21.3, 2024-2-9
|
||||
|
||||
Deployment: Feb 9, 2024 at 11:21:58 Central European Standard Time, https://explorer.solana.com/tx/44f2wcLyLiic1aycdaPTdfwXJBMeGeuA984kvCByg4L5iGprH6xW3D35gd3bvZ6kU3SipEtoY3kDuexJghbxL89T
|
||||
|
||||
- Remove deposit limit check on Openbook v1 when placing an order to sell
|
||||
deposits (#869)
|
||||
|
||||
### v0.21.2, 2024-1-30
|
||||
|
||||
Deployment: Jan 30, 2024 at 12:36:09 Central European Standard Time, https://explorer.solana.com/tx/2kw6XhRUpLbh1fsPyQimCgNWjhy717qnUvxNMtLcBS4VNu8i59AJK4wY7wfZV62gT3GkSRTyaDNyD7Dkrg2gUFxC
|
||||
|
||||
- Allow fast-listing of Openbook v1 markets (#839, #841)
|
||||
|
||||
### v0.21.1, 2024-1-
|
||||
### v0.21.1, 2024-1-3
|
||||
|
||||
Deployment: Jan 3, 2024 at 14:35:10 Central European Standard Time, https://explorer.solana.com/tx/345NMQAvvtXeuGENz8icErXjGNmgkdU84JpvAMJFWXEGYZ2BNxFFcyZsHp5ELwLNUzY4s2hLa6wxHWPBFsTBLspA
|
||||
|
||||
- Prevent withdraw operations from bringing token utilization over 100%.
|
||||
- Prevent extreme interest rates for tokens with borrows but near zero deposits.
|
||||
|
|
|
@ -3367,7 +3367,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mango-v4"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
dependencies = [
|
||||
"anchor-lang",
|
||||
"anchor-spl",
|
||||
|
|
|
@ -33,9 +33,9 @@ See DEVELOPING.md and FAQ-DEV.md
|
|||
|
||||
### Deployments
|
||||
|
||||
- devnet: 4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg
|
||||
- mainnet-beta: 4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg
|
||||
- primary mango group on mainnet-beta: 78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX
|
||||
- devnet: zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25
|
||||
- mainnet-beta: zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25
|
||||
- primary mango group on mainnet-beta: AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf
|
||||
|
||||
### Release
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
- $KEY as a path to a keypair (needs around 20 SOL for the buffer)
|
||||
- $RPC_URL as a url to an RPC node
|
||||
- 4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg is the address of the Mango v4 Program
|
||||
- zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25 is the address of the Mango v4 Program
|
||||
- FP4PxqHTVzeG2c6eZd7974F9WvKUSdBeduUK3rjYyvBw is the address of the Mango v4 Program Governance
|
||||
|
||||
- Check out the latest version of the `dev` branch
|
||||
|
@ -47,17 +47,18 @@
|
|||
|
||||
- Create IDL buffer
|
||||
|
||||
anchor idl write-buffer --provider.cluster $RPC_URL --provider.wallet $KEY --filepath target/idl/mango_v4_no_docs.json 4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg
|
||||
anchor idl write-buffer --provider.cluster $RPC_URL --provider.wallet $KEY --filepath target/idl/mango_v4_no_docs.json zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25
|
||||
|
||||
Save the returned address as $IDL_BUFFER
|
||||
|
||||
- Set IDL buffer authority
|
||||
|
||||
anchor idl set-authority --provider.cluster $RPC_URL --provider.wallet $KEY --program-id 4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg --new-authority FP4PxqHTVzeG2c6eZd7974F9WvKUSdBeduUK3rjYyvBw $IDL_BUFFER
|
||||
anchor idl set-authority --provider.cluster $RPC_URL --provider.wallet $KEY --program-id zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25 --new-authority FP4PxqHTVzeG2c6eZd7974F9WvKUSdBeduUK3rjYyvBw $IDL_BUFFER
|
||||
|
||||
- Make a gist for the proposal description, ideally based on previous upgrade proposals
|
||||
|
||||
- Go to the DAO proposal website and make a proposal:
|
||||
|
||||
- Upgrade program with the new buffer, set the spill address to the address of $KEY
|
||||
- Upgrade idl with the new buffer
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ enum MINTS {
|
|||
BTC = 'BTC',
|
||||
}
|
||||
const NUM_USERS = 4;
|
||||
const PROGRAM_ID = '4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg';
|
||||
const PROGRAM_ID = 'zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25';
|
||||
|
||||
interface TestUser {
|
||||
keypair: anchor.web3.Keypair;
|
||||
|
|
|
@ -552,7 +552,12 @@ async fn send_batched_log_errors_no_confirm(
|
|||
current_batch.append(ixs.clone());
|
||||
|
||||
tx_builder.instructions = current_batch.clone().to_instructions();
|
||||
if !tx_builder.transaction_size().is_ok() || current_batch.cu > max_cu {
|
||||
if tx_builder
|
||||
.transaction_size()
|
||||
.map(|ts| !ts.is_within_limit())
|
||||
.unwrap_or(true)
|
||||
|| current_batch.cu > max_cu
|
||||
{
|
||||
tx_builder.instructions = previous_batch.to_instructions();
|
||||
match tx_builder.send(client).await {
|
||||
Err(err) => error!("could not send transaction: {err:?}"),
|
||||
|
|
|
@ -92,7 +92,7 @@ impl<'a> LiquidateHelper<'a> {
|
|||
let exceeds_cu_limit = new_ixs.cu > self.config.max_cu_per_transaction;
|
||||
let exceeds_size_limit = {
|
||||
tx_builder.instructions = new_ixs.clone().to_instructions();
|
||||
!tx_builder.transaction_size()?.is_ok()
|
||||
!tx_builder.transaction_size()?.is_within_limit()
|
||||
};
|
||||
if exceeds_cu_limit || exceeds_size_limit {
|
||||
break;
|
||||
|
|
|
@ -114,16 +114,7 @@ impl Rebalancer {
|
|||
in_amount_quote: u64,
|
||||
) -> anyhow::Result<(Signature, jupiter::Quote)> {
|
||||
let quote_token = self.mango_client.context.token(QUOTE_TOKEN_INDEX);
|
||||
let sol_token = self.mango_client.context.token(
|
||||
*self
|
||||
.mango_client
|
||||
.context
|
||||
.token_indexes_by_name
|
||||
.get("SOL") // TODO: better use mint
|
||||
.unwrap(),
|
||||
);
|
||||
let quote_mint = quote_token.mint;
|
||||
let sol_mint = sol_token.mint;
|
||||
let jupiter_version = self.config.jupiter_version;
|
||||
|
||||
let full_route_job = self.jupiter_quote(
|
||||
|
@ -142,16 +133,8 @@ impl Rebalancer {
|
|||
);
|
||||
|
||||
// For the SOL -> output route we need to adjust the in amount by the SOL price
|
||||
let sol_price = self
|
||||
.account_fetcher
|
||||
.fetch_bank_price(&sol_token.first_bank())?;
|
||||
let in_amount_sol = (I80F48::from(in_amount_quote) / sol_price)
|
||||
.ceil()
|
||||
.to_num::<u64>();
|
||||
let direct_sol_route_job =
|
||||
self.jupiter_quote(sol_mint, output_mint, in_amount_sol, true, jupiter_version);
|
||||
|
||||
let jobs = vec![full_route_job, direct_quote_route_job, direct_sol_route_job];
|
||||
let jobs = vec![full_route_job, direct_quote_route_job];
|
||||
|
||||
let mut results = futures::future::join_all(jobs).await;
|
||||
let full_route = results.remove(0)?;
|
||||
|
@ -181,26 +164,15 @@ impl Rebalancer {
|
|||
in_amount: u64,
|
||||
) -> anyhow::Result<(Signature, jupiter::Quote)> {
|
||||
let quote_token = self.mango_client.context.token(QUOTE_TOKEN_INDEX);
|
||||
let sol_token = self.mango_client.context.token(
|
||||
*self
|
||||
.mango_client
|
||||
.context
|
||||
.token_indexes_by_name
|
||||
.get("SOL") // TODO: better use mint
|
||||
.unwrap(),
|
||||
);
|
||||
let quote_mint = quote_token.mint;
|
||||
let sol_mint = sol_token.mint;
|
||||
let jupiter_version = self.config.jupiter_version;
|
||||
|
||||
let full_route_job =
|
||||
self.jupiter_quote(input_mint, quote_mint, in_amount, false, jupiter_version);
|
||||
let direct_quote_route_job =
|
||||
self.jupiter_quote(input_mint, quote_mint, in_amount, true, jupiter_version);
|
||||
let direct_sol_route_job =
|
||||
self.jupiter_quote(input_mint, sol_mint, in_amount, true, jupiter_version);
|
||||
|
||||
let jobs = vec![full_route_job, direct_quote_route_job, direct_sol_route_job];
|
||||
let jobs = vec![full_route_job, direct_quote_route_job];
|
||||
|
||||
let mut results = futures::future::join_all(jobs).await;
|
||||
let full_route = results.remove(0)?;
|
||||
|
@ -231,7 +203,7 @@ impl Rebalancer {
|
|||
.prepare_swap_transaction(full)
|
||||
.await?;
|
||||
let tx_size = builder.transaction_size()?;
|
||||
if tx_size.is_ok() {
|
||||
if tx_size.is_within_limit() {
|
||||
return Ok((builder, full.clone()));
|
||||
}
|
||||
trace!(
|
||||
|
|
|
@ -2233,7 +2233,7 @@ pub struct TransactionSize {
|
|||
}
|
||||
|
||||
impl TransactionSize {
|
||||
pub fn is_ok(&self) -> bool {
|
||||
pub fn is_within_limit(&self) -> bool {
|
||||
let limit = Self::limit();
|
||||
self.length <= limit.length && self.accounts <= limit.accounts
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ impl Default for ComputeEstimates {
|
|||
// the base cost is mostly the division
|
||||
cu_per_charge_collateral_fees: 20_000,
|
||||
// per-chargable-token cost
|
||||
cu_per_charge_collateral_fees_token: 12_000,
|
||||
cu_per_charge_collateral_fees_token: 15_000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
168
mango_v4.json
168
mango_v4.json
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "0.22.0",
|
||||
"version": "0.23.0",
|
||||
"name": "mango_v4",
|
||||
"instructions": [
|
||||
{
|
||||
|
@ -1760,6 +1760,36 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sequenceCheck",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "group",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false,
|
||||
"relations": [
|
||||
"group",
|
||||
"owner"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "expectedSequenceNumber",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stubOracleCreate",
|
||||
"accounts": [
|
||||
|
@ -7871,13 +7901,8 @@
|
|||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
1
|
||||
]
|
||||
}
|
||||
"name": "sequenceNumber",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "netDeposits",
|
||||
|
@ -9669,13 +9694,8 @@
|
|||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
1
|
||||
]
|
||||
}
|
||||
"name": "sequenceNumber",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "netDeposits",
|
||||
|
@ -11008,6 +11028,9 @@
|
|||
},
|
||||
{
|
||||
"name": "TokenForceWithdraw"
|
||||
},
|
||||
{
|
||||
"name": "SequenceCheck"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -12871,6 +12894,71 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PerpLiqBaseOrPositivePnlLogV3",
|
||||
"fields": [
|
||||
{
|
||||
"name": "mangoGroup",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "perpMarketIndex",
|
||||
"type": "u16",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "liqor",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "liqee",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "baseTransferLiqee",
|
||||
"type": "i64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "quoteTransferLiqee",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "quoteTransferLiqor",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "quotePlatformFee",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "pnlTransfer",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "pnlSettleLimitTransferRecurring",
|
||||
"type": "i64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "pnlSettleLimitTransferOneshot",
|
||||
"type": "i64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "price",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PerpLiqBankruptcyLog",
|
||||
"fields": [
|
||||
|
@ -13888,6 +13976,46 @@
|
|||
"name": "fee",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "price",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ForceWithdrawLog",
|
||||
"fields": [
|
||||
{
|
||||
"name": "mangoGroup",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "mangoAccount",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "tokenIndex",
|
||||
"type": "u16",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "quantity",
|
||||
"type": "u64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "price",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "toTokenAccount",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -14242,6 +14370,16 @@
|
|||
"code": 6069,
|
||||
"name": "TokenAssetLiquidationDisabled",
|
||||
"msg": "the asset does not allow liquidation"
|
||||
},
|
||||
{
|
||||
"code": 6070,
|
||||
"name": "BorrowsRequireHealthAccountBank",
|
||||
"msg": "for borrows the bank must be in the health account list"
|
||||
},
|
||||
{
|
||||
"code": 6071,
|
||||
"name": "InvalidSequenceNumber",
|
||||
"msg": "invalid sequence number"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@blockworks-foundation/mango-v4",
|
||||
"version": "0.21.29",
|
||||
"version": "0.23.0-rc2",
|
||||
"description": "Typescript Client for mango-v4 program.",
|
||||
"repository": "https://github.com/blockworks-foundation/mango-v4",
|
||||
"author": {
|
||||
|
@ -62,7 +62,7 @@
|
|||
"trailingComma": "all"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blockworks-foundation/mango-v4-settings": "0.4.10",
|
||||
"@blockworks-foundation/mango-v4-settings": "0.14.15",
|
||||
"@blockworks-foundation/mangolana": "0.0.14",
|
||||
"@coral-xyz/anchor": "^0.28.1-beta.2",
|
||||
"@project-serum/serum": "0.13.65",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "mango-v4"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
description = "Created with Anchor"
|
||||
edition = "2021"
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ pub use perp_place_order::*;
|
|||
pub use perp_settle_fees::*;
|
||||
pub use perp_settle_pnl::*;
|
||||
pub use perp_update_funding::*;
|
||||
pub use sequence_check::*;
|
||||
pub use serum3_cancel_all_orders::*;
|
||||
pub use serum3_cancel_order::*;
|
||||
pub use serum3_close_open_orders::*;
|
||||
|
@ -123,6 +124,7 @@ mod perp_place_order;
|
|||
mod perp_settle_fees;
|
||||
mod perp_settle_pnl;
|
||||
mod perp_update_funding;
|
||||
mod sequence_check;
|
||||
mod serum3_cancel_all_orders;
|
||||
mod serum3_cancel_order;
|
||||
mod serum3_close_open_orders;
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
use crate::error::*;
|
||||
use crate::state::*;
|
||||
use anchor_lang::prelude::*;
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct SequenceCheck<'info> {
|
||||
#[account(
|
||||
constraint = group.load()?.is_ix_enabled(IxGate::SequenceCheck) @ MangoError::IxIsDisabled,
|
||||
)]
|
||||
pub group: AccountLoader<'info, Group>,
|
||||
|
||||
#[account(
|
||||
mut,
|
||||
has_one = group,
|
||||
has_one = owner,
|
||||
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||
pub owner: Signer<'info>,
|
||||
}
|
|
@ -145,6 +145,10 @@ pub enum MangoError {
|
|||
MissingFeedForCLMMOracle,
|
||||
#[msg("the asset does not allow liquidation")]
|
||||
TokenAssetLiquidationDisabled,
|
||||
#[msg("for borrows the bank must be in the health account list")]
|
||||
BorrowsRequireHealthAccountBank,
|
||||
#[msg("invalid sequence number")]
|
||||
InvalidSequenceNumber,
|
||||
}
|
||||
|
||||
impl MangoError {
|
||||
|
|
|
@ -96,6 +96,7 @@ pub fn ix_gate_set(ctx: Context<IxGateSet>, ix_gate: u128) -> Result<()> {
|
|||
);
|
||||
log_if_changed(&group, ix_gate, IxGate::Serum3PlaceOrderV2);
|
||||
log_if_changed(&group, ix_gate, IxGate::TokenForceWithdraw);
|
||||
log_if_changed(&group, ix_gate, IxGate::SequenceCheck);
|
||||
|
||||
group.ix_gate = ix_gate;
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ pub use perp_place_order::*;
|
|||
pub use perp_settle_fees::*;
|
||||
pub use perp_settle_pnl::*;
|
||||
pub use perp_update_funding::*;
|
||||
pub use sequence_check::*;
|
||||
pub use serum3_cancel_all_orders::*;
|
||||
pub use serum3_cancel_order::*;
|
||||
pub use serum3_cancel_order_by_client_order_id::*;
|
||||
|
@ -104,6 +105,7 @@ mod perp_place_order;
|
|||
mod perp_settle_fees;
|
||||
mod perp_settle_pnl;
|
||||
mod perp_update_funding;
|
||||
mod sequence_check;
|
||||
mod serum3_cancel_all_orders;
|
||||
mod serum3_cancel_order;
|
||||
mod serum3_cancel_order_by_client_order_id;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
use anchor_lang::prelude::*;
|
||||
|
||||
use crate::accounts_ix::*;
|
||||
use crate::error::MangoError;
|
||||
use crate::state::*;
|
||||
|
||||
pub fn sequence_check(ctx: Context<SequenceCheck>, expected_sequence_number: u8) -> Result<()> {
|
||||
let mut account = ctx.accounts.account.load_full_mut()?;
|
||||
|
||||
require_eq!(
|
||||
expected_sequence_number,
|
||||
account.fixed.sequence_number,
|
||||
MangoError::InvalidSequenceNumber
|
||||
);
|
||||
|
||||
account.fixed.sequence_number = account.fixed.sequence_number.wrapping_add(1);
|
||||
Ok(())
|
||||
}
|
|
@ -5,7 +5,7 @@ use anchor_lang::prelude::*;
|
|||
use fixed::types::I80F48;
|
||||
|
||||
use crate::accounts_ix::*;
|
||||
use crate::logs::{emit_stack, TokenCollateralFeeLog};
|
||||
use crate::logs::{emit_stack, TokenBalanceLog, TokenCollateralFeeLog};
|
||||
|
||||
pub fn token_charge_collateral_fees(ctx: Context<TokenChargeCollateralFees>) -> Result<()> {
|
||||
let group = ctx.accounts.group.load()?;
|
||||
|
@ -103,12 +103,25 @@ pub fn token_charge_collateral_fees(ctx: Context<TokenChargeCollateralFees>) ->
|
|||
bank.collected_fees_native += fee;
|
||||
bank.collected_collateral_fees += fee;
|
||||
|
||||
let token_info = health_cache.token_info(bank.token_index)?;
|
||||
let token_position = account.token_position(bank.token_index)?;
|
||||
|
||||
emit_stack(TokenCollateralFeeLog {
|
||||
mango_group: ctx.accounts.group.key(),
|
||||
mango_account: ctx.accounts.account.key(),
|
||||
token_index: bank.token_index,
|
||||
fee: fee.to_bits(),
|
||||
asset_usage_fraction: asset_usage_scaling.to_bits(),
|
||||
price: token_info.prices.oracle.to_bits(),
|
||||
});
|
||||
|
||||
emit_stack(TokenBalanceLog {
|
||||
mango_group: ctx.accounts.group.key(),
|
||||
mango_account: ctx.accounts.account.key(),
|
||||
token_index: bank.token_index,
|
||||
indexed_position: token_position.indexed_position.to_bits(),
|
||||
deposit_index: bank.deposit_index.to_bits(),
|
||||
borrow_index: bank.borrow_index.to_bits(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ use state::{
|
|||
TokenIndex, TCS_START_INCENTIVE,
|
||||
};
|
||||
|
||||
declare_id!("4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg");
|
||||
declare_id!("zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25");
|
||||
|
||||
#[program]
|
||||
pub mod mango_v4 {
|
||||
|
@ -458,6 +458,12 @@ pub mod mango_v4 {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sequence_check(ctx: Context<SequenceCheck>, expected_sequence_number: u8) -> Result<()> {
|
||||
#[cfg(feature = "enable-gpl")]
|
||||
instructions::sequence_check(ctx, expected_sequence_number)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// todo:
|
||||
// ckamm: generally, using an I80F48 arg will make it harder to call
|
||||
// because generic anchor clients won't know how to deal with it
|
||||
|
|
|
@ -803,6 +803,7 @@ pub struct TokenCollateralFeeLog {
|
|||
pub token_index: u16,
|
||||
pub asset_usage_fraction: i128,
|
||||
pub fee: i128,
|
||||
pub price: i128,
|
||||
}
|
||||
|
||||
#[event]
|
||||
|
|
|
@ -394,14 +394,18 @@ impl Bank {
|
|||
require_gte!(self.rate0, I80F48::ZERO);
|
||||
require_gte!(self.rate1, I80F48::ZERO);
|
||||
require_gte!(self.max_rate, I80F48::ZERO);
|
||||
require_gte!(self.adjustment_factor, 0.0);
|
||||
require_gte!(self.loan_fee_rate, 0.0);
|
||||
require_gte!(self.loan_origination_fee_rate, 0.0);
|
||||
require_gte!(self.maint_asset_weight, 0.0);
|
||||
require_gte!(self.stable_price_model.delay_growth_limit, 0.0);
|
||||
require_gte!(self.stable_price_model.stable_growth_limit, 0.0);
|
||||
require_gte!(self.init_asset_weight, 0.0);
|
||||
require_gte!(self.maint_asset_weight, self.init_asset_weight);
|
||||
require_gte!(self.maint_liab_weight, 0.0);
|
||||
require_gte!(self.init_liab_weight, 0.0);
|
||||
require_gte!(self.init_liab_weight, self.maint_liab_weight);
|
||||
require_gte!(self.liquidation_fee, 0.0);
|
||||
require_gte!(self.min_vault_to_deposits_ratio, 0.0);
|
||||
require_gte!(1.0, self.min_vault_to_deposits_ratio);
|
||||
require_gte!(self.net_borrow_limit_per_window_quote, -1);
|
||||
require_gt!(self.borrow_weight_scale_start_quote, 0.0);
|
||||
require_gt!(self.deposit_weight_scale_start_quote, 0.0);
|
||||
|
@ -411,6 +415,7 @@ impl Bank {
|
|||
require_gte!(self.flash_loan_swap_fee_rate, 0.0);
|
||||
require_gte!(self.interest_curve_scaling, 1.0);
|
||||
require_gte!(self.interest_target_utilization, 0.0);
|
||||
require_gte!(1.0, self.interest_target_utilization);
|
||||
require_gte!(self.maint_weight_shift_duration_inv, 0.0);
|
||||
require_gte!(self.maint_weight_shift_asset_target, 0.0);
|
||||
require_gte!(self.maint_weight_shift_liab_target, 0.0);
|
||||
|
|
|
@ -246,6 +246,7 @@ pub enum IxGate {
|
|||
TokenConditionalSwapCreateLinearAuction = 70,
|
||||
Serum3PlaceOrderV2 = 71,
|
||||
TokenForceWithdraw = 72,
|
||||
SequenceCheck = 73,
|
||||
// NOTE: Adding new variants requires matching changes in ts and the ix_gate_set instruction.
|
||||
}
|
||||
|
||||
|
|
|
@ -123,8 +123,7 @@ pub struct MangoAccount {
|
|||
|
||||
pub bump: u8,
|
||||
|
||||
#[derivative(Debug = "ignore")]
|
||||
pub padding: [u8; 1],
|
||||
pub sequence_number: u8,
|
||||
|
||||
// (Display only)
|
||||
// Cumulative (deposits - withdraws)
|
||||
|
@ -200,7 +199,7 @@ impl MangoAccount {
|
|||
in_health_region: 0,
|
||||
account_num: 0,
|
||||
bump: 0,
|
||||
padding: Default::default(),
|
||||
sequence_number: 0,
|
||||
net_deposits: 0,
|
||||
perp_spot_transfers: 0,
|
||||
health_region_begin_init_health: 0,
|
||||
|
@ -325,7 +324,7 @@ pub struct MangoAccountFixed {
|
|||
being_liquidated: u8,
|
||||
in_health_region: u8,
|
||||
pub bump: u8,
|
||||
pub padding: [u8; 1],
|
||||
pub sequence_number: u8,
|
||||
pub net_deposits: i64,
|
||||
pub perp_spot_transfers: i64,
|
||||
pub health_region_begin_init_health: i64,
|
||||
|
@ -2897,7 +2896,7 @@ mod tests {
|
|||
being_liquidated: fixed.being_liquidated,
|
||||
in_health_region: fixed.in_health_region,
|
||||
bump: fixed.bump,
|
||||
padding: Default::default(),
|
||||
sequence_number: 0,
|
||||
net_deposits: fixed.net_deposits,
|
||||
perp_spot_transfers: fixed.perp_spot_transfers,
|
||||
health_region_begin_init_health: fixed.health_region_begin_init_health,
|
||||
|
|
|
@ -462,6 +462,8 @@ async fn test_bank_maint_weight_shift() -> Result<(), TransportError> {
|
|||
mint: mints[0].pubkey,
|
||||
fallback_oracle: Pubkey::default(),
|
||||
options: mango_v4::instruction::TokenEdit {
|
||||
init_asset_weight_opt: Some(0.0),
|
||||
init_liab_weight_opt: Some(2.0),
|
||||
maint_weight_shift_start_opt: Some(start_time + 1000),
|
||||
maint_weight_shift_end_opt: Some(start_time + 2000),
|
||||
maint_weight_shift_asset_target_opt: Some(0.5),
|
||||
|
@ -685,3 +687,105 @@ async fn test_bank_deposit_limit() -> Result<(), TransportError> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_sequence_check() -> Result<(), TransportError> {
|
||||
let context = TestContext::new().await;
|
||||
let solana = &context.solana.clone();
|
||||
|
||||
let admin = TestKeypair::new();
|
||||
let owner = context.users[0].key;
|
||||
let payer = context.users[1].key;
|
||||
let mints = &context.mints[0..1];
|
||||
|
||||
let mango_setup::GroupWithTokens { group, .. } = mango_setup::GroupWithTokensConfig {
|
||||
admin,
|
||||
payer,
|
||||
mints: mints.to_vec(),
|
||||
..mango_setup::GroupWithTokensConfig::default()
|
||||
}
|
||||
.create(solana)
|
||||
.await;
|
||||
|
||||
let account = send_tx(
|
||||
solana,
|
||||
AccountCreateInstruction {
|
||||
account_num: 0,
|
||||
token_count: 6,
|
||||
serum3_count: 3,
|
||||
perp_count: 3,
|
||||
perp_oo_count: 3,
|
||||
token_conditional_swap_count: 3,
|
||||
group,
|
||||
owner,
|
||||
payer,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.account;
|
||||
|
||||
let mango_account = get_mango_account(solana, account).await;
|
||||
assert_eq!(mango_account.fixed.sequence_number, 0);
|
||||
|
||||
//
|
||||
// TEST: Sequence check with right sequence number
|
||||
//
|
||||
|
||||
send_tx(
|
||||
solana,
|
||||
SequenceCheckInstruction {
|
||||
account,
|
||||
owner,
|
||||
expected_sequence_number: 0,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mango_account = get_mango_account(solana, account).await;
|
||||
assert_eq!(mango_account.fixed.sequence_number, 1);
|
||||
|
||||
send_tx(
|
||||
solana,
|
||||
SequenceCheckInstruction {
|
||||
account,
|
||||
owner,
|
||||
expected_sequence_number: 1,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mango_account = get_mango_account(solana, account).await;
|
||||
assert_eq!(mango_account.fixed.sequence_number, 2);
|
||||
|
||||
//
|
||||
// TEST: Sequence check with wrong sequence number
|
||||
//
|
||||
|
||||
send_tx_expect_error!(
|
||||
solana,
|
||||
SequenceCheckInstruction {
|
||||
account,
|
||||
owner,
|
||||
expected_sequence_number: 1
|
||||
},
|
||||
MangoError::InvalidSequenceNumber
|
||||
);
|
||||
|
||||
send_tx_expect_error!(
|
||||
solana,
|
||||
SequenceCheckInstruction {
|
||||
account,
|
||||
owner,
|
||||
expected_sequence_number: 4
|
||||
},
|
||||
MangoError::InvalidSequenceNumber
|
||||
);
|
||||
|
||||
let mango_account = get_mango_account(solana, account).await;
|
||||
assert_eq!(mango_account.fixed.sequence_number, 2);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -501,6 +501,7 @@ async fn test_force_withdraw_token() -> Result<(), TransportError> {
|
|||
mint: token.mint.pubkey,
|
||||
fallback_oracle: Pubkey::default(),
|
||||
options: mango_v4::instruction::TokenEdit {
|
||||
init_asset_weight_opt: Some(0.0),
|
||||
maint_asset_weight_opt: Some(0.0),
|
||||
reduce_only_opt: Some(1),
|
||||
disable_asset_liquidation_opt: Some(true),
|
||||
|
|
|
@ -162,7 +162,7 @@ async fn test_ix_gate_set() -> Result<(), TransportError> {
|
|||
|
||||
//
|
||||
// test cu budget, ix has a lot of logging
|
||||
// e.g. Program 4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg consumed 66986 of 75000 compute units
|
||||
// e.g. Program zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25 consumed 66986 of 75000 compute units
|
||||
send_tx(
|
||||
solana,
|
||||
IxGateSetInstruction {
|
||||
|
|
|
@ -5139,3 +5139,42 @@ impl ClientInstruction for TokenChargeCollateralFeesInstruction {
|
|||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SequenceCheckInstruction {
|
||||
pub account: Pubkey,
|
||||
pub owner: TestKeypair,
|
||||
pub expected_sequence_number: u8,
|
||||
}
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl ClientInstruction for SequenceCheckInstruction {
|
||||
type Accounts = mango_v4::accounts::SequenceCheck;
|
||||
type Instruction = mango_v4::instruction::SequenceCheck;
|
||||
async fn to_instruction(
|
||||
&self,
|
||||
account_loader: impl ClientAccountLoader + 'async_trait,
|
||||
) -> (Self::Accounts, instruction::Instruction) {
|
||||
let program_id = mango_v4::id();
|
||||
let instruction = Self::Instruction {
|
||||
expected_sequence_number: self.expected_sequence_number,
|
||||
};
|
||||
|
||||
let account = account_loader
|
||||
.load_mango_account(&self.account)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let accounts = Self::Accounts {
|
||||
group: account.fixed.group,
|
||||
account: self.account,
|
||||
owner: self.owner.pubkey(),
|
||||
};
|
||||
|
||||
let instruction = make_instruction(program_id, &accounts, &instruction);
|
||||
(accounts, instruction)
|
||||
}
|
||||
|
||||
fn signers(&self) -> Vec<TestKeypair> {
|
||||
vec![self.owner]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
set -ex pipefail
|
||||
|
||||
WALLET_WITH_FUNDS=~/.config/solana/mango-mainnet-1.json
|
||||
PROGRAM_ID=4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg
|
||||
PROGRAM_ID=zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25
|
||||
|
||||
# build program,
|
||||
anchor build -- --features enable-gpl
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
# WALLET_WITH_FUNDS=~/.config/solana/mango-devnet.json
|
||||
# PROGRAM_ID=4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg
|
||||
# PROGRAM_ID=zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25
|
||||
|
||||
anchor build -- --features enable-gpl
|
||||
./idl-fixup.sh
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"name": "mainnet-beta.clarkeni",
|
||||
"publicKey": "DLdcpC6AsAJ9xeKMR3WhHrN5sM5o7GVVXQhQ5vwisTtz",
|
||||
"serum3ProgramId": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin",
|
||||
"mangoProgramId": "4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg",
|
||||
"mangoProgramId": "zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25",
|
||||
"banks": [
|
||||
{
|
||||
"name": "SOL",
|
||||
|
|
|
@ -73,6 +73,7 @@ async function main(): Promise<void> {
|
|||
group,
|
||||
usdcDevnetMint,
|
||||
usdcDevnetOracle.publicKey,
|
||||
PublicKey.default,
|
||||
0, // tokenIndex
|
||||
'USDC',
|
||||
{
|
||||
|
@ -101,6 +102,7 @@ async function main(): Promise<void> {
|
|||
group,
|
||||
solDevnetMint,
|
||||
solDevnetOracle,
|
||||
PublicKey.default,
|
||||
4, // tokenIndex
|
||||
'SOL',
|
||||
{
|
||||
|
@ -130,6 +132,7 @@ async function main(): Promise<void> {
|
|||
group,
|
||||
usdtDevnetMint,
|
||||
usdcDevnetOracle.publicKey,
|
||||
PublicKey.default,
|
||||
5, // tokenIndex
|
||||
'USDT',
|
||||
{
|
||||
|
@ -163,6 +166,7 @@ async function main(): Promise<void> {
|
|||
group.getFirstBankByMint(insuranceMint),
|
||||
0,
|
||||
'SOL/USDC',
|
||||
0.5,
|
||||
);
|
||||
await group.reloadAll(client);
|
||||
const serum3Market = group.getSerum3MarketByExternalMarket(
|
||||
|
@ -211,6 +215,7 @@ async function main(): Promise<void> {
|
|||
1.0,
|
||||
2 * 60 * 60,
|
||||
0.025,
|
||||
0,
|
||||
);
|
||||
await group.reloadAll(client);
|
||||
const perpMarket = group.getPerpMarketByMarketIndex(
|
||||
|
|
|
@ -6,7 +6,7 @@ async function main(): Promise<void> {
|
|||
const client = MangoClient.connectDefault(process.env.MB_CLUSTER_URL!);
|
||||
|
||||
const group = await client.getGroup(
|
||||
new PublicKey('78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX'),
|
||||
new PublicKey('AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf'),
|
||||
);
|
||||
const mangoAccounts = await client.getAllMangoAccounts(group, true);
|
||||
const solPerp = group.getPerpMarketByName('SOL-PERP');
|
||||
|
|
|
@ -34,7 +34,7 @@ async function main(): Promise<void> {
|
|||
);
|
||||
|
||||
const group = await client.getGroup(
|
||||
new PublicKey('78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX'),
|
||||
new PublicKey('AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf'),
|
||||
);
|
||||
|
||||
let account = await client.getMangoAccount(new PublicKey(MANGO_ACCOUNT_PK));
|
||||
|
@ -51,24 +51,24 @@ async function main(): Promise<void> {
|
|||
}),
|
||||
);
|
||||
|
||||
// const sig = await client.tcsTakeProfitOnDeposit(
|
||||
// group,
|
||||
// account,
|
||||
// group.getFirstBankByTokenIndex(4 as TokenIndex),
|
||||
// group.getFirstBankByTokenIndex(0 as TokenIndex),
|
||||
// group.getFirstBankByTokenIndex(4 as TokenIndex).uiPrice + 1,
|
||||
// false,
|
||||
// null,
|
||||
// null,
|
||||
// null,
|
||||
// );
|
||||
const sig = await client.tcsTakeProfitOnDeposit(
|
||||
group,
|
||||
account,
|
||||
group.getFirstBankByTokenIndex(4 as TokenIndex),
|
||||
group.getFirstBankByTokenIndex(0 as TokenIndex),
|
||||
group.getFirstBankByTokenIndex(4 as TokenIndex).uiPrice - 1,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
|
||||
// const sig = await client.tcsStopLossOnDeposit(
|
||||
// group,
|
||||
// account,
|
||||
// group.getFirstBankByTokenIndex(4 as TokenIndex),
|
||||
// group.getFirstBankByTokenIndex(0 as TokenIndex),
|
||||
// group.getFirstBankByTokenIndex(4 as TokenIndex).uiPrice - 1,
|
||||
// group.getFirstBankByTokenIndex(4 as TokenIndex).uiPrice - 0.001,
|
||||
// false,
|
||||
// null,
|
||||
// null,
|
||||
|
@ -80,7 +80,7 @@ async function main(): Promise<void> {
|
|||
// account,
|
||||
// group.getFirstBankByTokenIndex(0 as TokenIndex),
|
||||
// group.getFirstBankByTokenIndex(4 as TokenIndex),
|
||||
// group.getFirstBankByTokenIndex(4 as TokenIndex).uiPrice - 1,
|
||||
// group.getFirstBankByTokenIndex(4 as TokenIndex).uiPrice - 0.001,
|
||||
// true,
|
||||
// null,
|
||||
// null,
|
||||
|
@ -88,18 +88,18 @@ async function main(): Promise<void> {
|
|||
// null,
|
||||
// );
|
||||
|
||||
const sig = await client.tcsStopLossOnBorrow(
|
||||
group,
|
||||
account,
|
||||
group.getFirstBankByTokenIndex(0 as TokenIndex),
|
||||
group.getFirstBankByTokenIndex(4 as TokenIndex),
|
||||
group.getFirstBankByTokenIndex(4 as TokenIndex).uiPrice + 1,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
// const sig = await client.tcsStopLossOnBorrow(
|
||||
// group,
|
||||
// account,
|
||||
// group.getFirstBankByTokenIndex(0 as TokenIndex),
|
||||
// group.getFirstBankByTokenIndex(4 as TokenIndex),
|
||||
// group.getFirstBankByTokenIndex(4 as TokenIndex).uiPrice + 0.001,
|
||||
// true,
|
||||
// null,
|
||||
// null,
|
||||
// null,
|
||||
// null,
|
||||
// );
|
||||
|
||||
console.log(sig);
|
||||
|
||||
|
|
|
@ -277,7 +277,7 @@ async function main(): Promise<void> {
|
|||
});
|
||||
|
||||
const group = await client.getGroup(
|
||||
new PublicKey('78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX'),
|
||||
new PublicKey('AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf'),
|
||||
);
|
||||
|
||||
const mangoAccounts = await client.getAllMangoAccounts(group, true);
|
||||
|
|
|
@ -94,6 +94,7 @@ async function main() {
|
|||
group,
|
||||
usdcDevnetMint,
|
||||
usdcDevnetOracle.publicKey,
|
||||
PublicKey.default,
|
||||
0, // tokenIndex
|
||||
'USDC',
|
||||
{
|
||||
|
@ -124,6 +125,7 @@ async function main() {
|
|||
group,
|
||||
solDevnetMint,
|
||||
solDevnetOracle,
|
||||
PublicKey.default,
|
||||
1, // tokenIndex
|
||||
'SOL',
|
||||
{
|
||||
|
@ -218,6 +220,7 @@ async function main() {
|
|||
1.0,
|
||||
2 * 60 * 60,
|
||||
0.025,
|
||||
0,
|
||||
);
|
||||
await group.reloadAll(client);
|
||||
const perpMarket = group.getPerpMarketByMarketIndex(0 as PerpMarketIndex);
|
||||
|
|
|
@ -29,7 +29,7 @@ async function addSpotMarket() {
|
|||
console.log(`Admin ${admin.publicKey.toBase58()}`);
|
||||
|
||||
// fetch group
|
||||
const groupPk = '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX';
|
||||
const groupPk = 'AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf';
|
||||
const group = await client.getGroup(new PublicKey(groupPk));
|
||||
console.log(`Found group ${group.publicKey.toBase58()}`);
|
||||
|
||||
|
|
|
@ -206,6 +206,7 @@ async function registerTokens() {
|
|||
group,
|
||||
usdcMainnetMint,
|
||||
usdcMainnetOracle.publicKey,
|
||||
PublicKey.default,
|
||||
0,
|
||||
'USDC',
|
||||
{
|
||||
|
@ -226,6 +227,7 @@ async function registerTokens() {
|
|||
group,
|
||||
usdtMainnetMint,
|
||||
usdtMainnetOracle,
|
||||
PublicKey.default,
|
||||
1,
|
||||
'USDT',
|
||||
{
|
||||
|
@ -246,6 +248,7 @@ async function registerTokens() {
|
|||
group,
|
||||
daiMainnetMint,
|
||||
daiMainnetOracle,
|
||||
PublicKey.default,
|
||||
2,
|
||||
'DAI',
|
||||
{
|
||||
|
@ -266,6 +269,7 @@ async function registerTokens() {
|
|||
group,
|
||||
ethMainnetMint,
|
||||
ethMainnetOracle,
|
||||
PublicKey.default,
|
||||
3,
|
||||
'ETH',
|
||||
{
|
||||
|
@ -286,6 +290,7 @@ async function registerTokens() {
|
|||
group,
|
||||
solMainnetMint,
|
||||
solMainnetOracle,
|
||||
PublicKey.default,
|
||||
4,
|
||||
'SOL',
|
||||
{
|
||||
|
@ -306,6 +311,7 @@ async function registerTokens() {
|
|||
group,
|
||||
msolMainnetMint,
|
||||
msolMainnetOracle,
|
||||
PublicKey.default,
|
||||
5,
|
||||
'MSOL',
|
||||
{
|
||||
|
@ -450,6 +456,7 @@ async function registerPerpMarkets() {
|
|||
1.0,
|
||||
2 * 60 * 60,
|
||||
0.025,
|
||||
0,
|
||||
);
|
||||
|
||||
await client.perpCreateMarket(
|
||||
|
@ -482,6 +489,7 @@ async function registerPerpMarkets() {
|
|||
1.0,
|
||||
2 * 60 * 60,
|
||||
0.2, // 20% positive pnl liquidation fee?
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ const SOME_KEYPAIR =
|
|||
const CLUSTER: Cluster =
|
||||
(process.env.CLUSTER_OVERRIDE as Cluster) || 'mainnet-beta';
|
||||
|
||||
const GROUP_PK = '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX';
|
||||
const GROUP_PK = 'AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf';
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const options = AnchorProvider.defaultOptions();
|
||||
|
|
|
@ -34,7 +34,7 @@ async function main() {
|
|||
console.log(`Admin ${admin.publicKey.toBase58()}`);
|
||||
|
||||
const group = await client.getGroup(
|
||||
new PublicKey('78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX'),
|
||||
new PublicKey('AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf'),
|
||||
);
|
||||
console.log(`${group.toString()}`);
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ async function x(): Promise<void> {
|
|||
);
|
||||
|
||||
const group = await client.getGroup(
|
||||
new PublicKey('78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX'),
|
||||
new PublicKey('AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf'),
|
||||
);
|
||||
|
||||
const { bestRoute } = await fetchRoutes(
|
||||
|
|
|
@ -23,7 +23,7 @@ import { bpsToDecimal, percentageToDecimal, toNative } from '../src/utils';
|
|||
const { MB_CLUSTER_URL, MB_PAYER_KEYPAIR } = process.env;
|
||||
|
||||
const CLIENT_USER = MB_PAYER_KEYPAIR;
|
||||
const GROUP_PK = '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX';
|
||||
const GROUP_PK = 'AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf';
|
||||
|
||||
const defaultOracleConfig = {
|
||||
confFilter: 0.1,
|
||||
|
@ -60,31 +60,31 @@ async function buildClient(): Promise<MangoClient> {
|
|||
);
|
||||
}
|
||||
|
||||
async function groupEdit(): Promise<void> {
|
||||
const client = await buildClient();
|
||||
const group = await client.getGroup(new PublicKey(GROUP_PK));
|
||||
const ix = await client.program.methods
|
||||
.groupEdit(
|
||||
null, // admin
|
||||
null, // fastListingAdmin
|
||||
null, // securityAdmin
|
||||
null, // testing
|
||||
null, // version
|
||||
null, // depositLimitQuote
|
||||
null, // feesPayWithMngo
|
||||
null, // feesMngoBonusRate
|
||||
null, // feesSwapMangoAccount
|
||||
6, // feesMngoTokenIndex
|
||||
null, // feesExpiryInterval
|
||||
5, // allowedFastListingsPerInterval
|
||||
)
|
||||
.accounts({
|
||||
group: group.publicKey,
|
||||
admin: group.admin,
|
||||
})
|
||||
.instruction();
|
||||
console.log(serializeInstructionToBase64(ix));
|
||||
}
|
||||
// async function groupEdit(): Promise<void> {
|
||||
// const client = await buildClient();
|
||||
// const group = await client.getGroup(new PublicKey(GROUP_PK));
|
||||
// const ix = await client.program.methods
|
||||
// .groupEdit(
|
||||
// null, // admin
|
||||
// null, // fastListingAdmin
|
||||
// null, // securityAdmin
|
||||
// null, // testing
|
||||
// null, // version
|
||||
// null, // depositLimitQuote
|
||||
// null, // feesPayWithMngo
|
||||
// null, // feesMngoBonusRate
|
||||
// null, // feesSwapMangoAccount
|
||||
// 6, // feesMngoTokenIndex
|
||||
// null, // feesExpiryInterval
|
||||
// 5, // allowedFastListingsPerInterval
|
||||
// )
|
||||
// .accounts({
|
||||
// group: group.publicKey,
|
||||
// admin: group.admin,
|
||||
// })
|
||||
// .instruction();
|
||||
// console.log(serializeInstructionToBase64(ix));
|
||||
// }
|
||||
|
||||
// async function tokenRegister(): Promise<void> {
|
||||
// const client = await buildClient();
|
||||
|
@ -265,6 +265,7 @@ async function perpCreate(): Promise<void> {
|
|||
1,
|
||||
new BN(60 * 60),
|
||||
percentageToDecimal(10),
|
||||
0,
|
||||
)
|
||||
.accounts({
|
||||
group: group.publicKey,
|
||||
|
@ -358,6 +359,7 @@ async function perpEdit(): Promise<void> {
|
|||
params.positivePnlLiquidationFee,
|
||||
params.name,
|
||||
params.forceClose,
|
||||
0,
|
||||
)
|
||||
.accounts({
|
||||
group: group.publicKey,
|
||||
|
@ -466,7 +468,7 @@ async function idlSetAuthority(): Promise<void> {
|
|||
|
||||
async function main(): Promise<void> {
|
||||
try {
|
||||
await groupEdit();
|
||||
// await groupEdit();
|
||||
// await tokenRegister();
|
||||
// await tokenEdit();
|
||||
// await perpCreate();
|
||||
|
|
|
@ -9,7 +9,7 @@ const { MB_CLUSTER_URL, MB_PAYER_KEYPAIR, MANGO_ACCOUNT, MINT, NATIVE_AMOUNT } =
|
|||
process.env;
|
||||
|
||||
const CLIENT_USER = MB_PAYER_KEYPAIR;
|
||||
const GROUP_PK = '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX';
|
||||
const GROUP_PK = 'AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf';
|
||||
|
||||
async function buildClient(): Promise<MangoClient> {
|
||||
const clientKeypair = Keypair.fromSecretKey(
|
||||
|
|
|
@ -13,7 +13,7 @@ const CLUSTER_URL =
|
|||
const USER_KEYPAIR =
|
||||
process.env.USER_KEYPAIR_OVERRIDE || process.env.MB_PAYER_KEYPAIR;
|
||||
const GROUP_PK =
|
||||
process.env.GROUP_PK || '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX';
|
||||
process.env.GROUP_PK || 'AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf';
|
||||
const PERP_MARKET_INDEX = Number(
|
||||
process.env.PERP_MARKET_INDEX,
|
||||
) as PerpMarketIndex;
|
||||
|
|
|
@ -13,7 +13,7 @@ const CLUSTER_URL =
|
|||
const USER_KEYPAIR =
|
||||
process.env.USER_KEYPAIR_OVERRIDE || process.env.MB_PAYER_KEYPAIR;
|
||||
const GROUP_PK =
|
||||
process.env.GROUP_PK || '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX';
|
||||
process.env.GROUP_PK || 'AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf';
|
||||
const MARKET_INDEX = Number(process.env.MARKET_INDEX) as MarketIndex;
|
||||
|
||||
async function forceCloseSerum3Market(): Promise<void> {
|
||||
|
|
|
@ -12,7 +12,7 @@ const CLUSTER_URL =
|
|||
const USER_KEYPAIR =
|
||||
process.env.USER_KEYPAIR_OVERRIDE || process.env.MB_PAYER_KEYPAIR;
|
||||
const GROUP_PK =
|
||||
process.env.GROUP_PK || '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX';
|
||||
process.env.GROUP_PK || 'AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf';
|
||||
const TOKEN_INDEX = Number(process.env.TOKEN_INDEX) as TokenIndex;
|
||||
|
||||
async function forceWithdrawTokens(): Promise<void> {
|
||||
|
|
|
@ -5,7 +5,7 @@ import { toUiDecimals } from '../src/utils';
|
|||
async function run() {
|
||||
const client = await MangoClient.connectDefault(process.env.MB_CLUSTER_URL!);
|
||||
let group = await client.getGroup(
|
||||
new PublicKey('78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX'),
|
||||
new PublicKey('AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf'),
|
||||
);
|
||||
|
||||
let accounts = await client.getAllMangoAccounts(group, true);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { AnchorProvider, BN, Wallet } from '@coral-xyz/anchor';
|
||||
import { Cluster, Connection, Keypair, PublicKey } from '@solana/web3.js';
|
||||
import * as splToken from '@solana/spl-token';
|
||||
import { Cluster, Connection, Keypair, PublicKey } from '@solana/web3.js';
|
||||
import fs from 'fs';
|
||||
import { Bank } from '../../src/accounts/bank';
|
||||
import {
|
||||
|
@ -280,6 +280,7 @@ async function main() {
|
|||
group,
|
||||
newMint,
|
||||
newOracle.publicKey,
|
||||
PublicKey.default,
|
||||
newTokenIndex,
|
||||
'TMP',
|
||||
{
|
||||
|
|
|
@ -143,6 +143,7 @@ async function registerTokens(): Promise<void> {
|
|||
group,
|
||||
usdcMainnetMint,
|
||||
usdcMainnetOracle,
|
||||
PublicKey.default,
|
||||
0,
|
||||
'USDC',
|
||||
defaultTokenParams,
|
||||
|
|
|
@ -6,7 +6,7 @@ import { MANGO_V4_ID } from '../src/constants';
|
|||
|
||||
const { MB_CLUSTER_URL } = process.env;
|
||||
|
||||
const GROUP_PK = '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX';
|
||||
const GROUP_PK = 'AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf';
|
||||
|
||||
async function buildClient(): Promise<MangoClient> {
|
||||
const clientKeypair = new Keypair();
|
||||
|
|
|
@ -14,7 +14,7 @@ dotenv.config();
|
|||
const CLUSTER_URL =
|
||||
process.env.CLUSTER_URL_OVERRIDE || process.env.MB_CLUSTER_URL;
|
||||
const GROUP_PK =
|
||||
process.env.GROUP_PK || '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX';
|
||||
process.env.GROUP_PK || 'AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf';
|
||||
const CLUSTER: Cluster =
|
||||
(process.env.CLUSTER_OVERRIDE as Cluster) || 'mainnet-beta';
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ dotenv.config();
|
|||
const CLUSTER_URL =
|
||||
process.env.CLUSTER_URL_OVERRIDE || process.env.MB_CLUSTER_URL;
|
||||
const GROUP_PK =
|
||||
process.env.GROUP_PK || '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX';
|
||||
process.env.GROUP_PK || 'AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf';
|
||||
const CLUSTER: Cluster =
|
||||
(process.env.CLUSTER_OVERRIDE as Cluster) || 'mainnet-beta';
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import { getLiquidationBatches, getRiskStats } from '../src/risk';
|
|||
|
||||
const { MB_CLUSTER_URL } = process.env;
|
||||
|
||||
const GROUP_PK = '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX';
|
||||
const GROUP_PK = 'AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf';
|
||||
|
||||
async function buildClient(): Promise<MangoClient> {
|
||||
const clientKeypair = new Keypair();
|
||||
|
|
|
@ -76,7 +76,7 @@ async function main(): Promise<void> {
|
|||
});
|
||||
|
||||
const group = await client.getGroup(
|
||||
new PublicKey('78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX'),
|
||||
new PublicKey('AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf'),
|
||||
);
|
||||
|
||||
let mangoAccounts = await client.getAllMangoAccounts(group, true);
|
||||
|
|
|
@ -27,7 +27,7 @@ function getBankForOracle(group: Group, oracle: PublicKey): Bank | PerpMarket {
|
|||
async function main(): Promise<void> {
|
||||
const client = await MangoClient.connectDefault(process.env.MB_CLUSTER_URL!);
|
||||
const group = await client.getGroup(
|
||||
new PublicKey('78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX'),
|
||||
new PublicKey('AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf'),
|
||||
);
|
||||
|
||||
const oracles1 = Array.from(group.banksMapByName.values()).map(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import {
|
||||
LISTING_PRESETS,
|
||||
MidPriceImpact,
|
||||
getMidPriceImpacts,
|
||||
} from '@blockworks-foundation/mango-v4-settings/lib/helpers/listingTools';
|
||||
|
@ -9,6 +10,7 @@ import {
|
|||
getTokenOwnerRecord,
|
||||
getTokenOwnerRecordAddress,
|
||||
} from '@solana/spl-governance';
|
||||
import { Builder } from '../src/builder';
|
||||
|
||||
import {
|
||||
AccountMeta,
|
||||
|
@ -22,10 +24,10 @@ import fs from 'fs';
|
|||
import { Bank } from '../src/accounts/bank';
|
||||
import { Group } from '../src/accounts/group';
|
||||
import { MangoAccount } from '../src/accounts/mangoAccount';
|
||||
import { Builder } from '../src/builder';
|
||||
import { MangoClient } from '../src/client';
|
||||
import { NullTokenEditParams } from '../src/clientIxParamBuilder';
|
||||
import { MANGO_V4_MAIN_GROUP as MANGO_V4_PRIMARY_GROUP } from '../src/constants';
|
||||
import { I80F48 } from '../src/numbers/I80F48';
|
||||
import {
|
||||
LiqorPriceImpact,
|
||||
buildGroupGrid,
|
||||
|
@ -155,30 +157,69 @@ async function updateTokenParams(): Promise<void> {
|
|||
|
||||
const midPriceImpacts = getMidPriceImpacts(group.pis);
|
||||
|
||||
const pisForLiqor: LiqorPriceImpact[][] = await buildGroupGrid(
|
||||
group,
|
||||
allMangoAccounts,
|
||||
stepSize,
|
||||
);
|
||||
const pisForLiqor: LiqorPriceImpact[][] = [];
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
if (false) {
|
||||
const pisForLiqor: LiqorPriceImpact[][] = await buildGroupGrid(
|
||||
group,
|
||||
allMangoAccounts,
|
||||
stepSize,
|
||||
);
|
||||
}
|
||||
|
||||
// Deposit limits header
|
||||
console.log(
|
||||
`${'name'.padStart(20)} ${'maxLiqBatchUi'.padStart(
|
||||
15,
|
||||
)} ${'maxLiqBatchUi'.padStart(15)} ${'sellImpact'.padStart(
|
||||
12,
|
||||
)}$ ${'pi %'.padStart(12)}% ${'aNDUi'.padStart(20)}${'aNDQuoteUi'.padStart(
|
||||
20,
|
||||
)} ${'uiDeposits'.padStart(12)} ${'uiDeposits'.padStart(
|
||||
12,
|
||||
)} ${'depositLimitsUi'.padStart(12)}`,
|
||||
);
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
if (false) {
|
||||
// Deposit limits header
|
||||
console.log(
|
||||
`${'name'.padStart(20)} ${'maxLiqBatchUi'.padStart(
|
||||
15,
|
||||
)} ${'maxLiqBatchUi'.padStart(15)} ${'sellImpact'.padStart(
|
||||
12,
|
||||
)}$ ${'pi %'.padStart(12)}% ${'aNDUi'.padStart(
|
||||
20,
|
||||
)}${'aNDQuoteUi'.padStart(20)} ${'uiDeposits'.padStart(
|
||||
12,
|
||||
)} ${'uiDeposits'.padStart(12)} ${'depositLimitsUi'.padStart(12)}`,
|
||||
);
|
||||
}
|
||||
|
||||
Array.from(group.banksMapByTokenIndex.values())
|
||||
.map((banks) => banks[0])
|
||||
// .filter((bank) => bank.name == 'MSOL')
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.forEach(async (bank) => {
|
||||
const builder = Builder(NullTokenEditParams);
|
||||
let change = false;
|
||||
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
if (true) {
|
||||
const tier = Object.values(LISTING_PRESETS).find((x) =>
|
||||
x.initLiabWeight.toFixed(1) === '1.8'
|
||||
? x.initLiabWeight.toFixed(1) ===
|
||||
bank?.initLiabWeight.toNumber().toFixed(1) &&
|
||||
x.reduceOnly === bank.reduceOnly
|
||||
: x.initLiabWeight.toFixed(1) ===
|
||||
bank?.initLiabWeight.toNumber().toFixed(1),
|
||||
);
|
||||
if (!tier) {
|
||||
console.log(`${bank.name}, no tier found`);
|
||||
} else {
|
||||
console.log(
|
||||
`${bank.name.padStart(10)}, ${bank.loanFeeRate
|
||||
.mul(I80F48.fromNumber(100))
|
||||
.toFixed(2)}, ${bank.loanOriginationFeeRate
|
||||
.mul(I80F48.fromNumber(100))
|
||||
.toFixed(2)}, ${tier?.preset_name.padStart(5)}, ${(
|
||||
tier.loanFeeRate * 100
|
||||
).toFixed(2)}, ${(tier!.loanOriginationFeeRate * 100).toFixed(2)}`,
|
||||
);
|
||||
|
||||
builder.loanFeeRate(tier!.loanFeeRate);
|
||||
builder.loanOriginationFeeRate(tier!.loanOriginationFeeRate);
|
||||
builder.flashLoanSwapFeeRate(tier!.loanOriginationFeeRate);
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// formulas are sourced from here
|
||||
// https://www.notion.so/mango-markets/Mango-v4-Risk-parameter-recommendations-d309cdf5faac4aeea7560356e68532ab
|
||||
|
@ -189,115 +230,104 @@ async function updateTokenParams(): Promise<void> {
|
|||
// 4 * priceImpact.target_amount,
|
||||
// );
|
||||
|
||||
const builder = Builder(NullTokenEditParams);
|
||||
|
||||
// Net borrow limits
|
||||
if (!bank.areBorrowsReduceOnly()) {
|
||||
const netBorrowLimitPerWindowQuote = Math.max(
|
||||
10_000,
|
||||
Math.min(bank.uiDeposits() * bank.uiPrice, 300_000) / 3 +
|
||||
Math.max(0, bank.uiDeposits() * bank.uiPrice - 300_000) / 5,
|
||||
);
|
||||
builder.netBorrowLimitPerWindowQuote(
|
||||
toNativeI80F48ForQuote(netBorrowLimitPerWindowQuote).toNumber(),
|
||||
);
|
||||
change = true;
|
||||
if (
|
||||
netBorrowLimitPerWindowQuote !=
|
||||
toUiDecimalsForQuote(bank.netBorrowLimitPerWindowQuote)
|
||||
) {
|
||||
console.log(
|
||||
`${
|
||||
bank.name
|
||||
} new - ${netBorrowLimitPerWindowQuote.toLocaleString()}, old - ${toUiDecimalsForQuote(
|
||||
bank.netBorrowLimitPerWindowQuote,
|
||||
).toLocaleString()}`,
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
if (false) {
|
||||
// Net borrow limits
|
||||
const netBorrowLimitPerWindowQuote = Math.max(
|
||||
10_000,
|
||||
Math.min(bank.uiDeposits() * bank.uiPrice, 300_000) / 3 +
|
||||
Math.max(0, bank.uiDeposits() * bank.uiPrice - 300_000) / 5,
|
||||
);
|
||||
builder.netBorrowLimitPerWindowQuote(
|
||||
toNativeI80F48ForQuote(netBorrowLimitPerWindowQuote).toNumber(),
|
||||
);
|
||||
change = true;
|
||||
if (
|
||||
netBorrowLimitPerWindowQuote !=
|
||||
toUiDecimalsForQuote(bank.netBorrowLimitPerWindowQuote)
|
||||
) {
|
||||
console.log(
|
||||
`${
|
||||
bank.name
|
||||
} new - ${netBorrowLimitPerWindowQuote.toLocaleString()}, old - ${toUiDecimalsForQuote(
|
||||
bank.netBorrowLimitPerWindowQuote,
|
||||
).toLocaleString()}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Deposit limits
|
||||
if (bank.maintAssetWeight.toNumber() > 0) {
|
||||
{
|
||||
// Find asset's largest batch in $ we would need to liquidate, batches are extreme points of a range of price drop,
|
||||
// range is constrained by leverage provided
|
||||
// i.e. how much volatility we expect
|
||||
const r = findLargestAssetBatchUi(
|
||||
pisForLiqor,
|
||||
bank.name,
|
||||
Math.round(bank.maintAssetWeight.toNumber() * 100),
|
||||
100 - Math.round(bank.maintAssetWeight.toNumber() * 100),
|
||||
stepSize,
|
||||
);
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
if (false) {
|
||||
if (bank.maintAssetWeight.toNumber() > 0) {
|
||||
{
|
||||
// Find asset's largest batch in $ we would need to liquidate, batches are extreme points of a range of price drop,
|
||||
// range is constrained by leverage provided
|
||||
// i.e. how much volatility we expect
|
||||
const r = findLargestAssetBatchUi(
|
||||
pisForLiqor,
|
||||
bank.name,
|
||||
Math.round(bank.maintAssetWeight.toNumber() * 100),
|
||||
100 - Math.round(bank.maintAssetWeight.toNumber() * 100),
|
||||
stepSize,
|
||||
);
|
||||
|
||||
const maxLiqBatchQuoteUi = r[0];
|
||||
const maxLiqBatchUi = r[1];
|
||||
const maxLiqBatchQuoteUi = r[0];
|
||||
const maxLiqBatchUi = r[1];
|
||||
|
||||
const sellImpact = getPriceImpactForBank(
|
||||
midPriceImpacts,
|
||||
bank,
|
||||
(bank.liquidationFee.toNumber() * 100) / 2,
|
||||
);
|
||||
const sellImpact = getPriceImpactForBank(
|
||||
midPriceImpacts,
|
||||
bank,
|
||||
(bank.liquidationFee.toNumber() * 100) / 2,
|
||||
);
|
||||
|
||||
// Deposit limit = sell impact - largest batch
|
||||
const allowedNewDepositsQuoteUi =
|
||||
sellImpact.target_amount - maxLiqBatchQuoteUi;
|
||||
const allowedNewDepositsUi =
|
||||
sellImpact.target_amount / bank.uiPrice -
|
||||
maxLiqBatchQuoteUi / bank.uiPrice;
|
||||
// Deposit limit = sell impact - largest batch
|
||||
const allowedNewDepositsQuoteUi =
|
||||
sellImpact.target_amount - maxLiqBatchQuoteUi;
|
||||
const allowedNewDepositsUi =
|
||||
sellImpact.target_amount / bank.uiPrice -
|
||||
maxLiqBatchQuoteUi / bank.uiPrice;
|
||||
|
||||
let depositLimitUi = bank.uiDeposits() + allowedNewDepositsUi;
|
||||
const depositLimitUi = bank.uiDeposits() + allowedNewDepositsUi;
|
||||
|
||||
if (bank.name == 'JitoSOL') {
|
||||
depositLimitUi = Math.min(depositLimitUi, 12_000);
|
||||
}
|
||||
if (bank.name == 'bSOL') {
|
||||
depositLimitUi = Math.min(depositLimitUi, 6_000);
|
||||
}
|
||||
if (bank.name == 'MSOL') {
|
||||
depositLimitUi = Math.min(depositLimitUi, 50_000);
|
||||
}
|
||||
if (bank.name == 'JLP') {
|
||||
depositLimitUi = Math.min(depositLimitUi, 300_000);
|
||||
}
|
||||
if (bank.name == 'RAY') {
|
||||
depositLimitUi = Math.min(depositLimitUi, 300_000);
|
||||
}
|
||||
if (bank.name == 'wBTC (Portal)') {
|
||||
depositLimitUi = Math.max(depositLimitUi, 7.5);
|
||||
}
|
||||
if (bank.name == 'SOL') {
|
||||
depositLimitUi = Math.max(depositLimitUi, 50_000);
|
||||
}
|
||||
// LOG
|
||||
// console.log(
|
||||
// `${bank.name.padStart(20)} ${maxLiqBatchUi
|
||||
// .toLocaleString()
|
||||
// .padStart(15)} ${maxLiqBatchQuoteUi
|
||||
// .toLocaleString()
|
||||
// .padStart(15)}$ ${sellImpact.target_amount
|
||||
// .toLocaleString()
|
||||
// .padStart(12)}$ ${sellImpact.avg_price_impact_percent
|
||||
// .toLocaleString()
|
||||
// .padStart(12)}% ${allowedNewDepositsUi
|
||||
// .toLocaleString()
|
||||
// .padStart(20)}${allowedNewDepositsQuoteUi
|
||||
// .toLocaleString()
|
||||
// .padStart(20)}$ ${bank
|
||||
// .uiDeposits()
|
||||
// .toLocaleString()
|
||||
// .padStart(12)} ${(bank.uiDeposits() * bank.uiPrice)
|
||||
// .toLocaleString()
|
||||
// .padStart(12)}$ ${depositLimitUi
|
||||
// .toLocaleString()
|
||||
// .padStart(12)}`,
|
||||
// );
|
||||
|
||||
console.log(
|
||||
`${bank.name.padStart(20)} ${maxLiqBatchUi
|
||||
.toLocaleString()
|
||||
.padStart(15)} ${maxLiqBatchQuoteUi
|
||||
.toLocaleString()
|
||||
.padStart(15)}$ ${sellImpact.target_amount
|
||||
.toLocaleString()
|
||||
.padStart(12)}$ ${sellImpact.avg_price_impact_percent
|
||||
.toLocaleString()
|
||||
.padStart(12)}% ${allowedNewDepositsUi
|
||||
.toLocaleString()
|
||||
.padStart(20)}${allowedNewDepositsQuoteUi
|
||||
.toLocaleString()
|
||||
.padStart(20)}$ ${bank
|
||||
.uiDeposits()
|
||||
.toLocaleString()
|
||||
.padStart(12)} ${(bank.uiDeposits() * bank.uiPrice)
|
||||
.toLocaleString()
|
||||
.padStart(12)}$ ${depositLimitUi
|
||||
.toLocaleString()
|
||||
.padStart(12)}`,
|
||||
);
|
||||
|
||||
builder.depositLimit(toNative(depositLimitUi, bank.mintDecimals));
|
||||
change = true;
|
||||
builder.depositLimit(
|
||||
toNative(depositLimitUi, bank.mintDecimals),
|
||||
);
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const params = builder.build();
|
||||
console.log(bank.name);
|
||||
console.log(params.loanFeeRate);
|
||||
console.log(params.loanOriginationFeeRate);
|
||||
console.log(params.flashLoanSwapFeeRate);
|
||||
|
||||
const ix = await client.program.methods
|
||||
.tokenEdit(
|
||||
|
@ -341,6 +371,11 @@ async function updateTokenParams(): Promise<void> {
|
|||
params.maintWeightShiftAbort ?? false,
|
||||
false, // setFallbackOracle, unused
|
||||
params.depositLimit,
|
||||
params.zeroUtilRate,
|
||||
params.platformLiquidationFee,
|
||||
params.disableAssetLiquidation,
|
||||
params.collateralFeePerDay,
|
||||
params.forceWithdraw,
|
||||
)
|
||||
.accounts({
|
||||
group: group.publicKey,
|
||||
|
@ -401,7 +436,9 @@ async function updateTokenParams(): Promise<void> {
|
|||
walletSigner,
|
||||
MANGO_DAO_WALLET_GOVERNANCE,
|
||||
tokenOwnerRecord,
|
||||
PROPOSAL_TITLE ? PROPOSAL_TITLE : 'Update deposit limits for tokens',
|
||||
PROPOSAL_TITLE
|
||||
? PROPOSAL_TITLE
|
||||
: 'Update loan fee, loan origination fee, and flash loan fees in mango-v4',
|
||||
PROPOSAL_LINK ?? '',
|
||||
Object.values(proposals).length,
|
||||
instructions,
|
||||
|
|
|
@ -24,6 +24,7 @@ describe('Mango Account', () => {
|
|||
new BN(0),
|
||||
new BN(0),
|
||||
0,
|
||||
0,
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
|
|
|
@ -3,17 +3,11 @@ import { utf8 } from '@coral-xyz/anchor/dist/cjs/utils/bytes';
|
|||
import { OpenOrders, Order, Orderbook } from '@project-serum/serum/lib/market';
|
||||
import { AccountInfo, PublicKey } from '@solana/web3.js';
|
||||
import { MangoClient } from '../client';
|
||||
import {
|
||||
OPENBOOK_PROGRAM_ID,
|
||||
RUST_I64_MAX,
|
||||
RUST_I64_MIN,
|
||||
USDC_MINT,
|
||||
} from '../constants';
|
||||
import { OPENBOOK_PROGRAM_ID, RUST_I64_MAX, RUST_I64_MIN } from '../constants';
|
||||
import { I80F48, I80F48Dto, ONE_I80F48, ZERO_I80F48 } from '../numbers/I80F48';
|
||||
import {
|
||||
U64_MAX_BN,
|
||||
roundTo5,
|
||||
toNative,
|
||||
toNativeI80F48,
|
||||
toUiDecimals,
|
||||
toUiDecimalsForQuote,
|
||||
|
@ -50,6 +44,7 @@ export class MangoAccount {
|
|||
buybackFeesAccruedCurrent: BN;
|
||||
buybackFeesAccruedPrevious: BN;
|
||||
buybackFeesExpiryTimestamp: BN;
|
||||
sequenceNumber: number;
|
||||
headerVersion: number;
|
||||
tokens: unknown;
|
||||
serum3: unknown;
|
||||
|
@ -74,6 +69,7 @@ export class MangoAccount {
|
|||
obj.buybackFeesAccruedCurrent,
|
||||
obj.buybackFeesAccruedPrevious,
|
||||
obj.buybackFeesExpiryTimestamp,
|
||||
obj.sequenceNumber,
|
||||
obj.headerVersion,
|
||||
obj.tokens as TokenPositionDto[],
|
||||
obj.serum3 as Serum3PositionDto[],
|
||||
|
@ -100,6 +96,7 @@ export class MangoAccount {
|
|||
public buybackFeesAccruedCurrent: BN,
|
||||
public buybackFeesAccruedPrevious: BN,
|
||||
public buybackFeesExpiryTimestamp: BN,
|
||||
public sequenceNumber: number,
|
||||
public headerVersion: number,
|
||||
tokens: TokenPositionDto[],
|
||||
serum3: Serum3PositionDto[],
|
||||
|
@ -669,6 +666,15 @@ export class MangoAccount {
|
|||
maxSource = maxSource.min(equivalentSourceAmount);
|
||||
}
|
||||
|
||||
// Apply max swap fee
|
||||
const maxSwapFeeRate = I80F48.fromNumber(
|
||||
Math.max(
|
||||
sourceBank.flashLoanSwapFeeRate,
|
||||
targetBank.flashLoanSwapFeeRate,
|
||||
),
|
||||
);
|
||||
maxSource = maxSource.div(ONE_I80F48().add(maxSwapFeeRate));
|
||||
|
||||
return toUiDecimals(maxSource, group.getMintDecimals(sourceMintPk));
|
||||
}
|
||||
|
||||
|
@ -2145,6 +2151,13 @@ export class TokenConditionalSwap {
|
|||
sellBank.tokenIndex,
|
||||
liqorTcsChunkSizeInUsd,
|
||||
);
|
||||
|
||||
if (buyTokenPriceImpact <= 0 || sellTokenPriceImpact <= 0) {
|
||||
throw new Error(
|
||||
`Error compitong slippage/premium for token conditional swap!`,
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
((1 + buyTokenPriceImpact / 100) * (1 + sellTokenPriceImpact / 100) - 1) *
|
||||
100
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
import { AnchorProvider, BN, Program, Wallet } from '@coral-xyz/anchor';
|
||||
import {
|
||||
AnchorProvider,
|
||||
BN,
|
||||
Program,
|
||||
Provider,
|
||||
Wallet,
|
||||
} from '@coral-xyz/anchor';
|
||||
import { OpenOrders, decodeEventQueue } from '@project-serum/serum';
|
||||
import {
|
||||
createAccount,
|
||||
|
@ -63,6 +69,7 @@ import {
|
|||
} from './accounts/serum3';
|
||||
import {
|
||||
IxGateParams,
|
||||
PerpEditParams,
|
||||
TokenEditParams,
|
||||
TokenRegisterParams,
|
||||
buildIxGate,
|
||||
|
@ -1027,6 +1034,20 @@ export class MangoClient {
|
|||
return await this.sendAndConfirmTransactionForGroup(group, [ix]);
|
||||
}
|
||||
|
||||
public async sequenceCheckIx(
|
||||
group: Group,
|
||||
mangoAccount: MangoAccount,
|
||||
): Promise<TransactionInstruction> {
|
||||
return await this.program.methods
|
||||
.sequenceCheck(mangoAccount.sequenceNumber)
|
||||
.accounts({
|
||||
group: group.publicKey,
|
||||
account: mangoAccount.publicKey,
|
||||
owner: (this.program.provider as AnchorProvider).wallet.publicKey,
|
||||
})
|
||||
.instruction();
|
||||
}
|
||||
|
||||
public async getMangoAccount(
|
||||
mangoAccountPk: PublicKey,
|
||||
loadSerum3Oo = false,
|
||||
|
@ -2375,13 +2396,18 @@ export class MangoClient {
|
|||
externalMarketPk: PublicKey,
|
||||
limit?: number,
|
||||
): Promise<MangoSignatureStatus> {
|
||||
return await this.sendAndConfirmTransactionForGroup(group, [
|
||||
await this.serum3CancelAllOrdersIx(
|
||||
const [cancelAllIx, settle] = await Promise.all([
|
||||
this.serum3CancelAllOrdersIx(
|
||||
group,
|
||||
mangoAccount,
|
||||
externalMarketPk,
|
||||
limit,
|
||||
),
|
||||
this.serum3SettleFundsV2Ix(group, mangoAccount, externalMarketPk),
|
||||
]);
|
||||
return await this.sendAndConfirmTransactionForGroup(group, [
|
||||
cancelAllIx,
|
||||
settle,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -3942,8 +3968,9 @@ export class MangoClient {
|
|||
);
|
||||
const lowerLimit = 0;
|
||||
const upperLimit = thresholdPriceNativeNative;
|
||||
console.log(thresholdPriceNativeNative);
|
||||
|
||||
return await this.tokenConditionalSwapCreateIx(
|
||||
return await this.tokenConditionalSwapCreatePremiumAuctionIx(
|
||||
group,
|
||||
account,
|
||||
sellBank,
|
||||
|
@ -3958,6 +3985,9 @@ export class MangoClient {
|
|||
false,
|
||||
expiryTimestamp,
|
||||
thresholdPriceInSellPerBuyToken,
|
||||
120,
|
||||
2,
|
||||
10,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4016,7 +4046,7 @@ export class MangoClient {
|
|||
const lowerLimit = thresholdPriceNativeNative;
|
||||
const upperLimit = Number.MAX_SAFE_INTEGER;
|
||||
|
||||
return await this.tokenConditionalSwapCreateIx(
|
||||
return await this.tokenConditionalSwapCreatePremiumAuctionIx(
|
||||
group,
|
||||
account,
|
||||
sellBank,
|
||||
|
@ -4031,6 +4061,9 @@ export class MangoClient {
|
|||
false,
|
||||
expiryTimestamp,
|
||||
thresholdPriceInSellPerBuyToken,
|
||||
120,
|
||||
2,
|
||||
10,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4092,7 +4125,7 @@ export class MangoClient {
|
|||
const lowerLimit = 0;
|
||||
const upperLimit = thresholdPriceNativeNative;
|
||||
|
||||
return await this.tokenConditionalSwapCreateIx(
|
||||
return await this.tokenConditionalSwapCreatePremiumAuctionIx(
|
||||
group,
|
||||
account,
|
||||
sellBank,
|
||||
|
@ -4107,6 +4140,9 @@ export class MangoClient {
|
|||
allowMargin ?? false,
|
||||
expiryTimestamp,
|
||||
thresholdPriceInSellPerBuyToken,
|
||||
120,
|
||||
2,
|
||||
10,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4168,7 +4204,7 @@ export class MangoClient {
|
|||
const lowerLimit = thresholdPriceNativeNative;
|
||||
const upperLimit = Number.MAX_SAFE_INTEGER;
|
||||
|
||||
return await this.tokenConditionalSwapCreateIx(
|
||||
return await this.tokenConditionalSwapCreatePremiumAuctionIx(
|
||||
group,
|
||||
account,
|
||||
sellBank,
|
||||
|
@ -4183,6 +4219,9 @@ export class MangoClient {
|
|||
allowMargin ?? false,
|
||||
expiryTimestamp,
|
||||
thresholdPriceInSellPerBuyToken,
|
||||
120,
|
||||
2,
|
||||
10,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4224,7 +4263,7 @@ export class MangoClient {
|
|||
maxBuy,
|
||||
maxSell,
|
||||
);
|
||||
const pricePremiumRate = pricePremium > 0 ? pricePremium / 100 : 0.03;
|
||||
const pricePremiumRate = pricePremium / 100;
|
||||
|
||||
let intention: TokenConditionalSwapIntention;
|
||||
switch (tcsIntention) {
|
||||
|
@ -4458,8 +4497,8 @@ export class MangoClient {
|
|||
account: MangoAccount,
|
||||
sellBank: Bank,
|
||||
buyBank: Bank,
|
||||
lowerLimit: number,
|
||||
upperLimit: number,
|
||||
lowerLimitNative: number,
|
||||
upperLimitNative: number,
|
||||
maxBuy: number,
|
||||
maxSell: number,
|
||||
tcsIntention:
|
||||
|
@ -4473,19 +4512,10 @@ export class MangoClient {
|
|||
allowCreatingBorrows: boolean,
|
||||
expiryTimestamp: number | null,
|
||||
displayPriceInSellTokenPerBuyToken: boolean,
|
||||
durationSeconds: number,
|
||||
durationSeconds,
|
||||
premiumMultiplier = 1,
|
||||
extraPricePremiumBps = 0,
|
||||
): Promise<TransactionInstruction[]> {
|
||||
const lowerLimitNative = toNativeSellPerBuyTokenPrice(
|
||||
lowerLimit,
|
||||
sellBank,
|
||||
buyBank,
|
||||
);
|
||||
const upperLimitNative = toNativeSellPerBuyTokenPrice(
|
||||
upperLimit,
|
||||
sellBank,
|
||||
buyBank,
|
||||
);
|
||||
|
||||
let maxBuyNative, maxSellNative, buyAmountInUsd, sellAmountInUsd;
|
||||
if (maxBuy == Number.MAX_SAFE_INTEGER) {
|
||||
maxBuyNative = U64_MAX_BN;
|
||||
|
@ -4520,13 +4550,21 @@ export class MangoClient {
|
|||
sellBank.tokenIndex,
|
||||
liqorTcsChunkSizeInUsd,
|
||||
);
|
||||
|
||||
if (buyTokenPriceImpact <= 0 || sellTokenPriceImpact <= 0) {
|
||||
throw new Error(
|
||||
`Error compitong slippage/premium for token conditional swap!`,
|
||||
);
|
||||
}
|
||||
|
||||
maxPricePremiumPercent =
|
||||
((1 + buyTokenPriceImpact / 100) * (1 + sellTokenPriceImpact / 100) -
|
||||
1) *
|
||||
100;
|
||||
}
|
||||
const maxPricePremiumRate =
|
||||
maxPricePremiumPercent > 0 ? maxPricePremiumPercent / 100 : 0.03;
|
||||
let maxPricePremiumRate = maxPricePremiumPercent / 100;
|
||||
maxPricePremiumRate =
|
||||
maxPricePremiumRate * premiumMultiplier + extraPricePremiumBps / 10000;
|
||||
|
||||
let intention: TokenConditionalSwapIntention;
|
||||
switch (tcsIntention) {
|
||||
|
|
|
@ -49,7 +49,7 @@ export const DefaultTokenRegisterParams: TokenRegisterParams = {
|
|||
adjustmentFactor: 0.004,
|
||||
},
|
||||
loanFeeRate: 0.0005,
|
||||
loanOriginationFeeRate: 0.005,
|
||||
loanOriginationFeeRate: 0.0075,
|
||||
maintAssetWeight: 0,
|
||||
initAssetWeight: 0,
|
||||
maintLiabWeight: 1.4,
|
||||
|
@ -310,6 +310,7 @@ export interface IxGateParams {
|
|||
TokenConditionalSwapCreateLinearAuction: boolean;
|
||||
Serum3PlaceOrderV2: boolean;
|
||||
TokenForceWithdraw: boolean;
|
||||
SequenceCheck: boolean;
|
||||
}
|
||||
|
||||
// Default with all ixs enabled, use with buildIxGate
|
||||
|
@ -390,6 +391,7 @@ export const TrueIxGateParams: IxGateParams = {
|
|||
TokenConditionalSwapCreateLinearAuction: true,
|
||||
Serum3PlaceOrderV2: true,
|
||||
TokenForceWithdraw: true,
|
||||
SequenceCheck: true,
|
||||
};
|
||||
|
||||
// build ix gate e.g. buildIxGate(Builder(TrueIxGateParams).TokenDeposit(false).build()).toNumber(),
|
||||
|
@ -480,6 +482,7 @@ export function buildIxGate(p: IxGateParams): BN {
|
|||
toggleIx(ixGate, p, 'TokenConditionalSwapCreateLinearAuction', 70);
|
||||
toggleIx(ixGate, p, 'Serum3PlaceOrderV2', 71);
|
||||
toggleIx(ixGate, p, 'TokenForceWithdraw', 72);
|
||||
toggleIx(ixGate, p, 'SequenceCheck', 73);
|
||||
|
||||
return ixGate;
|
||||
}
|
||||
|
|
|
@ -21,13 +21,13 @@ export const OPENBOOK_PROGRAM_ID = {
|
|||
};
|
||||
|
||||
export const MANGO_V4_ID = {
|
||||
testnet: new PublicKey('4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg'),
|
||||
devnet: new PublicKey('4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg'),
|
||||
'mainnet-beta': new PublicKey('4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg'),
|
||||
testnet: new PublicKey('zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25'),
|
||||
devnet: new PublicKey('zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25'),
|
||||
'mainnet-beta': new PublicKey('zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25'),
|
||||
};
|
||||
|
||||
export const MANGO_V4_MAIN_GROUP = new PublicKey(
|
||||
'78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX',
|
||||
'AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf',
|
||||
);
|
||||
|
||||
export const USDC_MINT = new PublicKey(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
export type MangoV4 = {
|
||||
"version": "0.22.0",
|
||||
"version": "0.23.0",
|
||||
"name": "mango_v4",
|
||||
"instructions": [
|
||||
{
|
||||
|
@ -1760,6 +1760,36 @@ export type MangoV4 = {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sequenceCheck",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "group",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false,
|
||||
"relations": [
|
||||
"group",
|
||||
"owner"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "expectedSequenceNumber",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stubOracleCreate",
|
||||
"accounts": [
|
||||
|
@ -7871,13 +7901,8 @@ export type MangoV4 = {
|
|||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
1
|
||||
]
|
||||
}
|
||||
"name": "sequenceNumber",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "netDeposits",
|
||||
|
@ -9669,13 +9694,8 @@ export type MangoV4 = {
|
|||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
1
|
||||
]
|
||||
}
|
||||
"name": "sequenceNumber",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "netDeposits",
|
||||
|
@ -11008,6 +11028,9 @@ export type MangoV4 = {
|
|||
},
|
||||
{
|
||||
"name": "TokenForceWithdraw"
|
||||
},
|
||||
{
|
||||
"name": "SequenceCheck"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -12871,6 +12894,71 @@ export type MangoV4 = {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PerpLiqBaseOrPositivePnlLogV3",
|
||||
"fields": [
|
||||
{
|
||||
"name": "mangoGroup",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "perpMarketIndex",
|
||||
"type": "u16",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "liqor",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "liqee",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "baseTransferLiqee",
|
||||
"type": "i64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "quoteTransferLiqee",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "quoteTransferLiqor",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "quotePlatformFee",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "pnlTransfer",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "pnlSettleLimitTransferRecurring",
|
||||
"type": "i64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "pnlSettleLimitTransferOneshot",
|
||||
"type": "i64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "price",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PerpLiqBankruptcyLog",
|
||||
"fields": [
|
||||
|
@ -13888,6 +13976,46 @@ export type MangoV4 = {
|
|||
"name": "fee",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "price",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ForceWithdrawLog",
|
||||
"fields": [
|
||||
{
|
||||
"name": "mangoGroup",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "mangoAccount",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "tokenIndex",
|
||||
"type": "u16",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "quantity",
|
||||
"type": "u64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "price",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "toTokenAccount",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -14242,12 +14370,22 @@ export type MangoV4 = {
|
|||
"code": 6069,
|
||||
"name": "TokenAssetLiquidationDisabled",
|
||||
"msg": "the asset does not allow liquidation"
|
||||
},
|
||||
{
|
||||
"code": 6070,
|
||||
"name": "BorrowsRequireHealthAccountBank",
|
||||
"msg": "for borrows the bank must be in the health account list"
|
||||
},
|
||||
{
|
||||
"code": 6071,
|
||||
"name": "InvalidSequenceNumber",
|
||||
"msg": "invalid sequence number"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export const IDL: MangoV4 = {
|
||||
"version": "0.22.0",
|
||||
"version": "0.23.0",
|
||||
"name": "mango_v4",
|
||||
"instructions": [
|
||||
{
|
||||
|
@ -16008,6 +16146,36 @@ export const IDL: MangoV4 = {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sequenceCheck",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "group",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false,
|
||||
"relations": [
|
||||
"group",
|
||||
"owner"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "expectedSequenceNumber",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stubOracleCreate",
|
||||
"accounts": [
|
||||
|
@ -22119,13 +22287,8 @@ export const IDL: MangoV4 = {
|
|||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
1
|
||||
]
|
||||
}
|
||||
"name": "sequenceNumber",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "netDeposits",
|
||||
|
@ -23917,13 +24080,8 @@ export const IDL: MangoV4 = {
|
|||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
1
|
||||
]
|
||||
}
|
||||
"name": "sequenceNumber",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "netDeposits",
|
||||
|
@ -25256,6 +25414,9 @@ export const IDL: MangoV4 = {
|
|||
},
|
||||
{
|
||||
"name": "TokenForceWithdraw"
|
||||
},
|
||||
{
|
||||
"name": "SequenceCheck"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -27119,6 +27280,71 @@ export const IDL: MangoV4 = {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PerpLiqBaseOrPositivePnlLogV3",
|
||||
"fields": [
|
||||
{
|
||||
"name": "mangoGroup",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "perpMarketIndex",
|
||||
"type": "u16",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "liqor",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "liqee",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "baseTransferLiqee",
|
||||
"type": "i64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "quoteTransferLiqee",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "quoteTransferLiqor",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "quotePlatformFee",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "pnlTransfer",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "pnlSettleLimitTransferRecurring",
|
||||
"type": "i64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "pnlSettleLimitTransferOneshot",
|
||||
"type": "i64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "price",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PerpLiqBankruptcyLog",
|
||||
"fields": [
|
||||
|
@ -28136,6 +28362,46 @@ export const IDL: MangoV4 = {
|
|||
"name": "fee",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "price",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ForceWithdrawLog",
|
||||
"fields": [
|
||||
{
|
||||
"name": "mangoGroup",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "mangoAccount",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "tokenIndex",
|
||||
"type": "u16",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "quantity",
|
||||
"type": "u64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "price",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "toTokenAccount",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -28490,6 +28756,16 @@ export const IDL: MangoV4 = {
|
|||
"code": 6069,
|
||||
"name": "TokenAssetLiquidationDisabled",
|
||||
"msg": "the asset does not allow liquidation"
|
||||
},
|
||||
{
|
||||
"code": 6070,
|
||||
"name": "BorrowsRequireHealthAccountBank",
|
||||
"msg": "for borrows the bank must be in the health account list"
|
||||
},
|
||||
{
|
||||
"code": 6071,
|
||||
"name": "InvalidSequenceNumber",
|
||||
"msg": "invalid sequence number"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
|
@ -30,10 +30,10 @@
|
|||
dependencies:
|
||||
regenerator-runtime "^0.14.0"
|
||||
|
||||
"@blockworks-foundation/mango-v4-settings@0.4.10":
|
||||
version "0.4.10"
|
||||
resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4-settings/-/mango-v4-settings-0.4.10.tgz#7a30db53c81abea56c2dd83e928259246e3b4e7d"
|
||||
integrity sha512-J4RhfhcNmBn0CeqjN4mlaou+vPW9NGpWlbkx1+ZczsJw6r5tIkQ82MDqKMKvyIgn457krRVdJ9+gLmHEln4QfA==
|
||||
"@blockworks-foundation/mango-v4-settings@0.14.15":
|
||||
version "0.14.15"
|
||||
resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4-settings/-/mango-v4-settings-0.14.15.tgz#0ac04f2cffbd27a4129bc2086ec1418e29393880"
|
||||
integrity sha512-GBo43KCosdaohbtS3Rtz8e2zsLsiN3JqTfLKVtStRYO3f2tQLzeo/D2Khz07psw2egq6TCNZJH7+v32iGrPq0w==
|
||||
dependencies:
|
||||
bn.js "^5.2.1"
|
||||
eslint-config-prettier "^9.0.0"
|
||||
|
|
Loading…
Reference in New Issue