mango-v4/ts/client/scripts/liqtest/liqtest-create-group.ts

370 lines
9.7 KiB
TypeScript
Raw Normal View History

import { AnchorProvider, Wallet } from '@coral-xyz/anchor';
import {
AddressLookupTableProgram,
Connection,
Keypair,
PublicKey,
} from '@solana/web3.js';
import fs from 'fs';
Merge dev changes (#532) * Fix script Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Fix docs build job (#501) * workaround where rpc rejects base58 encoded pubkeys (#502) Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Rename settle-bot to settler, fix build (#492) * Fix settler build, rename due to heroku not liking '-' * Temporarily remove ref tag * Remove temporary branch trigger * Add oracleProvider to Bank and PerpMarket (#491) * Add oracleProvider to Bank and PerpMarket * v0.9.6 * Fix null checks on getters for PerpMarket and Bank (#505) * Export OracleProvider * Fix null checks on getters * token_liq_bankruptcy: Use oracle for valuing insurance fund tokens (#503) Previously a token from the insurance fund was valued at 1 USD. Now it uses the oracle associated with it (USDC oracle). * v0.9.7 * ts: Fix ix gate enum, add code for creating a disable-tx gov ix * Fee buyback: Respect USDC oracle (#504) * refactor script (#509) Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * IxGateSet: Log AccountBuybackFeesWithMngo state * TokenRegister: Sanity checks on token_index * Allow token/market names to fill storage bytes completely Previously the last byte was always zero. * HealthRegion: Whitelist allowed instruction types (#508) This fixes a security issue where bankruptcy related instructions could be called inside a health region. Now health regions are limited to compute optimization like when placing multiple orders in one transaction. This limitation also makes it impossible to abuse health regions for flash loans. Use the FlashLoan instructions for that purpose. * Add fly deploy scripts (#490) * Bump program version to v0.10.0 * liquidator docs (#512) * liquidator docs Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * update Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * update Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> --------- Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Quality of life fixes (#511) * breaking: make pegLimit an optional arg * pass externally cached blockhashes to sendTransaction * convenience accessors for connection & walletPk on client * add script to sim accounts with leverage change (#514) Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Fix bug: only account for borrows we are offsetting (#513) * Fix bug: only account for borrows we are offsetting Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * fix Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Bank: Unittest for net borrow limits --------- Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> Co-authored-by: Christian Kamm <mail@ckamm.de> * extend script, fix util function Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Fix interest rate computation in client (#520) Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * minor ts fixes Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Temporarily disable health region use on mm script (#507) * Use new shared mango-feeds-connector crate for chain_data (#515) * Add prometheus metrics to crank (#517) * Add prometheus metrics to keeper * update script Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * fix bug where unrealised profit was not abs'ed Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Fix script Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * update script Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * in perp settle fees, dont error, rather return early, this enables blindly concatenating perp settle fees to perp settle pnl (#526) * in perp settle fees, dont error, rather return early Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Fixes from review Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> --------- Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * update script Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Net borrow limits: Use correct price for check (#527) * Changelog for program-v0.10.0 and idl update * script for grabbing logs Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Perp funding: Fix logging in update funding + deactivate pos (#528) * update Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Fix test Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * sync rate params to latest proposal (#523) * sync rate params to latest proposal Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Fixes from review Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Fixes from review Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> --------- Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Limit funding and interest accrual during downtimes (#529) Previously, if the funding or interest updating instruction wasn't called for a long time (like for a solana downtime or the security council halting the program), the next update would apply funding or interest for the whole time interval since the last update. This could lead to a bad downtime situation becoming worse. Instead, limit the maximum funding and interest time interval to one hour. * Changelog for program-v0.11.0, bump version, update idl * Don't reload openorders if there's no active markets * update Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * reorg Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Emit perp fees settled on update_funding. Required to have a full picture of total perp market fees. (#530) --------- Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> Co-authored-by: microwavedcola1 <microwavedcola@gmail.com> Co-authored-by: microwavedcola1 <89031858+microwavedcola1@users.noreply.github.com> Co-authored-by: Christian Kamm <mail@ckamm.de> Co-authored-by: Maximilian Schneider <mail@maximilianschneider.net> Co-authored-by: tlrsssss <tjshipe@gmail.com> Co-authored-by: Nicholas Clarke <nicholasgclarke@gmail.com>
2023-04-07 05:57:53 -07:00
import { MangoClient } from '../../src/client';
import { MANGO_V4_ID } from '../../src/constants';
//
// Script which depoys a new mango group, and registers 3 tokens
// with stub oracles
//
// default to group 1, to not conflict with the normal group
2022-09-01 02:47:37 -07:00
const GROUP_NUM = Number(process.env.GROUP_NUM || 200);
const MAINNET_MINTS = new Map([
['USDC', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'],
['ETH', '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs'],
['SOL', 'So11111111111111111111111111111111111111112'],
['MNGO', 'MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac'],
]);
const STUB_PRICES = new Map([
['USDC', 1.0],
['ETH', 1200.0], // eth and usdc both have 6 decimals
['SOL', 0.015], // sol has 9 decimals, equivalent to $15 per SOL
['MNGO', 0.02], // same price/decimals as SOL for convenience
]);
2022-09-01 02:47:37 -07:00
// External markets are matched with those in https://github.com/blockworks-foundation/mango-client-v3/blob/main/src/ids.json
// and verified to have best liquidity for pair on https://openserum.io/
const MAINNET_SERUM3_MARKETS = new Map([
['ETH/USDC', 'FZxi3yWkE5mMjyaZj6utmYL54QQYfMCKMcLaQZq4UwnA'],
['SOL/USDC', '8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6'],
2022-09-01 02:47:37 -07:00
]);
const MIN_VAULT_TO_DEPOSITS_RATIO = 0.2;
const NET_BORROWS_WINDOW_SIZE_TS = 24 * 60 * 60;
const NET_BORROWS_LIMIT_NATIVE = 1 * Math.pow(10, 7) * Math.pow(10, 6);
async function main() {
const options = AnchorProvider.defaultOptions();
options.commitment = 'processed';
options.preflightCommitment = 'finalized';
2022-09-01 02:47:37 -07:00
const connection = new Connection(process.env.CLUSTER_URL!, options);
const admin = Keypair.fromSecretKey(
Buffer.from(
JSON.parse(
fs.readFileSync(process.env.MANGO_MAINNET_PAYER_KEYPAIR!, 'utf-8'),
),
),
);
const adminWallet = new Wallet(admin);
console.log(`Admin ${adminWallet.publicKey.toBase58()}`);
const adminProvider = new AnchorProvider(connection, adminWallet, options);
const client = await MangoClient.connect(
adminProvider,
'mainnet-beta',
MANGO_V4_ID['mainnet-beta'],
{
idsSource: 'get-program-accounts',
prioritizationFee: 100,
txConfirmationCommitment: 'confirmed',
},
);
// group
console.log(`Creating Group...`);
try {
const insuranceMint = new PublicKey(MAINNET_MINTS.get('USDC')!);
await client.groupCreate(GROUP_NUM, true, 0, insuranceMint);
} catch (error) {
console.log(error);
}
const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM);
console.log(`...registered group ${group.publicKey}`);
// stub oracles
let oracles = new Map();
for (let [name, mint] of MAINNET_MINTS) {
console.log(`Creating stub oracle for ${name}...`);
const mintPk = new PublicKey(mint);
try {
2022-09-01 02:47:37 -07:00
const price = STUB_PRICES.get(name)!;
2022-08-09 01:57:03 -07:00
await client.stubOracleCreate(group, mintPk, price);
} catch (error) {
console.log(error);
}
2022-08-08 07:31:38 -07:00
const oracle = (await client.getStubOracle(group, mintPk))[0];
console.log(`...created stub oracle ${oracle.publicKey}`);
oracles.set(name, oracle.publicKey);
}
const defaultOracleConfig = {
confFilter: 0.1,
maxStalenessSlots: null,
};
const defaultInterestRate = {
adjustmentFactor: 0.01,
util0: 0.4,
rate0: 0.07,
util1: 0.8,
rate1: 0.9,
maxRate: 1.5,
};
2022-09-01 02:47:37 -07:00
// register token 0
console.log(`Registering USDC...`);
const usdcMainnetMint = new PublicKey(MAINNET_MINTS.get('USDC')!);
const usdcMainnetOracle = oracles.get('USDC');
try {
await client.tokenRegister(
group,
2022-09-01 02:47:37 -07:00
usdcMainnetMint,
usdcMainnetOracle,
defaultOracleConfig,
2022-09-01 02:47:37 -07:00
0,
'USDC',
defaultInterestRate,
2022-08-08 08:48:55 -07:00
0.0,
2022-08-09 01:57:03 -07:00
0.0001,
2022-09-01 02:47:37 -07:00
1,
1,
1,
1,
0,
MIN_VAULT_TO_DEPOSITS_RATIO,
NET_BORROWS_WINDOW_SIZE_TS,
NET_BORROWS_LIMIT_NATIVE,
);
await group.reloadAll(client);
} catch (error) {
console.log(error);
}
2022-09-01 02:47:37 -07:00
// register token 1
console.log(`Registering ETH...`);
const ethMainnetMint = new PublicKey(MAINNET_MINTS.get('ETH')!);
const ethMainnetOracle = oracles.get('ETH');
try {
await client.tokenRegister(
group,
ethMainnetMint,
ethMainnetOracle,
defaultOracleConfig,
2022-09-01 02:47:37 -07:00
1,
'ETH',
defaultInterestRate,
2022-08-08 08:48:55 -07:00
0.0,
2022-08-09 01:57:03 -07:00
0.0001,
2022-09-01 02:47:37 -07:00
0.9,
0.8,
1.1,
1.2,
0.05,
MIN_VAULT_TO_DEPOSITS_RATIO,
NET_BORROWS_WINDOW_SIZE_TS,
NET_BORROWS_LIMIT_NATIVE,
);
await group.reloadAll(client);
} catch (error) {
console.log(error);
}
// register token 2
console.log(`Registering SOL...`);
const solMainnetMint = new PublicKey(MAINNET_MINTS.get('SOL')!);
const solMainnetOracle = oracles.get('SOL');
try {
await client.tokenRegister(
group,
solMainnetMint,
solMainnetOracle,
defaultOracleConfig,
2, // tokenIndex
'SOL',
defaultInterestRate,
2022-08-08 08:48:55 -07:00
0.0,
2022-08-09 01:57:03 -07:00
0.0001,
0.9,
0.8,
1.1,
1.2,
0.05,
MIN_VAULT_TO_DEPOSITS_RATIO,
NET_BORROWS_WINDOW_SIZE_TS,
NET_BORROWS_LIMIT_NATIVE,
);
await group.reloadAll(client);
} catch (error) {
console.log(error);
}
// log tokens/banks
2022-09-01 02:47:37 -07:00
for (const bank of await group.banksMapByMint.values()) {
console.log(`${bank.toString()}`);
}
2022-09-01 04:43:17 -07:00
console.log('Registering SOL/USDC serum market...');
try {
await client.serum3RegisterMarket(
group,
new PublicKey(MAINNET_SERUM3_MARKETS.get('SOL/USDC')!),
group.getFirstBankByMint(new PublicKey(MAINNET_MINTS.get('SOL')!)),
group.getFirstBankByMint(new PublicKey(MAINNET_MINTS.get('USDC')!)),
1,
'SOL/USDC',
);
} catch (error) {
console.log(error);
}
console.log('Registering MNGO-PERP market...');
const mngoMainnetOracle = oracles.get('MNGO');
try {
await client.perpCreateMarket(
group,
mngoMainnetOracle,
0,
'MNGO-PERP',
defaultOracleConfig,
6,
10,
100000, // base lots
0.9,
0.8,
1.1,
1.2,
0.0,
0.0,
0.05,
-0.001,
0.002,
0,
-0.1,
0.1,
10,
false,
0,
0,
0,
0,
-1.0,
2 * 60 * 60,
0.025,
);
} catch (error) {
console.log(error);
}
2022-09-01 04:43:17 -07:00
await createAndPopulateAlt(client, admin);
process.exit();
}
main();
async function createAndPopulateAlt(client: MangoClient, admin: Keypair) {
let 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'),
});
let sig = await client.sendAndConfirmTransaction([createIx[0]]);
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);
console.log(`...https://explorer.solana.com/tx/${sig}`);
group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM);
} catch (error) {
console.log(error);
}
}
// Extend using mango v4 relevant pub keys
try {
let 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),
);
let serum3MarketAddresses = Array.from(
group.serum3MarketsMapByExternal.values(),
)
.flat()
.map((serum3Market) => serum3Market.publicKey);
let serum3ExternalMarketAddresses = Array.from(
group.serum3ExternalMarketsMap.values(),
)
.flat()
.map((serum3ExternalMarket) => [
serum3ExternalMarket.publicKey,
serum3ExternalMarket.bidsAddress,
serum3ExternalMarket.asksAddress,
])
.flat();
let perpMarketAddresses = Array.from(
group.perpMarketsMapByMarketIndex.values(),
)
.flat()
.map((perpMarket) => [
perpMarket.publicKey,
perpMarket.oracle,
perpMarket.bids,
perpMarket.asks,
perpMarket.eventQueue,
])
.flat();
async function extendTable(addresses: PublicKey[]) {
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 sig = await client.sendAndConfirmTransaction([extendIx]);
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);
await extendTable(perpMarketAddresses);
} catch (error) {
console.log(error);
}
}