configuring users to trade on openbook

This commit is contained in:
Godmode Galactus 2023-05-11 20:12:31 +02:00
parent f6c3428080
commit de5cc1c827
No known key found for this signature in database
GPG Key ID: A04142C71ABB0DEA
12 changed files with 470 additions and 76 deletions

1
.gitmodules vendored
View File

@ -1,3 +1,4 @@
[submodule "thirdparty/openbook-v2"]
path = thirdparty/openbook-v2
url = https://github.com/openbook-dex/openbook-v2.git
branch = master

View File

@ -2,23 +2,31 @@ import { AnchorProvider, Provider } 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";
export function getProviderFromKeypair(connection: Connection, authority: Keypair) : AnchorProvider {
export class TestProvider extends AnchorProvider {
keypair: Keypair;
constructor(connection: Connection, keypair: Keypair) {
let txSigner = async (tx: Transaction) => {
tx.partialSign(authority);
return tx
};
let allSigner = async (txs : Transaction[]) => {
txs.forEach(x=> x.partialSign(authority));
return txs;
};
return new AnchorProvider(connection,
{
signTransaction: txSigner,
signAllTransactions: allSigner,
publicKey : authority.publicKey,
},
{commitment: 'confirmed'}
)
tx.partialSign(this.keypair);
return tx
};
let allSigner = async (txs : Transaction[]) => {
txs.forEach(x=> x.partialSign(this.keypair));
return txs;
};
super(
connection,
{
signTransaction: txSigner,
signAllTransactions: allSigner,
publicKey : keypair.publicKey,
},
{commitment: 'confirmed'}
)
this.keypair = keypair;
}
getKeypair() : Keypair {
return this.keypair
}
}

View File

@ -1,4 +1,4 @@
import { command, number, option, string, run } from 'cmd-ts';
import { command, number, option, string, run, boolean, flag } from 'cmd-ts';
import * as fs from 'fs';
@ -6,16 +6,15 @@ 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 { createPayer } from './general/create_payers';
import { User, createUser, mintUser } from './general/create_users';
import { configure_accounts } from './general/accounts';
import { OutputFile } from './output_file';
import { getProviderFromKeypair } from './anchor_utils';
import { MintUtils } from './general/mint_utils';
import { configureOpenbookV2 } from './openbook-v2/configure_openbook';
import { OpenbookConfigurator } from './openbook-v2/configure_openbook';
const numberOfAccountsToBeCreated = option({
type: number,
defaultValue: () => 1024,
defaultValue: () => 256,
long: 'number-of-accounts',
});
@ -58,6 +57,14 @@ const nbMints = option({
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",
@ -75,6 +82,7 @@ const app = command(
nbPayers,
balancePerPayer,
nbMints,
skipProgramDeployment,
outFile,
},
handler: ({
@ -84,6 +92,7 @@ const app = command(
nbPayers,
balancePerPayer,
nbMints,
skipProgramDeployment,
outFile,
}) => {
console.log("configuring a new test instance");
@ -94,6 +103,7 @@ const app = command(
nbPayers,
balancePerPayer,
nbMints,
skipProgramDeployment,
outFile,
).then(_ => {
console.log("configuration finished");
@ -112,6 +122,7 @@ async function configure(
nbPayers: number,
balancePerPayer: number,
nbMints: number,
skipProgramDeployment: boolean,
outFile: String,
) {
// create connections
@ -140,18 +151,11 @@ async function configure(
let programIds = programOutputData.map(x => {
return x.program_id
});
console.log("starting program deployment");
await deploy_programs(endpoint, authorityFile.toString(), programs);
console.log("programs deployed");
console.log("Creating payers");
let payers = await Promise.all(Array.from(Array(nbPayers).keys()).map(_ => createPayer(connection, authority, balancePerPayer)));
console.log("Payers created");
console.log("Creating accounts")
let accounts = await configure_accounts(connection, authority, numberOfAccountsToBeCreated, programIds);
console.log("Accounts created")
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);
@ -161,14 +165,52 @@ async function configure(
console.log("Configuring openbook-v2")
let index = programs.findIndex(x => x.name === "openbook_v2");
let openbookProgramId = programOutputData[index].program_id;
await configureOpenbookV2(connection, authority, mintUtils, mints, openbookProgramId);
let openbookConfigurator = new OpenbookConfigurator(connection, authority, mintUtils, openbookProgramId);
let markets = await openbookConfigurator.configureOpenbookV2(mints);
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
user => mintUser(connection, authority, mints, mintUtils, user.publicKey, 100_000_000_000)
))
let userOpenOrders = await Promise.all(users.map(
/// user is crazy betting all his money in crypto market
user => openbookConfigurator.configureMarketForUser(user, markets, 100_000_000_000)
))
let userData: User [] = users.map((user, i) => {
return {
keypair: user,
openOrders: userOpenOrders[i],
token: tokenAccounts[i],
}
})
console.log("Users created");
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.marketPk, market.oracle, market.quoteVault, market.baseVault, market.baseMint, market.quoteMint] ).flat();
const userAccountsList = userData.map(user => {
const allOpenOrdersAccounts = user.openOrders.map(x=>x.openOrders).flat();
const allTokenAccounts = user.token.map(x => x.tokenAccount);
return allOpenOrdersAccounts.concat(allTokenAccounts)
}).flat()
accounts = accounts.concat(marketAccountsList).concat(userAccountsList);
console.log("Accounts created")
let outputFile: OutputFile = {
programs: programOutputData,
known_accounts: accounts,
payers: payers.map(x => Array.from(x.secretKey)),
mints: mints,
users: userData,
mints,
markets,
}
console.log("creating output file")

View File

@ -1,16 +0,0 @@
import { Connection, Keypair, LAMPORTS_PER_SOL, SystemProgram, Transaction, sendAndConfirmTransaction } from "@solana/web3.js";
export async function createPayer(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
}

View File

@ -0,0 +1,44 @@
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 { OpenOrders } from "../openbook-v2/configure_openbook";
export interface User {
keypair: Keypair,
token : TokenAccountData[],
openOrders: 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
}
interface TokenAccountData {
mint: PublicKey,
tokenAccount: 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,
tokenAccount: tokenAccount
}
})
)
}

