refactor to run from root and format

This commit is contained in:
Maximilian Schneider 2023-05-14 21:44:25 +02:00
parent 3c99ebf336
commit 6fc642d491
20 changed files with 4305 additions and 4637 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
/target /target
node_modules node_modules
/configure/config.json
package-lock.json package-lock.json
**/config.json

View File

@ -30,7 +30,7 @@ Here are arguments required by the script, all the arguments are optional:
--authority, -a <str> - a string [optional][default: ~/.config/solana/id.json] --authority, -a <str> - a string [optional][default: ~/.config/solana/id.json]
--number-of-payers, -p <number> - Number of payers used for testing [optional][default: 10] --number-of-payers, -p <number> - Number of payers used for testing [optional][default: 10]
--payer-balance, -b <number> - Balance of payer in SOLs [optional][default: 1 SOLs] --payer-balance, -b <number> - Balance of payer in SOLs [optional][default: 1 SOLs]
--output-file, -o <str> - a string [optional][default: config.json] --output-file, -o <str> - a string [optional][default: configure/config.json]
``` ```
Once the cluster configuration is successfully done we create a json file `config.json` Once the cluster configuration is successfully done we create a json file `config.json`
@ -39,7 +39,7 @@ To configure cluster:
```sh ```sh
cd configure cd configure
ts-node configure_all.ts -a /home/user/.config/solana/id.json yarn configure -a ../solana_configure_local_cluster/faucet.json
cd .. cd ..
``` ```

View File

@ -1,6 +1,21 @@
import { AnchorProvider, BN, Program, Provider, web3 } from "@project-serum/anchor"; import {
AnchorProvider,
BN,
Program,
Provider,
web3,
} from "@project-serum/anchor";
import { SuccessfulTxSimulationResponse } from "@project-serum/anchor/dist/cjs/utils/rpc"; import { SuccessfulTxSimulationResponse } from "@project-serum/anchor/dist/cjs/utils/rpc";
import { Connection, PublicKey, Transaction, Signer, SendOptions, ConfirmOptions, Commitment, Keypair } from "@solana/web3.js"; import {
Connection,
PublicKey,
Transaction,
Signer,
SendOptions,
ConfirmOptions,
Commitment,
Keypair,
} from "@solana/web3.js";
import { Command } from "./output_file"; import { Command } from "./output_file";
import { IDL, OpenbookV2 } from "./openbook-v2/openbook_v2"; import { IDL, OpenbookV2 } from "./openbook-v2/openbook_v2";
import { U64_MAX_BN } from "@blockworks-foundation/mango-v4"; import { U64_MAX_BN } from "@blockworks-foundation/mango-v4";
@ -12,26 +27,26 @@ export class TestProvider extends AnchorProvider {
constructor(connection: Connection, keypair: Keypair) { constructor(connection: Connection, keypair: Keypair) {
let txSigner = async (tx: Transaction) => { let txSigner = async (tx: Transaction) => {
tx.partialSign(this.keypair); tx.partialSign(this.keypair);
return tx return tx;
}; };
let allSigner = async (txs : Transaction[]) => { let allSigner = async (txs: Transaction[]) => {
txs.forEach(x=> x.partialSign(this.keypair)); txs.forEach((x) => x.partialSign(this.keypair));
return txs; return txs;
}; };
super( super(
connection, connection,
{ {
signTransaction: txSigner, signTransaction: txSigner,
signAllTransactions: allSigner, signAllTransactions: allSigner,
publicKey : keypair.publicKey, publicKey: keypair.publicKey,
}, },
{commitment: 'confirmed'} { commitment: "confirmed" }
) );
this.keypair = keypair; this.keypair = keypair;
} }
getKeypair() : Keypair { getKeypair(): Keypair {
return this.keypair return this.keypair;
} }
} }

View File

@ -1,13 +1,12 @@
import { Keypair } from "@solana/web3.js"; import { Keypair } from "@solana/web3.js";
import * as fs from 'fs'; import * as fs from "fs";
export function getKeypairFromFile(filePath: String): Keypair { export function getKeypairFromFile(filePath: String): Keypair {
return Keypair.fromSecretKey( return Keypair.fromSecretKey(
Uint8Array.from( Uint8Array.from(
JSON.parse( JSON.parse(
process.env.KEYPAIR || process.env.KEYPAIR || fs.readFileSync(filePath.toString(), "utf-8")
fs.readFileSync(filePath.toString(), 'utf-8'), )
),
),
) )
);
} }

View File

@ -1,229 +0,0 @@
import { command, number, option, string, run, boolean, flag } from 'cmd-ts';
import * as fs from 'fs';
import programs from './programs.json';
import { Commitment, Connection, Keypair, LAMPORTS_PER_SOL, Transaction } from '@solana/web3.js';
import { getKeypairFromFile } from './common_utils';
import { deploy_programs } from './deploy_programs';
import { User, createUser, mintUser } from './general/create_users';
import { configure_accounts } from './general/accounts';
import { Command, OutputFile } from './output_file';
import { MintUtils } from './general/mint_utils';
import { OpenbookConfigurator } from './openbook-v2/configure_openbook';
const numberOfAccountsToBeCreated = option({
type: number,
defaultValue: () => 256,
long: 'number-of-accounts',
});
const endpoint = option({
type: string,
defaultValue: () => "http://127.0.0.1:8899",
long: 'url',
short: 'u',
description: "RPC url",
});
const authority = option({
type: string,
defaultValue: () => "~/.config/solana/id.json",
long: 'authority',
short: 'a'
});
const nbPayers = option({
type: number,
defaultValue: () => 10,
long: 'number-of-payers',
short: 'p',
description: "Number of payers used for testing"
});
const balancePerPayer = option({
type: number,
defaultValue: () => 1,
long: 'payer-balance',
short: 'b',
description: "Balance of payer in SOLs"
});
const nbMints = option({
type: number,
defaultValue: () => 10,
long: 'number-of-mints',
short: 'm',
description: "Number of mints"
});
const skipProgramDeployment = flag({
type: boolean,
defaultValue: () => false,
long: 'skip-program-deployment',
short: 's',
description: "Skip deploying programs"
});
const outFile = option({
type: string,
defaultValue: () => "config.json",
long: 'output-file',
short: 'o'
});
const app = command(
{
name: "configure",
args: {
endpoint,
numberOfAccountsToBeCreated,
authority,
nbPayers,
balancePerPayer,
nbMints,
skipProgramDeployment,
outFile,
},
handler: ({
endpoint,
numberOfAccountsToBeCreated,
authority,
nbPayers,
balancePerPayer,
nbMints,
skipProgramDeployment,
outFile,
}) => {
console.log("configuring a new test instance");
configure(
endpoint,
numberOfAccountsToBeCreated,
authority,
nbPayers,
balancePerPayer,
nbMints,
skipProgramDeployment,
outFile,
).then(_ => {
console.log("configuration finished");
});
},
}
)
run(app, process.argv.slice(2))
// configure part
async function configure(
endpoint: String,
numberOfAccountsToBeCreated: number,
authorityFile: String,
nbPayers: number,
balancePerPayer: number,
nbMints: number,
skipProgramDeployment: boolean,
outFile: String,
) {
// create connections
const connection = new Connection(
endpoint.toString(),
'confirmed' as Commitment,
);
// configure authority
const authority = getKeypairFromFile(authorityFile);
const authorityBalance = await connection.getBalance(authority.publicKey);
const requiredBalance = nbPayers * (balancePerPayer * LAMPORTS_PER_SOL) + 100 * LAMPORTS_PER_SOL;
if (authorityBalance < requiredBalance) {
console.log("authority may have low balance balance " + authorityBalance + " required balance " + requiredBalance);
}
let programOutputData = programs.map(x => {
let kp = getKeypairFromFile(x.programKeyPath);
let emptyCommands : Command[] = [];
return {
name: x.name,
program_id: kp.publicKey,
commands: emptyCommands,
}
})
let programIds = programOutputData.map(x => {
return x.program_id
});
if (!skipProgramDeployment) {
console.log("starting program deployment");
await deploy_programs(endpoint, authorityFile.toString(), programs);
console.log("programs deployed");
}
console.log("Creating Mints");
let mintUtils = new MintUtils(connection, authority);
let mints = await mintUtils.createMints(nbMints);
console.log("Mints created")
console.log("Configuring openbook-v2")
let index = programs.findIndex(x => x.name === "openbook_v2");
let openbookProgramId = programOutputData[index].program_id;
let openbookConfigurator = new OpenbookConfigurator(connection, authority, mintUtils, openbookProgramId);
let markets = await openbookConfigurator.configureOpenbookV2(mints);
programOutputData[index].commands = await openbookConfigurator.getCommands();
console.log("Finished configuring openbook")
console.log("Creating users");
let users = await Promise.all(Array.from(Array(nbPayers).keys()).map(_ => createUser(connection, authority, balancePerPayer)));
let tokenAccounts = await Promise.all(users.map(
/// user is richer than bill gates, but not as rich as certain world leaders
async(user) => await mintUser(connection, authority, mints, mintUtils, user.publicKey, 100_000_000_000_000_000)
))
let userOpenOrders = await Promise.all(users.map(
/// user is crazy betting all his money in crypto market
async(user) => await openbookConfigurator.configureMarketForUser(user, markets)
))
let userData: User [] = users.map((user, i) => {
return {
secret: Array.from(user.secretKey),
open_orders: userOpenOrders[i],
token_data: tokenAccounts[i],
}
})
console.log("Users created");
console.log("Filling up orderbook");
await Promise.all( userData.map( async(user, i) => {
for (const market of markets) {
await openbookConfigurator.fillOrderBook(user, users[i], market, 32);
}
}) )
console.log("Orderbook filled");
console.log("Creating accounts")
let accounts = await configure_accounts(connection, authority, numberOfAccountsToBeCreated, programIds);
// adding known accounts
const marketAccountsList = markets.map(market => [market.asks, market.bids, market.market_pk, market.oracle, market.quote_vault, market.base_vault, market.base_mint, market.quote_mint] ).flat();
const userAccountsList = userData.map(user => {
const allOpenOrdersAccounts = user.open_orders.map(x=>x.open_orders).flat();
const allTokenAccounts = user.token_data.map(x => x.token_account);
return allOpenOrdersAccounts.concat(allTokenAccounts)
}).flat()
accounts = accounts.concat(marketAccountsList).concat(userAccountsList);
console.log("Accounts created")
let outputFile: OutputFile = {
programs: programOutputData,
known_accounts: accounts,
users: userData,
mints,
markets,
}
console.log("creating output file")
fs.writeFileSync(outFile.toString(), JSON.stringify(outputFile));
}

