mango-v4/ts/client/scripts/mainnet-no-margin-group.ts

482 lines
12 KiB
TypeScript

import { AnchorProvider, Wallet } from '@coral-xyz/anchor';
import {
AddressLookupTableProgram,
ComputeBudgetProgram,
Connection,
Keypair,
PublicKey,
SYSVAR_INSTRUCTIONS_PUBKEY,
SYSVAR_RENT_PUBKEY,
SystemProgram,
} from '@solana/web3.js';
import fs from 'fs';
import { TokenIndex } from '../src/accounts/bank';
import { Group } from '../src/accounts/group';
import { MangoClient } from '../src/client';
import { DefaultTokenRegisterParams } from '../src/clientIxParamBuilder';
import { MANGO_V4_ID } from '../src/constants';
import { buildVersionedTx } from '../src/utils';
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
NATIVE_MINT,
TOKEN_PROGRAM_ID,
} from '../src/utils/spl';
const MANGO_PROGRAM = MANGO_V4_ID['mainnet-beta'];
const MAINNET_MINTS = new Map([
['USDC', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'], // 0
['SOL', 'So11111111111111111111111111111111111111112'], // 1
]);
const MAINNET_ORACLES = new Map([
['USDC', 'Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD'],
['SOL', 'H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG'],
]);
const MAINNET_SERUM3_MARKETS = new Map([
['SOL/USDC', '8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6'],
]);
const {
MB_CLUSTER_URL,
MB_PAYER_KEYPAIR,
GROUP_NUM,
}: {
MB_CLUSTER_URL: string;
MB_PAYER_KEYPAIR: string;
GROUP_NUM: number;
} = process.env as any;
const defaultOracleConfig = {
confFilter: 0.1,
maxStalenessSlots: null,
};
const defaultInterestRate = {
adjustmentFactor: 0.0,
util0: 0.0,
rate0: 0.0,
util1: 0.0,
rate1: 0.0,
maxRate: 0.51,
};
const defaultTokenParams = {
...DefaultTokenRegisterParams,
oracleConfig: defaultOracleConfig,
interestRateParams: defaultInterestRate,
loanOriginationFeeRate: 0.0,
loanFeeRate: 0.0,
initAssetWeight: 0,
maintAssetWeight: 0,
initLiabWeight: 1,
maintLiabWeight: 1,
liquidationFee: 0,
minVaultToDepositsRatio: 1,
netBorrowLimitPerWindowQuote: 0,
};
async function buildAdminClient(): Promise<[MangoClient, Keypair]> {
const admin = Keypair.fromSecretKey(
Buffer.from(JSON.parse(fs.readFileSync(MB_PAYER_KEYPAIR!, 'utf-8'))),
);
const options = AnchorProvider.defaultOptions();
const connection = new Connection(MB_CLUSTER_URL!, options);
const adminWallet = new Wallet(admin);
const adminProvider = new AnchorProvider(connection, adminWallet, options);
const client = await MangoClient.connect(
adminProvider,
'mainnet-beta',
MANGO_PROGRAM,
{
idsSource: 'get-program-accounts',
},
);
return [client, admin];
}
async function buildUserClient(): Promise<[MangoClient, Group, Keypair]> {
const options = AnchorProvider.defaultOptions();
const connection = new Connection(MB_CLUSTER_URL!, options);
const user = Keypair.fromSecretKey(
Buffer.from(JSON.parse(fs.readFileSync(MB_PAYER_KEYPAIR, 'utf-8'))),
);
const userWallet = new Wallet(user);
const userProvider = new AnchorProvider(connection, userWallet, options);
const client = await MangoClient.connect(
userProvider,
'mainnet-beta',
MANGO_PROGRAM,
);
const group = await client.getGroupForCreator(user.publicKey, GROUP_NUM);
return [client, group, user];
}
async function createGroup(): Promise<void> {
const result = await buildAdminClient();
const client = result[0];
const admin = result[1];
const insuranceMint = new PublicKey(MAINNET_MINTS.get('USDC')!);
await client.groupCreate(GROUP_NUM, true, 2, insuranceMint);
const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM);
console.log(`...registered group ${group.publicKey}`);
await client.groupEdit(
group,
undefined, // admin
admin.publicKey, // fast listing
);
console.log(`...set fast listing admin`);
}
async function registerTokens(): Promise<void> {
const result = await buildAdminClient();
const client = result[0];
const admin = result[1];
const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM);
const usdcMainnetMint = new PublicKey(MAINNET_MINTS.get('USDC')!);
const usdcMainnetOracle = new PublicKey(MAINNET_ORACLES.get('USDC')!);
let sig = await client.tokenRegister(
group,
usdcMainnetMint,
usdcMainnetOracle,
PublicKey.default,
0,
'USDC',
defaultTokenParams,
);
console.log(`registered usdc ${sig}`);
const solMainnetMint = new PublicKey(MAINNET_MINTS.get('SOL')!);
const solMainnetOracle = new PublicKey(MAINNET_ORACLES.get('SOL')!);
sig = await client.tokenRegisterTrustless(
group,
solMainnetMint,
solMainnetOracle,
1,
'SOL',
);
console.log(`registered sol ${sig}`);
}
async function registerSerum3Market(): Promise<void> {
const result = await buildAdminClient();
const client = result[0];
const admin = result[1];
const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM);
await client.serum3RegisterMarket(
group,
new PublicKey(MAINNET_SERUM3_MARKETS.get('SOL/USDC')!),
group.getFirstBankByTokenIndex(1 as TokenIndex),
group.getFirstBankByTokenIndex(0 as TokenIndex),
0,
'SOL/USDC',
0.5,
);
}
async function createAndPopulateAlt() {
const result = await buildAdminClient();
const client = result[0];
const admin = result[1];
const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM);
const connection = client.program.provider.connection;
// Create ALT, and set to group at index 0
if (group.addressLookupTables[0].equals(PublicKey.default)) {
try {
console.log(`ALT: Creating`);
const createIx = AddressLookupTableProgram.createLookupTable({
authority: admin.publicKey,
payer: admin.publicKey,
recentSlot: await connection.getSlot('finalized'),
});
const createTx = await buildVersionedTx(
client.program.provider as AnchorProvider,
[createIx[0]],
);
let sig = await connection.sendTransaction(createTx);
console.log(
`...created ALT ${createIx[1]} https://explorer.solana.com/tx/${sig}`,
);
console.log(`ALT: set at index 0 for group...`);
sig = (await client.altSet(group, createIx[1], 0)).signature;
console.log(`...https://explorer.solana.com/tx/${sig}`);
} catch (error) {
console.log(error);
}
}
// Extend using mango v4 relevant pub keys
try {
const bankAddresses = Array.from(group.banksMapByMint.values())
.flat()
.map((bank) => [bank.publicKey, bank.oracle, bank.vault])
.flat()
.concat(
Array.from(group.banksMapByMint.values())
.flat()
.map((mintInfo) => mintInfo.publicKey),
);
const serum3MarketAddresses = Array.from(
group.serum3MarketsMapByExternal.values(),
)
.flat()
.map((serum3Market) => serum3Market.publicKey);
const serum3ExternalMarketAddresses = Array.from(
group.serum3ExternalMarketsMap.values(),
)
.flat()
.map((serum3ExternalMarket) => [
serum3ExternalMarket.publicKey,
serum3ExternalMarket.bidsAddress,
serum3ExternalMarket.asksAddress,
])
.flat();
const perpMarketAddresses = Array.from(
group.perpMarketsMapByMarketIndex.values(),
)
.flat()
.map((perpMarket) => [
perpMarket.publicKey,
perpMarket.oracle,
perpMarket.bids,
perpMarket.asks,
perpMarket.eventQueue,
])
.flat();
// eslint-disable-next-line no-inner-declarations
async function extendTable(addresses: PublicKey[]): Promise<void> {
await group.reloadAll(client);
const alt =
await client.program.provider.connection.getAddressLookupTable(
group.addressLookupTables[0],
);
addresses = addresses.filter(
(newAddress) =>
alt.value?.state.addresses &&
alt.value?.state.addresses.findIndex((addressInALt) =>
addressInALt.equals(newAddress),
) === -1,
);
if (addresses.length === 0) {
return;
}
const extendIx = AddressLookupTableProgram.extendLookupTable({
lookupTable: group.addressLookupTables[0],
payer: admin.publicKey,
authority: admin.publicKey,
addresses,
});
const extendTx = await buildVersionedTx(
client.program.provider as AnchorProvider,
[extendIx],
);
const sig = await client.program.provider.connection.sendTransaction(
extendTx,
);
console.log(`https://explorer.solana.com/tx/${sig}`);
}
console.log(`ALT: extending using mango v4 relevant public keys`);
await extendTable(bankAddresses);
await extendTable(serum3MarketAddresses);
await extendTable(serum3ExternalMarketAddresses);
// TODO: dont extend for perps atm
await extendTable(perpMarketAddresses);
// Well known addresses
await extendTable([
SystemProgram.programId,
SYSVAR_RENT_PUBKEY,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID,
NATIVE_MINT,
SYSVAR_INSTRUCTIONS_PUBKEY,
ComputeBudgetProgram.programId,
]);
} catch (error) {
console.log(error);
}
}
async function doUserAction(): Promise<void> {
const result = await buildUserClient();
const client = result[0];
const group = result[1];
const user = result[2];
let mangoAccount = await client.getMangoAccountForOwner(
group,
user.publicKey,
0,
);
if (!mangoAccount) {
await client.createMangoAccount(group, 0);
mangoAccount = await client.getMangoAccountForOwner(
group,
user.publicKey,
0,
);
}
// await client.tokenDeposit(
// group,
// mangoAccount!,
// new PublicKey(MAINNET_MINTS.get('SOL')!),
// 0.01,
// );
// await client.tcsStopLossOnDeposit(
// group,
// mangoAccount!,
// group.getFirstBankByTokenIndex(1 as TokenIndex),
// group.getFirstBankByTokenIndex(0 as TokenIndex),
// group.getFirstBankByTokenIndex(1 as TokenIndex).uiPrice * 1.1,
// false,
// null,
// null,
// null,
// );
await mangoAccount?.reload(client);
mangoAccount
?.tokenConditionalSwapsActive()
.map((tcs) => console.log(tcs.toString(group)));
}
async function doUserAction2(): Promise<void> {
const result = await buildUserClient();
const client = result[0];
const group = result[1];
const user = result[2];
let mangoAccount = await client.getMangoAccountForOwner(
group,
user.publicKey,
1,
);
if (!mangoAccount) {
await client.createMangoAccount(group, 1);
mangoAccount = await client.getMangoAccountForOwner(
group,
user.publicKey,
1,
);
}
await client.tokenDeposit(
group,
mangoAccount!,
new PublicKey(MAINNET_MINTS.get('USDC')!),
5,
);
}
async function placeAuction(): Promise<void> {
const result = await buildUserClient();
const client = result[0];
const group = result[1];
const user = result[2];
const mangoAccount = await client.getMangoAccountForOwner(
group,
user.publicKey,
1,
);
console.log(mangoAccount?.publicKey.toString());
const usdcBank = group.getFirstBankByMint(
new PublicKey(MAINNET_MINTS.get('USDC')!),
);
const solBank = group.getFirstBankByMint(
new PublicKey(MAINNET_MINTS.get('SOL')!),
);
await client.tokenConditionalSwapCancelAll(group, mangoAccount!);
for (let i = 0; i < 3; i += 1) {
await client.tokenConditionalSwapCreateLinearAuction(
group,
mangoAccount!,
usdcBank,
solBank,
20.0,
24.0,
0.1,
Number.MAX_SAFE_INTEGER,
true,
false,
true,
Math.floor(Date.now() / 1000) + 10,
180000,
null,
);
}
// await client.tokenConditionalSwapCreateLinearAuction(
// group,
// mangoAccount!,
// solBank,
// usdcBank,
// 1 / 24.0,
// 1 / 19.0,
// 2.0,
// Number.MAX_SAFE_INTEGER,
// true,
// false,
// true,
// Math.floor(Date.now() / 1000) + 300,
// 180,
// null,
// );
// await client.tokenConditionalSwapCreatePremiumAuction(
// group,
// mangoAccount!,
// usdcBank,
// solBank,
// 20.0,
// 26.0,
// 2.0,
// Number.MAX_SAFE_INTEGER,
// null,
// 1, // in percent, eww
// true,
// false,
// null,
// true,
// 300,
// );
}
async function main(): Promise<void> {
try {
// await createGroup();
// await registerTokens();
// await registerSerum3Market();
// await createAndPopulateAlt();
// await doUserAction();
// await doUserAction2();
await placeAuction();
} catch (error) {
console.log(error);
}
}
main();