View File

@ -1,12 +1,65 @@
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import { getProviderFromKeypair } from "../anchor_utils";
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 { BN, Program, web3 } from "@project-serum/anchor";
export async function configureOpenbookV2(connection: Connection, authority: Keypair, mintUtils: MintUtils, mints: PublicKey[], openbookProgramId: PublicKey): Promise<Market[]> {
let anchorProvider = getProviderFromKeypair(connection, authority);
let quoteMint = mints[0];
let admin = Keypair.generate();
return await Promise.all(mints.slice(1).map((mint, index) => createMarket(anchorProvider, mintUtils, admin, openbookProgramId, mint, quoteMint, authority, index)))
export interface OpenOrders {
market: PublicKey,
openOrders: PublicKey
}
export class OpenbookConfigurator {
anchorProvider: TestProvider;
mintUtils: MintUtils;
openbookProgramId: PublicKey;
constructor(connection: Connection, authority: Keypair, mintUtils: MintUtils, openbookProgramId: PublicKey) {
this.anchorProvider = new TestProvider(connection, authority);
this.mintUtils = mintUtils;
this.openbookProgramId = 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.anchorProvider, this.mintUtils, admin, this.openbookProgramId, mint, quoteMint, index)))
}
public async configureMarketForUser(user: Keypair, markets: Market[], depositAmount: number) : Promise<OpenOrders[]> {
let program = new Program<OpenbookV2>(
IDL as OpenbookV2,
this.openbookProgramId,
this.anchorProvider,
);
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.marketPk.toBuffer(), accountIndex.toBuffer("le", 4)], this.openbookProgramId)
await program.methods.initOpenOrders(
0,
64
).accounts({
openOrdersAccount: openOrders,
market: market.marketPk,
owner: user.publicKey,
payer: this.anchorProvider.publicKey,
systemProgram: web3.SystemProgram.programId,
}).signers([user]).rpc();
return [market.marketPk, openOrders]
})
)
return openOrders.map(x=> {
return {
market : x[0],
openOrders : x[1],
}
})
}
}

View File

