import { AnchorProvider } from '@coral-xyz/anchor'; import { BN, Wallet } from '@project-serum/anchor'; import { serializeInstructionToBase64 } from '@solana/spl-governance'; import { AccountMeta, Connection, Keypair, PublicKey, SYSVAR_RENT_PUBKEY, SystemProgram, } from '@solana/web3.js'; import fs from 'fs'; import { TokenIndex } from '../src/accounts/bank'; import { PerpMarketIndex } from '../src/accounts/perp'; import { Builder } from '../src/builder'; import { MangoClient } from '../src/client'; import { NullPerpEditParams, NullTokenEditParams, TrueIxGateParams, buildIxGate, } from '../src/clientIxParamBuilder'; import { MANGO_V4_ID, OPENBOOK_PROGRAM_ID } from '../src/constants'; 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 defaultOracleConfig = { confFilter: 0.1, maxStalenessSlots: 120, }; const defaultInterestRate = { adjustmentFactor: 0.004, util0: 0.7, rate0: 0.1, util1: 0.85, rate1: 0.2, maxRate: 2.0, }; async function buildClient(): Promise { const clientKeypair = Keypair.fromSecretKey( Buffer.from(JSON.parse(fs.readFileSync(CLIENT_USER!, 'utf-8'))), ); const options = AnchorProvider.defaultOptions(); const connection = new Connection(MB_CLUSTER_URL!, options); const clientWallet = new Wallet(clientKeypair); const clientProvider = new AnchorProvider(connection, clientWallet, options); return await MangoClient.connect( clientProvider, 'mainnet-beta', MANGO_V4_ID['mainnet-beta'], { idsSource: 'get-program-accounts', }, ); } async function tokenRegister(): Promise { const client = await buildClient(); const group = await client.getGroup(new PublicKey(GROUP_PK)); const ix = await client.program.methods .tokenRegister( 8 as TokenIndex, 'wBTC (Portal)', defaultOracleConfig, defaultInterestRate, bpsToDecimal(50), bpsToDecimal(5), 0.9, 0.8, 1.1, 1.2, percentageToDecimal(5), percentageToDecimal(20), new BN(24 * 60 * 60), new BN(toNative(50000, 6).toNumber()), ) .accounts({ group: group.publicKey, admin: group.admin, mint: new PublicKey('3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh'), oracle: new PublicKey('GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU'), payer: (client.program.provider as AnchorProvider).wallet.publicKey, rent: SYSVAR_RENT_PUBKEY, }) .instruction(); // const coder = new BorshCoder(IDL); // console.log(coder.instruction.decode(ix.data)); console.log(await serializeInstructionToBase64(ix)); } async function tokenEdit(): Promise { const client = await buildClient(); const group = await client.getGroup(new PublicKey(GROUP_PK)); const params = Builder(NullTokenEditParams) .borrowWeightScaleStartQuote(new BN(toNative(100000, 6)).toNumber()) .depositWeightScaleStartQuote(new BN(toNative(100000, 6)).toNumber()) .build(); const ix = await client.program.methods .tokenEdit( params.oracle, params.oracleConfig, params.groupInsuranceFund, params.interestRateParams, params.loanFeeRate, params.loanOriginationFeeRate, params.maintAssetWeight, params.initAssetWeight, params.maintLiabWeight, params.initLiabWeight, params.liquidationFee, params.stablePriceDelayIntervalSeconds, params.stablePriceDelayGrowthLimit, params.stablePriceGrowthLimit, params.minVaultToDepositsRatio, params.netBorrowLimitPerWindowQuote !== null ? new BN(params.netBorrowLimitPerWindowQuote) : null, params.netBorrowLimitWindowSizeTs !== null ? new BN(params.netBorrowLimitWindowSizeTs) : null, params.borrowWeightScaleStartQuote, params.depositWeightScaleStartQuote, params.resetStablePrice ?? false, params.resetNetBorrowLimit ?? false, params.reduceOnly, params.name, params.forceClose, ) .accounts({ group: group.publicKey, oracle: new PublicKey('GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU'), admin: group.admin, mintInfo: new PublicKey('59rgC1pa45EziDPyFgJgE7gbv7Dd7VaGmd2D93i1dtFk'), }) .remainingAccounts([ { pubkey: new PublicKey('8gabXzwdPn5TvtuQvysh3CxVbjfNY3TZd5XEG5qnueUm'), isWritable: true, isSigner: false, } as AccountMeta, ]) .instruction(); console.log(serializeInstructionToBase64(ix)); } async function serum3Register(): Promise { const client = await buildClient(); const group = await client.getGroup(new PublicKey(GROUP_PK)); const ix = await client.program.methods .serum3RegisterMarket(3, 'ETH (Portal)/USDC') .accounts({ group: group.publicKey, admin: group.admin, serumProgram: OPENBOOK_PROGRAM_ID['mainnet-beta'], serumMarketExternal: new PublicKey( 'BbJgE7HZMaDp5NTYvRh5jZSkQPVDTU8ubPFtpogUkEj4', ), baseBank: group.getFirstBankByMint( new PublicKey('7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs'), ).publicKey, quoteBank: group.getFirstBankByMint( new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'), ).publicKey, payer: (client.program.provider as AnchorProvider).wallet.publicKey, }) .instruction(); console.log(serializeInstructionToBase64(ix)); } async function perpCreate(): Promise { const client = await buildClient(); const bids = new Keypair(); const asks = new Keypair(); const eventQueue = new Keypair(); const bookSideSize = (client.program as any)._coder.accounts.size( (client.program.account.bookSide as any)._idlAccount, ); const eventQueueSize = (client.program as any)._coder.accounts.size( (client.program.account.eventQueue as any)._idlAccount, ); const group = await client.getGroup(new PublicKey(GROUP_PK)); const ix = await client.program.methods .perpCreateMarket( 2, 'SOL-PERP', defaultOracleConfig, 9, new BN(100), new BN(10000000), 0.9, 0.8, 1.1, 1.2, 0, 0, percentageToDecimal(5), bpsToDecimal(-1), bpsToDecimal(4), percentageToDecimal(-5), percentageToDecimal(5), new BN(100), false, bpsToDecimal(0.5), toNative(0.0001, 6).toNumber(), toNative(100, 6).toNumber(), percentageToDecimal(1), 0, 1, new BN(60 * 60), percentageToDecimal(10), ) .accounts({ group: group.publicKey, admin: group.admin, oracle: new PublicKey('H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG'), bids: bids.publicKey, asks: asks.publicKey, eventQueue: eventQueue.publicKey, payer: (client.program.provider as AnchorProvider).wallet.publicKey, }) .preInstructions([ // book sides SystemProgram.createAccount({ programId: client.program.programId, space: bookSideSize, lamports: await client.program.provider.connection.getMinimumBalanceForRentExemption( bookSideSize, ), fromPubkey: (client.program.provider as AnchorProvider).wallet .publicKey, newAccountPubkey: bids.publicKey, }), SystemProgram.createAccount({ programId: client.program.programId, space: bookSideSize, lamports: await client.program.provider.connection.getMinimumBalanceForRentExemption( bookSideSize, ), fromPubkey: (client.program.provider as AnchorProvider).wallet .publicKey, newAccountPubkey: asks.publicKey, }), // event queue SystemProgram.createAccount({ programId: client.program.programId, space: eventQueueSize, lamports: await client.program.provider.connection.getMinimumBalanceForRentExemption( eventQueueSize, ), fromPubkey: (client.program.provider as AnchorProvider).wallet .publicKey, newAccountPubkey: eventQueue.publicKey, }), ]) .signers([bids, asks, eventQueue]) .instruction(); console.log(serializeInstructionToBase64(ix)); } async function perpEdit(): Promise { const client = await buildClient(); const group = await client.getGroup(new PublicKey(GROUP_PK)); const perpMarket = group.getPerpMarketByMarketIndex(0 as PerpMarketIndex); const params = Builder(NullPerpEditParams) .positivePnlLiquidationFee(bpsToDecimal(250)) .build(); const ix = await client.program.methods .perpEditMarket( params.oracle, params.oracleConfig, params.baseDecimals, params.maintBaseAssetWeight, params.initBaseAssetWeight, params.maintBaseLiabWeight, params.initBaseLiabWeight, params.maintOverallAssetWeight, params.initOverallAssetWeight, params.baseLiquidationFee, params.makerFee, params.takerFee, params.minFunding, params.maxFunding, params.impactQuantity !== null ? new BN(params.impactQuantity) : null, params.groupInsuranceFund, params.feePenalty, params.settleFeeFlat, params.settleFeeAmountThreshold, params.settleFeeFractionLowHealth, params.stablePriceDelayIntervalSeconds, params.stablePriceDelayGrowthLimit, params.stablePriceGrowthLimit, params.settlePnlLimitFactor, params.settlePnlLimitWindowSize !== null ? new BN(params.settlePnlLimitWindowSize) : null, params.reduceOnly, params.resetStablePrice ?? false, params.positivePnlLiquidationFee, params.name, params.forceClose, ) .accounts({ group: group.publicKey, oracle: params.oracle ?? perpMarket.oracle, admin: group.admin, perpMarket: perpMarket.publicKey, }) .instruction(); console.log(serializeInstructionToBase64(ix)); } async function ixDisable(): Promise { const client = await buildClient(); const group = await client.getGroup(new PublicKey(GROUP_PK)); const ixGateParams = TrueIxGateParams; ixGateParams.HealthRegion = false; const ix = await client.program.methods .ixGateSet(buildIxGate(ixGateParams)) .accounts({ group: group.publicKey, admin: group.securityAdmin, }) .instruction(); console.log(await serializeInstructionToBase64(ix)); } async function createMangoAccount(): Promise { const client = await buildClient(); const group = await client.getGroup(new PublicKey(GROUP_PK)); const ix = await client.program.methods .accountCreate(0, 8, 8, 8, 32, 'Mango DAO 0') .accounts({ group: group.publicKey, owner: new PublicKey('5tgfd6XgwiXB9otEnzFpXK11m7Q7yZUaAJzWK4oT5UGF'), payer: new PublicKey('5tgfd6XgwiXB9otEnzFpXK11m7Q7yZUaAJzWK4oT5UGF'), }) .instruction(); console.log(await serializeInstructionToBase64(ix)); } async function main(): Promise { try { // await tokenRegister(); // await tokenEdit(); // await perpCreate(); await perpEdit(); // await serum3Register(); // await ixDisable(); // await createMangoAccount(); } catch (error) { console.log(error); } } try { main(); } catch (error) { console.log(error); }