configuring users to trade on openbook
This commit is contained in:
parent
f6c3428080
commit
de5cc1c827
|
@ -1,3 +1,4 @@
|
|||
[submodule "thirdparty/openbook-v2"]
|
||||
path = thirdparty/openbook-v2
|
||||
url = https://github.com/openbook-dex/openbook-v2.git
|
||||
branch = master
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
|
@ -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],
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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[],
|
||||
}
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue