Skip to content

Commit

Permalink
Liquidator: update integration tests for openbook v2
Browse files Browse the repository at this point in the history
  • Loading branch information
farnyser committed May 21, 2024
1 parent af7e7d2 commit b99d2f5
Show file tree
Hide file tree
Showing 3 changed files with 260 additions and 7 deletions.
26 changes: 26 additions & 0 deletions ts/client/scripts/liqtest/liqtest-create-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ const MINTS = JSON.parse(process.env.MINTS || '').map((s) => new PublicKey(s));
const SERUM_MARKETS = JSON.parse(process.env.SERUM_MARKETS || '').map(
(s) => new PublicKey(s),
);
const OBV2_MARKETS = JSON.parse(process.env.OBV2_MARKETS || '').map(
(s) => new PublicKey(s),
);

const MAINNET_MINTS = new Map([
['USDC', MINTS[0]],
Expand Down Expand Up @@ -261,6 +264,29 @@ async function main(): Promise<void> {
}
}

let nextOpbv2MarketIndex = 0;
for (const [name, mint] of MAINNET_MINTS) {
if (name == 'USDC') {
continue;
}

console.log(`Registering ${name}/USDC obv2 market...`);
try {
await client.openbookV2RegisterMarket(
group,
new PublicKey(OBV2_MARKETS[nextOpbv2MarketIndex]),
group.getFirstBankByMint(new PublicKey(mint)),
group.getFirstBankByMint(usdcMint),
nextOpbv2MarketIndex,
`${name}/USDC`,
0,
);
nextOpbv2MarketIndex += 1;
} catch (error) {
console.log(error);
}
}

console.log('Registering MNGO-PERP market...');
if (!group.banksMapByMint.get(usdcMint.toString())) {
console.log('stopping, no USDC bank');
Expand Down
148 changes: 146 additions & 2 deletions ts/client/scripts/liqtest/liqtest-create-tokens-and-markets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,30 @@ import {
Keypair,
PublicKey,
sendAndConfirmTransaction,
TransactionInstruction,
Signer,
} from '@solana/web3.js';
import * as splToken from '@solana/spl-token';
import * as serum from '@project-serum/serum';
import * as obv2 from '@openbook-dex/openbook-v2';
import fs from 'fs';
import { MangoClient } from '../../src/client';
import { MANGO_V4_ID, OPENBOOK_PROGRAM_ID } from '../../src/constants';
import {
MANGO_V4_ID,
OPENBOOK_PROGRAM_ID,
OPENBOOK_V2_PROGRAM_ID,
} from '../../src/constants';
import { connect } from 'http2';
import { generateSerum3MarketExternalVaultSignerAddress } from '../../src/accounts/serum3';
import { OracleConfigParams } from '../../src';

//
// Script which creates three mints and two serum3 markets relating them
//

const MINT_COUNT = 5;
const SERUM_MARKET_COUNT = 4;
const OBV2_MARKET_COUNT = 4;

function getVaultOwnerAndNonce(
market: PublicKey,
Expand Down Expand Up @@ -78,9 +87,11 @@ async function main(): Promise<void> {
}
//const mints = [new PublicKey('5aMD1uEcWnXnptwmyfxmTWHzx3KeMsZ7jmiJAZ3eiAdH'), new PublicKey('FijXcDUkgTiMsghQVpjRDBdUPtkrJfQdfRZkr6zLkdkW'), new PublicKey('3tVDfiFQAAT3rqLNMXUaH2p5X5R4fjz8LYEvFEQ9fDYB')]

// make markets
const quoteMint = mints[0];

// Make serum markets
const serumMarkets: PublicKey[] = [];
const quoteMint = mints[0];
for (const baseMint of mints.slice(1, 1 + SERUM_MARKET_COUNT)) {
const feeRateBps = 0.25; // don't think this does anything
const quoteDustThreshold = 100;
Expand Down Expand Up @@ -193,6 +204,134 @@ async function main(): Promise<void> {
serumMarkets.push(market.publicKey);
}

// Make openbook-v2 markets
const obv2Markets: PublicKey[] = [];
for (const baseMint of mints.slice(1, 1 + OBV2_MARKET_COUNT)) {
const baseLotSize = 1000;
const quoteLotSize = 1; // makes prices be in 1000ths

const openbookv2ProgramId = OPENBOOK_V2_PROGRAM_ID.devnet;
const market = Keypair.generate();
const requestQueue = Keypair.generate();
const eventQueue = Keypair.generate();
const bids = Keypair.generate();
const asks = Keypair.generate();
const baseVault = Keypair.generate();
const quoteVault = Keypair.generate();

const [vaultOwner, vaultSignerNonce] = getVaultOwnerAndNonce(
market.publicKey,
openbookv2ProgramId,
);

await splToken.createAccount(
connection,
admin,
baseMint,
vaultOwner,
baseVault,
);
await splToken.createAccount(
connection,
admin,
quoteMint,
vaultOwner,
quoteVault,
);
const provider = new AnchorProvider(
connection,
new Wallet(admin),
AnchorProvider.defaultOptions(),
);
const obv2client = new obv2.OpenBookV2Client(provider, openbookv2ProgramId);
const createMarket = await obv2client.createMarketIx(
admin.publicKey,
'',
quoteMint,
baseMint,
new BN(quoteLotSize),
new BN(baseLotSize),
new BN(0),
new BN(0),
new BN(0),
null,
null,
admin.publicKey,
admin.publicKey,
admin.publicKey,
new OracleConfigParams(),
market,
admin.publicKey,
);

// const tx = new Transaction();
// tx.add(
// SystemProgram.createAccount({
// fromPubkey: admin.publicKey,
// newAccountPubkey: market.publicKey,
// lamports: await connection.getMinimumBalanceForRentExemption(
// serum.Market.getLayout(openbookv2ProgramId).span,
// ),
// space: serum.Market.getLayout(openbookv2ProgramId).span,
// programId: openbookv2ProgramId,
// }),
// SystemProgram.createAccount({
// fromPubkey: admin.publicKey,
// newAccountPubkey: requestQueue.publicKey,
// lamports: await connection.getMinimumBalanceForRentExemption(5120 + 12),
// space: 5120 + 12,
// programId: openbookv2ProgramId,
// }),
// SystemProgram.createAccount({
// fromPubkey: admin.publicKey,
// newAccountPubkey: eventQueue.publicKey,
// lamports: await connection.getMinimumBalanceForRentExemption(
// 262144 + 12,
// ),
// space: 262144 + 12,
// programId: openbookv2ProgramId,
// }),
// SystemProgram.createAccount({
// fromPubkey: admin.publicKey,
// newAccountPubkey: bids.publicKey,
// lamports: await connection.getMinimumBalanceForRentExemption(
// 65536 + 12,
// ),
// space: 65536 + 12,
// programId: openbookv2ProgramId,
// }),
// SystemProgram.createAccount({
// fromPubkey: admin.publicKey,
// newAccountPubkey: asks.publicKey,
// lamports: await connection.getMinimumBalanceForRentExemption(
// 65536 + 12,
// ),
// space: 65536 + 12,
// programId: openbookv2ProgramId,
// }),
// );
// await sendAndConfirmTransaction(connection, tx, [
// admin,
// market,
// requestQueue,
// eventQueue,
// bids,
// asks,
// ]);
//
const tx2 = new Transaction();
const signers: Signer[] = [admin];
for (const x of createMarket[0]) {
tx2.add(x);
}
for (const x of createMarket[1]) {
signers.push(x);
}

await sendAndConfirmTransaction(connection, tx2, signers);
obv2Markets.push(market.publicKey);
}

console.log(
"MINTS='[" + mints.map((pk) => '"' + pk.toBase58() + '"').join(',') + "]'",
);
Expand All @@ -201,6 +340,11 @@ async function main(): Promise<void> {
serumMarkets.map((pk) => '"' + pk.toBase58() + '"').join(',') +
"]'",
);
console.log(
"OBV2_MARKETS='[" +
obv2Markets.map((pk) => '"' + pk.toBase58() + '"').join(',') +
"]'",
);

process.exit();
}
Expand Down
93 changes: 88 additions & 5 deletions ts/client/scripts/liqtest/liqtest-make-candidates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@ import { Cluster, Connection, Keypair, PublicKey } from '@solana/web3.js';
import fs from 'fs';
import { Bank } from '../../src/accounts/bank';
import { MangoAccount } from '../../src/accounts/mangoAccount';
import {
PerpMarket,
PerpOrderSide,
PerpOrderType,
} from '../../src/accounts/perp';
import { PerpMarket } from '../../src/accounts/perp';
import { PerpOrderSide, PerpOrderType } from '../../src/accounts/bookSide';
import {
Serum3OrderType,
Serum3SelfTradeBehavior,
Expand All @@ -20,6 +17,11 @@ import {
NullTokenEditParams,
} from '../../src/clientIxParamBuilder';
import { MANGO_V4_ID } from '../../src/constants';
import {
OpenbookV2OrderType,
OpenbookV2SelfTradeBehavior,
OpenbookV2Side,
} from '../../src';

//
// This script creates liquidation candidates
Expand Down Expand Up @@ -265,6 +267,87 @@ async function main() {
}
}

// Openbook-v2 order scenario
{
const name = 'LIQTEST, obv2 orders';

console.log(`Creating mangoaccount...`);
const mangoAccount = await createMangoAccount(name);
console.log(
`...created mangoAccount ${mangoAccount.publicKey} for ${name}`,
);

const market = group.getOpenbookV2MarketByName('SOL/USDC')!;
const sellMint = new PublicKey(MAINNET_MINTS.get('USDC')!);
const buyMint = new PublicKey(MAINNET_MINTS.get('SOL')!);

await client.tokenDepositNative(
group,
mangoAccount,
sellMint,
new BN(150000),
);
await mangoAccount.reload(client);

// temporarily up the init asset weight of the bought token
await client.tokenEdit(
group,
buyMint,
Builder(NullTokenEditParams)
.oracle(group.getFirstBankByMint(buyMint).oracle)
.maintAssetWeight(1.0)
.initAssetWeight(1.0)
.build(),
);
try {
// At a price of $0.015/ui-SOL we can buy 10 ui-SOL for the 0.15 USDC (150k native-USDC) we have.
// With maint weight of 0.9 we have 10x main-leverage. Buying 11x as much causes liquidation.
await client.openbookV2PlaceOrder(
group,
mangoAccount,
market.openbookMarketExternal,
OpenbookV2Side.bid,
0.015,
11 * 10,
OpenbookV2SelfTradeBehavior.abortTransaction,
OpenbookV2OrderType.limit,
0,
5,
);
await mangoAccount.reload(client);

for (let market of group.openbookV2MarketsMapByMarketIndex.values()) {
if (market.name == 'SOL/USDC') {
continue;
}
await client.openbookV2PlaceOrder(
group,
mangoAccount,
market.openbookMarketExternal,
OpenbookV2Side.bid,
0.001,
1,
OpenbookV2SelfTradeBehavior.abortTransaction,
OpenbookV2OrderType.limit,
0,
5,
);
await mangoAccount.reload(client);
}
} finally {
// restore the weights
await client.tokenEdit(
group,
buyMint,
Builder(NullTokenEditParams)
.oracle(group.getFirstBankByMint(buyMint).oracle)
.maintAssetWeight(0.9)
.initAssetWeight(0.8)
.build(),
);
}
}

// Perp orders bring health <0, liquidator force closes
{
const name = 'LIQTEST, perp orders';
Expand Down

0 comments on commit b99d2f5

Please sign in to comment.