diff --git a/ts/client/ids.json b/ts/client/ids.json index 7882b8b0d..86a2b763b 100644 --- a/ts/client/ids.json +++ b/ts/client/ids.json @@ -1,34 +1,66 @@ { - "testnet": {}, - "devnet": { - "m43thNJ58XCjL798ZSq6JGAG1BnWskhdq5or6kcnfsD": { - "8nBa69Ed8LCeP5YpZ1qB58DTEXq8fq7epfH5RsUVFATb": { - "banks": { - "USDC": "ChuTYko8TLHb8Xn72gAe7PQTS9ULvrTayjMzjRGSmUn8", - "SOL": "3V7vwKfQPhJn2bSywqsrvJwwCK9B5Dy3mE2SXCFxfW1N", - "ORCA": "fiHgPevezzWH3zWFsqnHdcA9Qeg6B15HfsDXGygBcqF", - "BTC": "HGw2wgfnytS3uEwPeyNijhoruA3K7msQaogkxC8EKdGX" + "groups": [ + { + "cluster": "devnet", + "name": "devnet.microwavedcola", + "publicKey": "8SPemjpDsXAqJNCL5vF2qk1XsocPVDTdY7sWVeU7t4NV", + "serum3ProgramId": "DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY", + "mangoProgramId": "m43thNJ58XCjL798ZSq6JGAG1BnWskhdq5or6kcnfsD", + "banks": [ + { + "name": "BTC", + "publicKey": "7JRb4RzjAwTffgsLBh65gL4fyLJqzZc98Z1WKBDCJopZ" }, - "stubOracles": { - "USDC": "DfbZP2mdLnHKWT5tVGb3MyaqEJpEfVQGi8LSP1gxgCeN" + { + "name": "USDC", + "publicKey": "97hK4n6sZFDJAnCfyS3vSWeugZmdyhvMJv3WjLNuZAdo" }, - "mintInfos": { - "ORCA": "GXW8pBd3wZx8QZCoxsTj4CT3qGfoSGED6SB2bKXonZAs", - "BTC": "6onpaK9yFJBcV5d6Vs8vUnWF5pKDBDCo3rq4E9gva6nh", - "USDC": "4gdSUfDBo5YibmanYL1N5uDdcBSdkpx75AwmUZWasFPW", - "SOL": "BEckAgpZQmSpcA2ncgb3LWfRHxnwG3WsNqpkaXQzAMA2" + { + "name": "ORCA", + "publicKey": "Dmh7P1gsZdLrPabuDtTzPYPgTLJWwu8e59TxXQ2Q5V9u" }, - "serum3Markets": { - "BTC/USDC": "AThBBA35mBxnUi3rT7YPVZKDnpZbi2ZsNSzJZkfJrFoA" - }, - "serum3MarketExternals": { - "BTC/USDC": "DW83EpHFywBxCHmyARxwj3nzxJd7MUdSeznmrdzZKNZB" - }, - "perpMarkets": { - "BTC/USDC": "D2cYz3LdYfzcpNcbx4TFr4P8C24XUzPtXPnyZSyhA8oa" + { + "name": "SOL", + "publicKey": "GyCanBHkomvNZGJiDyRZpajXjZ5GWGN6KL4JXtcM9Fnn" } - } + ], + "stubOracles": [ + { + "name": "USDC", + "publicKey": "6vWHjKupnkpRfN61DvESQwKt4cNSAkXbej7aQ4TRwFEm" + } + ], + "mintInfos": [ + { + "name": "USDC", + "publicKey": "FiDdmANpx3JDdDEJpvDimpVUhAnnduGZ5YPyd6yWovkt" + }, + { + "name": "BTC", + "publicKey": "A2jFoKiSLoRbtgJUiXGnRGCVrMTwZNth3K7rcxc9pu57" + }, + { + "name": "ORCA", + "publicKey": "3cZZk1jZDZqh2HzgvFvMQ67QDWMZfLbcFp9uziE63iSS" + }, + { + "name": "SOL", + "publicKey": "9UqfN1us6YYigrXjWA6yazeTg9EUfNa5eiJSFJj4qbeq" + } + ], + "serum3Markets": [ + { + "name": "BTC/USDC", + "publicKey": "3BABCXXwr9UG782xPHaVjBYG7H2B9HkuY4tGZy9MtU5T", + "marketExternal": "DW83EpHFywBxCHmyARxwj3nzxJd7MUdSeznmrdzZKNZB" + } + ], + "perpMarkets": [ + { + "name": "BTC/USDC", + "publicKey": "5ZwVhP5PYkKtx2H4WL2JxSvWL6AALFzwubwM5dsR5XHF" + } + ] } - }, - "mainnet": {} -} + ] +} \ No newline at end of file diff --git a/ts/client/src/accounts/group.ts b/ts/client/src/accounts/group.ts index 0c162f17e..03209a5e5 100644 --- a/ts/client/src/accounts/group.ts +++ b/ts/client/src/accounts/group.ts @@ -1,7 +1,7 @@ import { Market } from '@project-serum/serum'; import { PublicKey } from '@solana/web3.js'; import { MangoClient } from '../client'; -import { MANGO_V4_ID, SERUM3_PROGRAM_ID } from '../constants'; +import { SERUM3_PROGRAM_ID } from '../constants'; import { Id } from '../ids'; import { Bank, MintInfo } from './bank'; import { PerpMarket } from './perp'; @@ -44,12 +44,8 @@ export class Group { public async reloadAll(client: MangoClient) { let ids: Id | undefined = undefined; - if (client.useIds) { - ids = Id.fromIds( - client.cluster, - MANGO_V4_ID[client.cluster], - this.publicKey, - ); + if (client.groupName) { + ids = Id.fromIds(client.groupName); } // console.time('group.reload'); diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index f02a060a3..f1583e52e 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -35,6 +35,7 @@ import { Serum3Side, } from './accounts/serum3'; import { SERUM3_PROGRAM_ID } from './constants'; +import { Id } from './ids'; import { buildOrcaInstruction, ORCA_TOKEN_SWAP_ID_DEVNET, @@ -53,7 +54,7 @@ export class MangoClient { public program: Program, public programId: PublicKey, public cluster: Cluster, - public useIds: boolean, + public groupName?: string, ) {} /// public @@ -1193,7 +1194,6 @@ export class MangoClient { provider: Provider, cluster: Cluster, programId: PublicKey, - useIds: boolean, ): MangoClient { // TODO: use IDL on chain or in repository? decide... // Alternatively we could fetch IDL from chain. @@ -1204,7 +1204,29 @@ export class MangoClient { new Program(idl as MangoV4, programId, provider), programId, cluster, - useIds, + ); + } + + static connectForGroupName( + provider: Provider, + groupName: string, + ): MangoClient { + // TODO: use IDL on chain or in repository? decide... + // Alternatively we could fetch IDL from chain. + // const idl = await Program.fetchIdl(MANGO_V4_ID, provider); + let idl = IDL; + + const id = Id.fromIds(groupName); + + return new MangoClient( + new Program( + idl as MangoV4, + new PublicKey(id.publicKey), + provider, + ), + new PublicKey(id.publicKey), + id.cluster, + groupName, ); } diff --git a/ts/client/src/ids.ts b/ts/client/src/ids.ts index 663d138c6..56e1c4fa7 100644 --- a/ts/client/src/ids.ts +++ b/ts/client/src/ids.ts @@ -1,47 +1,67 @@ import { Cluster, PublicKey } from '@solana/web3.js'; import ids from '../ids.json'; -import { MANGO_V4_ID } from './constants'; export class Id { constructor( - public banks: Map, - public stubOracles: Map, - public mintInfos: Map, - public serum3Markets: Map, - public serum3MarketExternals: Map, - public perpMarkets: Map, + public cluster: Cluster, + public name: string, + public publicKey: string, + public serum3ProgramId: string, + public mangoProgramId: string, + public banks: { name: string; publicKey: string }[], + public stubOracles: { name: string; publicKey: string }[], + public mintInfos: { name: string; publicKey: string }[], + public serum3Markets: { + name: string; + publicKey: string; + marketExternal: string; + }[], + public perpMarkets: { name: string; publicKey: string }[], ) {} public getBanks(): PublicKey[] { - return Array.from(this.banks.values()); + return Array.from(this.banks.map((bank) => new PublicKey(bank.publicKey))); } public getStubOracles(): PublicKey[] { - return Array.from(this.stubOracles.values()); + return Array.from( + this.stubOracles.map((stubOracle) => new PublicKey(stubOracle.publicKey)), + ); } public getMintInfos(): PublicKey[] { - return Array.from(this.mintInfos.values()); + return Array.from( + this.mintInfos.map((mintInfo) => new PublicKey(mintInfo.publicKey)), + ); } public getSerum3Markets(): PublicKey[] { - return Array.from(this.serum3Markets.values()); + return Array.from( + this.serum3Markets.map( + (serum3Market) => new PublicKey(serum3Market.publicKey), + ), + ); } public getPerpMarkets(): PublicKey[] { - return Array.from(this.perpMarkets.values()); + return Array.from( + this.perpMarkets.map((perpMarket) => new PublicKey(perpMarket.publicKey)), + ); } - static fromIds(cluster: Cluster, programId: PublicKey, group: PublicKey): Id { - let groupConfig = - ids['devnet'][MANGO_V4_ID['devnet'].toBase58()][group.toString()]; + static fromIds(name: string): Id { + let groupConfig = ids.groups.find((id) => id['name'] === name); return new Id( - new Map(Object.entries(groupConfig['banks'])), - new Map(Object.entries(groupConfig['stubOracles'])), - new Map(Object.entries(groupConfig['mintInfos'])), - new Map(Object.entries(groupConfig['serum3Markets'])), - new Map(Object.entries(groupConfig['serum3MarketExternals'])), - new Map(Object.entries(groupConfig['perpMarkets'])), + groupConfig.cluster as Cluster, + name, + groupConfig.publicKey, + groupConfig.serum3ProgramId, + groupConfig.mangoProgramId, + groupConfig['banks'], + groupConfig['stubOracles'], + groupConfig['mintInfos'], + groupConfig['serum3Markets'], + groupConfig['perpMarkets'], ); } } diff --git a/ts/client/src/mango_v4.ts b/ts/client/src/mango_v4.ts index 2ffc1f230..dd811e769 100644 --- a/ts/client/src/mango_v4.ts +++ b/ts/client/src/mango_v4.ts @@ -1875,6 +1875,32 @@ export type MangoV4 = { ], "args": [] }, + { + "name": "computeHealth", + "accounts": [ + { + "name": "group", + "isMut": false, + "isSigner": false + }, + { + "name": "account", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "healthType", + "type": { + "defined": "HealthType" + } + } + ], + "returns": { + "defined": "I80F48" + } + }, { "name": "benchmark", "accounts": [], @@ -2267,13 +2293,22 @@ export type MangoV4 = { "defined": "BookSideType" } }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 3 + ] + } + }, { "name": "bumpIndex", - "type": "u64" + "type": "u32" }, { "name": "freeListLen", - "type": "u64" + "type": "u32" }, { "name": "freeListHead", @@ -2285,7 +2320,7 @@ export type MangoV4 = { }, { "name": "leafCount", - "type": "u64" + "type": "u32" }, { "name": "nodes", @@ -2660,6 +2695,14 @@ export type MangoV4 = { "name": "openOrders", "type": "publicKey" }, + { + "name": "previousNativeCoinReserved", + "type": "u64" + }, + { + "name": "previousNativePcReserved", + "type": "u64" + }, { "name": "marketIndex", "type": "u16" @@ -2861,11 +2904,11 @@ export type MangoV4 = { "fields": [ { "name": "head", - "type": "u64" + "type": "u32" }, { "name": "count", - "type": "u64" + "type": "u32" }, { "name": "seqNum", @@ -5124,6 +5167,32 @@ export const IDL: MangoV4 = { ], "args": [] }, + { + "name": "computeHealth", + "accounts": [ + { + "name": "group", + "isMut": false, + "isSigner": false + }, + { + "name": "account", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "healthType", + "type": { + "defined": "HealthType" + } + } + ], + "returns": { + "defined": "I80F48" + } + }, { "name": "benchmark", "accounts": [], @@ -5516,13 +5585,22 @@ export const IDL: MangoV4 = { "defined": "BookSideType" } }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 3 + ] + } + }, { "name": "bumpIndex", - "type": "u64" + "type": "u32" }, { "name": "freeListLen", - "type": "u64" + "type": "u32" }, { "name": "freeListHead", @@ -5534,7 +5612,7 @@ export const IDL: MangoV4 = { }, { "name": "leafCount", - "type": "u64" + "type": "u32" }, { "name": "nodes", @@ -5909,6 +5987,14 @@ export const IDL: MangoV4 = { "name": "openOrders", "type": "publicKey" }, + { + "name": "previousNativeCoinReserved", + "type": "u64" + }, + { + "name": "previousNativePcReserved", + "type": "u64" + }, { "name": "marketIndex", "type": "u16" @@ -6110,11 +6196,11 @@ export const IDL: MangoV4 = { "fields": [ { "name": "head", - "type": "u64" + "type": "u32" }, { "name": "count", - "type": "u64" + "type": "u32" }, { "name": "seqNum", diff --git a/ts/client/src/scripts/add-group-to-ids-json.ts b/ts/client/src/scripts/add-group-to-ids-json.ts index 76f76fd9f..f126aa45a 100644 --- a/ts/client/src/scripts/add-group-to-ids-json.ts +++ b/ts/client/src/scripts/add-group-to-ids-json.ts @@ -1,9 +1,10 @@ import { AnchorProvider, Wallet } from '@project-serum/anchor'; + import { Connection, Keypair } from '@solana/web3.js'; import fs from 'fs'; import idsJson from '../../ids.json'; import { MangoClient } from '../client'; -import { MANGO_V4_ID } from '../constants'; +import { MANGO_V4_ID, SERUM3_PROGRAM_ID } from '../constants'; import { Id } from '../ids'; function replacer(key, value) { @@ -15,6 +16,9 @@ function replacer(key, value) { } async function main() { + const groupName = 'devnet.microwavedcola'; + const cluster = 'devnet'; + // build client and fetch group for admin const options = AnchorProvider.defaultOptions(); const connection = new Connection( @@ -30,9 +34,8 @@ async function main() { const userProvider = new AnchorProvider(connection, userWallet, options); const client = await MangoClient.connect( userProvider, - 'devnet', - MANGO_V4_ID['devnet'], - false, + cluster, + MANGO_V4_ID[cluster], ); const admin = Keypair.fromSecretKey( Buffer.from( @@ -54,31 +57,43 @@ async function main() { // build ids const toDump = new Id( - new Map(banks.map((tuple) => [tuple.name, tuple.publicKey])), - new Map( - stubOracles.map((tuple) => [ - banksMapByMint.get(tuple.mint.toBase58())!.name, - tuple.publicKey, - ]), - ), - new Map( - mintInfos.map((tuple) => [ - banksMapByMint.get(tuple.mint.toBase58())!.name, - tuple.publicKey, - ]), - ), - new Map(serum3Markets.map((tuple) => [tuple.name, tuple.publicKey])), - new Map( - serum3Markets.map((tuple) => [tuple.name, tuple.serumMarketExternal]), - ), - new Map(perpMarkets.map((tuple) => [tuple.name, tuple.publicKey])), + cluster, + groupName, + group.publicKey.toBase58(), + SERUM3_PROGRAM_ID[cluster].toBase58(), + MANGO_V4_ID[cluster].toBase58(), + banks.map((tuple) => ({ + name: tuple.name, + publicKey: tuple.publicKey.toBase58(), + })), + stubOracles.map((tuple) => ({ + name: banksMapByMint.get(tuple.mint.toBase58())!.name, + publicKey: tuple.publicKey.toBase58(), + })), + mintInfos.map((tuple) => ({ + name: banksMapByMint.get(tuple.mint.toBase58())!.name, + publicKey: tuple.publicKey.toBase58(), + })), + serum3Markets.map((tuple) => ({ + name: tuple.name, + publicKey: tuple.publicKey.toBase58(), + marketExternal: tuple.serumMarketExternal.toBase58(), + })), + perpMarkets.map((tuple) => ({ + name: tuple.name, + publicKey: tuple.publicKey.toBase58(), + })), ); // adds ids for group in existing ids.json - idsJson['devnet'][MANGO_V4_ID['devnet'].toBase58()] = {}; - idsJson['devnet'][MANGO_V4_ID['devnet'].toBase58()][ - group.publicKey.toBase58() - ] = toDump; + const existingGroup = idsJson.groups.find((group) => group.name == groupName); + if (existingGroup) { + console.log('Updating existing group with latest state...'); + } else { + console.log('Group does not exist yet...'); + } + idsJson.groups = idsJson.groups.filter((group) => group.name !== groupName); + idsJson.groups.push(toDump); // dump const file = `${process.cwd()}/ts/client/ids.json`; diff --git a/ts/client/src/scripts/example1-admin-close.ts b/ts/client/src/scripts/example1-admin-close.ts index af8aec3d1..d54e0c7d5 100644 --- a/ts/client/src/scripts/example1-admin-close.ts +++ b/ts/client/src/scripts/example1-admin-close.ts @@ -27,7 +27,6 @@ async function main() { adminProvider, 'devnet', MANGO_V4_ID['devnet'], - false, ); const group = await client.getGroupForAdmin(admin.publicKey); diff --git a/ts/client/src/scripts/example1-admin.ts b/ts/client/src/scripts/example1-admin.ts index e7722c70b..b4c77f627 100644 --- a/ts/client/src/scripts/example1-admin.ts +++ b/ts/client/src/scripts/example1-admin.ts @@ -48,7 +48,6 @@ async function main() { adminProvider, 'devnet', MANGO_V4_ID['devnet'], - false, ); // group @@ -99,7 +98,9 @@ async function main() { } catch (error) { console.log(error); } - const usdcDevnetOracle = (await client.getStubOracle(group, usdcDevnetMint))[0]; + const usdcDevnetOracle = ( + await client.getStubOracle(group, usdcDevnetMint) + )[0]; console.log(`...created stub oracle ${usdcDevnetOracle.publicKey}`); try { await client.tokenRegister( diff --git a/ts/client/src/scripts/example1-ids-json.ts b/ts/client/src/scripts/example1-ids-json.ts index f4c650f64..4652ce6a4 100644 --- a/ts/client/src/scripts/example1-ids-json.ts +++ b/ts/client/src/scripts/example1-ids-json.ts @@ -2,7 +2,6 @@ import { AnchorProvider, Wallet } from '@project-serum/anchor'; import { Connection, Keypair } from '@solana/web3.js'; import fs from 'fs'; import { MangoClient } from '../client'; -import { MANGO_V4_ID } from '../constants'; async function main() { const options = AnchorProvider.defaultOptions(); @@ -18,11 +17,9 @@ async function main() { ); const userWallet = new Wallet(user); const userProvider = new AnchorProvider(connection, userWallet, options); - const client = await MangoClient.connect( + const client = await MangoClient.connectForGroupName( userProvider, - 'devnet', - MANGO_V4_ID['devnet'], - true /* Use ids json instead of getProgramAccounts */, + 'devnet.microwavedcola' /* Use ids json instead of getProgramAccounts */, ); console.log(`User ${userWallet.publicKey.toBase58()}`); diff --git a/ts/client/src/scripts/example1-user.ts b/ts/client/src/scripts/example1-user.ts index c565c39b0..486a2d593 100644 --- a/ts/client/src/scripts/example1-user.ts +++ b/ts/client/src/scripts/example1-user.ts @@ -34,7 +34,6 @@ async function main() { userProvider, 'devnet', MANGO_V4_ID['devnet'], - false, ); console.log(`User ${userWallet.publicKey.toBase58()}`); diff --git a/ts/client/src/scripts/scratch/example1-create-liquidation-candidate.ts b/ts/client/src/scripts/scratch/example1-create-liquidation-candidate.ts index 3451d464b..3c61330d2 100644 --- a/ts/client/src/scripts/scratch/example1-create-liquidation-candidate.ts +++ b/ts/client/src/scripts/scratch/example1-create-liquidation-candidate.ts @@ -23,7 +23,6 @@ async function main() { user1Provider, 'devnet', MANGO_V4_ID['devnet'], - false, ); console.log(`user1 ${user1Wallet.publicKey.toBase58()}`); @@ -64,7 +63,6 @@ async function main() { user2Provider, 'devnet', MANGO_V4_ID['devnet'], - false, ); console.log(`user2 ${user2Wallet.publicKey.toBase58()}`); @@ -111,7 +109,6 @@ async function main() { adminProvider, 'devnet', MANGO_V4_ID['devnet'], - false, ); await client.setStubOracle(group, group.banksMap.get('USDC')?.oracle!, 0.5); diff --git a/ts/client/src/scripts/scratch/example1-ob.ts b/ts/client/src/scripts/scratch/example1-ob.ts index 92a639ee6..5a57faf4d 100644 --- a/ts/client/src/scripts/scratch/example1-ob.ts +++ b/ts/client/src/scripts/scratch/example1-ob.ts @@ -28,7 +28,6 @@ async function main() { userProvider, 'devnet', MANGO_V4_ID['devnet'], - false, ); console.log(`User ${userWallet.publicKey.toBase58()}`); diff --git a/ts/client/src/scripts/scratch/example1-user-account.ts b/ts/client/src/scripts/scratch/example1-user-account.ts index 49850e163..664fa78a7 100644 --- a/ts/client/src/scripts/scratch/example1-user-account.ts +++ b/ts/client/src/scripts/scratch/example1-user-account.ts @@ -29,7 +29,6 @@ async function main() { userProvider, 'devnet', MANGO_V4_ID['devnet'], - false, ); console.log(`User ${userWallet.publicKey.toBase58()}`); diff --git a/ts/client/src/scripts/scratch/scratch.ts b/ts/client/src/scripts/scratch/scratch.ts index 37fe863ac..0a22be10b 100644 --- a/ts/client/src/scripts/scratch/scratch.ts +++ b/ts/client/src/scripts/scratch/scratch.ts @@ -28,7 +28,6 @@ const main = async () => { adminProvider, 'devnet', MANGO_V4_ID['devnet'], - false, ); const btcMint = new PublicKey('3UNBZ6o52WTWwjac2kPUb4FyodhU1vFkRJheu1Sh2TvU');