diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index 25b695754..6c57145ac 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -231,7 +231,7 @@ export class MangoClient { liquidationFee: number, minVaultToDepositsRatio: number, netBorrowLimitWindowSizeTs: number, - netBorrowsLimitNative: number, + netBorrowLimitPerWindowQuote: number, ): Promise { return await this.program.methods .tokenRegister( @@ -248,7 +248,7 @@ export class MangoClient { liquidationFee, minVaultToDepositsRatio, new BN(netBorrowLimitWindowSizeTs), - new BN(netBorrowsLimitNative), + new BN(netBorrowLimitPerWindowQuote), ) .accounts({ group: group.publicKey, @@ -559,8 +559,8 @@ export class MangoClient { accountNumber ?? 0, tokenCount ?? 8, serum3Count ?? 8, - perpCount ?? 0, - perpOoCount ?? 0, + perpCount ?? 8, + perpOoCount ?? 8, name ?? '', ) .accounts({ diff --git a/ts/client/src/debug-scripts/debug-banks.ts b/ts/client/src/debug-scripts/debug-banks.ts index c06685b7e..2c73e84ac 100644 --- a/ts/client/src/debug-scripts/debug-banks.ts +++ b/ts/client/src/debug-scripts/debug-banks.ts @@ -1,19 +1,19 @@ -import * as dotenv from 'dotenv'; -dotenv.config(); import { AnchorProvider, Wallet } from '@project-serum/anchor'; import { coder } from '@project-serum/anchor/dist/cjs/spl/token'; import { Cluster, Connection, Keypair } from '@solana/web3.js'; +import * as dotenv from 'dotenv'; import fs from 'fs'; import { MangoClient } from '../client'; import { MANGO_V4_ID } from '../constants'; import { I80F48, ZERO_I80F48 } from '../numbers/I80F48'; import { toUiDecimals } from '../utils'; +dotenv.config(); const CLUSTER_URL = process.env.CLUSTER_URL_OVERRIDE || process.env.MB_CLUSTER_URL; const PAYER_KEYPAIR = process.env.PAYER_KEYPAIR_OVERRIDE || process.env.MB_PAYER_KEYPAIR; -const GROUP_NUM = Number(process.env.GROUP_NUM || 2); +const GROUP_NUM = Number(process.env.GROUP_NUM || 0); const CLUSTER: Cluster = (process.env.CLUSTER_OVERRIDE as Cluster) || 'mainnet-beta'; diff --git a/ts/client/src/debug-scripts/mb-debug-user.ts b/ts/client/src/debug-scripts/debug-user.ts similarity index 100% rename from ts/client/src/debug-scripts/mb-debug-user.ts rename to ts/client/src/debug-scripts/debug-user.ts diff --git a/ts/client/src/mango_v4.ts b/ts/client/src/mango_v4.ts index ed6cf0ccd..82f820faa 100644 --- a/ts/client/src/mango_v4.ts +++ b/ts/client/src/mango_v4.ts @@ -3855,17 +3855,6 @@ export type MangoV4 = { }, { "name": "beingLiquidated", - "docs": [ - "Tracks that this account should be liquidated until init_health >= 0.", - "", - "Normally accounts can not be liquidated while maint_health >= 0. But when an account", - "reaches maint_health < 0, liquidators will call a liquidation instruction and thereby", - "set this flag. Now the account may be liquidated until init_health >= 0.", - "", - "Many actions should be disabled while the account is being liquidated, even if", - "its maint health has recovered to positive. Creating new open orders would, for example,", - "confuse liquidators." - ], "type": "u8" }, { @@ -5775,19 +5764,6 @@ export type MangoV4 = { }, { "name": "StablePriceModel", - "docs": [ - "Maintains a \"stable_price\" based on the oracle price.", - "", - "The stable price follows the oracle price, but its relative rate of", - "change is limited (to `stable_growth_limit`) and futher reduced if", - "the oracle price is far from the `delay_price`.", - "", - "Conceptually the `delay_price` is itself a time delayed", - "(`24 * delay_interval_seconds`, assume 24h) and relative rate of change limited", - "function of the oracle price. It is implemented as averaging the oracle", - "price over every `delay_interval_seconds` (assume 1h) and then applying the", - "`delay_growth_limit` between intervals." - ], "type": { "kind": "struct", "fields": [ @@ -5804,13 +5780,6 @@ export type MangoV4 = { }, { "name": "delayPrices", - "docs": [ - "Stored delay_price for each delay_interval.", - "If we want the delay_price to be 24h delayed, we would store one for each hour.", - "This is used in a cyclical way: We use the maximally-delayed value at delay_interval_index", - "and once enough time passes to move to the next delay interval, that gets overwritten and", - "we use the next one." - ], "type": { "array": [ "f64", @@ -5820,46 +5789,26 @@ export type MangoV4 = { }, { "name": "delayAccumulatorPrice", - "docs": [ - "The delay price is based on an average over each delay_interval. The contributions", - "to the average are summed up here." - ], "type": "f64" }, { "name": "delayAccumulatorTime", - "docs": [ - "Accumulating the total time for the above average." - ], "type": "u32" }, { "name": "delayIntervalSeconds", - "docs": [ - "Length of a delay_interval" - ], "type": "u32" }, { "name": "delayGrowthLimit", - "docs": [ - "Maximal relative difference between two delay_price in consecutive intervals." - ], "type": "f32" }, { "name": "stableGrowthLimit", - "docs": [ - "Maximal per-second relative difference of the stable price.", - "It gets further reduced if stable and delay price disagree." - ], "type": "f32" }, { "name": "lastDelayIntervalIndex", - "docs": [ - "The delay_interval_index that update() was last called on." - ], "type": "u8" }, { @@ -6031,14 +5980,6 @@ export type MangoV4 = { }, { "name": "HealthType", - "docs": [ - "There are two types of health, initial health used for opening new positions and maintenance", - "health used for liquidations. They are both calculated as a weighted sum of the assets", - "minus the liabilities but the maint. health uses slightly larger weights for assets and", - "slightly smaller weights for the liabilities. Zero is used as the bright line for both", - "i.e. if your init health falls below zero, you cannot open new positions and if your maint. health", - "falls below zero you will be liquidated." - ], "type": { "kind": "enum", "variants": [ @@ -11271,17 +11212,6 @@ export const IDL: MangoV4 = { }, { "name": "beingLiquidated", - "docs": [ - "Tracks that this account should be liquidated until init_health >= 0.", - "", - "Normally accounts can not be liquidated while maint_health >= 0. But when an account", - "reaches maint_health < 0, liquidators will call a liquidation instruction and thereby", - "set this flag. Now the account may be liquidated until init_health >= 0.", - "", - "Many actions should be disabled while the account is being liquidated, even if", - "its maint health has recovered to positive. Creating new open orders would, for example,", - "confuse liquidators." - ], "type": "u8" }, { @@ -13191,19 +13121,6 @@ export const IDL: MangoV4 = { }, { "name": "StablePriceModel", - "docs": [ - "Maintains a \"stable_price\" based on the oracle price.", - "", - "The stable price follows the oracle price, but its relative rate of", - "change is limited (to `stable_growth_limit`) and futher reduced if", - "the oracle price is far from the `delay_price`.", - "", - "Conceptually the `delay_price` is itself a time delayed", - "(`24 * delay_interval_seconds`, assume 24h) and relative rate of change limited", - "function of the oracle price. It is implemented as averaging the oracle", - "price over every `delay_interval_seconds` (assume 1h) and then applying the", - "`delay_growth_limit` between intervals." - ], "type": { "kind": "struct", "fields": [ @@ -13220,13 +13137,6 @@ export const IDL: MangoV4 = { }, { "name": "delayPrices", - "docs": [ - "Stored delay_price for each delay_interval.", - "If we want the delay_price to be 24h delayed, we would store one for each hour.", - "This is used in a cyclical way: We use the maximally-delayed value at delay_interval_index", - "and once enough time passes to move to the next delay interval, that gets overwritten and", - "we use the next one." - ], "type": { "array": [ "f64", @@ -13236,46 +13146,26 @@ export const IDL: MangoV4 = { }, { "name": "delayAccumulatorPrice", - "docs": [ - "The delay price is based on an average over each delay_interval. The contributions", - "to the average are summed up here." - ], "type": "f64" }, { "name": "delayAccumulatorTime", - "docs": [ - "Accumulating the total time for the above average." - ], "type": "u32" }, { "name": "delayIntervalSeconds", - "docs": [ - "Length of a delay_interval" - ], "type": "u32" }, { "name": "delayGrowthLimit", - "docs": [ - "Maximal relative difference between two delay_price in consecutive intervals." - ], "type": "f32" }, { "name": "stableGrowthLimit", - "docs": [ - "Maximal per-second relative difference of the stable price.", - "It gets further reduced if stable and delay price disagree." - ], "type": "f32" }, { "name": "lastDelayIntervalIndex", - "docs": [ - "The delay_interval_index that update() was last called on." - ], "type": "u8" }, { @@ -13447,14 +13337,6 @@ export const IDL: MangoV4 = { }, { "name": "HealthType", - "docs": [ - "There are two types of health, initial health used for opening new positions and maintenance", - "health used for liquidations. They are both calculated as a weighted sum of the assets", - "minus the liabilities but the maint. health uses slightly larger weights for assets and", - "slightly smaller weights for the liabilities. Zero is used as the bright line for both", - "i.e. if your init health falls below zero, you cannot open new positions and if your maint. health", - "falls below zero you will be liquidated." - ], "type": { "kind": "enum", "variants": [ diff --git a/ts/client/src/scripts/mb-admin.ts b/ts/client/src/scripts/mb-admin.ts index 064266591..9fb983f8c 100644 --- a/ts/client/src/scripts/mb-admin.ts +++ b/ts/client/src/scripts/mb-admin.ts @@ -15,39 +15,40 @@ import { } from '../accounts/serum3'; import { MangoClient } from '../client'; import { MANGO_V4_ID } from '../constants'; -import { buildVersionedTx } from '../utils'; +import { buildVersionedTx, toNative } from '../utils'; + +const GROUP_NUM = Number(process.env.GROUP_NUM || 0); const MAINNET_MINTS = new Map([ - ['USDC', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'], - ['USDT', 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'], - ['ETH', '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs'], // Ether (Portal) - ['SOL', 'So11111111111111111111111111111111111111112'], // Wrapped SOL - ['MSOL', 'mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So'], - ['MNGO', 'MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac'], - ['RAY', '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R'], - ['DUST', 'DUSTawucrTsGU8hcqRdHDCbuYhCPADMLM2VcCb8VnFnQ'], + ['USDC', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'], // 0 + ['USDT', 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'], // 1 + ['DAI', 'EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o'], // 2 + ['ETH', '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs'], // 3 Ether (Portal) + ['SOL', 'So11111111111111111111111111111111111111112'], // 4 Wrapped SOL + ['MSOL', 'mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So'], // 5 + ['MNGO', 'MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac'], // 6 ]); const MAINNET_ORACLES = new Map([ + // USDC - stub oracle ['USDT', '3vxLXJqLqF3JG5TCbYycbKWRBbCJQLxQmBGCkyqEEefL'], - ['BTC', 'GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU'], + ['DAI', 'CtJ8EkqLmeYyGB8s4jevpeNsvmD4dxVR2krfsDLcvV8Y'], ['ETH', 'JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB'], ['SOL', 'H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG'], ['MSOL', 'E4v1BBgoso9s64TQvmyownAVJbhbEPGyzA3qn4n46qj9'], ['MNGO', '79wm3jjcPr6RaNQ4DGvP5KxG1mNd3gEBsg6FsNVFezK4'], - ['RAY', 'AnLf8tVYCM816gmBjiy8n53eXKKEDydT5piYjjQDPgTB'], - ['DUST', 'C5tuUPi7xJHBHZGZX6wWYf1Svm6jtTVwYrYrBCiEVejK'], + ['BTC', 'GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU'], ]); // External markets are matched with those in https://github.com/openbook-dex/openbook-ts/blob/master/packages/serum/src/markets.json const MAINNET_SERUM3_MARKETS = new Map([ - ['SOL/USDC', '9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT'], + ['SOL/USDC', '8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6'], ]); const MIN_VAULT_TO_DEPOSITS_RATIO = 0.2; const NET_BORROWS_WINDOW_SIZE_TS = 24 * 60 * 60; -const NET_BORROWS_LIMIT_NATIVE = 1 * Math.pow(10, 7) * Math.pow(10, 6); +const NET_BORROW_LIMIT_PER_WINDOW_QUOTE = toNative(1000000, 6).toNumber(); -const { MB_CLUSTER_URL, MB_PAYER_KEYPAIR, MB_USER_KEYPAIR, MB_USER2_KEYPAIR } = +const { MB_CLUSTER_URL, MB_PAYER_KEYPAIR, MB_USER_KEYPAIR, MB_USER4_KEYPAIR } = process.env; async function buildAdminClient(): Promise<[MangoClient, Keypair]> { @@ -96,7 +97,7 @@ async function buildUserClient( Buffer.from(JSON.parse(fs.readFileSync(MB_PAYER_KEYPAIR!, 'utf-8'))), ); console.log(`Admin ${admin.publicKey.toBase58()}`); - const group = await client.getGroupForCreator(admin.publicKey, 2); + const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM); return [client, group, user]; } @@ -107,8 +108,8 @@ async function createGroup() { console.log(`Creating Group...`); const insuranceMint = new PublicKey(MAINNET_MINTS.get('USDC')!); - await client.groupCreate(2, true, 0, insuranceMint); - const group = await client.getGroupForCreator(admin.publicKey, 2); + await client.groupCreate(GROUP_NUM, true, 2, insuranceMint); + const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM); console.log(`...registered group ${group.publicKey}`); } @@ -117,7 +118,7 @@ async function registerTokens() { const client = result[0]; const admin = result[1]; - const group = await client.getGroupForCreator(admin.publicKey, 2); + const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM); const defaultOracleConfig = { confFilter: 0.1, @@ -159,7 +160,7 @@ async function registerTokens() { 0, MIN_VAULT_TO_DEPOSITS_RATIO, NET_BORROWS_WINDOW_SIZE_TS, - NET_BORROWS_LIMIT_NATIVE, + NET_BORROW_LIMIT_PER_WINDOW_QUOTE, ); console.log(`Registering USDT...`); @@ -182,7 +183,30 @@ async function registerTokens() { 0.025, MIN_VAULT_TO_DEPOSITS_RATIO, NET_BORROWS_WINDOW_SIZE_TS, - NET_BORROWS_LIMIT_NATIVE, + NET_BORROW_LIMIT_PER_WINDOW_QUOTE, + ); + + console.log(`Registering DAI...`); + const daiMainnetMint = new PublicKey(MAINNET_MINTS.get('DAI')!); + const daiMainnetOracle = new PublicKey(MAINNET_ORACLES.get('DAI')!); + await client.tokenRegister( + group, + daiMainnetMint, + daiMainnetOracle, + defaultOracleConfig, + 2, + 'DAI', + defaultInterestRate, + 0.005, + 0.0005, + 0.95, + 0.9, + 1.05, + 1.1, + 0.025, + MIN_VAULT_TO_DEPOSITS_RATIO, + NET_BORROWS_WINDOW_SIZE_TS, + NET_BORROW_LIMIT_PER_WINDOW_QUOTE, ); console.log(`Registering ETH...`); @@ -205,7 +229,7 @@ async function registerTokens() { 0.05, MIN_VAULT_TO_DEPOSITS_RATIO, NET_BORROWS_WINDOW_SIZE_TS, - NET_BORROWS_LIMIT_NATIVE, + NET_BORROW_LIMIT_PER_WINDOW_QUOTE, ); console.log(`Registering SOL...`); @@ -216,7 +240,7 @@ async function registerTokens() { solMainnetMint, solMainnetOracle, defaultOracleConfig, - 5, + 4, 'SOL', defaultInterestRate, 0.005, @@ -228,7 +252,7 @@ async function registerTokens() { 0.05, MIN_VAULT_TO_DEPOSITS_RATIO, NET_BORROWS_WINDOW_SIZE_TS, - NET_BORROWS_LIMIT_NATIVE, + NET_BORROW_LIMIT_PER_WINDOW_QUOTE, ); console.log(`Registering MSOL...`); @@ -239,7 +263,7 @@ async function registerTokens() { msolMainnetMint, msolMainnetOracle, defaultOracleConfig, - 6, + 5, 'MSOL', defaultInterestRate, 0.005, @@ -251,143 +275,47 @@ async function registerTokens() { 0.05, MIN_VAULT_TO_DEPOSITS_RATIO, NET_BORROWS_WINDOW_SIZE_TS, - NET_BORROWS_LIMIT_NATIVE, - ); - console.log(`Registering RAY...`); - const rayMainnetMint = new PublicKey(MAINNET_MINTS.get('RAY')!); - const rayMainnetOracle = new PublicKey(MAINNET_ORACLES.get('RAY')!); - await client.tokenRegister( - group, - rayMainnetMint, - rayMainnetOracle, - defaultOracleConfig, - 7, - 'RAY', - { - adjustmentFactor: 0.004, - util0: 0.7, - rate0: 0.2, - util1: 0.85, - rate1: 0.4, - maxRate: 4.0, - }, - 0.005, - 0.0005, - 7 / 8, - 3 / 4, - 8 / 7, - 4 / 3, - 1 / 16, - MIN_VAULT_TO_DEPOSITS_RATIO, - NET_BORROWS_WINDOW_SIZE_TS, - NET_BORROWS_LIMIT_NATIVE, + NET_BORROW_LIMIT_PER_WINDOW_QUOTE, ); - console.log(`Registering DUST...`); - const dustMainnetMint = new PublicKey(MAINNET_MINTS.get('DUST')!); - const dustMainnetOracle = new PublicKey(MAINNET_ORACLES.get('DUST')!); - await client.tokenRegister( + console.log(`Registering MNGO...`); + await client.groupEdit(group, group.admin, group.admin); + const mngoMainnetMint = new PublicKey(MAINNET_MINTS.get('MNGO')!); + const mngoMainnetOracle = new PublicKey(MAINNET_ORACLES.get('MNGO')!); + await client.tokenRegisterTrustless( group, - dustMainnetMint, - dustMainnetOracle, - defaultOracleConfig, - 8, - 'DUST', - { - adjustmentFactor: 0.004, - util0: 0.7, - rate0: 0.3, - util1: 0.85, - rate1: 0.6, - maxRate: 6.0, - }, - 0.005, - 0.0005, - 0, // no asset weight for isolation - 0, - 81 / 80, - 41 / 40, // 40x leverage so we can test something - 1 / 160, // no liquidation fee - MIN_VAULT_TO_DEPOSITS_RATIO, - NET_BORROWS_WINDOW_SIZE_TS, - NET_BORROWS_LIMIT_NATIVE, + mngoMainnetMint, + mngoMainnetOracle, + 6, + 'MNGO', ); // log tokens/banks await group.reloadAll(client); - for (const bank of await Array.from(group.banksMapByMint.values()).flat()) { + for (const bank of await Array.from(group.banksMapByMint.values()) + .flat() + .sort((a, b) => a.tokenIndex - b.tokenIndex)) { console.log(`${bank.toString()}`); } } -async function unregisterTokens() { - const result = await buildAdminClient(); - const client = result[0]; - const admin = result[1]; - - const group = await client.getGroupForCreator(admin.publicKey, 2); - - let bank = group.getFirstBankByTokenIndex(8 as TokenIndex); - let sig = await client.tokenDeregister(group, bank.mint); - console.log( - `Removed token ${bank.name}, sig https://explorer.solana.com/tx/${sig}`, - ); -} - async function registerSerum3Markets() { const result = await buildAdminClient(); const client = result[0]; const admin = result[1]; - const group = await client.getGroupForCreator(admin.publicKey, 2); - - // Bump version to 1 to unlock serum3 feature - await client.groupEdit( - group, - group.admin, - group.fastListingAdmin, - undefined, - 1, - ); + const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM); // Register SOL serum market - await client.serum3RegisterMarket( group, new PublicKey(MAINNET_SERUM3_MARKETS.get('SOL/USDC')!), group.getFirstBankByMint(new PublicKey(MAINNET_MINTS.get('SOL')!)), group.getFirstBankByMint(new PublicKey(MAINNET_MINTS.get('USDC')!)), - 1, + 0, 'SOL/USDC', ); } - -async function unregisterSerum3Markets() { - const result = await buildAdminClient(); - const client = result[0]; - const admin = result[1]; - - const group = await client.getGroupForCreator(admin.publicKey, 2); - - let serum3Market = group.getSerum3MarketByName('RAY/SOL'); - let sig = await client.serum3deregisterMarket( - group, - serum3Market.serumMarketExternal, - ); - console.log( - `Deregistered serum market ${serum3Market.name}, sig https://explorer.solana.com/tx/${sig}`, - ); - - serum3Market = group.getSerum3MarketByName('DUST/SOL'); - sig = await client.serum3deregisterMarket( - group, - serum3Market.serumMarketExternal, - ); - console.log( - `Deregistered serum market ${serum3Market.name}, sig https://explorer.solana.com/tx/${sig}`, - ); -} - async function createUser(userKeypair: string) { const result = await buildUserClient(userKeypair); const client = result[0]; @@ -421,89 +349,49 @@ async function createUser(userKeypair: string) { console.log(`...deposited 1 SOL`); } -async function expandMangoAccount(userKeypair: string) { - const result = await buildUserClient(userKeypair); - const client = result[0]; - const group = result[1]; - const user = result[2]; - - const mangoAccounts = await client.getMangoAccountsForOwner( - group, - user.publicKey, - ); - if (!mangoAccounts) { - throw new Error(`MangoAccounts not found for user ${user.publicKey}`); +async function main() { + try { + // await createGroup(); + } catch (error) { + console.log(error); + } + try { + // await registerTokens(); + } catch (error) { + console.log(error); + } + try { + // await registerSerum3Markets(); + } catch (error) { + console.log(error); + } + try { + await createUser(MB_USER_KEYPAIR!); + await createUser(MB_USER4_KEYPAIR!); + } catch (error) { + console.log(error); } - for (const mangoAccount of mangoAccounts) { - console.log(`...found MangoAccount ${mangoAccount.publicKey.toBase58()}`); - await client.expandMangoAccount(group, mangoAccount, 8, 2, 0, 0); - } + try { + } catch (error) {} } -async function placeSerum3TradeAndCancelIt(userKeypair: string) { - const result = await buildUserClient(userKeypair); - const client = result[0]; - const group = result[1]; - const user = result[2]; - - const mangoAccounts = await client.getMangoAccountsForOwner( - group, - user.publicKey, - ); - if (!mangoAccounts) { - throw new Error(`MangoAccounts not found for user ${user.publicKey}`); - } - - for (const mangoAccount of mangoAccounts) { - console.log(`...found MangoAccount ${mangoAccount.publicKey.toBase58()}`); - console.log(`...placing serum3 order`); - await client.serum3PlaceOrder( - group, - mangoAccount, - new PublicKey(MAINNET_SERUM3_MARKETS.get('SOL/USDC')!), - Serum3Side.bid, - 1, - 1, - Serum3SelfTradeBehavior.decrementTake, - Serum3OrderType.limit, - Date.now(), - 10, - ); - console.log(`...current own orders on OB`); - let orders = await mangoAccount.loadSerum3OpenOrdersForMarket( - client, - group, - new PublicKey(MAINNET_SERUM3_MARKETS.get('SOL/USDC')!), - ); - for (const order of orders) { - console.log(order); - } - console.log(`...cancelling serum3 orders`); - await client.serum3CancelAllOrders( - group, - mangoAccount, - new PublicKey(MAINNET_SERUM3_MARKETS.get('SOL/USDC')!), - 10, - ); - console.log(`...current own orders on OB`); - orders = await mangoAccount.loadSerum3OpenOrdersForMarket( - client, - group, - new PublicKey(MAINNET_SERUM3_MARKETS.get('SOL/USDC')!), - ); - for (const order of orders) { - console.log(order); - } - } +try { + main(); +} catch (error) { + console.log(error); } +//////////////////////////////////////////////////////////// +/// UNUSED ///////////////////////////////////////////////// +//////////////////////////////////////////////////////////// + async function createAndPopulateAlt() { const result = await buildAdminClient(); const client = result[0]; const admin = result[1]; - const group = await client.getGroupForCreator(admin.publicKey, 2); + const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM); const connection = client.program.provider.connection; @@ -618,40 +506,114 @@ async function createAndPopulateAlt() { } } -async function main() { - try { - // await createGroup(); - } catch (error) { - console.log(error); - } - try { - // await registerTokens(); - // await unregisterTokens(); - } catch (error) { - console.log(error); - } - try { - // await registerSerum3Markets(); - // await unregisterSerum3Markets(); - } catch (error) { - console.log(error); - } - try { - // await createUser(MB_USER_KEYPAIR!); - // await createUser(MB_USER2_KEYPAIR!); - // await expandMangoAccount(MB_USER_KEYPAIR!); - // await placeSerum3TradeAndCancelIt(MB_USER_KEYPAIR!); - } catch (error) { - console.log(error); +async function expandMangoAccount(userKeypair: string) { + const result = await buildUserClient(userKeypair); + const client = result[0]; + const group = result[1]; + const user = result[2]; + + const mangoAccounts = await client.getMangoAccountsForOwner( + group, + user.publicKey, + ); + if (!mangoAccounts) { + throw new Error(`MangoAccounts not found for user ${user.publicKey}`); } - try { - // await createAndPopulateAlt(); - } catch (error) {} + for (const mangoAccount of mangoAccounts) { + console.log( + `...expanding MangoAccount ${mangoAccount.publicKey.toBase58()}`, + ); + await client.expandMangoAccount(group, mangoAccount, 8, 8, 8, 8); + } } -try { - main(); -} catch (error) { - console.log(error); +async function placeSerum3TradeAndCancelIt(userKeypair: string) { + const result = await buildUserClient(userKeypair); + const client = result[0]; + const group = result[1]; + const user = result[2]; + + const mangoAccounts = await client.getMangoAccountsForOwner( + group, + user.publicKey, + ); + if (!mangoAccounts) { + throw new Error(`MangoAccounts not found for user ${user.publicKey}`); + } + + for (const mangoAccount of mangoAccounts) { + console.log(`...found MangoAccount ${mangoAccount.publicKey.toBase58()}`); + console.log(`...placing serum3 order`); + await client.serum3PlaceOrder( + group, + mangoAccount, + new PublicKey(MAINNET_SERUM3_MARKETS.get('SOL/USDC')!), + Serum3Side.bid, + 1, + 1, + Serum3SelfTradeBehavior.decrementTake, + Serum3OrderType.limit, + Date.now(), + 10, + ); + console.log(`...current own orders on OB`); + let orders = await mangoAccount.loadSerum3OpenOrdersForMarket( + client, + group, + new PublicKey(MAINNET_SERUM3_MARKETS.get('SOL/USDC')!), + ); + for (const order of orders) { + console.log(order); + } + console.log(`...cancelling serum3 orders`); + await client.serum3CancelAllOrders( + group, + mangoAccount, + new PublicKey(MAINNET_SERUM3_MARKETS.get('SOL/USDC')!), + 10, + ); + console.log(`...current own orders on OB`); + orders = await mangoAccount.loadSerum3OpenOrdersForMarket( + client, + group, + new PublicKey(MAINNET_SERUM3_MARKETS.get('SOL/USDC')!), + ); + for (const order of orders) { + console.log(order); + } + } +} + +async function deregisterSerum3Markets() { + const result = await buildAdminClient(); + const client = result[0]; + const admin = result[1]; + + const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM); + + // change xxx/xxx to market of choice + let serum3Market = group.getSerum3MarketByName('XXX/XXX'); + let sig = await client.serum3deregisterMarket( + group, + serum3Market.serumMarketExternal, + ); + console.log( + `...deregistered serum market ${serum3Market.name}, sig https://explorer.solana.com/tx/${sig}`, + ); +} + +async function deregisterTokens() { + const result = await buildAdminClient(); + const client = result[0]; + const admin = result[1]; + + const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM); + + // change -1 to tokenIndex of choice + let bank = group.getFirstBankByTokenIndex(-1 as TokenIndex); + let sig = await client.tokenDeregister(group, bank.mint); + console.log( + `...removed token ${bank.name}, sig https://explorer.solana.com/tx/${sig}`, + ); }