mango-simulation/configure_cluster/utils/mango_utils.ts

812 lines
30 KiB
TypeScript
Executable File

import * as anchor from '@project-serum/anchor';
import { Market, OpenOrders } from "@project-serum/serum";
import * as mango_client_v3 from '@blockworks-foundation/mango-client';
import { Connection, LAMPORTS_PER_SOL } from '@solana/web3.js';
import * as splToken from '@solana/spl-token';
import {
NATIVE_MINT,
Mint,
TOKEN_PROGRAM_ID,
MintLayout,
} from "@solana/spl-token";
import {
PublicKey,
Keypair,
Transaction,
SystemProgram,
sendAndConfirmTransaction,
Signer,
} from '@solana/web3.js';
import { SerumUtils, } from "./serum_utils";
import { MintUtils, TokenData, } from './mint_utils';
import { BN } from 'bn.js';
import {
GroupConfig,
OracleConfig,
PerpMarketConfig,
SpotMarketConfig,
TokenConfig,
Cluster,
PerpEventQueueHeaderLayout,
PerpEventLayout,
BookSideLayout,
makeCreatePerpMarketInstruction,
I80F48,
PerpMarketLayout,
makeAddPerpMarketInstruction,
makeDepositInstruction,
Config as MangoConfig,
sleep
} from '@blockworks-foundation/mango-client';
import { token } from '@project-serum/anchor/dist/cjs/utils';
import { Config } from './config';
export interface PerpMarketData {
publicKey: PublicKey,
asks: PublicKey,
bids: PublicKey,
eventQ: PublicKey,
}
export interface MangoTokenData extends TokenData {
rootBank: PublicKey,
nodeBank: PublicKey,
marketIndex: number,
perpMarket: PerpMarketData,
}
export interface MangoCookie {
mangoGroup: PublicKey,
signerKey: PublicKey,
mangoCache: PublicKey,
usdcRootBank: PublicKey,
usdcNodeBank: PublicKey,
usdcVault: PublicKey,
usdcMint: PublicKey,
tokens: Array<[String, MangoTokenData]>,
MSRM: PublicKey,
}
export interface MangoUser {
kp: Keypair,
mangoAddress: PublicKey,
}
export class MangoUtils {
private conn: Connection;
private serumUtils: SerumUtils;
private mintUtils: MintUtils;
private mangoClient: mango_client_v3.MangoClient;
private authority: Keypair;
private mangoProgramId: PublicKey;
private dexProgramId: PublicKey;
constructor(conn: Connection, authority: Keypair, mangoProgramId: PublicKey, dexProgramId: PublicKey, pythProgramId: PublicKey) {
this.conn = conn;
this.authority = authority;
this.mangoProgramId = mangoProgramId;
this.dexProgramId = dexProgramId;
this.serumUtils = new SerumUtils(conn, authority, dexProgramId);
this.mintUtils = new MintUtils(conn, authority, dexProgramId, pythProgramId);
this.mangoClient = new mango_client_v3.MangoClient(conn, mangoProgramId);
}
async createAccountForMango(size: number): Promise<PublicKey> {
const lamports = await this.conn.getMinimumBalanceForRentExemption(size);
let address = Keypair.generate();
const transaction = new Transaction().add(
SystemProgram.createAccount({
fromPubkey: this.authority.publicKey,
newAccountPubkey: address.publicKey,
lamports,
space: size,
programId: this.mangoProgramId,
}))
transaction.feePayer = this.authority.publicKey;
let hash = await this.conn.getRecentBlockhash();
transaction.recentBlockhash = hash.blockhash;
// Sign transaction, broadcast, and confirm
await sendAndConfirmTransaction(
this.conn,
transaction,
[this.authority, address],
{ commitment: 'confirmed' },
);
// airdrop all mongo accounts 1000 SOLs
// const signature = await this.conn.requestAirdrop(address.publicKey, LAMPORTS_PER_SOL * 1000);
// const blockHash = await this.conn.getRecentBlockhash('confirmed');
// const blockHeight = await this.conn.getBlockHeight('confirmed')
// await this.conn.confirmTransaction({signature: signature, blockhash: blockHash.blockhash, lastValidBlockHeight: blockHeight});
return address.publicKey;
}
public async createMangoCookie(tokensList: Array<String>): Promise<MangoCookie> {
const size = mango_client_v3.MangoGroupLayout.span;
let group_address = await this.createAccountForMango(size);
let root_bank_address = await this.createAccountForMango(mango_client_v3.RootBankLayout.span);
let node_bank_address = await this.createAccountForMango(mango_client_v3.NodeBankLayout.span);
let mango_cache = await this.createAccountForMango(mango_client_v3.MangoCacheLayout.span);
const { signerKey, signerNonce } = await mango_client_v3.createSignerKeyAndNonce(
this.mangoProgramId,
group_address,
);
let mangoCookie: MangoCookie = {
mangoGroup: null,
signerKey,
mangoCache: null,
usdcRootBank: null,
usdcNodeBank: null,
usdcVault: null,
tokens: new Array<[String, MangoTokenData]>(),
usdcMint: await this.mintUtils.createMint(6),
MSRM: await this.mintUtils.createMint(6),
};
let usdc_vault = await this.mintUtils.createTokenAccount(mangoCookie.usdcMint, this.authority, signerKey);
splToken.mintTo(this.conn, this.authority, mangoCookie.usdcMint, usdc_vault, this.authority, 1000000 * 1000000);
mangoCookie.usdcVault = usdc_vault;
let insurance_vault = await this.mintUtils.createTokenAccount(mangoCookie.usdcMint, this.authority, signerKey);
splToken.mintTo(this.conn, this.authority, mangoCookie.usdcMint, insurance_vault, this.authority, 1000000 * 1000000);
let fee_vault = await this.mintUtils.createTokenAccount(mangoCookie.usdcMint, this.authority, TOKEN_PROGRAM_ID);
splToken.mintTo(this.conn, this.authority, mangoCookie.usdcMint, fee_vault, this.authority, 1000000 * 1000000);
let msrm_vault = await this.mintUtils.createTokenAccount(mangoCookie.MSRM, this.authority, signerKey);
mangoCookie.usdcRootBank = root_bank_address;
mangoCookie.usdcNodeBank = node_bank_address;
console.log('mango program id : ' + this.mangoProgramId)
console.log('serum program id : ' + this.dexProgramId)
let ix = mango_client_v3.makeInitMangoGroupInstruction(
this.mangoProgramId,
group_address,
signerKey,
this.authority.publicKey,
mangoCookie.usdcMint,
usdc_vault,
node_bank_address,
root_bank_address,
insurance_vault,
PublicKey.default,
fee_vault,
mango_cache,
this.dexProgramId,
new anchor.BN(signerNonce),
new anchor.BN(10),
mango_client_v3.I80F48.fromNumber(0.7),
mango_client_v3.I80F48.fromNumber(0.06),
mango_client_v3.I80F48.fromNumber(1.5),
);
let ixCacheRootBank = mango_client_v3.makeCacheRootBankInstruction(this.mangoProgramId,
group_address,
mango_cache,
[root_bank_address]);
let ixupdateRootBank = mango_client_v3.makeUpdateRootBankInstruction(this.mangoProgramId,
group_address,
mango_cache,
root_bank_address,
[node_bank_address]);
await this.processInstruction(ix, [this.authority]);
await this.processInstruction(ixCacheRootBank, [this.authority]);
await this.processInstruction(ixupdateRootBank, [this.authority]);
mangoCookie.mangoGroup = group_address;
mangoCookie.mangoCache = mango_cache;
console.log('Mango group created, creating tokens')
// create mngo
const mngoData = await this.createMangoToken(mangoCookie, tokensList[0], 0, 6, 100);
let tokenData = await Promise.all(tokensList.filter((a,b)=> b > 0).map((tokenStr, tokenIndex) => this.createMangoToken(mangoCookie, tokenStr, tokenIndex+1, 6, 100)));
tokenData.push(mngoData)
await this.mangoClient.cachePrices(mangoCookie.mangoGroup, mangoCookie.mangoCache, tokenData.map(x=>x.priceOracle.publicKey), this.authority);
//tokensList.map((tokenStr, tokenIndex) => this.createMangoToken(mangoCookie, tokenStr, tokenIndex, 6, 100));
return mangoCookie;
}
public async createMangoToken(mangoCookie: MangoCookie, tokenName: String, tokenIndex: number, nbDecimals, startingPrice): Promise<MangoTokenData> {
console.log('Creating token ' + tokenName + " at index " + tokenIndex)
const tokenData = await this.mintUtils.createNewToken(mangoCookie.usdcMint, nbDecimals, startingPrice);
let mangoTokenData: MangoTokenData = {
market: tokenData.market,
marketIndex: tokenIndex,
mint: tokenData.mint,
priceOracle: tokenData.priceOracle,
nbDecimals: tokenData.nbDecimals,
startingPrice: startingPrice,
nodeBank: await this.createAccountForMango(mango_client_v3.NodeBankLayout.span),
rootBank: await this.createAccountForMango(mango_client_v3.RootBankLayout.span),
perpMarket: null,
};
// add oracle to mango
let add_oracle_ix = mango_client_v3.makeAddOracleInstruction(
this.mangoProgramId,
mangoCookie.mangoGroup,
mangoTokenData.priceOracle.publicKey,
this.authority.publicKey,
);
// add oracle
{
const transaction = new Transaction();
transaction.add(add_oracle_ix);
transaction.feePayer = this.authority.publicKey;
let hash = await this.conn.getRecentBlockhash();
transaction.recentBlockhash = hash.blockhash;
// Sign transaction, broadcast, and confirm
await this.mangoClient.sendTransaction(
transaction,
this.authority,
[],
3600,
'confirmed',
);
}
await this.initSpotMarket(mangoCookie, mangoTokenData);
const group = await this.mangoClient.getMangoGroup(mangoCookie.mangoGroup);
mangoTokenData.marketIndex = group.getTokenIndex(mangoTokenData.mint)
mangoTokenData.perpMarket = await this.initPerpMarket(mangoCookie, mangoTokenData);
mangoCookie.tokens.push([tokenName, mangoTokenData]);
return mangoTokenData;
}
public async initSpotMarket(mangoCookie: MangoCookie, token: MangoTokenData) {
const vault = await this.mintUtils.createTokenAccount(token.mint, this.authority, mangoCookie.signerKey);
// add spot market to mango
let add_spot_ix = mango_client_v3.makeAddSpotMarketInstruction(
this.mangoProgramId,
mangoCookie.mangoGroup,
token.priceOracle.publicKey,
token.market.address,
this.dexProgramId,
token.mint,
token.nodeBank,
vault,
token.rootBank,
this.authority.publicKey,
mango_client_v3.I80F48.fromNumber(10),
mango_client_v3.I80F48.fromNumber(5),
mango_client_v3.I80F48.fromNumber(0.05),
mango_client_v3.I80F48.fromNumber(0.7),
mango_client_v3.I80F48.fromNumber(0.06),
mango_client_v3.I80F48.fromNumber(1.5),
);
let ixCacheRootBank = mango_client_v3.makeCacheRootBankInstruction(this.mangoProgramId,
mangoCookie.mangoGroup,
mangoCookie.mangoCache,
[token.rootBank]);
let ixupdateRootBank = mango_client_v3.makeUpdateRootBankInstruction(this.mangoProgramId,
mangoCookie.mangoGroup,
mangoCookie.mangoCache,
token.rootBank,
[token.nodeBank]);
const transaction = new Transaction();
transaction.add(add_spot_ix);
transaction.add(ixCacheRootBank);
transaction.add(ixupdateRootBank);
transaction.feePayer = this.authority.publicKey;
let hash = await this.conn.getRecentBlockhash();
transaction.recentBlockhash = hash.blockhash;
await sendAndConfirmTransaction(
this.conn,
transaction,
[this.authority],
{ commitment: 'confirmed', maxRetries: 100 }
)
}
public async getMangoGroup(mangoCookie: MangoCookie) {
return this.mangoClient.getMangoGroup(mangoCookie.mangoGroup)
}
private async initPerpMarket(mangoCookie: MangoCookie, token: MangoTokenData) {
const maxNumEvents = 256;
// const perpMarketPk = await this.createAccountForMango(
// PerpMarketLayout.span,
// );
const [perpMarketPk] = await PublicKey.findProgramAddress(
[
mangoCookie.mangoGroup.toBytes(),
new Buffer('PerpMarket', 'utf-8'),
token.priceOracle.publicKey.toBytes(),
],
this.mangoProgramId,
);
const eventQ = await this.createAccountForMango(
PerpEventQueueHeaderLayout.span + maxNumEvents * PerpEventLayout.span,
);
const bids = await this.createAccountForMango(
BookSideLayout.span,
);
const mangoMint = token.marketIndex == 0 ? token.mint : mangoCookie.tokens[0][1].mint;
const asks = await this.createAccountForMango(
BookSideLayout.span,
);
const [mngoVaultPk] = await PublicKey.findProgramAddress(
[
perpMarketPk.toBytes(),
TOKEN_PROGRAM_ID.toBytes(),
mangoMint.toBytes(),
],
this.mangoProgramId,
);
const instruction = await makeCreatePerpMarketInstruction(
this.mangoProgramId,
mangoCookie.mangoGroup,
token.priceOracle.publicKey,
perpMarketPk,
eventQ,
bids,
asks,
mangoMint,
mngoVaultPk,
this.authority.publicKey,
mangoCookie.signerKey,
I80F48.fromNumber(10),
I80F48.fromNumber(5),
I80F48.fromNumber(0.05),
I80F48.fromNumber(0),
I80F48.fromNumber(0.005),
new BN(1000),
new BN(1000),
I80F48.fromNumber(1),
I80F48.fromNumber(200),
new BN(3600),
new BN(0),
new BN(2),
new BN(2),
new BN(0),
new BN(6)
)
const transaction = new Transaction();
transaction.add(instruction);
await this.mangoClient.sendTransaction(transaction, this.authority, [], 3600, 'confirmed');
//await sendAndConfirmTransaction(this.conn, transaction, additionalSigners);
const perpMarketData: PerpMarketData = {
publicKey: perpMarketPk,
asks: asks,
bids: bids,
eventQ: eventQ,
}
return perpMarketData;
}
public async createAndInitPerpMarket(mangoCookie: MangoCookie, token: MangoTokenData): Promise<PerpMarketData> {
const blockHash = await this.conn.getLatestBlockhashAndContext('confirmed')
const signature = await this.mangoClient.addPerpMarket(
await this.getMangoGroup(mangoCookie),
token.priceOracle.publicKey,
token.mint,
this.authority,
10,
5,
0.05,
0,
0.0005,
1000,
1000,
256,
1,
200,
3600,
0,
2,
);
this.conn.confirmTransaction({ blockhash: blockHash.value.blockhash, lastValidBlockHeight: blockHash.value.lastValidBlockHeight, signature: signature }, 'confirmed')
const mangoGroup = await this.mangoClient.getMangoGroup(mangoCookie.mangoGroup);
const tokenIndex = token.marketIndex;
const perpMarketPk = mangoGroup.perpMarkets[tokenIndex].perpMarket
const perpMarket = await this.mangoClient.getPerpMarket(perpMarketPk, token.nbDecimals, 6);
// const perpMarketData : PerpMarketData = {
// publicKey: perpMarketPk,
// asks: perpMarket.asks,
// bids: perpMarket.bids,
// eventQ: perpMarket.eventQueue,
// }
const perpMarketData: PerpMarketData = {
publicKey: PublicKey.default,
asks: PublicKey.default,
bids: PublicKey.default,
eventQ: PublicKey.default,
}
return perpMarketData
}
public async refreshTokenCache(mangoCookie: MangoCookie, tokenData: MangoTokenData) {
let ixupdateRootBank = mango_client_v3.makeUpdateRootBankInstruction(this.mangoProgramId,
mangoCookie.mangoGroup,
mangoCookie.mangoCache,
tokenData.rootBank,
[tokenData.nodeBank]);
const transaction = new Transaction();
transaction.add(ixupdateRootBank);
transaction.feePayer = this.authority.publicKey;
let hash = await this.conn.getRecentBlockhash();
transaction.recentBlockhash = hash.blockhash;
// Sign transaction, broadcast, and confirm
await sendAndConfirmTransaction(
this.conn,
transaction,
[this.authority],
{ commitment: 'confirmed' },
);
}
public async refreshRootBankCache(mangoContext: MangoCookie) {
let ixCacheRootBank = mango_client_v3.makeCacheRootBankInstruction(this.mangoProgramId,
mangoContext.mangoGroup,
mangoContext.mangoCache,
Array.from(mangoContext.tokens).map(x => x[1].rootBank));
const transaction = new Transaction();
transaction.add(ixCacheRootBank);
transaction.feePayer = this.authority.publicKey;
let hash = await this.conn.getRecentBlockhash();
transaction.recentBlockhash = hash.blockhash;
// Sign transaction, broadcast, and confirm
await sendAndConfirmTransaction(
this.conn,
transaction,
[this.authority],
{ commitment: 'confirmed' },
);
}
async refreshAllTokenCache(mangoContext: MangoCookie) {
await this.refreshRootBankCache(mangoContext);
await Promise.all(
Array.from(mangoContext.tokens).map(x => this.refreshTokenCache(mangoContext, x[1]))
);
}
async createSpotOpenOrdersAccount(mangoContext: MangoCookie, mangoAccount: PublicKey, owner: Keypair, tokenData: TokenData): Promise<PublicKey> {
let mangoGroup = await this.mangoClient.getMangoGroup(mangoContext.mangoGroup);
const marketIndex = new BN(mangoGroup.tokens.findIndex(x => x.mint.equals(tokenData.mint)));
const [spotOpenOrdersAccount, _bump] = await PublicKey.findProgramAddress(
[
mangoAccount.toBuffer(),
marketIndex.toBuffer("le", 8),
Buffer.from("OpenOrders"),
], this.mangoProgramId);
const space = OpenOrders.getLayout(this.dexProgramId).span;
//await this.createAccount( spotOpenOrdersAccount, owner, DEX_ID, space);
const lamports = await this.conn.getMinimumBalanceForRentExemption(space);
let ix2 = mango_client_v3.makeCreateSpotOpenOrdersInstruction(
this.mangoProgramId,
mangoContext.mangoGroup,
mangoAccount,
owner.publicKey,
this.dexProgramId,
spotOpenOrdersAccount,
tokenData.market.address,
mangoContext.signerKey,
)
await this.processInstruction(ix2, [owner]);
return spotOpenOrdersAccount;
}
async processInstruction(ix: anchor.web3.TransactionInstruction, signers: Array<Signer>) {
const transaction = new Transaction();
transaction.add(ix);
transaction.feePayer = this.authority.publicKey;
signers.push(this.authority);
let hash = await this.conn.getRecentBlockhash();
transaction.recentBlockhash = hash.blockhash;
// Sign transaction, broadcast, and confirm
try {
await this.mangoClient.sendTransaction(transaction,
this.authority,
[],
3600,
'confirmed');
}
catch (ex) {
const ext = ex as anchor.web3.SendTransactionError;
if (ext != null) {
console.log("Error processing instruction : " + ext.message)
}
throw ex;
}
}
convertCookie2Json(mangoCookie: MangoCookie, cluster: Cluster) {
const oracles = Array.from(mangoCookie.tokens).map(x => {
const oracle: OracleConfig = {
publicKey: x[1].priceOracle.publicKey,
symbol: x[0] + 'USDC'
}
return oracle;
})
const perpMarkets = Array.from(mangoCookie.tokens).map(x => {
const perpMarket: PerpMarketConfig = {
publicKey: x[1].perpMarket.publicKey,
asksKey: x[1].perpMarket.asks,
bidsKey: x[1].perpMarket.bids,
eventsKey: x[1].perpMarket.eventQ,
marketIndex: x[1].marketIndex,
baseDecimals: x[1].nbDecimals,
baseSymbol: x[0].toString(),
name: (x[0] + 'USDC PERP'),
quoteDecimals: 6,
}
return perpMarket
})
const spotMarkets = Array.from(mangoCookie.tokens).map(x => {
const spotMarket: SpotMarketConfig = {
name: x[0] + 'USDC spot Market',
marketIndex: x[1].marketIndex,
publicKey: x[1].market.address,
asksKey: x[1].market.asksAddress,
bidsKey: x[1].market.bidsAddress,
baseDecimals: x[1].nbDecimals,
baseSymbol: x[0].toString(),
eventsKey: x[1].market.decoded.eventQueue,
quoteDecimals: 6,
}
return spotMarket;
})
const tokenConfigs = Array.from(mangoCookie.tokens).map(x => {
const tokenConfig: TokenConfig = {
decimals: x[1].nbDecimals,
mintKey: x[1].mint,
nodeKeys: [x[1].nodeBank],
rootKey: x[1].rootBank,
symbol: x[0].toString(),
}
return tokenConfig
})
// quote token config
tokenConfigs.push(
{
decimals: 6,
mintKey: mangoCookie.usdcMint,
rootKey: mangoCookie.usdcRootBank,
nodeKeys: [mangoCookie.usdcNodeBank],
symbol: "USDC",
}
)
const groupConfig: GroupConfig = {
cluster,
mangoProgramId: this.mangoProgramId,
name: cluster,
publicKey: mangoCookie.mangoGroup,
quoteSymbol: "USDC",
oracles: oracles,
serumProgramId: this.dexProgramId,
perpMarkets: perpMarkets,
spotMarkets: spotMarkets,
tokens: tokenConfigs,
}
groupConfig["cacheKey"] = mangoCookie.mangoCache
const groupConfigs: GroupConfig[] = [groupConfig]
const cluster_urls: Record<Cluster, string> = {
"devnet": "https://mango.devnet.rpcpool.com",
"localnet": "http://127.0.0.1:8899",
"mainnet": "https://mango.rpcpool.com/946ef7337da3f5b8d3e4a34e7f88",
"testnet": "http://api.testnet.rpcpool.com"
};
const config = new Config(cluster_urls, groupConfigs);
return config.toJson();
}
async json2Cookie(json: any, cluster: Cluster) : Promise<MangoCookie> {
const clusterConfig = new MangoConfig(json)
const group = clusterConfig.getGroup(cluster, cluster);
let mangoCookie: MangoCookie = {
mangoGroup: null,
signerKey: null,
mangoCache: null,
usdcRootBank: null,
usdcNodeBank: null,
usdcVault: null,
tokens: new Array<[String, MangoTokenData]>(),
usdcMint: null,
MSRM: null,
};
const mangoGroup = await this.mangoClient.getMangoGroup(group.publicKey);
let quoteToken = mangoGroup.getQuoteTokenInfo();
const quoteRootBankIndex = await mangoGroup.getRootBankIndex(quoteToken.rootBank);
const rootBanks = await (await mangoGroup.loadRootBanks(this.conn));
const quoteRootBank = rootBanks[quoteRootBankIndex];
const quoteNodeBanks = await quoteRootBank.loadNodeBanks(this.conn);
mangoCookie.mangoGroup = group.publicKey;
mangoCookie.mangoCache = mangoGroup.mangoCache;
mangoCookie.usdcRootBank = quoteToken.rootBank;
mangoCookie.usdcNodeBank = quoteNodeBanks[0].publicKey;
mangoCookie.usdcVault = quoteNodeBanks[0].vault;
mangoCookie.usdcMint = mangoGroup.getQuoteTokenInfo().mint;
const rootBanksF = rootBanks.filter(x => x != undefined);
mangoCookie.tokens = mangoGroup.tokens.map((x, index) => {
if (x.rootBank.equals(PublicKey.default)) {
return ["", null]
}
let rootBank = rootBanksF.find(y => y.publicKey.equals(x.rootBank))
let tokenData : MangoTokenData = {
market: null,
marketIndex: index,
mint: x.mint,
nbDecimals: 6,
rootBank: x.rootBank,
nodeBank: rootBank.nodeBanks[0],
perpMarket: null,
priceOracle: null,
startingPrice: 0
};
return ["", tokenData]
})
return mangoCookie
}
async createUser(
mangoCookie,
mangoGroup: mango_client_v3.MangoGroup,
usdcAcc: PublicKey,
rootBanks : mango_client_v3.RootBank[],
nodeBanks : mango_client_v3.NodeBank[],
fundingAccounts : PublicKey[],
authority: Keypair,
): Promise<MangoUser> {
const user = Keypair.generate();
// transfer 1 sol to the user
{
const ix = SystemProgram.transfer({
fromPubkey: authority.publicKey,
lamports : LAMPORTS_PER_SOL,
programId: anchor.web3.SystemProgram.programId,
toPubkey: user.publicKey,
})
await anchor.web3.sendAndConfirmTransaction( this.conn, new Transaction().add(ix), [authority]);
}
const mangoAcc = await this.mangoClient.createMangoAccount(
mangoGroup,
user,
1,
user.publicKey,
);
//const mangoAccount = await this.mangoClient.getMangoAccount(user.mangoAddress, this.dexProgramId)
const depositUsdcIx = makeDepositInstruction(
this.mangoProgramId,
mangoCookie.mangoGroup,
this.authority.publicKey,
mangoGroup.mangoCache,
mangoAcc,
mangoCookie.usdcRootBank,
mangoCookie.usdcNodeBank,
mangoCookie.usdcVault,
usdcAcc,
new BN(10_000_000_000),
);
const blockHashInfo = await this.conn.getLatestBlockhashAndContext();
const transaction = new Transaction()
.add(depositUsdcIx)
transaction.recentBlockhash = blockHashInfo.value.blockhash;
transaction.feePayer = this.authority.publicKey;
await this.mangoClient.sendTransaction(transaction, this.authority, [], 3600, 'confirmed')
for (const tokenIte of mangoCookie.tokens)
{
if (tokenIte[1] === null)
{
continue;
}
const marketIndex = tokenIte[1].marketIndex;
const deposit = makeDepositInstruction(
this.mangoProgramId,
mangoCookie.mangoGroup,
this.authority.publicKey,
mangoGroup.mangoCache,
mangoAcc,
rootBanks[marketIndex].publicKey,
nodeBanks[marketIndex].publicKey,
nodeBanks[marketIndex].vault,
fundingAccounts[marketIndex],
new BN(1_000_000_000),
);
const blockHashInfo = await this.conn.getLatestBlockhashAndContext();
const transaction = new Transaction()
.add(deposit)
transaction.recentBlockhash = blockHashInfo.value.blockhash;
transaction.feePayer = this.authority.publicKey;
await this.mangoClient.sendTransaction(transaction, this.authority, [], 3600, 'confirmed')
}
return { kp: user, mangoAddress: mangoAcc };
}
public async createAndMintUsers(mangoCookie: MangoCookie, nbUsers: number, authority : Keypair): Promise<MangoUser[]> {
const mangoGroup = await this.getMangoGroup(mangoCookie)
const rootBanks = await mangoGroup.loadRootBanks(this.conn)
const nodeBanksList = await Promise.all(rootBanks.map(x => x != undefined ? x.loadNodeBanks(this.conn): Promise.resolve(undefined)))
const nodeBanks = nodeBanksList.map(x => x!=undefined ? x[0] : undefined);
const usdcAcc = await this.mintUtils.createTokenAccount(mangoCookie.usdcMint, this.authority, this.authority.publicKey);
await splToken.mintTo(
this.conn,
this.authority,
mangoCookie.usdcMint,
usdcAcc,
this.authority,
10_000_000_000 * nbUsers,
)
const tmpAccounts : PublicKey []= new Array(mangoCookie.tokens.length)
for (const tokenIte of mangoCookie.tokens) {
if (tokenIte[1] === null)
{
continue;
}
const acc = await this.mintUtils.createTokenAccount(tokenIte[1].mint, this.authority, this.authority.publicKey);
await splToken.mintTo(
this.conn,
this.authority,
tokenIte[1].mint,
acc,
this.authority,
1_000_000_000 * nbUsers,
)
tmpAccounts[tokenIte[1].marketIndex] = acc
}
// create in batches of 10
let users : MangoUser[] = [];
for (let i=0; i<Math.floor((nbUsers/10)); ++i) {
let users_batch = await Promise.all( [...Array(10)].map(_x => this.createUser(mangoCookie, mangoGroup, usdcAcc, rootBanks, nodeBanks, tmpAccounts, authority)));
users = users.concat(users_batch)
}
if (nbUsers%10 != 0) {
let last_batch = await Promise.all( [...Array(nbUsers%10)].map(_x => this.createUser(mangoCookie, mangoGroup, usdcAcc, rootBanks, nodeBanks, tmpAccounts, authority)));
users = users.concat(last_batch)
}
return users;
}
}