Compare commits
6 Commits
24de4eeb78
...
c4cf616eb0
Author | SHA1 | Date |
---|---|---|
Godmode Galactus | c4cf616eb0 | |
Maximilian Schneider | 6fc642d491 | |
Godmode Galactus | 3c99ebf336 | |
Godmode Galactus | 3bb7cbeb2b | |
Maximilian Schneider | 60393d3784 | |
Maximilian Schneider | ec24103f2a |
|
@ -1,3 +1,4 @@
|
|||
/target
|
||||
node_modules
|
||||
/configure/config.json
|
||||
package-lock.json
|
||||
**/config.json
|
||||
|
|
|
@ -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]
|
||||
--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]
|
||||
--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`
|
||||
|
@ -39,7 +39,7 @@ To configure cluster:
|
|||
|
||||
```sh
|
||||
cd configure
|
||||
ts-node configure_all.ts -a /home/user/.config/solana/id.json
|
||||
yarn configure -a ../solana_configure_local_cluster/faucet.json
|
||||
cd ..
|
||||
```
|
||||
|
||||
|
|
|
@ -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 { 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 { IDL, OpenbookV2 } from "./openbook-v2/openbook_v2";
|
||||
import { U64_MAX_BN } from "@blockworks-foundation/mango-v4";
|
||||
|
@ -12,26 +27,26 @@ export class TestProvider extends AnchorProvider {
|
|||
constructor(connection: Connection, keypair: Keypair) {
|
||||
let txSigner = async (tx: Transaction) => {
|
||||
tx.partialSign(this.keypair);
|
||||
return tx
|
||||
return tx;
|
||||
};
|
||||
|
||||
let allSigner = async (txs : Transaction[]) => {
|
||||
txs.forEach(x=> x.partialSign(this.keypair));
|
||||
let allSigner = async (txs: Transaction[]) => {
|
||||
txs.forEach((x) => x.partialSign(this.keypair));
|
||||
return txs;
|
||||
};
|
||||
|
||||
super(
|
||||
connection,
|
||||
connection,
|
||||
{
|
||||
signTransaction: txSigner,
|
||||
signAllTransactions: allSigner,
|
||||
publicKey : keypair.publicKey,
|
||||
publicKey: keypair.publicKey,
|
||||
},
|
||||
{commitment: 'confirmed'}
|
||||
)
|
||||
{ commitment: "confirmed" }
|
||||
);
|
||||
this.keypair = keypair;
|
||||
}
|
||||
getKeypair() : Keypair {
|
||||
return this.keypair
|
||||
getKeypair(): Keypair {
|
||||
return this.keypair;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import { Keypair } from "@solana/web3.js";
|
||||
import * as fs from 'fs';
|
||||
import * as fs from "fs";
|
||||
|
||||
export function getKeypairFromFile(filePath: String): Keypair {
|
||||
return Keypair.fromSecretKey(
|
||||
Uint8Array.from(
|
||||
JSON.parse(
|
||||
process.env.KEYPAIR ||
|
||||
fs.readFileSync(filePath.toString(), 'utf-8'),
|
||||
),
|
||||
),
|
||||
return Keypair.fromSecretKey(
|
||||
Uint8Array.from(
|
||||
JSON.parse(
|
||||
process.env.KEYPAIR || fs.readFileSync(filePath.toString(), "utf-8")
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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 { exec } from "child_process";
|
||||
import * as fs from "fs"
|
||||
import * as fs from "fs";
|
||||
import { promisify } from "util";
|
||||
import { getKeypairFromFile } from "./common_utils";
|
||||
|
||||
export interface ProgramData {
|
||||
name: string,
|
||||
programPath: string,
|
||||
programKeyPath: string,
|
||||
idl: string,
|
||||
name: string;
|
||||
programPath: string;
|
||||
programKeyPath: string;
|
||||
idl: string;
|
||||
}
|
||||
|
||||
export async function deploy_programs(url: String, payer: string, programs: ProgramData[]) {
|
||||
for (const program of programs) {
|
||||
let cmd = '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);
|
||||
}
|
||||
export async function deploy_programs(
|
||||
url: String,
|
||||
payer: string,
|
||||
programs: ProgramData[]
|
||||
) {
|
||||
for (const program of programs) {
|
||||
let cmd =
|
||||
"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) {
|
||||
console.log(stderr);
|
||||
}
|
||||
if (stderr.length > 0) {
|
||||
console.log(stderr);
|
||||
}
|
||||
|
||||
/** TODO: this is not working yet bc. anchor wants a workspace
|
||||
if (program.idl.length > 0) {
|
||||
let programId = getKeypairFromFile(program.programKeyPath);
|
||||
console.log("deploying idl file for program " + programId.publicKey);
|
||||
|
@ -44,5 +65,6 @@ export async function deploy_programs(url: String, payer: string, programs: Prog
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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[] = [];
|
||||
// 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);
|
||||
const lamports = await connection.getMinimumBalanceForRentExemption(
|
||||
size
|
||||
);
|
||||
let kp = Keypair.generate();
|
||||
const program = programs[Math.floor(Math.random() * programs.length)];
|
||||
|
||||
const lamports = await connection.getMinimumBalanceForRentExemption(size);
|
||||
let kp = Keypair.generate();
|
||||
const program = programs[Math.floor(Math.random() * programs.length)];
|
||||
const transaction = new Transaction().add(
|
||||
SystemProgram.createAccount({
|
||||
fromPubkey: authority.publicKey,
|
||||
newAccountPubkey: kp.publicKey,
|
||||
lamports,
|
||||
space: size,
|
||||
programId: program,
|
||||
})
|
||||
);
|
||||
|
||||
const transaction = new Transaction().add(
|
||||
SystemProgram.createAccount({
|
||||
fromPubkey: authority.publicKey,
|
||||
newAccountPubkey: kp.publicKey,
|
||||
lamports,
|
||||
space: size,
|
||||
programId: program,
|
||||
}))
|
||||
transaction.feePayer = authority.publicKey;
|
||||
let hash = await connection.getRecentBlockhash();
|
||||
transaction.recentBlockhash = hash.blockhash;
|
||||
// Sign transaction, broadcast, and confirm
|
||||
await sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[authority, kp],
|
||||
{ commitment: "confirmed" }
|
||||
);
|
||||
|
||||
transaction.feePayer = authority.publicKey;
|
||||
let hash = await connection.getRecentBlockhash();
|
||||
transaction.recentBlockhash = hash.blockhash;
|
||||
// Sign transaction, broadcast, and confirm
|
||||
await sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[authority, kp],
|
||||
{ commitment: 'confirmed' },
|
||||
);
|
||||
|
||||
return kp.publicKey
|
||||
}))
|
||||
all_accounts = all_accounts.concat(accounts);
|
||||
}
|
||||
return all_accounts
|
||||
return kp.publicKey;
|
||||
})
|
||||
);
|
||||
all_accounts = all_accounts.concat(accounts);
|
||||
}
|
||||
return all_accounts;
|
||||
}
|
||||
|
|
|
@ -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 { 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";
|
||||
|
||||
export interface User {
|
||||
secret: number[],
|
||||
token_data : TokenAccountData[],
|
||||
open_orders: OpenOrders[],
|
||||
secret: number[];
|
||||
token_data: TokenAccountData[];
|
||||
open_orders: OpenOrders[];
|
||||
}
|
||||
|
||||
export async function createUser(connection: Connection, authority: Keypair, balancePerPayer: number): Promise<Keypair> {
|
||||
let payer = Keypair.generate();
|
||||
let transfer_ix = SystemProgram.transfer({
|
||||
fromPubkey: authority.publicKey,
|
||||
toPubkey: payer.publicKey,
|
||||
lamports: balancePerPayer * LAMPORTS_PER_SOL,
|
||||
});
|
||||
let tx = new Transaction().add(transfer_ix);
|
||||
tx.feePayer = authority.publicKey;
|
||||
const bh = await connection.getLatestBlockhash();
|
||||
tx.recentBlockhash = bh.blockhash;
|
||||
sendAndConfirmTransaction(connection, tx, [authority]);
|
||||
return payer
|
||||
export async function createUser(
|
||||
connection: Connection,
|
||||
authority: Keypair,
|
||||
balancePerPayer: number
|
||||
): Promise<Keypair> {
|
||||
let payer = Keypair.generate();
|
||||
let transfer_ix = SystemProgram.transfer({
|
||||
fromPubkey: authority.publicKey,
|
||||
toPubkey: payer.publicKey,
|
||||
lamports: balancePerPayer * LAMPORTS_PER_SOL,
|
||||
});
|
||||
let tx = new Transaction().add(transfer_ix);
|
||||
tx.feePayer = authority.publicKey;
|
||||
const bh = await connection.getLatestBlockhash();
|
||||
tx.recentBlockhash = bh.blockhash;
|
||||
sendAndConfirmTransaction(connection, tx, [authority]);
|
||||
return payer;
|
||||
}
|
||||
|
||||
interface TokenAccountData {
|
||||
mint: PublicKey,
|
||||
token_account: PublicKey
|
||||
mint: PublicKey;
|
||||
token_account: PublicKey;
|
||||
}
|
||||
|
||||
export async function mintUser(connection: Connection, authority: Keypair, mints: PublicKey[], mintUtils: MintUtils, user: PublicKey, amount: number) : 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
|
||||
}
|
||||
})
|
||||
)
|
||||
export async function mintUser(
|
||||
connection: Connection,
|
||||
authority: Keypair,
|
||||
mints: PublicKey[],
|
||||
mintUtils: MintUtils,
|
||||
user: PublicKey,
|
||||
amount: number
|
||||
): 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,
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,63 +1,59 @@
|
|||
import * as splToken from "@solana/spl-token";
|
||||
import {
|
||||
PublicKey,
|
||||
Connection,
|
||||
Keypair,
|
||||
} from "@solana/web3.js";
|
||||
import { PublicKey, Connection, Keypair } from "@solana/web3.js";
|
||||
|
||||
export interface TokenData {
|
||||
mint : PublicKey,
|
||||
startingPrice : number,
|
||||
nbDecimals: number,
|
||||
priceOracle: Keypair | undefined,
|
||||
mint: PublicKey;
|
||||
startingPrice: number;
|
||||
nbDecimals: number;
|
||||
priceOracle: Keypair | undefined;
|
||||
}
|
||||
|
||||
export class MintUtils {
|
||||
private conn: Connection;
|
||||
private authority: Keypair;
|
||||
|
||||
private conn: Connection;
|
||||
private authority: Keypair;
|
||||
constructor(conn: Connection, 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) {
|
||||
this.conn = conn;
|
||||
this.authority = authority;
|
||||
}
|
||||
public async createMints(nbMints: number): Promise<PublicKey[]> {
|
||||
return await Promise.all(
|
||||
Array.from(Array(nbMints).keys()).map((_) => {
|
||||
return this.createMint();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
public async createNewToken(nbDecimals = 6, startingPrice = 1_000_000) {
|
||||
const mint = await this.createMint(nbDecimals);
|
||||
const tokenData: TokenData = {
|
||||
mint: mint,
|
||||
startingPrice: startingPrice,
|
||||
nbDecimals: nbDecimals,
|
||||
priceOracle: undefined,
|
||||
};
|
||||
return tokenData;
|
||||
}
|
||||
|
||||
public async createMints(nbMints: number) : Promise<PublicKey[]> {
|
||||
return await Promise.all(Array.from(Array(nbMints).keys()).map(_ => {
|
||||
return this.createMint()
|
||||
}))
|
||||
}
|
||||
|
||||
public async createNewToken(nbDecimals = 6, startingPrice = 1_000_000) {
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
public async createTokenAccount(
|
||||
mint: PublicKey,
|
||||
payer: Keypair,
|
||||
owner: PublicKey
|
||||
) {
|
||||
const account = Keypair.generate();
|
||||
return splToken.createAccount(this.conn, payer, mint, owner, account);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
const lamports = await connection.getMinimumBalanceForRentExemption(size);
|
||||
let address = Keypair.generate();
|
||||
export async function createAccount(
|
||||
connection: Connection,
|
||||
authority: Keypair,
|
||||
size: number,
|
||||
owner: PublicKey
|
||||
): Promise<PublicKey> {
|
||||
const lamports = await connection.getMinimumBalanceForRentExemption(size);
|
||||
let address = Keypair.generate();
|
||||
|
||||
const transaction = new Transaction().add(
|
||||
SystemProgram.createAccount({
|
||||
fromPubkey: authority.publicKey,
|
||||
newAccountPubkey: address.publicKey,
|
||||
lamports,
|
||||
space: size,
|
||||
programId: owner,
|
||||
}))
|
||||
const transaction = new Transaction().add(
|
||||
SystemProgram.createAccount({
|
||||
fromPubkey: authority.publicKey,
|
||||
newAccountPubkey: address.publicKey,
|
||||
lamports,
|
||||
space: size,
|
||||
programId: owner,
|
||||
})
|
||||
);
|
||||
|
||||
transaction.feePayer = authority.publicKey;
|
||||
let hash = await connection.getRecentBlockhash();
|
||||
transaction.recentBlockhash = hash.blockhash;
|
||||
// Sign transaction, broadcast, and confirm
|
||||
await sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[authority, address],
|
||||
{ commitment: 'confirmed' },
|
||||
);
|
||||
return address.publicKey;
|
||||
}
|
||||
transaction.feePayer = authority.publicKey;
|
||||
let hash = await connection.getRecentBlockhash();
|
||||
transaction.recentBlockhash = hash.blockhash;
|
||||
// Sign transaction, broadcast, and confirm
|
||||
await sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[authority, address],
|
||||
{ commitment: "confirmed" }
|
||||
);
|
||||
return address.publicKey;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -3,7 +3,7 @@ import { TestProvider } from "../anchor_utils";
|
|||
import { Market, createMarket } from "./create_markets";
|
||||
import { MintUtils } from "../general/mint_utils";
|
||||
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 { User } from "../general/create_users";
|
||||
import { U64_MAX_BN } from "@blockworks-foundation/mango-v4";
|
||||
|
@ -12,136 +12,176 @@ import { Command } from "../output_file";
|
|||
import assert from "assert";
|
||||
|
||||
export interface OpenOrders {
|
||||
market: PublicKey,
|
||||
open_orders: PublicKey
|
||||
market: PublicKey;
|
||||
open_orders: PublicKey;
|
||||
}
|
||||
|
||||
export class OpenbookConfigurator {
|
||||
anchorProvider: TestProvider;
|
||||
mintUtils: MintUtils;
|
||||
openbookProgramId: PublicKey;
|
||||
program: Program<OpenbookV2>;
|
||||
|
||||
anchorProvider: TestProvider;
|
||||
mintUtils: MintUtils;
|
||||
openbookProgramId: PublicKey;
|
||||
program: Program<OpenbookV2>;
|
||||
constructor(
|
||||
connection: Connection,
|
||||
authority: Keypair,
|
||||
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) {
|
||||
this.anchorProvider = new TestProvider(connection, authority);
|
||||
this.mintUtils = mintUtils;
|
||||
this.openbookProgramId = openbookProgramId;
|
||||
this.program = new Program<OpenbookV2>(
|
||||
IDL as OpenbookV2,
|
||||
this.openbookProgramId,
|
||||
public async configureOpenbookV2(mints: PublicKey[]): Promise<Market[]> {
|
||||
let quoteMint = mints[0];
|
||||
let admin = Keypair.generate();
|
||||
return await Promise.all(
|
||||
mints
|
||||
.slice(1)
|
||||
.map((mint, index) =>
|
||||
createMarket(
|
||||
this.program,
|
||||
this.anchorProvider,
|
||||
);
|
||||
}
|
||||
|
||||
public async configureOpenbookV2(mints: PublicKey[]): Promise<Market[]> {
|
||||
let quoteMint = mints[0];
|
||||
let admin = Keypair.generate();
|
||||
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]
|
||||
})
|
||||
this.mintUtils,
|
||||
admin,
|
||||
this.openbookProgramId,
|
||||
mint,
|
||||
quoteMint,
|
||||
index
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return openOrders.map(x=> {
|
||||
return {
|
||||
market : x[0],
|
||||
open_orders : x[1],
|
||||
}
|
||||
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) => {
|
||||
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) {
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
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.
|
||||
/// 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
|
||||
public async getCommands() : Promise<Command[]> {
|
||||
let side = {bid:{}} ;
|
||||
let placeOrder = {limit:{}};
|
||||
let placeOrderIx = await this.program.methods.placeOrder(
|
||||
/// this is a special method.
|
||||
/// 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
|
||||
public async getCommands(): Promise<Command[]> {
|
||||
let side = { bid: {} };
|
||||
let placeOrder = { limit: {} };
|
||||
let placeOrderIx = await this.program.methods
|
||||
.placeOrder(
|
||||
side,
|
||||
new BN(0),
|
||||
new BN(0),
|
||||
|
@ -150,8 +190,9 @@ export class OpenbookConfigurator {
|
|||
placeOrder,
|
||||
false,
|
||||
U64_MAX_BN,
|
||||
255,
|
||||
).accounts({
|
||||
255
|
||||
)
|
||||
.accounts({
|
||||
asks: PublicKey.default,
|
||||
baseVault: PublicKey.default,
|
||||
bids: PublicKey.default,
|
||||
|
@ -164,31 +205,34 @@ export class OpenbookConfigurator {
|
|||
quoteVault: PublicKey.default,
|
||||
systemProgram: web3.SystemProgram.programId,
|
||||
tokenProgram: TOKEN_PROGRAM_ID,
|
||||
}).instruction();
|
||||
})
|
||||
.instruction();
|
||||
|
||||
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);
|
||||
let placeOrderCommand : Command = {
|
||||
name: "placeOrder",
|
||||
instruction: Array.from(placeOrderIx.data),
|
||||
argument_sizes,
|
||||
assert(
|
||||
argument_sizes.reduce((sum, current) => sum + current, 0) ===
|
||||
placeOrderIx.data.length
|
||||
);
|
||||
let placeOrderCommand: Command = {
|
||||
name: "placeOrder",
|
||||
instruction: Array.from(placeOrderIx.data),
|
||||
argument_sizes,
|
||||
};
|
||||
|
||||
let consumeEvents = await this.program.methods.consumeEvents(
|
||||
new BN(0),
|
||||
).accounts(
|
||||
{
|
||||
eventQueue: PublicKey.default,
|
||||
market: PublicKey.default,
|
||||
}
|
||||
).instruction();
|
||||
let consumeEvents = await this.program.methods
|
||||
.consumeEvents(new BN(0))
|
||||
.accounts({
|
||||
eventQueue: PublicKey.default,
|
||||
market: PublicKey.default,
|
||||
})
|
||||
.instruction();
|
||||
|
||||
let consumeEventsCommand : Command = {
|
||||
instruction: Array.from(consumeEvents.data),
|
||||
name: "consumeEvents",
|
||||
argument_sizes: [8, 1]
|
||||
}
|
||||
let consumeEventsCommand: Command = {
|
||||
instruction: Array.from(consumeEvents.data),
|
||||
name: "consumeEvents",
|
||||
argument_sizes: [8, 1],
|
||||
};
|
||||
|
||||
return [placeOrderCommand, consumeEventsCommand]
|
||||
return [placeOrderCommand, consumeEventsCommand];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,92 +1,136 @@
|
|||
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
||||
import IDL from '../programs/openbook_v2.json'
|
||||
import { Program, web3, BN } from '@project-serum/anchor';
|
||||
import { createAccount } from '../general/solana_utils';
|
||||
import { MintUtils } from '../general/mint_utils';
|
||||
import { I80F48, I80F48Dto } from '@blockworks-foundation/mango-v4';
|
||||
import { OpenbookV2 } from './openbook_v2';
|
||||
import { TestProvider } from '../anchor_utils';
|
||||
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
|
||||
import IDL from "../programs/openbook_v2.json";
|
||||
import { Program, web3, BN } from "@project-serum/anchor";
|
||||
import { createAccount } from "../general/solana_utils";
|
||||
import { MintUtils } from "../general/mint_utils";
|
||||
import { I80F48, I80F48Dto } from "@blockworks-foundation/mango-v4";
|
||||
import { OpenbookV2 } from "./openbook_v2";
|
||||
import { TestProvider } from "../anchor_utils";
|
||||
|
||||
export interface Market {
|
||||
name: string,
|
||||
admin : number[],
|
||||
market_pk: PublicKey
|
||||
oracle: PublicKey,
|
||||
asks: PublicKey,
|
||||
bids: PublicKey,
|
||||
event_queue: PublicKey,
|
||||
base_vault: PublicKey,
|
||||
quote_vault: PublicKey,
|
||||
base_mint: PublicKey,
|
||||
quote_mint: PublicKey,
|
||||
market_index: number,
|
||||
name: string;
|
||||
admin: number[];
|
||||
market_pk: PublicKey;
|
||||
oracle: PublicKey;
|
||||
asks: PublicKey;
|
||||
bids: PublicKey;
|
||||
event_queue: PublicKey;
|
||||
base_vault: PublicKey;
|
||||
quote_vault: PublicKey;
|
||||
base_mint: PublicKey;
|
||||
quote_mint: PublicKey;
|
||||
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> {
|
||||
let [oracleId, _tmp] = PublicKey.findProgramAddressSync([Buffer.from("StubOracle"), baseMint.toBytes()], openbookProgramId)
|
||||
const admin:PublicKey = adminKp.publicKey;
|
||||
export async function createMarket(
|
||||
program: Program<OpenbookV2>,
|
||||
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({
|
||||
oracle: oracleId,
|
||||
admin,
|
||||
mint: baseMint,
|
||||
payer: anchorProvider.wallet.publicKey,
|
||||
systemProgram: web3.SystemProgram.programId,
|
||||
oracle: oracleId,
|
||||
admin,
|
||||
mint: baseMint,
|
||||
payer: anchorProvider.wallet.publicKey,
|
||||
systemProgram: web3.SystemProgram.programId,
|
||||
})
|
||||
.signers([adminKp])
|
||||
.rpc();
|
||||
|
||||
// bookside size = 123720
|
||||
let asks = await createAccount(anchorProvider.connection, anchorProvider.keypair, 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);
|
||||
// bookside size = 123720
|
||||
let asks = await createAccount(
|
||||
anchorProvider.connection,
|
||||
anchorProvider.keypair,
|
||||
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 quoteVault = await mintUtils.createTokenAccount(quoteMint, anchorProvider.keypair, marketPk);
|
||||
let name = 'index ' + index.toString() + ' wrt 0';
|
||||
let baseVault = await mintUtils.createTokenAccount(
|
||||
baseMint,
|
||||
anchorProvider.keypair,
|
||||
marketPk
|
||||
);
|
||||
let quoteVault = await mintUtils.createTokenAccount(
|
||||
quoteMint,
|
||||
anchorProvider.keypair,
|
||||
marketPk
|
||||
);
|
||||
let name = "index " + index.toString() + " wrt 0";
|
||||
|
||||
await program.methods.createMarket(
|
||||
marketIndex,
|
||||
name,
|
||||
{
|
||||
confFilter: 0,
|
||||
maxStalenessSlots: 100,
|
||||
},
|
||||
new BN(1), new BN(1), 0, 0, 0
|
||||
).accounts(
|
||||
{
|
||||
admin,
|
||||
market: marketPk,
|
||||
bids,
|
||||
asks,
|
||||
eventQueue,
|
||||
payer: anchorProvider.publicKey,
|
||||
baseVault,
|
||||
quoteVault,
|
||||
baseMint,
|
||||
quoteMint,
|
||||
systemProgram: web3.SystemProgram.programId,
|
||||
oracle: oracleId,
|
||||
}
|
||||
).signers([adminKp])
|
||||
await program.methods
|
||||
.createMarket(
|
||||
marketIndex,
|
||||
name,
|
||||
{
|
||||
confFilter: 0,
|
||||
maxStalenessSlots: 100,
|
||||
},
|
||||
new BN(1),
|
||||
new BN(1),
|
||||
0,
|
||||
0,
|
||||
0
|
||||
)
|
||||
.accounts({
|
||||
admin,
|
||||
market: marketPk,
|
||||
bids,
|
||||
asks,
|
||||
eventQueue,
|
||||
payer: anchorProvider.publicKey,
|
||||
baseVault,
|
||||
quoteVault,
|
||||
baseMint,
|
||||
quoteMint,
|
||||
systemProgram: web3.SystemProgram.programId,
|
||||
oracle: oracleId,
|
||||
})
|
||||
.signers([adminKp])
|
||||
.rpc();
|
||||
|
||||
return {
|
||||
admin: Array.from(adminKp.secretKey),
|
||||
name,
|
||||
bids,
|
||||
asks,
|
||||
event_queue: eventQueue,
|
||||
base_mint: baseMint,
|
||||
base_vault: baseVault,
|
||||
market_index: index,
|
||||
market_pk: marketPk,
|
||||
oracle: oracleId,
|
||||
quote_mint: quoteMint,
|
||||
quote_vault: quoteVault,
|
||||
}
|
||||
}
|
||||
return {
|
||||
admin: Array.from(adminKp.secretKey),
|
||||
name,
|
||||
bids,
|
||||
asks,
|
||||
event_queue: eventQueue,
|
||||
base_mint: baseMint,
|
||||
base_vault: baseVault,
|
||||
market_index: index,
|
||||
market_pk: marketPk,
|
||||
oracle: oracleId,
|
||||
quote_mint: quoteMint,
|
||||
quote_vault: quoteVault,
|
||||
};
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,21 +3,21 @@ import { Market } from "./openbook-v2/create_markets";
|
|||
import { User } from "./general/create_users";
|
||||
|
||||
export interface Command {
|
||||
name: String,
|
||||
instruction: number[],
|
||||
argument_sizes: number[],
|
||||
name: String;
|
||||
instruction: number[];
|
||||
argument_sizes: number[];
|
||||
}
|
||||
|
||||
export interface ProgramOutputData {
|
||||
name: String,
|
||||
program_id: PublicKey,
|
||||
commands: Command [],
|
||||
name: String;
|
||||
program_id: PublicKey;
|
||||
commands: Command[];
|
||||
}
|
||||
|
||||
export interface OutputFile {
|
||||
users: User[],
|
||||
programs: ProgramOutputData[],
|
||||
known_accounts: PublicKey[],
|
||||
mints: PublicKey[],
|
||||
markets: Market[],
|
||||
users: User[];
|
||||
programs: ProgramOutputData[];
|
||||
known_accounts: PublicKey[];
|
||||
mints: PublicKey[];
|
||||
markets: Market[];
|
||||
}
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
[
|
||||
{
|
||||
"name": "pyth_mock",
|
||||
"programPath": "programs/pyth_mock.so",
|
||||
"programKeyPath": "programs/pyth_mock.json",
|
||||
"idl": ""
|
||||
},
|
||||
{
|
||||
"name": "openbook_v2",
|
||||
"programPath": "programs/openbook_v2.so",
|
||||
"programKeyPath": "programs/openbook_v2-keypair.json",
|
||||
"idl": "programs/openbook_v2.json"
|
||||
}
|
||||
{
|
||||
"name": "pyth_mock",
|
||||
"programPath": "configure/programs/pyth_mock.so",
|
||||
"programKeyPath": "configure/programs/pyth_mock.json",
|
||||
"idl": ""
|
||||
},
|
||||
{
|
||||
"name": "openbook_v2",
|
||||
"programPath": "configure/programs/openbook_v2.so",
|
||||
"programKeyPath": "configure/programs/openbook_v2-keypair.json",
|
||||
"idl": ""
|
||||
},
|
||||
{
|
||||
"noop": "noop",
|
||||
"programPath": "configure/programs/spl_noop.so",
|
||||
"programKeyPath": "configure/programs/spl_noop.json",
|
||||
"idl": ""
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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
|
||||
]
|
||||
|
|
|
@ -640,9 +640,7 @@
|
|||
},
|
||||
{
|
||||
"name": "cancelAllOrders",
|
||||
"docs": [
|
||||
"Cancel up to `limit` orders."
|
||||
],
|
||||
"docs": ["Cancel up to `limit` orders."],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "openOrdersAccount",
|
||||
|
@ -679,9 +677,7 @@
|
|||
},
|
||||
{
|
||||
"name": "cancelAllOrdersBySide",
|
||||
"docs": [
|
||||
"Cancel up to `limit` orders on a single side of the book."
|
||||
],
|
||||
"docs": ["Cancel up to `limit` orders on a single side of the book."],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "openOrdersAccount",
|
||||
|
@ -793,9 +789,7 @@
|
|||
},
|
||||
{
|
||||
"name": "settleFunds",
|
||||
"docs": [
|
||||
"Withdraw any available tokens."
|
||||
],
|
||||
"docs": ["Withdraw any available tokens."],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "openOrdersAccount",
|
||||
|
@ -842,9 +836,7 @@
|
|||
},
|
||||
{
|
||||
"name": "sweepFees",
|
||||
"docs": [
|
||||
"Sweep fees, as a [`Market`](crate::state::Market)'s admin."
|
||||
],
|
||||
"docs": ["Sweep fees, as a [`Market`](crate::state::Market)'s admin."],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "market",
|
||||
|
@ -876,9 +868,7 @@
|
|||
},
|
||||
{
|
||||
"name": "closeMarket",
|
||||
"docs": [
|
||||
"Close a [`Market`](crate::state::Market)."
|
||||
],
|
||||
"docs": ["Close a [`Market`](crate::state::Market)."],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "admin",
|
||||
|
@ -1014,23 +1004,17 @@
|
|||
"fields": [
|
||||
{
|
||||
"name": "admin",
|
||||
"docs": [
|
||||
"Admin who can close this market"
|
||||
],
|
||||
"docs": ["Admin who can close this market"],
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "marketIndex",
|
||||
"docs": [
|
||||
"Index of this market"
|
||||
],
|
||||
"docs": ["Index of this market"],
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"name": "bump",
|
||||
"docs": [
|
||||
"PDA bump"
|
||||
],
|
||||
"docs": ["PDA bump"],
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
|
@ -1049,57 +1033,39 @@
|
|||
{
|
||||
"name": "padding1",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
1
|
||||
]
|
||||
"array": ["u8", 1]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"docs": [
|
||||
"Name. Trailing zero bytes are ignored."
|
||||
],
|
||||
"docs": ["Name. Trailing zero bytes are ignored."],
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
16
|
||||
]
|
||||
"array": ["u8", 16]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bids",
|
||||
"docs": [
|
||||
"Address of the BookSide account for bids"
|
||||
],
|
||||
"docs": ["Address of the BookSide account for bids"],
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "asks",
|
||||
"docs": [
|
||||
"Address of the BookSide account for asks"
|
||||
],
|
||||
"docs": ["Address of the BookSide account for asks"],
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "eventQueue",
|
||||
"docs": [
|
||||
"Address of the EventQueue account"
|
||||
],
|
||||
"docs": ["Address of the EventQueue account"],
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "oracle",
|
||||
"docs": [
|
||||
"Oracle account address"
|
||||
],
|
||||
"docs": ["Oracle account address"],
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "oracleConfig",
|
||||
"docs": [
|
||||
"Oracle configuration"
|
||||
],
|
||||
"docs": ["Oracle configuration"],
|
||||
"type": {
|
||||
"defined": "OracleConfig"
|
||||
}
|
||||
|
@ -1137,16 +1103,12 @@
|
|||
},
|
||||
{
|
||||
"name": "seqNum",
|
||||
"docs": [
|
||||
"Total number of orders seen"
|
||||
],
|
||||
"docs": ["Total number of orders seen"],
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "registrationTime",
|
||||
"docs": [
|
||||
"Timestamp in seconds that the market was registered at."
|
||||
],
|
||||
"docs": ["Timestamp in seconds that the market was registered at."],
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
|
@ -1161,45 +1123,34 @@
|
|||
},
|
||||
{
|
||||
"name": "takerFee",
|
||||
"docs": [
|
||||
"Fee for taker orders, may not be negative."
|
||||
],
|
||||
"docs": ["Fee for taker orders, may not be negative."],
|
||||
"type": {
|
||||
"defined": "I80F48"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "feesAccrued",
|
||||
"docs": [
|
||||
"Fees accrued in native quote currency"
|
||||
],
|
||||
"docs": ["Fees accrued in native quote currency"],
|
||||
"type": {
|
||||
"defined": "I80F48"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "feesSettled",
|
||||
"docs": [
|
||||
"Fees settled in native quote currency"
|
||||
],
|
||||
"docs": ["Fees settled in native quote currency"],
|
||||
"type": {
|
||||
"defined": "I80F48"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "feePenalty",
|
||||
"docs": [
|
||||
"Fee (in quote native) to charge for ioc orders"
|
||||
],
|
||||
"docs": ["Fee (in quote native) to charge for ioc orders"],
|
||||
"type": "f32"
|
||||
},
|
||||
{
|
||||
"name": "padding2",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
4
|
||||
]
|
||||
"array": ["u8", 4]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1249,10 +1200,7 @@
|
|||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
1888
|
||||
]
|
||||
"array": ["u8", 1888]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1270,10 +1218,7 @@
|
|||
{
|
||||
"name": "name",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
32
|
||||
]
|
||||
"array": ["u8", 32]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1291,10 +1236,7 @@
|
|||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
3
|
||||
]
|
||||
"array": ["u8", 3]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1307,9 +1249,7 @@
|
|||
},
|
||||
{
|
||||
"name": "buybackFeesAccruedPrevious",
|
||||
"docs": [
|
||||
"Fees buyback amount from the previous expiry interval."
|
||||
],
|
||||
"docs": ["Fees buyback amount from the previous expiry interval."],
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
|
@ -1328,10 +1268,7 @@
|
|||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
208
|
||||
]
|
||||
"array": ["u8", 208]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1341,10 +1278,7 @@
|
|||
{
|
||||
"name": "padding3",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
7
|
||||
]
|
||||
"array": ["u8", 7]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1388,10 +1322,7 @@
|
|||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
128
|
||||
]
|
||||
"array": ["u8", 128]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1427,10 +1358,7 @@
|
|||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
256
|
||||
]
|
||||
"array": ["u8", 256]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1467,10 +1395,7 @@
|
|||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
64
|
||||
]
|
||||
"array": ["u8", 64]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1490,10 +1415,7 @@
|
|||
{
|
||||
"name": "name",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
32
|
||||
]
|
||||
"array": ["u8", 32]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1511,10 +1433,7 @@
|
|||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
3
|
||||
]
|
||||
"array": ["u8", 3]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1538,10 +1457,7 @@
|
|||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
208
|
||||
]
|
||||
"array": ["u8", 208]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1561,16 +1477,12 @@
|
|||
},
|
||||
{
|
||||
"name": "bidsBaseLots",
|
||||
"docs": [
|
||||
"Base lots in open bids"
|
||||
],
|
||||
"docs": ["Base lots in open bids"],
|
||||
"type": "i64"
|
||||
},
|
||||
{
|
||||
"name": "asksBaseLots",
|
||||
"docs": [
|
||||
"Base lots in open asks"
|
||||
],
|
||||
"docs": ["Base lots in open asks"],
|
||||
"type": "i64"
|
||||
},
|
||||
{
|
||||
|
@ -1618,10 +1530,7 @@
|
|||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
88
|
||||
]
|
||||
"array": ["u8", 88]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1639,10 +1548,7 @@
|
|||
{
|
||||
"name": "padding1",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
7
|
||||
]
|
||||
"array": ["u8", 7]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1660,10 +1566,7 @@
|
|||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
64
|
||||
]
|
||||
"array": ["u8", 64]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1687,10 +1590,7 @@
|
|||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
72
|
||||
]
|
||||
"array": ["u8", 72]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1733,10 +1633,7 @@
|
|||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
3
|
||||
]
|
||||
"array": ["u8", 3]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1749,21 +1646,14 @@
|
|||
},
|
||||
{
|
||||
"name": "key",
|
||||
"docs": [
|
||||
"only the top `prefix_len` bits of `key` are relevant"
|
||||
],
|
||||
"docs": ["only the top `prefix_len` bits of `key` are relevant"],
|
||||
"type": "u128"
|
||||
},
|
||||
{
|
||||
"name": "children",
|
||||
"docs": [
|
||||
"indexes into `BookSide::nodes`"
|
||||
],
|
||||
"docs": ["indexes into `BookSide::nodes`"],
|
||||
"type": {
|
||||
"array": [
|
||||
"u32",
|
||||
2
|
||||
]
|
||||
"array": ["u32", 2]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1775,19 +1665,13 @@
|
|||
"iterate through the whole bookside."
|
||||
],
|
||||
"type": {
|
||||
"array": [
|
||||
"u64",
|
||||
2
|
||||
]
|
||||
"array": ["u64", 2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
72
|
||||
]
|
||||
"array": ["u8", 72]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1795,24 +1679,18 @@
|
|||
},
|
||||
{
|
||||
"name": "LeafNode",
|
||||
"docs": [
|
||||
"LeafNodes represent an order in the binary tree"
|
||||
],
|
||||
"docs": ["LeafNodes represent an order in the binary tree"],
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "tag",
|
||||
"docs": [
|
||||
"NodeTag"
|
||||
],
|
||||
"docs": ["NodeTag"],
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "ownerSlot",
|
||||
"docs": [
|
||||
"Index into the owning OpenOrdersAccount's OpenOrders"
|
||||
],
|
||||
"docs": ["Index into the owning OpenOrdersAccount's OpenOrders"],
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
|
@ -1825,10 +1703,7 @@
|
|||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
1
|
||||
]
|
||||
"array": ["u8", 1]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1842,38 +1717,27 @@
|
|||
{
|
||||
"name": "padding2",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
2
|
||||
]
|
||||
"array": ["u8", 2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "key",
|
||||
"docs": [
|
||||
"The binary tree key, see new_node_key()"
|
||||
],
|
||||
"docs": ["The binary tree key, see new_node_key()"],
|
||||
"type": "u128"
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"docs": [
|
||||
"Address of the owning OpenOrdersAccount"
|
||||
],
|
||||
"docs": ["Address of the owning OpenOrdersAccount"],
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "quantity",
|
||||
"docs": [
|
||||
"Number of base lots to buy or sell, always >=1"
|
||||
],
|
||||
"docs": ["Number of base lots to buy or sell, always >=1"],
|
||||
"type": "i64"
|
||||
},
|
||||
{
|
||||
"name": "timestamp",
|
||||
"docs": [
|
||||
"The time the order was placed"
|
||||
],
|
||||
"docs": ["The time the order was placed"],
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
|
@ -1888,18 +1752,13 @@
|
|||
},
|
||||
{
|
||||
"name": "clientOrderId",
|
||||
"docs": [
|
||||
"User defined id for this order, used in FillEvents"
|
||||
],
|
||||
"docs": ["User defined id for this order, used in FillEvents"],
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
32
|
||||
]
|
||||
"array": ["u8", 32]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1917,10 +1776,7 @@
|
|||
{
|
||||
"name": "data",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
119
|
||||
]
|
||||
"array": ["u8", 119]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1959,10 +1815,7 @@
|
|||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
3
|
||||
]
|
||||
"array": ["u8", 3]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1980,10 +1833,7 @@
|
|||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
512
|
||||
]
|
||||
"array": ["u8", 512]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2032,10 +1882,7 @@
|
|||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
199
|
||||
]
|
||||
"array": ["u8", 199]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -2065,10 +1912,7 @@
|
|||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
4
|
||||
]
|
||||
"array": ["u8", 4]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2086,10 +1930,7 @@
|
|||
{
|
||||
"name": "padding2",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
32
|
||||
]
|
||||
"array": ["u8", 32]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2103,10 +1944,7 @@
|
|||
{
|
||||
"name": "padding3",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
16
|
||||
]
|
||||
"array": ["u8", 16]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2116,10 +1954,7 @@
|
|||
{
|
||||
"name": "padding4",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
16
|
||||
]
|
||||
"array": ["u8", 16]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2137,10 +1972,7 @@
|
|||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
8
|
||||
]
|
||||
"array": ["u8", 8]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -2166,10 +1998,7 @@
|
|||
{
|
||||
"name": "padding0",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
5
|
||||
]
|
||||
"array": ["u8", 5]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2191,10 +2020,7 @@
|
|||
{
|
||||
"name": "padding1",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
136
|
||||
]
|
||||
"array": ["u8", 136]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -2220,9 +2046,7 @@
|
|||
"fields": [
|
||||
{
|
||||
"name": "stablePrice",
|
||||
"docs": [
|
||||
"Current stable price to use in health"
|
||||
],
|
||||
"docs": ["Current stable price to use in health"],
|
||||
"type": "f64"
|
||||
},
|
||||
{
|
||||
|
@ -2239,10 +2063,7 @@
|
|||
"we use the next one."
|
||||
],
|
||||
"type": {
|
||||
"array": [
|
||||
"f64",
|
||||
24
|
||||
]
|
||||
"array": ["f64", 24]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2255,16 +2076,12 @@
|
|||
},
|
||||
{
|
||||
"name": "delayAccumulatorTime",
|
||||
"docs": [
|
||||
"Accumulating the total time for the above average."
|
||||
],
|
||||
"docs": ["Accumulating the total time for the above average."],
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"name": "delayIntervalSeconds",
|
||||
"docs": [
|
||||
"Length of a delay_interval"
|
||||
],
|
||||
"docs": ["Length of a delay_interval"],
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
|
@ -2292,19 +2109,13 @@
|
|||
{
|
||||
"name": "padding",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
7
|
||||
]
|
||||
"array": ["u8", 7]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
48
|
||||
]
|
||||
"array": ["u8", 48]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -2925,4 +2736,4 @@
|
|||
"msg": "The receiver is invalid. Makes sure the receiver's owner is the market admin"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
]
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
[192,195,39,97,233,148,78,104,48,36,19,25,94,80,158,110,226,196,146,130,210,207,234,219,73,15,79,151,96,211,21,71,14,183,1,132,46,77,8,178,66,55,164,177,111,122,151,200,206,99,140,188,41,150,137,242,188,221,242,204,233,23,69,241]
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -4,6 +4,9 @@
|
|||
"main": "index.js",
|
||||
"repository": "https://github.com/blockworks-foundation/solana-rpc-testing.git",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"configure": "ts-node configure/main.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.1.0",
|
||||
"ts-node": "^10.9.1",
|
||||
|
|
|
@ -18,10 +18,8 @@ pub struct Bencher;
|
|||
|
||||
impl Bencher {
|
||||
pub async fn bench<B: BenchFn>(args: Args) -> anyhow::Result<Metric> {
|
||||
let rpc_client = args.get_rpc_client();
|
||||
|
||||
let futs = (0..args.threads).map(|_| {
|
||||
let rpc_client = rpc_client.clone();
|
||||
let rpc_client = args.get_rpc_client();
|
||||
let duration = args.get_duration_to_run_test();
|
||||
|
||||
tokio::spawn(async move {
|
||||
|
|
|
@ -5,6 +5,7 @@ mod metrics;
|
|||
mod openbook;
|
||||
mod solana_runtime;
|
||||
mod test_registry;
|
||||
mod utils;
|
||||
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::test_registry::TestingTask;
|
||||
use crate::utils::noop;
|
||||
use async_trait::async_trait;
|
||||
use rand::{rngs::StdRng, Rng, SeedableRng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use solana_sdk::compute_budget;
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::{
|
||||
instruction::{AccountMeta, Instruction},
|
||||
|
@ -88,21 +89,20 @@ impl TestingTask for SimulateOpenbookV2PlaceOrder {
|
|||
|
||||
let task = tokio::spawn(async move {
|
||||
let start = Instant::now();
|
||||
let mut rng = StdRng::from_seed(user.get_keypair().pubkey().to_bytes());
|
||||
|
||||
let mut place_order_ix = place_order_cmd.instruction;
|
||||
let rpc_client = args.get_rpc_client();
|
||||
let mut side = false;
|
||||
let mut price_diff: i64 = 1;
|
||||
let mut max_base_lots = 1;
|
||||
while start.elapsed().as_secs() < args.duration_in_seconds {
|
||||
let side = rng.gen::<bool>(); // 0 for bid and 1 for ask
|
||||
let order_type: u8 = 0;
|
||||
let price_diff = (rng.gen::<u8>() % 32) as i64;
|
||||
|
||||
let price_lots: i64 = if side {
|
||||
1000 - price_diff
|
||||
} else {
|
||||
1000 + price_diff
|
||||
};
|
||||
let max_base_lots: i64 = rng.gen_range(0..10);
|
||||
let place_order_params = PlaceOrderArgs {
|
||||
client_order_id: 100,
|
||||
side: side as u8,
|
||||
|
@ -149,9 +149,18 @@ impl TestingTask for SimulateOpenbookV2PlaceOrder {
|
|||
);
|
||||
|
||||
let recent_blockhash = *block_hash.read().await;
|
||||
|
||||
// to generate new signature each time
|
||||
let noop_ix = noop::timestamp();
|
||||
// to have higher compute budget limit
|
||||
let cu_limits_ix =
|
||||
compute_budget::ComputeBudgetInstruction::set_compute_unit_limit(
|
||||
1000000,
|
||||
);
|
||||
|
||||
let transaction = Transaction::new(
|
||||
&[&user.get_keypair()],
|
||||
Message::new(&[ix], Some(&user.pubkey())),
|
||||
Message::new(&[noop_ix, cu_limits_ix, ix], Some(&user.pubkey())),
|
||||
recent_blockhash,
|
||||
);
|
||||
let signature = transaction.signatures[0];
|
||||
|
@ -164,6 +173,11 @@ impl TestingTask for SimulateOpenbookV2PlaceOrder {
|
|||
} else {
|
||||
successful_orders_count.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
// update side and price diff
|
||||
side = !side;
|
||||
price_diff = price_diff % 6 + 1;
|
||||
max_base_lots = max_base_lots % 10 + 1;
|
||||
}
|
||||
});
|
||||
tasks.push(task);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
pub mod noop;
|
|
@ -0,0 +1,15 @@
|
|||
use chrono::Utc;
|
||||
use solana_sdk::{instruction::Instruction, pubkey::Pubkey};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn instruction(data: Vec<u8>) -> Instruction {
|
||||
Instruction {
|
||||
program_id: Pubkey::from_str("zSZRvv8VgXtKNyw9t8fu4QKC4TL2P9DfSsvzBmBL8yn").unwrap(),
|
||||
accounts: vec![],
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn timestamp() -> Instruction {
|
||||
instruction(Utc::now().timestamp_micros().to_le_bytes().into())
|
||||
}
|
Loading…
Reference in New Issue