View File

@ -1,31 +1,52 @@
import { Connection, Keypair, LAMPORTS_PER_SOL, SystemProgram, PublicKey, Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; import {
Connection,
Keypair,
LAMPORTS_PER_SOL,
SystemProgram,
PublicKey,
Transaction,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import * as web3 from "@solana/web3.js"; import * as web3 from "@solana/web3.js";
import { exec } from "child_process"; import { exec } from "child_process";
import * as fs from "fs" import * as fs from "fs";
import { promisify } from "util"; import { promisify } from "util";
import { getKeypairFromFile } from "./common_utils"; import { getKeypairFromFile } from "./common_utils";
export interface ProgramData { export interface ProgramData {
name: string, name: string;
programPath: string, programPath: string;
programKeyPath: string, programKeyPath: string;
idl: string, idl: string;
} }
export async function deploy_programs(url: String, payer: string, programs: ProgramData[]) { export async function deploy_programs(
for (const program of programs) { url: String,
let cmd = 'solana program deploy --program-id ' + program.programKeyPath + ' --keypair ' + payer + ' --url ' + url + ' ' + program.programPath; payer: string,
let execPromise = promisify(exec) programs: ProgramData[]
// wait for exec to complete ) {
const {stdout, stderr} = await execPromise(cmd); for (const program of programs) {
if (stdout.length > 0) { let cmd =
console.log(stdout); "solana program deploy --program-id " +
} program.programKeyPath +
" --keypair " +
payer +
" --url " +
url +
" " +
program.programPath;
let execPromise = promisify(exec);
// wait for exec to complete
const { stdout, stderr } = await execPromise(cmd);
if (stdout.length > 0) {
console.log(stdout);
}
if (stderr.length > 0) { if (stderr.length > 0) {
console.log(stderr); console.log(stderr);
} }
/** TODO: this is not working yet bc. anchor wants a workspace
if (program.idl.length > 0) { if (program.idl.length > 0) {
let programId = getKeypairFromFile(program.programKeyPath); let programId = getKeypairFromFile(program.programKeyPath);
console.log("deploying idl file for program " + programId.publicKey); console.log("deploying idl file for program " + programId.publicKey);
@ -44,5 +65,6 @@ export async function deploy_programs(url: String, payer: string, programs: Prog
} }
} }
} }
} */
}
} }

View File

@ -1,46 +1,62 @@
import { Connection, Keypair, SystemProgram, PublicKey, Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; import {
Connection,
Keypair,
SystemProgram,
PublicKey,
Transaction,
sendAndConfirmTransaction,
} from "@solana/web3.js";
export async function configure_accounts(connection: Connection, authority: Keypair, count: number, programs: PublicKey[]): Promise<PublicKey[]> { export async function configure_accounts(
connection: Connection,
authority: Keypair,
count: number,
programs: PublicKey[]
): Promise<PublicKey[]> {
let all_accounts: PublicKey[] = [];
// create accounts in batches of 16
for (let i = 0; i < count; i += 16) {
let end = Math.min(i + 16, count);
let nbOfAccs = end - i;
let accounts = await Promise.all(
Array.from(Array(nbOfAccs).keys()).map(async (_) => {
let size = Math.random() * 10_000_000;
if (size < 100) {
size = 100;
}
size = Math.floor(size);
let all_accounts: PublicKey[] = []; const lamports = await connection.getMinimumBalanceForRentExemption(
// create accounts in batches of 16 size
for (let i = 0; i < count; i += 16) { );
let end = Math.min(i + 16, count); let kp = Keypair.generate();
let nbOfAccs = end - i; const program = programs[Math.floor(Math.random() * programs.length)];
let accounts = await Promise.all(Array.from(Array(nbOfAccs).keys()).map(async _ => {
let size = Math.random() * 10_000_000;
if (size < 100) {
size = 100;
}
size = Math.floor(size);
const lamports = await connection.getMinimumBalanceForRentExemption(size); const transaction = new Transaction().add(
let kp = Keypair.generate(); SystemProgram.createAccount({
const program = programs[Math.floor(Math.random() * programs.length)]; fromPubkey: authority.publicKey,
newAccountPubkey: kp.publicKey,
lamports,
space: size,
programId: program,
})
);
const transaction = new Transaction().add( transaction.feePayer = authority.publicKey;
SystemProgram.createAccount({ let hash = await connection.getRecentBlockhash();
fromPubkey: authority.publicKey, transaction.recentBlockhash = hash.blockhash;
newAccountPubkey: kp.publicKey, // Sign transaction, broadcast, and confirm
lamports, await sendAndConfirmTransaction(
space: size, connection,
programId: program, transaction,
})) [authority, kp],
{ commitment: "confirmed" }
);
transaction.feePayer = authority.publicKey; return kp.publicKey;
let hash = await connection.getRecentBlockhash(); })
transaction.recentBlockhash = hash.blockhash; );
// Sign transaction, broadcast, and confirm all_accounts = all_accounts.concat(accounts);
await sendAndConfirmTransaction( }
connection, return all_accounts;
transaction,
[authority, kp],
{ commitment: 'confirmed' },
);
return kp.publicKey
}))
all_accounts = all_accounts.concat(accounts);
}
return all_accounts
} }

View File

@ -1,44 +1,74 @@
import { Connection, Keypair, LAMPORTS_PER_SOL, PublicKey, SystemProgram, Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; import {
Connection,
Keypair,
LAMPORTS_PER_SOL,
PublicKey,
SystemProgram,
Transaction,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import { Market } from "../openbook-v2/create_markets"; import { Market } from "../openbook-v2/create_markets";
import { MintUtils } from "./mint_utils"; import { MintUtils } from "./mint_utils";
import * as splToken from '@solana/spl-token' import * as splToken from "@solana/spl-token";
import { OpenOrders } from "../openbook-v2/configure_openbook"; import { OpenOrders } from "../openbook-v2/configure_openbook";
export interface User { export interface User {
secret: number[], secret: number[];
token_data : TokenAccountData[], token_data: TokenAccountData[];
open_orders: OpenOrders[], open_orders: OpenOrders[];
} }
export async function createUser(connection: Connection, authority: Keypair, balancePerPayer: number): Promise<Keypair> { export async function createUser(
let payer = Keypair.generate(); connection: Connection,
let transfer_ix = SystemProgram.transfer({ authority: Keypair,
fromPubkey: authority.publicKey, balancePerPayer: number
toPubkey: payer.publicKey, ): Promise<Keypair> {
lamports: balancePerPayer * LAMPORTS_PER_SOL, let payer = Keypair.generate();
}); let transfer_ix = SystemProgram.transfer({
let tx = new Transaction().add(transfer_ix); fromPubkey: authority.publicKey,
tx.feePayer = authority.publicKey; toPubkey: payer.publicKey,
const bh = await connection.getLatestBlockhash(); lamports: balancePerPayer * LAMPORTS_PER_SOL,
tx.recentBlockhash = bh.blockhash; });
sendAndConfirmTransaction(connection, tx, [authority]); let tx = new Transaction().add(transfer_ix);
return payer tx.feePayer = authority.publicKey;
const bh = await connection.getLatestBlockhash();
tx.recentBlockhash = bh.blockhash;
sendAndConfirmTransaction(connection, tx, [authority]);
return payer;
} }
interface TokenAccountData { interface TokenAccountData {
mint: PublicKey, mint: PublicKey;
token_account: PublicKey token_account: PublicKey;
} }
export async function mintUser(connection: Connection, authority: Keypair, mints: PublicKey[], mintUtils: MintUtils, user: PublicKey, amount: number) : Promise<TokenAccountData[]> { export async function mintUser(
return await Promise.all( connection: Connection,
mints.map(async(mint)=> { authority: Keypair,
const tokenAccount = await mintUtils.createTokenAccount(mint, authority, user); mints: PublicKey[],
await splToken.mintTo(connection, authority, mint, tokenAccount, authority, amount); mintUtils: MintUtils,
return { user: PublicKey,
mint: mint, amount: number
token_account: tokenAccount ): Promise<TokenAccountData[]> {
} return await Promise.all(
}) mints.map(async (mint) => {
) const tokenAccount = await mintUtils.createTokenAccount(
mint,
authority,
user
);
await splToken.mintTo(
connection,
authority,
mint,
tokenAccount,
authority,
amount
);
return {
mint: mint,
token_account: tokenAccount,
};
})
);
} }

View File

@ -1,63 +1,59 @@
import * as splToken from "@solana/spl-token"; import * as splToken from "@solana/spl-token";
import { import { PublicKey, Connection, Keypair } from "@solana/web3.js";
PublicKey,
Connection,
Keypair,
} from "@solana/web3.js";
export interface TokenData { export interface TokenData {
mint : PublicKey, mint: PublicKey;
startingPrice : number, startingPrice: number;
nbDecimals: number, nbDecimals: number;
priceOracle: Keypair | undefined, priceOracle: Keypair | undefined;
} }
export class MintUtils { export class MintUtils {
private conn: Connection;
private authority: Keypair;
private conn: Connection; constructor(conn: Connection, authority: Keypair) {
private authority: Keypair; this.conn = conn;
this.authority = authority;
}
async createMint(nb_decimals = 6): Promise<PublicKey> {
const kp = Keypair.generate();
return await splToken.createMint(
this.conn,
this.authority,
this.authority.publicKey,
this.authority.publicKey,
nb_decimals,
kp
);
}
constructor(conn: Connection, authority: Keypair) { public async createMints(nbMints: number): Promise<PublicKey[]> {
this.conn = conn; return await Promise.all(
this.authority = authority; Array.from(Array(nbMints).keys()).map((_) => {
} return this.createMint();
})
);
}
async createMint(nb_decimals = 6) : Promise<PublicKey> { public async createNewToken(nbDecimals = 6, startingPrice = 1_000_000) {
const kp = Keypair.generate(); const mint = await this.createMint(nbDecimals);
return await splToken.createMint(this.conn, const tokenData: TokenData = {
this.authority, mint: mint,
this.authority.publicKey, startingPrice: startingPrice,
this.authority.publicKey, nbDecimals: nbDecimals,
nb_decimals, priceOracle: undefined,
kp) };
} return tokenData;
}
public async createMints(nbMints: number) : Promise<PublicKey[]> { public async createTokenAccount(
return await Promise.all(Array.from(Array(nbMints).keys()).map(_ => { mint: PublicKey,
return this.createMint() payer: Keypair,
})) owner: PublicKey
} ) {
const account = Keypair.generate();
public async createNewToken(nbDecimals = 6, startingPrice = 1_000_000) { return splToken.createAccount(this.conn, payer, mint, owner, account);
const mint = await this.createMint(nbDecimals); }
const tokenData : TokenData = { }
mint: mint,
startingPrice : startingPrice,
nbDecimals: nbDecimals,
priceOracle : undefined,
};
return tokenData;
}
public async createTokenAccount(mint: PublicKey, payer: Keypair, owner: PublicKey) {
const account = Keypair.generate();
return splToken.createAccount(
this.conn,
payer,
mint,
owner,
account
)
}
}

View File

@ -1,27 +1,40 @@
import { Connection, Keypair, PublicKey, SystemProgram, Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; import {
Connection,
Keypair,
PublicKey,
SystemProgram,
Transaction,
sendAndConfirmTransaction,
} from "@solana/web3.js";
export async function createAccount(connection: Connection, authority: Keypair, size: number, owner: PublicKey): Promise<PublicKey> { export async function createAccount(
const lamports = await connection.getMinimumBalanceForRentExemption(size); connection: Connection,
let address = Keypair.generate(); authority: Keypair,
size: number,
owner: PublicKey
): Promise<PublicKey> {
const lamports = await connection.getMinimumBalanceForRentExemption(size);
let address = Keypair.generate();
const transaction = new Transaction().add( const transaction = new Transaction().add(
SystemProgram.createAccount({ SystemProgram.createAccount({
fromPubkey: authority.publicKey, fromPubkey: authority.publicKey,
newAccountPubkey: address.publicKey, newAccountPubkey: address.publicKey,
lamports, lamports,
space: size, space: size,
programId: owner, programId: owner,
})) })
);
transaction.feePayer = authority.publicKey; transaction.feePayer = authority.publicKey;
let hash = await connection.getRecentBlockhash(); let hash = await connection.getRecentBlockhash();
transaction.recentBlockhash = hash.blockhash; transaction.recentBlockhash = hash.blockhash;
// Sign transaction, broadcast, and confirm // Sign transaction, broadcast, and confirm
await sendAndConfirmTransaction( await sendAndConfirmTransaction(
connection, connection,
transaction, transaction,
[authority, address], [authority, address],
{ commitment: 'confirmed' }, { commitment: "confirmed" }
); );
return address.publicKey; return address.publicKey;
} }

282
configure/main.ts Normal file
View File

@ -0,0 +1,282 @@
import { command, number, option, string, run, boolean, flag } from "cmd-ts";
import * as fs from "fs";
import programs from "./programs.json";
import {
Commitment,
Connection,
Keypair,
LAMPORTS_PER_SOL,
Transaction,
} from "@solana/web3.js";
import { getKeypairFromFile } from "./common_utils";
import { deploy_programs } from "./deploy_programs";
import { User, createUser, mintUser } from "./general/create_users";
import { configure_accounts } from "./general/accounts";
import { Command, OutputFile } from "./output_file";
import { MintUtils } from "./general/mint_utils";
import { OpenbookConfigurator } from "./openbook-v2/configure_openbook";
const numberOfAccountsToBeCreated = option({
type: number,
defaultValue: () => 256,
long: "number-of-accounts",
});
const endpoint = option({
type: string,
defaultValue: () => "http://127.0.0.1:8899",
long: "url",
short: "u",
description: "RPC url",
});
const authority = option({
type: string,
defaultValue: () => "~/.config/solana/id.json",
long: "authority",
short: "a",
});
const nbPayers = option({
type: number,
defaultValue: () => 10,
long: "number-of-payers",
short: "p",
description: "Number of payers used for testing",
});
const balancePerPayer = option({
type: number,
defaultValue: () => 1,
long: "payer-balance",
short: "b",
description: "Balance of payer in SOLs",
});
const nbMints = option({
type: number,
defaultValue: () => 10,
long: "number-of-mints",
short: "m",
description: "Number of mints",
});
const skipProgramDeployment = flag({
type: boolean,
defaultValue: () => false,
long: "skip-program-deployment",
short: "s",
description: "Skip deploying programs",
});
const outFile = option({
type: string,
defaultValue: () => "cofigure/config.json",
long: "output-file",
short: "o",
});
const app = command({
name: "configure",
args: {
endpoint,
numberOfAccountsToBeCreated,
authority,
nbPayers,
balancePerPayer,
nbMints,
skipProgramDeployment,
outFile,
},
handler: ({
endpoint,
numberOfAccountsToBeCreated,
authority,
nbPayers,
balancePerPayer,
nbMints,
skipProgramDeployment,
outFile,
}) => {
console.log("configuring a new test instance");
configure(
endpoint,
numberOfAccountsToBeCreated,
authority,
nbPayers,
balancePerPayer,
nbMints,
skipProgramDeployment,
outFile
).then((_) => {
console.log("configuration finished");
});
},
});
run(app, process.argv.slice(2));
// configure part
async function configure(
endpoint: String,
numberOfAccountsToBeCreated: number,
authorityFile: String,
nbPayers: number,
balancePerPayer: number,
nbMints: number,
skipProgramDeployment: boolean,
outFile: String
) {
// create connections
const connection = new Connection(
endpoint.toString(),
"confirmed" as Commitment
);
// configure authority
const authority = getKeypairFromFile(authorityFile);
const authorityBalance = await connection.getBalance(authority.publicKey);
const requiredBalance =
nbPayers * (balancePerPayer * LAMPORTS_PER_SOL) + 100 * LAMPORTS_PER_SOL;
if (authorityBalance < requiredBalance) {
console.log(
"authority may have low balance balance " +
authorityBalance +
" required balance " +
requiredBalance
);
}
let programOutputData = programs.map((x) => {
let kp = getKeypairFromFile(x.programKeyPath);
let emptyCommands: Command[] = [];
return {
name: x.name,
program_id: kp.publicKey,
commands: emptyCommands,
};
});
let programIds = programOutputData.map((x) => {
return x.program_id;
});
if (!skipProgramDeployment) {
console.log("starting program deployment");
await deploy_programs(endpoint, authorityFile.toString(), programs);
console.log("programs deployed");
}
console.log("Creating Mints");
let mintUtils = new MintUtils(connection, authority);
let mints = await mintUtils.createMints(nbMints);
console.log("Mints created");
console.log("Configuring openbook-v2");
let index = programs.findIndex((x) => x.name === "openbook_v2");
let openbookProgramId = programOutputData[index].program_id;
let openbookConfigurator = new OpenbookConfigurator(
connection,
authority,
mintUtils,
openbookProgramId
);
let markets = await openbookConfigurator.configureOpenbookV2(mints);
programOutputData[index].commands = await openbookConfigurator.getCommands();
console.log("Finished configuring openbook");
console.log("Creating users");
let users = await Promise.all(
Array.from(Array(nbPayers).keys()).map((_) =>
createUser(connection, authority, balancePerPayer)
)
);
let tokenAccounts = await Promise.all(
users.map(
/// user is richer than bill gates, but not as rich as certain world leaders
async (user) =>
await mintUser(
connection,
authority,
mints,
mintUtils,
user.publicKey,
100_000_000_000_000_000
)
)
);
let userOpenOrders = await Promise.all(
users.map(
/// user is crazy betting all his money in crypto market
async (user) =>
await openbookConfigurator.configureMarketForUser(user, markets)
)
);
let userData: User[] = users.map((user, i) => {
return {
secret: Array.from(user.secretKey),
open_orders: userOpenOrders[i],
token_data: tokenAccounts[i],
};
});
console.log("Users created");
console.log("Filling up orderbook");
await Promise.all(
userData.map(async (user, i) => {
for (const market of markets) {
await openbookConfigurator.fillOrderBook(user, users[i], market, 32);
}
})
);
console.log("Orderbook filled");
console.log("Creating accounts");
let accounts = await configure_accounts(
connection,
authority,
numberOfAccountsToBeCreated,
programIds
);
// adding known accounts
const marketAccountsList = markets
.map((market) => [
market.asks,
market.bids,
market.market_pk,
market.oracle,
market.quote_vault,
market.base_vault,
market.base_mint,
market.quote_mint,
])
.flat();
const userAccountsList = userData
.map((user) => {
const allOpenOrdersAccounts = user.open_orders
.map((x) => x.open_orders)
.flat();
const allTokenAccounts = user.token_data.map((x) => x.token_account);
return allOpenOrdersAccounts.concat(allTokenAccounts);
})
.flat();
accounts = accounts.concat(marketAccountsList).concat(userAccountsList);
console.log("Accounts created");
let outputFile: OutputFile = {
programs: programOutputData,
known_accounts: accounts,
users: userData,
mints,
markets,
};
console.log("creating output file");
fs.writeFileSync(outFile.toString(), JSON.stringify(outputFile));
}

View File

@ -3,7 +3,7 @@ import { TestProvider } from "../anchor_utils";
import { Market, createMarket } from "./create_markets"; import { Market, createMarket } from "./create_markets";
import { MintUtils } from "../general/mint_utils"; import { MintUtils } from "../general/mint_utils";
import { OpenbookV2 } from "./openbook_v2"; import { OpenbookV2 } from "./openbook_v2";
import IDL from '../programs/openbook_v2.json' import IDL from "../programs/openbook_v2.json";
import { BN, Program, web3, IdlTypes } from "@project-serum/anchor"; import { BN, Program, web3, IdlTypes } from "@project-serum/anchor";
import { User } from "../general/create_users"; import { User } from "../general/create_users";
import { U64_MAX_BN } from "@blockworks-foundation/mango-v4"; import { U64_MAX_BN } from "@blockworks-foundation/mango-v4";
@ -12,136 +12,176 @@ import { Command } from "../output_file";
import assert from "assert"; import assert from "assert";
export interface OpenOrders { export interface OpenOrders {
market: PublicKey, market: PublicKey;
open_orders: PublicKey open_orders: PublicKey;
} }
export class OpenbookConfigurator { export class OpenbookConfigurator {
anchorProvider: TestProvider;
mintUtils: MintUtils;
openbookProgramId: PublicKey;
program: Program<OpenbookV2>;
anchorProvider: TestProvider; constructor(
mintUtils: MintUtils; connection: Connection,
openbookProgramId: PublicKey; authority: Keypair,
program: Program<OpenbookV2>; mintUtils: MintUtils,
openbookProgramId: PublicKey
) {
this.anchorProvider = new TestProvider(connection, authority);
this.mintUtils = mintUtils;
this.openbookProgramId = openbookProgramId;
this.program = new Program<OpenbookV2>(
IDL as OpenbookV2,
this.openbookProgramId,
this.anchorProvider
);
}
constructor(connection: Connection, authority: Keypair, mintUtils: MintUtils, openbookProgramId: PublicKey) { public async configureOpenbookV2(mints: PublicKey[]): Promise<Market[]> {
this.anchorProvider = new TestProvider(connection, authority); let quoteMint = mints[0];
this.mintUtils = mintUtils; let admin = Keypair.generate();
this.openbookProgramId = openbookProgramId; return await Promise.all(
this.program = new Program<OpenbookV2>( mints
IDL as OpenbookV2, .slice(1)
this.openbookProgramId, .map((mint, index) =>
createMarket(
this.program,
this.anchorProvider, this.anchorProvider,
); this.mintUtils,
} admin,
this.openbookProgramId,
public async configureOpenbookV2(mints: PublicKey[]): Promise<Market[]> { mint,
let quoteMint = mints[0]; quoteMint,
let admin = Keypair.generate(); index
return await Promise.all(mints.slice(1).map((mint, index) => createMarket(this.program, this.anchorProvider, this.mintUtils, admin, this.openbookProgramId, mint, quoteMint, index))) )
}
public async configureMarketForUser(user: Keypair, markets: Market[],) : Promise<OpenOrders[]> {
const openOrders = await Promise.all(
markets.map(async(market) => {
let accountIndex = new BN(0);
let [openOrders, _tmp] = PublicKey.findProgramAddressSync([Buffer.from("OpenOrders"), user.publicKey.toBuffer(), market.market_pk.toBuffer(), accountIndex.toBuffer("le", 4)], this.openbookProgramId)
await this.program.methods.initOpenOrders(
0,
64
).accounts({
openOrdersAccount: openOrders,
market: market.market_pk,
owner: user.publicKey,
payer: this.anchorProvider.publicKey,
systemProgram: web3.SystemProgram.programId,
}).signers([user]).rpc();
return [market.market_pk, openOrders]
})
) )
);
}
return openOrders.map(x=> { public async configureMarketForUser(
return { user: Keypair,
market : x[0], markets: Market[]
open_orders : x[1], ): Promise<OpenOrders[]> {
} const openOrders = await Promise.all(
markets.map(async (market) => {
let accountIndex = new BN(0);
let [openOrders, _tmp] = PublicKey.findProgramAddressSync(
[
Buffer.from("OpenOrders"),
user.publicKey.toBuffer(),
market.market_pk.toBuffer(),
accountIndex.toBuffer("le", 4),
],
this.openbookProgramId
);
await this.program.methods
.initOpenOrders(0, 64)
.accounts({
openOrdersAccount: openOrders,
market: market.market_pk,
owner: user.publicKey,
payer: this.anchorProvider.publicKey,
systemProgram: web3.SystemProgram.programId,
})
.signers([user])
.rpc();
return [market.market_pk, openOrders];
})
);
return openOrders.map((x) => {
return {
market: x[0],
open_orders: x[1],
};
});
}
public async fillOrderBook(
user: User,
userKp: Keypair,
market: Market,
nbOrders: number
) {
for (let i = 0; i < nbOrders; ++i) {
let side = { bid: {} };
let placeOrder = { limit: {} };
await this.program.methods
.placeOrder(
side,
new BN(1000 - 1 - i),
new BN(10),
new BN(1000000),
new BN(i),
placeOrder,
false,
U64_MAX_BN,
255
)
.accounts({
asks: market.asks,
baseVault: market.base_vault,
bids: market.bids,
eventQueue: market.event_queue,
market: market.market_pk,
openOrdersAccount: user.open_orders[market.market_index].open_orders,
oracle: market.oracle,
owner: userKp.publicKey,
payer: user.token_data[0].token_account,
quoteVault: market.quote_vault,
systemProgram: web3.SystemProgram.programId,
tokenProgram: TOKEN_PROGRAM_ID,
}) })
.signers([userKp])
.rpc();
} }
public async fillOrderBook(user: User, userKp: Keypair, market: Market, nbOrders: number) { for (let i = 0; i < nbOrders; ++i) {
let side = { ask: {} };
let placeOrder = { limit: {} };
for( let i=0; i<nbOrders; ++i) { await this.program.methods
.placeOrder(
let side = {bid:{}} ; side,
let placeOrder = {limit:{}}; new BN(1000 + 1 + i),
new BN(10000),
await this.program.methods.placeOrder( new BN(1000000),
side, new BN(i + nbOrders + 1),
new BN(1000-1-i), placeOrder,
new BN(10), false,
new BN(1000000), U64_MAX_BN,
new BN(i), 255
placeOrder, )
false, .accounts({
U64_MAX_BN, asks: market.asks,
255, baseVault: market.base_vault,
).accounts({ bids: market.bids,
asks: market.asks, eventQueue: market.event_queue,
baseVault: market.base_vault, market: market.market_pk,
bids: market.bids, openOrdersAccount: user.open_orders[market.market_index].open_orders,
eventQueue: market.event_queue, oracle: market.oracle,
market: market.market_pk, owner: userKp.publicKey,
openOrdersAccount: user.open_orders[market.market_index].open_orders, payer: user.token_data[market.market_index + 1].token_account,
oracle: market.oracle, quoteVault: market.quote_vault,
owner: userKp.publicKey, systemProgram: web3.SystemProgram.programId,
payer: user.token_data[0].token_account, tokenProgram: TOKEN_PROGRAM_ID,
quoteVault: market.quote_vault, })
systemProgram: web3.SystemProgram.programId, .signers([userKp])
tokenProgram: TOKEN_PROGRAM_ID, .rpc();
}).signers([userKp]).rpc();
}
for( let i=0; i<nbOrders; ++i) {
let side = {ask:{}} ;
let placeOrder = {limit:{}};
await this.program.methods.placeOrder(
side,
new BN(1000+1+i),
new BN(10000),
new BN(1000000),
new BN(i+nbOrders+1),
placeOrder,
false,
U64_MAX_BN,
255,
).accounts({
asks: market.asks,
baseVault: market.base_vault,
bids: market.bids,
eventQueue: market.event_queue,
market: market.market_pk,
openOrdersAccount: user.open_orders[market.market_index].open_orders,
oracle: market.oracle,
owner: userKp.publicKey,
payer: user.token_data[market.market_index+1].token_account,
quoteVault: market.quote_vault,
systemProgram: web3.SystemProgram.programId,
tokenProgram: TOKEN_PROGRAM_ID,
}).signers([userKp]).rpc();
}
} }
}
/// this is a special method.
/// this is a special method. /// It is pain to create an anchor instruction in rust
/// It is pain to create an anchor instruction in rust /// so this method will create the instruction in typescript and serialize into bytes and store it into command type
/// so this method will create the instruction in typescript and serialize into bytes and store it into command type public async getCommands(): Promise<Command[]> {
public async getCommands() : Promise<Command[]> { let side = { bid: {} };
let side = {bid:{}} ; let placeOrder = { limit: {} };
let placeOrder = {limit:{}}; let placeOrderIx = await this.program.methods
let placeOrderIx = await this.program.methods.placeOrder( .placeOrder(
side, side,
new BN(0), new BN(0),
new BN(0), new BN(0),
@ -150,8 +190,9 @@ export class OpenbookConfigurator {
placeOrder, placeOrder,
false, false,
U64_MAX_BN, U64_MAX_BN,
255, 255
).accounts({ )
.accounts({
asks: PublicKey.default, asks: PublicKey.default,
baseVault: PublicKey.default, baseVault: PublicKey.default,
bids: PublicKey.default, bids: PublicKey.default,
@ -164,31 +205,34 @@ export class OpenbookConfigurator {
quoteVault: PublicKey.default, quoteVault: PublicKey.default,
systemProgram: web3.SystemProgram.programId, systemProgram: web3.SystemProgram.programId,
tokenProgram: TOKEN_PROGRAM_ID, tokenProgram: TOKEN_PROGRAM_ID,
}).instruction(); })
.instruction();
let argument_sizes = [8, 1, 8, 8, 8, 8, 1, 1, 8, 1]; let argument_sizes = [8, 1, 8, 8, 8, 8, 1, 1, 8, 1];
assert(argument_sizes.reduce( (sum, current) => sum + current, 0 ) === placeOrderIx.data.length); assert(
let placeOrderCommand : Command = { argument_sizes.reduce((sum, current) => sum + current, 0) ===
name: "placeOrder", placeOrderIx.data.length
instruction: Array.from(placeOrderIx.data), );
argument_sizes, let placeOrderCommand: Command = {
name: "placeOrder",
instruction: Array.from(placeOrderIx.data),
argument_sizes,
}; };
let consumeEvents = await this.program.methods.consumeEvents( let consumeEvents = await this.program.methods
new BN(0), .consumeEvents(new BN(0))
).accounts( .accounts({
{ eventQueue: PublicKey.default,
eventQueue: PublicKey.default, market: PublicKey.default,
market: PublicKey.default, })
} .instruction();
).instruction();
let consumeEventsCommand : Command = { let consumeEventsCommand: Command = {
instruction: Array.from(consumeEvents.data), instruction: Array.from(consumeEvents.data),
name: "consumeEvents", name: "consumeEvents",
argument_sizes: [8, 1] argument_sizes: [8, 1],
} };
return [placeOrderCommand, consumeEventsCommand] return [placeOrderCommand, consumeEventsCommand];
} }
} }

View File

@ -1,92 +1,136 @@
import { Connection, Keypair, PublicKey } from '@solana/web3.js'; import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import IDL from '../programs/openbook_v2.json' import IDL from "../programs/openbook_v2.json";
import { Program, web3, BN } from '@project-serum/anchor'; import { Program, web3, BN } from "@project-serum/anchor";
import { createAccount } from '../general/solana_utils'; import { createAccount } from "../general/solana_utils";
import { MintUtils } from '../general/mint_utils'; import { MintUtils } from "../general/mint_utils";
import { I80F48, I80F48Dto } from '@blockworks-foundation/mango-v4'; import { I80F48, I80F48Dto } from "@blockworks-foundation/mango-v4";
import { OpenbookV2 } from './openbook_v2'; import { OpenbookV2 } from "./openbook_v2";
import { TestProvider } from '../anchor_utils'; import { TestProvider } from "../anchor_utils";
export interface Market { export interface Market {
name: string, name: string;
admin : number[], admin: number[];
market_pk: PublicKey market_pk: PublicKey;
oracle: PublicKey, oracle: PublicKey;
asks: PublicKey, asks: PublicKey;
bids: PublicKey, bids: PublicKey;
event_queue: PublicKey, event_queue: PublicKey;
base_vault: PublicKey, base_vault: PublicKey;
quote_vault: PublicKey, quote_vault: PublicKey;
base_mint: PublicKey, base_mint: PublicKey;
quote_mint: PublicKey, quote_mint: PublicKey;
market_index: number, market_index: number;
} }
export async function createMarket(program:Program<OpenbookV2>, anchorProvider: TestProvider, mintUtils: MintUtils, adminKp: Keypair, openbookProgramId: PublicKey, baseMint: PublicKey, quoteMint: PublicKey, index: number): Promise<Market> { export async function createMarket(
let [oracleId, _tmp] = PublicKey.findProgramAddressSync([Buffer.from("StubOracle"), baseMint.toBytes()], openbookProgramId) program: Program<OpenbookV2>,
const admin:PublicKey = adminKp.publicKey; anchorProvider: TestProvider,
mintUtils: MintUtils,
adminKp: Keypair,
openbookProgramId: PublicKey,
baseMint: PublicKey,
quoteMint: PublicKey,
index: number
): Promise<Market> {
let [oracleId, _tmp] = PublicKey.findProgramAddressSync(
[Buffer.from("StubOracle"), baseMint.toBytes()],
openbookProgramId
);
const admin: PublicKey = adminKp.publicKey;
await program.methods.stubOracleCreate({ val: I80F48.fromNumber(1.0).getData() }) await program.methods
.stubOracleCreate({ val: I80F48.fromNumber(1.0).getData() })
.accounts({ .accounts({
oracle: oracleId, oracle: oracleId,
admin, admin,
mint: baseMint, mint: baseMint,
payer: anchorProvider.wallet.publicKey, payer: anchorProvider.wallet.publicKey,
systemProgram: web3.SystemProgram.programId, systemProgram: web3.SystemProgram.programId,
}) })
.signers([adminKp]) .signers([adminKp])
.rpc(); .rpc();
// bookside size = 123720 // bookside size = 123720
let asks = await createAccount(anchorProvider.connection, anchorProvider.keypair, 123720, openbookProgramId); let asks = await createAccount(
let bids = await createAccount(anchorProvider.connection, anchorProvider.keypair, 123720, openbookProgramId); anchorProvider.connection,
let eventQueue = await createAccount(anchorProvider.connection, anchorProvider.keypair, 97688, openbookProgramId); anchorProvider.keypair,
let marketIndex : BN = new BN(index); 123720,
openbookProgramId
);
let bids = await createAccount(
anchorProvider.connection,
anchorProvider.keypair,
123720,
openbookProgramId
);
let eventQueue = await createAccount(
anchorProvider.connection,
anchorProvider.keypair,
97688,
openbookProgramId
);
let marketIndex: BN = new BN(index);
let [marketPk, _tmp2] = PublicKey.findProgramAddressSync([Buffer.from("Market"), admin.toBuffer(), marketIndex.toBuffer("le", 4)], openbookProgramId) let [marketPk, _tmp2] = PublicKey.findProgramAddressSync(
[Buffer.from("Market"), admin.toBuffer(), marketIndex.toBuffer("le", 4)],
openbookProgramId
);
let baseVault = await mintUtils.createTokenAccount(baseMint, anchorProvider.keypair, marketPk); let baseVault = await mintUtils.createTokenAccount(
let quoteVault = await mintUtils.createTokenAccount(quoteMint, anchorProvider.keypair, marketPk); baseMint,
let name = 'index ' + index.toString() + ' wrt 0'; anchorProvider.keypair,
marketPk
);
let quoteVault = await mintUtils.createTokenAccount(
quoteMint,
anchorProvider.keypair,
marketPk
);
let name = "index " + index.toString() + " wrt 0";
await program.methods.createMarket( await program.methods
marketIndex, .createMarket(
name, marketIndex,
{ name,
confFilter: 0, {
maxStalenessSlots: 100, confFilter: 0,
}, maxStalenessSlots: 100,
new BN(1), new BN(1), 0, 0, 0 },
).accounts( new BN(1),
{ new BN(1),
admin, 0,
market: marketPk, 0,
bids, 0
asks, )
eventQueue, .accounts({
payer: anchorProvider.publicKey, admin,
baseVault, market: marketPk,
quoteVault, bids,
baseMint, asks,
quoteMint, eventQueue,
systemProgram: web3.SystemProgram.programId, payer: anchorProvider.publicKey,
oracle: oracleId, baseVault,
} quoteVault,
).signers([adminKp]) baseMint,
quoteMint,
systemProgram: web3.SystemProgram.programId,
oracle: oracleId,
})
.signers([adminKp])
.rpc(); .rpc();
return { return {
admin: Array.from(adminKp.secretKey), admin: Array.from(adminKp.secretKey),
name, name,
bids, bids,
asks, asks,
event_queue: eventQueue, event_queue: eventQueue,
base_mint: baseMint, base_mint: baseMint,
base_vault: baseVault, base_vault: baseVault,
market_index: index, market_index: index,
market_pk: marketPk, market_pk: marketPk,
oracle: oracleId, oracle: oracleId,
quote_mint: quoteMint, quote_mint: quoteMint,
quote_vault: quoteVault, quote_vault: quoteVault,
} };
} }

File diff suppressed because it is too large Load Diff

View File

@ -3,21 +3,21 @@ import { Market } from "./openbook-v2/create_markets";
import { User } from "./general/create_users"; import { User } from "./general/create_users";
export interface Command { export interface Command {
name: String, name: String;
instruction: number[], instruction: number[];
argument_sizes: number[], argument_sizes: number[];
} }
export interface ProgramOutputData { export interface ProgramOutputData {
name: String, name: String;
program_id: PublicKey, program_id: PublicKey;
commands: Command [], commands: Command[];
} }
export interface OutputFile { export interface OutputFile {
users: User[], users: User[];
programs: ProgramOutputData[], programs: ProgramOutputData[];
known_accounts: PublicKey[], known_accounts: PublicKey[];
mints: PublicKey[], mints: PublicKey[];
markets: Market[], markets: Market[];
} }

View File

@ -1,14 +1,14 @@
[ [
{ {
"name": "pyth_mock", "name": "pyth_mock",
"programPath": "programs/pyth_mock.so", "programPath": "configure/programs/pyth_mock.so",
"programKeyPath": "programs/pyth_mock.json", "programKeyPath": "configure/programs/pyth_mock.json",
"idl": "" "idl": ""
}, },
{ {
"name": "openbook_v2", "name": "openbook_v2",
"programPath": "programs/openbook_v2.so", "programPath": "configure/programs/openbook_v2.so",
"programKeyPath": "programs/openbook_v2-keypair.json", "programKeyPath": "configure/programs/openbook_v2-keypair.json",
"idl": "programs/openbook_v2.json" "idl": ""
} }
] ]

View File

@ -1 +1,6 @@
[171,85,64,152,85,43,106,98,158,185,190,190,234,79,138,30,140,60,95,30,192,14,16,22,82,32,87,208,65,91,89,245,57,63,214,97,128,249,112,13,187,5,224,38,17,8,25,178,88,226,115,45,80,88,164,168,139,142,172,189,196,225,156,28] [
171, 85, 64, 152, 85, 43, 106, 98, 158, 185, 190, 190, 234, 79, 138, 30, 140,
60, 95, 30, 192, 14, 16, 22, 82, 32, 87, 208, 65, 91, 89, 245, 57, 63, 214,
97, 128, 249, 112, 13, 187, 5, 224, 38, 17, 8, 25, 178, 88, 226, 115, 45, 80,
88, 164, 168, 139, 142, 172, 189, 196, 225, 156, 28
]

View File

@ -640,9 +640,7 @@
}, },
{ {
"name": "cancelAllOrders", "name": "cancelAllOrders",
"docs": [ "docs": ["Cancel up to `limit` orders."],
"Cancel up to `limit` orders."
],
"accounts": [ "accounts": [
{ {
"name": "openOrdersAccount", "name": "openOrdersAccount",
@ -679,9 +677,7 @@
}, },
{ {
"name": "cancelAllOrdersBySide", "name": "cancelAllOrdersBySide",
"docs": [ "docs": ["Cancel up to `limit` orders on a single side of the book."],
"Cancel up to `limit` orders on a single side of the book."
],
"accounts": [ "accounts": [
{ {
"name": "openOrdersAccount", "name": "openOrdersAccount",
@ -793,9 +789,7 @@
}, },
{ {
"name": "settleFunds", "name": "settleFunds",
"docs": [ "docs": ["Withdraw any available tokens."],
"Withdraw any available tokens."
],
"accounts": [ "accounts": [
{ {
"name": "openOrdersAccount", "name": "openOrdersAccount",
@ -842,9 +836,7 @@
}, },
{ {
"name": "sweepFees", "name": "sweepFees",
"docs": [ "docs": ["Sweep fees, as a [`Market`](crate::state::Market)'s admin."],
"Sweep fees, as a [`Market`](crate::state::Market)'s admin."
],
"accounts": [ "accounts": [
{ {
"name": "market", "name": "market",
@ -876,9 +868,7 @@
}, },
{ {
"name": "closeMarket", "name": "closeMarket",
"docs": [ "docs": ["Close a [`Market`](crate::state::Market)."],
"Close a [`Market`](crate::state::Market)."
],
"accounts": [ "accounts": [
{ {
"name": "admin", "name": "admin",
@ -1014,23 +1004,17 @@
"fields": [ "fields": [
{ {
"name": "admin", "name": "admin",
"docs": [ "docs": ["Admin who can close this market"],
"Admin who can close this market"
],
"type": "publicKey" "type": "publicKey"
}, },
{ {
"name": "marketIndex", "name": "marketIndex",
"docs": [ "docs": ["Index of this market"],
"Index of this market"
],
"type": "u32" "type": "u32"
}, },
{ {
"name": "bump", "name": "bump",
"docs": [ "docs": ["PDA bump"],
"PDA bump"
],
"type": "u8" "type": "u8"
}, },
{ {
@ -1049,57 +1033,39 @@
{ {
"name": "padding1", "name": "padding1",
"type": { "type": {
"array": [ "array": ["u8", 1]
"u8",
1
]
} }
}, },
{ {
"name": "name", "name": "name",
"docs": [ "docs": ["Name. Trailing zero bytes are ignored."],
"Name. Trailing zero bytes are ignored."
],
"type": { "type": {
"array": [ "array": ["u8", 16]
"u8",
16
]
} }
}, },
{ {
"name": "bids", "name": "bids",
"docs": [ "docs": ["Address of the BookSide account for bids"],
"Address of the BookSide account for bids"
],
"type": "publicKey" "type": "publicKey"
}, },
{ {
"name": "asks", "name": "asks",
"docs": [ "docs": ["Address of the BookSide account for asks"],
"Address of the BookSide account for asks"
],
"type": "publicKey" "type": "publicKey"
}, },
{ {
"name": "eventQueue", "name": "eventQueue",
"docs": [ "docs": ["Address of the EventQueue account"],
"Address of the EventQueue account"
],
"type": "publicKey" "type": "publicKey"
}, },
{ {
"name": "oracle", "name": "oracle",
"docs": [ "docs": ["Oracle account address"],
"Oracle account address"
],
"type": "publicKey" "type": "publicKey"
}, },
{ {
"name": "oracleConfig", "name": "oracleConfig",
"docs": [ "docs": ["Oracle configuration"],
"Oracle configuration"
],
"type": { "type": {
"defined": "OracleConfig" "defined": "OracleConfig"
} }
@ -1137,16 +1103,12 @@
}, },
{ {
"name": "seqNum", "name": "seqNum",
"docs": [ "docs": ["Total number of orders seen"],
"Total number of orders seen"
],
"type": "u64" "type": "u64"
}, },
{ {
"name": "registrationTime", "name": "registrationTime",
"docs": [ "docs": ["Timestamp in seconds that the market was registered at."],
"Timestamp in seconds that the market was registered at."
],
"type": "u64" "type": "u64"
}, },
{ {
@ -1161,45 +1123,34 @@
}, },
{ {
"name": "takerFee", "name": "takerFee",
"docs": [ "docs": ["Fee for taker orders, may not be negative."],
"Fee for taker orders, may not be negative."
],
"type": { "type": {
"defined": "I80F48" "defined": "I80F48"
} }
}, },
{ {
"name": "feesAccrued", "name": "feesAccrued",
"docs": [ "docs": ["Fees accrued in native quote currency"],
"Fees accrued in native quote currency"
],
"type": { "type": {
"defined": "I80F48" "defined": "I80F48"
} }
}, },
{ {
"name": "feesSettled", "name": "feesSettled",
"docs": [ "docs": ["Fees settled in native quote currency"],
"Fees settled in native quote currency"
],
"type": { "type": {
"defined": "I80F48" "defined": "I80F48"
} }
}, },
{ {
"name": "feePenalty", "name": "feePenalty",
"docs": [ "docs": ["Fee (in quote native) to charge for ioc orders"],
"Fee (in quote native) to charge for ioc orders"
],
"type": "f32" "type": "f32"
}, },
{ {
"name": "padding2", "name": "padding2",
"type": { "type": {
"array": [ "array": ["u8", 4]
"u8",
4
]
} }
}, },
{ {
@ -1249,10 +1200,7 @@
{ {
"name": "reserved", "name": "reserved",
"type": { "type": {
"array": [ "array": ["u8", 1888]
"u8",
1888
]
} }
} }
] ]
@ -1270,10 +1218,7 @@
{ {
"name": "name", "name": "name",
"type": { "type": {
"array": [ "array": ["u8", 32]
"u8",
32
]
} }
}, },
{ {
@ -1291,10 +1236,7 @@
{ {
"name": "padding", "name": "padding",
"type": { "type": {
"array": [ "array": ["u8", 3]
"u8",
3
]
} }
}, },
{ {
@ -1307,9 +1249,7 @@
}, },
{ {
"name": "buybackFeesAccruedPrevious", "name": "buybackFeesAccruedPrevious",
"docs": [ "docs": ["Fees buyback amount from the previous expiry interval."],
"Fees buyback amount from the previous expiry interval."
],
"type": "u64" "type": "u64"
}, },
{ {
@ -1328,10 +1268,7 @@
{ {
"name": "reserved", "name": "reserved",
"type": { "type": {
"array": [ "array": ["u8", 208]
"u8",
208
]
} }
}, },
{ {
@ -1341,10 +1278,7 @@
{ {
"name": "padding3", "name": "padding3",
"type": { "type": {
"array": [ "array": ["u8", 7]
"u8",
7
]
} }
}, },
{ {
@ -1388,10 +1322,7 @@
{ {
"name": "reserved", "name": "reserved",
"type": { "type": {
"array": [ "array": ["u8", 128]
"u8",
128
]
} }
} }
] ]
@ -1427,10 +1358,7 @@
{ {
"name": "reserved", "name": "reserved",
"type": { "type": {
"array": [ "array": ["u8", 256]
"u8",
256
]
} }
}, },
{ {
@ -1467,10 +1395,7 @@
{ {
"name": "reserved", "name": "reserved",
"type": { "type": {
"array": [ "array": ["u8", 64]
"u8",
64
]
} }
} }
] ]
@ -1490,10 +1415,7 @@
{ {
"name": "name", "name": "name",
"type": { "type": {
"array": [ "array": ["u8", 32]
"u8",
32
]
} }
}, },
{ {
@ -1511,10 +1433,7 @@
{ {
"name": "padding", "name": "padding",
"type": { "type": {
"array": [ "array": ["u8", 3]
"u8",
3
]
} }
}, },
{ {
@ -1538,10 +1457,7 @@
{ {
"name": "reserved", "name": "reserved",
"type": { "type": {
"array": [ "array": ["u8", 208]
"u8",
208
]
} }
} }
] ]
@ -1561,16 +1477,12 @@
}, },
{ {
"name": "bidsBaseLots", "name": "bidsBaseLots",
"docs": [ "docs": ["Base lots in open bids"],
"Base lots in open bids"
],
"type": "i64" "type": "i64"
}, },
{ {
"name": "asksBaseLots", "name": "asksBaseLots",
"docs": [ "docs": ["Base lots in open asks"],
"Base lots in open asks"
],
"type": "i64" "type": "i64"
}, },
{ {
@ -1618,10 +1530,7 @@
{ {
"name": "reserved", "name": "reserved",
"type": { "type": {
"array": [ "array": ["u8", 88]
"u8",
88
]
} }
} }
] ]
@ -1639,10 +1548,7 @@
{ {
"name": "padding1", "name": "padding1",
"type": { "type": {
"array": [ "array": ["u8", 7]
"u8",
7
]
} }
}, },
{ {
@ -1660,10 +1566,7 @@
{ {
"name": "reserved", "name": "reserved",
"type": { "type": {
"array": [ "array": ["u8", 64]
"u8",
64
]
} }
} }
] ]
@ -1687,10 +1590,7 @@
{ {
"name": "reserved", "name": "reserved",
"type": { "type": {
"array": [ "array": ["u8", 72]
"u8",
72
]
} }
} }
] ]
@ -1733,10 +1633,7 @@
{ {
"name": "padding", "name": "padding",
"type": { "type": {
"array": [ "array": ["u8", 3]
"u8",
3
]
} }
}, },
{ {
@ -1749,21 +1646,14 @@
}, },
{ {
"name": "key", "name": "key",
"docs": [ "docs": ["only the top `prefix_len` bits of `key` are relevant"],
"only the top `prefix_len` bits of `key` are relevant"
],
"type": "u128" "type": "u128"
}, },
{ {
"name": "children", "name": "children",
"docs": [ "docs": ["indexes into `BookSide::nodes`"],
"indexes into `BookSide::nodes`"
],
"type": { "type": {
"array": [ "array": ["u32", 2]
"u32",
2
]
} }
}, },
{ {
@ -1775,19 +1665,13 @@
"iterate through the whole bookside." "iterate through the whole bookside."
], ],
"type": { "type": {
"array": [ "array": ["u64", 2]
"u64",
2
]
} }
}, },
{ {
"name": "reserved", "name": "reserved",
"type": { "type": {
"array": [ "array": ["u8", 72]
"u8",
72
]
} }
} }
] ]
@ -1795,24 +1679,18 @@
}, },
{ {
"name": "LeafNode", "name": "LeafNode",
"docs": [ "docs": ["LeafNodes represent an order in the binary tree"],
"LeafNodes represent an order in the binary tree"
],
"type": { "type": {
"kind": "struct", "kind": "struct",
"fields": [ "fields": [
{ {
"name": "tag", "name": "tag",
"docs": [ "docs": ["NodeTag"],
"NodeTag"
],
"type": "u8" "type": "u8"
}, },
{ {
"name": "ownerSlot", "name": "ownerSlot",
"docs": [ "docs": ["Index into the owning OpenOrdersAccount's OpenOrders"],
"Index into the owning OpenOrdersAccount's OpenOrders"
],
"type": "u8" "type": "u8"
}, },
{ {
@ -1825,10 +1703,7 @@
{ {
"name": "padding", "name": "padding",
"type": { "type": {
"array": [ "array": ["u8", 1]
"u8",
1
]
} }
}, },
{ {
@ -1842,38 +1717,27 @@
{ {
"name": "padding2", "name": "padding2",
"type": { "type": {
"array": [ "array": ["u8", 2]
"u8",
2
]
} }
}, },
{ {
"name": "key", "name": "key",
"docs": [ "docs": ["The binary tree key, see new_node_key()"],
"The binary tree key, see new_node_key()"
],
"type": "u128" "type": "u128"
}, },
{ {
"name": "owner", "name": "owner",
"docs": [ "docs": ["Address of the owning OpenOrdersAccount"],
"Address of the owning OpenOrdersAccount"
],
"type": "publicKey" "type": "publicKey"
}, },
{ {
"name": "quantity", "name": "quantity",
"docs": [ "docs": ["Number of base lots to buy or sell, always >=1"],
"Number of base lots to buy or sell, always >=1"
],
"type": "i64" "type": "i64"
}, },
{ {
"name": "timestamp", "name": "timestamp",
"docs": [ "docs": ["The time the order was placed"],
"The time the order was placed"
],
"type": "u64" "type": "u64"
}, },
{ {
@ -1888,18 +1752,13 @@
}, },
{ {
"name": "clientOrderId", "name": "clientOrderId",
"docs": [ "docs": ["User defined id for this order, used in FillEvents"],
"User defined id for this order, used in FillEvents"
],
"type": "u64" "type": "u64"
}, },
{ {
"name": "reserved", "name": "reserved",
"type": { "type": {
"array": [ "array": ["u8", 32]
"u8",
32
]
} }
} }
] ]
@ -1917,10 +1776,7 @@
{ {
"name": "data", "name": "data",
"type": { "type": {
"array": [ "array": ["u8", 119]
"u8",
119
]
} }
} }
] ]
@ -1959,10 +1815,7 @@
{ {
"name": "padding", "name": "padding",
"type": { "type": {
"array": [ "array": ["u8", 3]
"u8",
3
]
} }
}, },
{ {
@ -1980,10 +1833,7 @@
{ {
"name": "reserved", "name": "reserved",
"type": { "type": {
"array": [ "array": ["u8", 512]
"u8",
512
]
} }
}, },
{ {
@ -2032,10 +1882,7 @@
{ {
"name": "padding", "name": "padding",
"type": { "type": {
"array": [ "array": ["u8", 199]
"u8",
199
]
} }
} }
] ]
@ -2065,10 +1912,7 @@
{ {
"name": "padding", "name": "padding",
"type": { "type": {
"array": [ "array": ["u8", 4]
"u8",
4
]
} }
}, },
{ {
@ -2086,10 +1930,7 @@
{ {
"name": "padding2", "name": "padding2",
"type": { "type": {
"array": [ "array": ["u8", 32]
"u8",
32
]
} }
}, },
{ {
@ -2103,10 +1944,7 @@
{ {
"name": "padding3", "name": "padding3",
"type": { "type": {
"array": [ "array": ["u8", 16]
"u8",
16
]
} }
}, },
{ {
@ -2116,10 +1954,7 @@
{ {
"name": "padding4", "name": "padding4",
"type": { "type": {
"array": [ "array": ["u8", 16]
"u8",
16
]
} }
}, },
{ {
@ -2137,10 +1972,7 @@
{ {
"name": "reserved", "name": "reserved",
"type": { "type": {
"array": [ "array": ["u8", 8]
"u8",
8
]
} }
} }
] ]
@ -2166,10 +1998,7 @@
{ {
"name": "padding0", "name": "padding0",
"type": { "type": {
"array": [ "array": ["u8", 5]
"u8",
5
]
} }
}, },
{ {
@ -2191,10 +2020,7 @@
{ {
"name": "padding1", "name": "padding1",
"type": { "type": {
"array": [ "array": ["u8", 136]
"u8",
136
]
} }
} }
] ]
@ -2220,9 +2046,7 @@
"fields": [ "fields": [
{ {
"name": "stablePrice", "name": "stablePrice",
"docs": [ "docs": ["Current stable price to use in health"],
"Current stable price to use in health"
],
"type": "f64" "type": "f64"
}, },
{ {
@ -2239,10 +2063,7 @@
"we use the next one." "we use the next one."
], ],
"type": { "type": {
"array": [ "array": ["f64", 24]
"f64",
24
]
} }
}, },
{ {
@ -2255,16 +2076,12 @@
}, },
{ {
"name": "delayAccumulatorTime", "name": "delayAccumulatorTime",
"docs": [ "docs": ["Accumulating the total time for the above average."],
"Accumulating the total time for the above average."
],
"type": "u32" "type": "u32"
}, },
{ {
"name": "delayIntervalSeconds", "name": "delayIntervalSeconds",
"docs": [ "docs": ["Length of a delay_interval"],
"Length of a delay_interval"
],
"type": "u32" "type": "u32"
}, },
{ {
@ -2292,19 +2109,13 @@
{ {
"name": "padding", "name": "padding",
"type": { "type": {
"array": [ "array": ["u8", 7]
"u8",
7
]
} }
}, },
{ {
"name": "reserved", "name": "reserved",
"type": { "type": {
"array": [ "array": ["u8", 48]
"u8",
48
]
} }
} }
] ]
@ -2925,4 +2736,4 @@
"msg": "The receiver is invalid. Makes sure the receiver's owner is the market admin" "msg": "The receiver is invalid. Makes sure the receiver's owner is the market admin"
} }
] ]
} }

View File

@ -1 +1,6 @@
[247,81,41,82,59,37,100,159,77,210,53,136,212,197,48,156,35,235,118,52,60,249,192,135,247,217,123,52,53,60,223,78,205,15,251,191,21,149,104,160,69,71,75,237,133,4,137,222,132,215,169,167,197,234,74,145,175,129,228,68,34,166,170,187] [
247, 81, 41, 82, 59, 37, 100, 159, 77, 210, 53, 136, 212, 197, 48, 156, 35,
235, 118, 52, 60, 249, 192, 135, 247, 217, 123, 52, 53, 60, 223, 78, 205, 15,
251, 191, 21, 149, 104, 160, 69, 71, 75, 237, 133, 4, 137, 222, 132, 215, 169,
167, 197, 234, 74, 145, 175, 129, 228, 68, 34, 166, 170, 187
]

View File

@ -4,6 +4,9 @@
"main": "index.js", "main": "index.js",
"repository": "https://github.com/blockworks-foundation/solana-rpc-testing.git", "repository": "https://github.com/blockworks-foundation/solana-rpc-testing.git",
"license": "MIT", "license": "MIT",
"scripts": {
"configure": "ts-node configure/main.ts"
},
"devDependencies": { "devDependencies": {
"@types/node": "^20.1.0", "@types/node": "^20.1.0",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",