390 lines
11 KiB
TypeScript
390 lines
11 KiB
TypeScript
import { AnchorProvider, BN, Wallet } from '@coral-xyz/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<MangoClient> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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);
|
|
}
|