import { AnchorProvider, Wallet } from '@coral-xyz/anchor'; import { BN } from '@project-serum/anchor'; import { serializeInstructionToBase64 } from '@solana/spl-governance'; import { Connection, Keypair, PublicKey, SystemProgram, TransactionInstruction, } from '@solana/web3.js'; import fs from 'fs'; import { PerpMarketIndex } from '../src/accounts/perp'; import { Builder } from '../src/builder'; import { MangoClient } from '../src/client'; import { NullPerpEditParams, TrueIxGateParams, buildIxGate, } from '../src/clientIxParamBuilder'; import { MANGO_V4_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 groupEdit(): Promise { // 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 { // 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), // 60 * 60, // 0.06, // 0.0003, // percentageToDecimal(20), // new BN(24 * 60 * 60), // new BN(toNative(50000, 6).toNumber()), // 5_000_000_000, // 5_000_000_000, // 0, // 0.0005, // 0.0005, // 0.0005, // ) // .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, // params.tokenConditionalSwapTakerFeeRate, // params.tokenConditionalSwapMakerFeeRate, // params.flashLoanSwapFeeRate, // ) // .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), 0, ) .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, params.platformLiquidationFee, ) .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, 4, 32, 'Mango DAO 0') .accounts({ group: group.publicKey, owner: new PublicKey('5tgfd6XgwiXB9otEnzFpXK11m7Q7yZUaAJzWK4oT5UGF'), payer: new PublicKey('5tgfd6XgwiXB9otEnzFpXK11m7Q7yZUaAJzWK4oT5UGF'), }) .instruction(); console.log(await serializeInstructionToBase64(ix)); } async function idlResize(): Promise { // anchor constant for all idl-specific instructions const idlIxBytes = [0x40, 0xf4, 0xbc, 0x78, 0xa7, 0xe9, 0x69, 0x0a]; const idlIxNum = 6; // resize const newSize = new BN(19000); const ix = new TransactionInstruction({ keys: [ { pubkey: new PublicKey('3foqXduY5PabCn6LjNrLo3waNf3Hy6vQgqavoVUCsUN9'), // idl account isSigner: false, isWritable: true, }, { pubkey: new PublicKey('FP4PxqHTVzeG2c6eZd7974F9WvKUSdBeduUK3rjYyvBw'), // authority isSigner: true, isWritable: true, }, { pubkey: new PublicKey('11111111111111111111111111111111'), // system program isSigner: false, isWritable: false, }, ], programId: MANGO_V4_ID['mainnet-beta'], data: Buffer.from(idlIxBytes.concat([idlIxNum], newSize.toArray('le', 8))), }); console.log(await serializeInstructionToBase64(ix)); } async function idlSetAuthority(): Promise { // anchor constant for all idl-specific instructions const idlIxBytes = [0x40, 0xf4, 0xbc, 0x78, 0xa7, 0xe9, 0x69, 0x0a]; const idlIxNum = 4; // setAuthority const newAuthority = new PublicKey( '8SSLjXBEVk9nesbhi9UMCA32uijbVBUqWoKPPQPTekzt', ); const ix = new TransactionInstruction({ keys: [ { pubkey: new PublicKey('3foqXduY5PabCn6LjNrLo3waNf3Hy6vQgqavoVUCsUN9'), // idl account isSigner: false, isWritable: true, }, { pubkey: new PublicKey('FP4PxqHTVzeG2c6eZd7974F9WvKUSdBeduUK3rjYyvBw'), // authority isSigner: true, isWritable: true, }, ], programId: MANGO_V4_ID['mainnet-beta'], data: Buffer.concat([ Buffer.from(idlIxBytes.concat([idlIxNum])), newAuthority.toBuffer(), ]), }); console.log(await serializeInstructionToBase64(ix)); } async function main(): Promise { try { // await groupEdit(); // await tokenRegister(); // await tokenEdit(); // await perpCreate(); // await perpEdit(); // await serum3Register(); // await ixDisable(); // await createMangoAccount(); // await idlResize(); // await idlSetAuthority(); } catch (error) { console.log(error); } } try { main(); } catch (error) { console.log(error); }