@ -1,10 +1,11 @@
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
import IDL from '../programs/openbook_v2.json'
import { AnchorProvider, Idl, Program, web3, BN } from '@project-serum/anchor';
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,
@ -21,7 +22,7 @@ export interface Market {
marketIndex: number,
}
export async function createMarket(anchorProvider: AnchorProvider, mintUtils: MintUtils, adminKp: Keypair, openbookProgramId: PublicKey, baseMint: PublicKey, quoteMint: PublicKey, payer: Keypair, index: number): Promise<Market> {
export async function createMarket(anchorProvider: TestProvider, mintUtils: MintUtils, adminKp: Keypair, openbookProgramId: PublicKey, baseMint: PublicKey, quoteMint: PublicKey, index: number): Promise<Market> {
let program = new Program<OpenbookV2>(
IDL as OpenbookV2,
openbookProgramId,
@ -35,23 +36,23 @@ export async function createMarket(anchorProvider: AnchorProvider, mintUtils: Mi
oracle: oracleId,
admin,
mint: baseMint,
payer: payer.publicKey,
payer: anchorProvider.wallet.publicKey,
systemProgram: web3.SystemProgram.programId,
})
.signers([adminKp, payer])
.signers([adminKp])
.rpc();
// bookside size = 123720
let asks = await createAccount(anchorProvider.connection, payer, 123720, openbookProgramId);
let bids = await createAccount(anchorProvider.connection, payer, 123720, openbookProgramId);
let eventQueue = await createAccount(anchorProvider.connection, payer, 97688, openbookProgramId);
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"), 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, payer, marketPk);
let quoteVault = await mintUtils.createTokenAccount(quoteMint, payer, marketPk);
let name = 'token at index ' + index.toString() + ' wrt at index 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,
@ -68,7 +69,7 @@ export async function createMarket(anchorProvider: AnchorProvider, mintUtils: Mi
bids,
asks,
eventQueue,
payer: payer.publicKey,
payer: anchorProvider.publicKey,
baseVault,
quoteVault,
baseMint,
@ -76,7 +77,7 @@ export async function createMarket(anchorProvider: AnchorProvider, mintUtils: Mi
systemProgram: web3.SystemProgram.programId,
oracle: oracleId,
}
).signers([adminKp, payer])
).signers([adminKp])
.rpc();
return {

View File

@ -4,6 +4,9 @@ export type OpenbookV2 = {
"instructions": [
{
"name": "createMarket",
"docs": [
"Create a [`Market`](crate::state::Market) for a given token pair."
],
"accounts": [
{
"name": "admin",
@ -149,6 +152,24 @@ export type OpenbookV2 = {
},
{
"name": "placeOrder",
"docs": [
"Place an order.",
"",
"Different types of orders have different effects on the order book,",
"as described in [`PlaceOrderType`](crate::state::PlaceOrderType).",
"",
"`price_lots` refers to the price in lots: the number of quote lots",
"per base lot. It is ignored for `PlaceOrderType::Market` orders.",
"",
"`expiry_timestamp` is a unix timestamp for when this order should",
"expire. If 0 is passed in, the order will never expire. If the time",
"is in the past, the instruction is skipped. Timestamps in the future",
"are reduced to now + 65,535s.",
"",
"`limit` determines the maximum number of orders from the book to fill,",
"and can be used to limit CU spent. When the limit is reached, processing",
"stops and the instruction succeeds."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -377,6 +398,12 @@ export type OpenbookV2 = {
},
{
"name": "placeTakeOrder",
"docs": [
"Place an order that shall take existing liquidity off of the book, not",
"add a new order off the book.",
"",
"This type of order allows for instant token settlement for the taker."
],
"accounts": [
{
"name": "owner",
@ -483,6 +510,31 @@ export type OpenbookV2 = {
},
{
"name": "consumeEvents",
"docs": [
"Process up to `limit` [events](crate::state::AnyEvent).",
"",
"When a user places a 'take' order, they do not know beforehand which",
"market maker will have placed the 'make' order that they get executed",
"against. This prevents them from passing in a market maker's",
"[`OpenOrdersAccount`](crate::state::OpenOrdersAccount), which is needed",
"to credit/debit the relevant tokens to/from the maker. As such, Openbook",
"uses a 'crank' system, where `place_order` only emits events, and",
"`consume_events` handles token settlement.",
"",
"Currently, there are two types of events: [`FillEvent`](crate::state::FillEvent)s",
"and [`OutEvent`](crate::state::OutEvent)s.",
"",
"A `FillEvent` is emitted when an order is filled, and it is handled by",
"debiting whatever the taker is selling from the taker and crediting",
"it to the maker, and debiting whatever the taker is buying from the",
"maker and crediting it to the taker. Note that *no tokens are moved*,",
"these are just debits and credits to each party's [`Position`](crate::state::Position).",
"",
"An `OutEvent` is emitted when a limit order needs to be removed from",
"the book during a `place_order` invocation, and it is handled by",
"crediting whatever the maker would have sold (quote token in a bid,",
"base token in an ask) back to the maker."
],
"accounts": [
{
"name": "market",
@ -504,6 +556,12 @@ export type OpenbookV2 = {
},
{
"name": "cancelOrder",
"docs": [
"Cancel an order by its `order_id`.",
"",
"Note that this doesn't emit an [`OutEvent`](crate::state::OutEvent) because a",
"maker knows that they will be passing in their own [`OpenOrdersAccount`](crate::state::OpenOrdersAccount)."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -540,6 +598,12 @@ export type OpenbookV2 = {
},
{
"name": "cancelOrderByClientOrderId",
"docs": [
"Cancel an order by its `client_order_id`.",
"",
"Note that this doesn't emit an [`OutEvent`](crate::state::OutEvent) because a",
"maker knows that they will be passing in their own [`OpenOrdersAccount`](crate::state::OpenOrdersAccount)."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -576,6 +640,9 @@ export type OpenbookV2 = {
},
{
"name": "cancelAllOrders",
"docs": [
"Cancel up to `limit` orders."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -612,6 +679,9 @@ export type OpenbookV2 = {
},
{
"name": "cancelAllOrdersBySide",
"docs": [
"Cancel up to `limit` orders on a single side of the book."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -656,6 +726,13 @@ export type OpenbookV2 = {
},
{
"name": "deposit",
"docs": [
"Desposit a certain amount of `base_amount_lots` and `quote_amount_lots`",
"into one's [`Position`](crate::state::Position).",
"",
"Makers might wish to `deposit`, rather than have actual tokens moved for",
"each trade, in order to reduce CUs."
],
"accounts": [
{
"name": "owner",
@ -716,6 +793,9 @@ export type OpenbookV2 = {
},
{
"name": "settleFunds",
"docs": [
"Withdraw any available tokens."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -762,6 +842,9 @@ export type OpenbookV2 = {
},
{
"name": "sweepFees",
"docs": [
"Sweep fees, as a [`Market`](crate::state::Market)'s admin."
],
"accounts": [
{
"name": "market",
@ -793,6 +876,9 @@ export type OpenbookV2 = {
},
{
"name": "closeMarket",
"docs": [
"Close a [`Market`](crate::state::Market)."
],
"accounts": [
{
"name": "admin",
@ -2877,6 +2963,9 @@ export const IDL: OpenbookV2 = {
"instructions": [
{
"name": "createMarket",
"docs": [
"Create a [`Market`](crate::state::Market) for a given token pair."
],
"accounts": [
{
"name": "admin",
@ -3022,6 +3111,24 @@ export const IDL: OpenbookV2 = {
},
{
"name": "placeOrder",
"docs": [
"Place an order.",
"",
"Different types of orders have different effects on the order book,",
"as described in [`PlaceOrderType`](crate::state::PlaceOrderType).",
"",
"`price_lots` refers to the price in lots: the number of quote lots",
"per base lot. It is ignored for `PlaceOrderType::Market` orders.",
"",
"`expiry_timestamp` is a unix timestamp for when this order should",
"expire. If 0 is passed in, the order will never expire. If the time",
"is in the past, the instruction is skipped. Timestamps in the future",
"are reduced to now + 65,535s.",
"",
"`limit` determines the maximum number of orders from the book to fill,",
"and can be used to limit CU spent. When the limit is reached, processing",
"stops and the instruction succeeds."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -3250,6 +3357,12 @@ export const IDL: OpenbookV2 = {
},
{
"name": "placeTakeOrder",
"docs": [
"Place an order that shall take existing liquidity off of the book, not",
"add a new order off the book.",
"",
"This type of order allows for instant token settlement for the taker."
],
"accounts": [
{
"name": "owner",
@ -3356,6 +3469,31 @@ export const IDL: OpenbookV2 = {
},
{
"name": "consumeEvents",
"docs": [
"Process up to `limit` [events](crate::state::AnyEvent).",
"",
"When a user places a 'take' order, they do not know beforehand which",
"market maker will have placed the 'make' order that they get executed",
"against. This prevents them from passing in a market maker's",
"[`OpenOrdersAccount`](crate::state::OpenOrdersAccount), which is needed",
"to credit/debit the relevant tokens to/from the maker. As such, Openbook",
"uses a 'crank' system, where `place_order` only emits events, and",
"`consume_events` handles token settlement.",
"",
"Currently, there are two types of events: [`FillEvent`](crate::state::FillEvent)s",
"and [`OutEvent`](crate::state::OutEvent)s.",
"",
"A `FillEvent` is emitted when an order is filled, and it is handled by",
"debiting whatever the taker is selling from the taker and crediting",
"it to the maker, and debiting whatever the taker is buying from the",
"maker and crediting it to the taker. Note that *no tokens are moved*,",
"these are just debits and credits to each party's [`Position`](crate::state::Position).",
"",
"An `OutEvent` is emitted when a limit order needs to be removed from",
"the book during a `place_order` invocation, and it is handled by",
"crediting whatever the maker would have sold (quote token in a bid,",
"base token in an ask) back to the maker."
],
"accounts": [
{
"name": "market",
@ -3377,6 +3515,12 @@ export const IDL: OpenbookV2 = {
},
{
"name": "cancelOrder",
"docs": [
"Cancel an order by its `order_id`.",
"",
"Note that this doesn't emit an [`OutEvent`](crate::state::OutEvent) because a",
"maker knows that they will be passing in their own [`OpenOrdersAccount`](crate::state::OpenOrdersAccount)."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -3413,6 +3557,12 @@ export const IDL: OpenbookV2 = {
},
{
"name": "cancelOrderByClientOrderId",
"docs": [
"Cancel an order by its `client_order_id`.",
"",
"Note that this doesn't emit an [`OutEvent`](crate::state::OutEvent) because a",
"maker knows that they will be passing in their own [`OpenOrdersAccount`](crate::state::OpenOrdersAccount)."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -3449,6 +3599,9 @@ export const IDL: OpenbookV2 = {
},
{
"name": "cancelAllOrders",
"docs": [
"Cancel up to `limit` orders."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -3485,6 +3638,9 @@ export const IDL: OpenbookV2 = {
},
{
"name": "cancelAllOrdersBySide",
"docs": [
"Cancel up to `limit` orders on a single side of the book."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -3529,6 +3685,13 @@ export const IDL: OpenbookV2 = {
},
{
"name": "deposit",
"docs": [
"Desposit a certain amount of `base_amount_lots` and `quote_amount_lots`",
"into one's [`Position`](crate::state::Position).",
"",
"Makers might wish to `deposit`, rather than have actual tokens moved for",
"each trade, in order to reduce CUs."
],
"accounts": [
{
"name": "owner",
@ -3589,6 +3752,9 @@ export const IDL: OpenbookV2 = {
},
{
"name": "settleFunds",
"docs": [
"Withdraw any available tokens."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -3635,6 +3801,9 @@ export const IDL: OpenbookV2 = {
},
{
"name": "sweepFees",
"docs": [
"Sweep fees, as a [`Market`](crate::state::Market)'s admin."
],
"accounts": [
{
"name": "market",
@ -3666,6 +3835,9 @@ export const IDL: OpenbookV2 = {
},
{
"name": "closeMarket",
"docs": [
"Close a [`Market`](crate::state::Market)."
],
"accounts": [
{
"name": "admin",

View File

@ -1,4 +1,6 @@
import { PublicKey } from "@solana/web3.js";
import { Market } from "./openbook-v2/create_markets";
import { User } from "./general/create_users";
export interface ProgramOutputData {
name: String,
@ -6,8 +8,9 @@ export interface ProgramOutputData {
}
export interface OutputFile {
payers: number[][],
users: User[],
programs: ProgramOutputData[],
known_accounts: PublicKey[],
mints: PublicKey[],
markets: Market[],
}

View File

@ -4,6 +4,9 @@
"instructions": [
{
"name": "createMarket",
"docs": [
"Create a [`Market`](crate::state::Market) for a given token pair."
],
"accounts": [
{
"name": "admin",
@ -149,6 +152,24 @@
},
{
"name": "placeOrder",
"docs": [
"Place an order.",
"",
"Different types of orders have different effects on the order book,",
"as described in [`PlaceOrderType`](crate::state::PlaceOrderType).",
"",
"`price_lots` refers to the price in lots: the number of quote lots",
"per base lot. It is ignored for `PlaceOrderType::Market` orders.",
"",
"`expiry_timestamp` is a unix timestamp for when this order should",
"expire. If 0 is passed in, the order will never expire. If the time",
"is in the past, the instruction is skipped. Timestamps in the future",
"are reduced to now + 65,535s.",
"",
"`limit` determines the maximum number of orders from the book to fill,",
"and can be used to limit CU spent. When the limit is reached, processing",
"stops and the instruction succeeds."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -377,6 +398,12 @@
},
{
"name": "placeTakeOrder",
"docs": [
"Place an order that shall take existing liquidity off of the book, not",
"add a new order off the book.",
"",
"This type of order allows for instant token settlement for the taker."
],
"accounts": [
{
"name": "owner",
@ -483,6 +510,31 @@
},
{
"name": "consumeEvents",
"docs": [
"Process up to `limit` [events](crate::state::AnyEvent).",
"",
"When a user places a 'take' order, they do not know beforehand which",
"market maker will have placed the 'make' order that they get executed",
"against. This prevents them from passing in a market maker's",
"[`OpenOrdersAccount`](crate::state::OpenOrdersAccount), which is needed",
"to credit/debit the relevant tokens to/from the maker. As such, Openbook",
"uses a 'crank' system, where `place_order` only emits events, and",
"`consume_events` handles token settlement.",
"",
"Currently, there are two types of events: [`FillEvent`](crate::state::FillEvent)s",
"and [`OutEvent`](crate::state::OutEvent)s.",
"",
"A `FillEvent` is emitted when an order is filled, and it is handled by",
"debiting whatever the taker is selling from the taker and crediting",
"it to the maker, and debiting whatever the taker is buying from the",
"maker and crediting it to the taker. Note that *no tokens are moved*,",
"these are just debits and credits to each party's [`Position`](crate::state::Position).",
"",
"An `OutEvent` is emitted when a limit order needs to be removed from",
"the book during a `place_order` invocation, and it is handled by",
"crediting whatever the maker would have sold (quote token in a bid,",
"base token in an ask) back to the maker."
],
"accounts": [
{
"name": "market",
@ -504,6 +556,12 @@
},
{
"name": "cancelOrder",
"docs": [
"Cancel an order by its `order_id`.",
"",
"Note that this doesn't emit an [`OutEvent`](crate::state::OutEvent) because a",
"maker knows that they will be passing in their own [`OpenOrdersAccount`](crate::state::OpenOrdersAccount)."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -540,6 +598,12 @@
},
{
"name": "cancelOrderByClientOrderId",
"docs": [
"Cancel an order by its `client_order_id`.",
"",
"Note that this doesn't emit an [`OutEvent`](crate::state::OutEvent) because a",
"maker knows that they will be passing in their own [`OpenOrdersAccount`](crate::state::OpenOrdersAccount)."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -576,6 +640,9 @@
},
{
"name": "cancelAllOrders",
"docs": [
"Cancel up to `limit` orders."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -612,6 +679,9 @@
},
{
"name": "cancelAllOrdersBySide",
"docs": [
"Cancel up to `limit` orders on a single side of the book."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -656,6 +726,13 @@
},
{
"name": "deposit",
"docs": [
"Desposit a certain amount of `base_amount_lots` and `quote_amount_lots`",
"into one's [`Position`](crate::state::Position).",
"",
"Makers might wish to `deposit`, rather than have actual tokens moved for",
"each trade, in order to reduce CUs."
],
"accounts": [
{
"name": "owner",
@ -716,6 +793,9 @@
},
{
"name": "settleFunds",
"docs": [
"Withdraw any available tokens."
],
"accounts": [
{
"name": "openOrdersAccount",
@ -762,6 +842,9 @@
},
{
"name": "sweepFees",
"docs": [
"Sweep fees, as a [`Market`](crate::state::Market)'s admin."
],
"accounts": [
{
"name": "market",
@ -793,6 +876,9 @@
},
{
"name": "closeMarket",
"docs": [
"Close a [`Market`](crate::state::Market)."
],
"accounts": [
{
"name": "admin",

Binary file not shown.

@ -1 +1 @@
Subproject commit 3d227cce696891b2e5f6cc7ae71d94a718952c1f
Subproject commit b7754174bf8c8cbcbda25372fbd0f8dc8b429317