Skip to main content

DeepBookV3 SDK

The DeepBook typescript SDK abstracts away the transaction calls, allowing for direct interactions with the DeepBook package. To use the SDK in your projects, install the @mysten/deepbook package.

npm install @mysten/deepbook-v3

Constants

The DeepBookV3 SDK includes a constants file (/utils/constants.ts) that maintains the latest deployed addresses for DeepBook, as well as a few staple coins and pools.

Toggle constants.ts code

sdk/deepbook/src/utils/constants.ts
import { normalizeStructTag, SUI_TYPE_ARG } from '@mysten/sui/utils';

export const PACKAGE_ID = '0xdee9';

export const MODULE_CLOB = 'clob_v2';

export const MODULE_CUSTODIAN = 'custodian_v2';

export const CREATION_FEE = 100 * 1e9;

export const NORMALIZED_SUI_COIN_TYPE = normalizeStructTag(SUI_TYPE_ARG);

export const ORDER_DEFAULT_EXPIRATION_IN_MS = 1000 * 60 * 60 * 24; // 24 hours

export const FLOAT_SCALING_FACTOR = 1_000_000_000n;

DeepBookClient

To work with DeepBook, you must create a DeepBookClient. To construct the DeepBookClient, pass in a SuiClient, the sender address, and environment. The Sui TypeScript SDK provides the SuiClient and key functionality necessary to process transactions. The following example imports those libraries, as well.

import { SuiClient, getFullnodeUrl } from "@mysten/sui/client";
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
import { decodeSuiPrivateKey } from "@mysten/sui/cryptography";

import { DeepBookClient } from "@mysten/deepbook-v3";

class DeepBookMarketMaker {
dbClient: DeepBookClient; // For building transactions
suiClient: SuiClient; // For executing transactions
keypair: Ed25519Keypair; // For signing transactions

constructor(privateKey: string, env: 'testnet' | 'mainnet') {
this.keypair = this.getSignerFromPK(privateKey);
this.suiClient = new SuiClient({
url: getFullnodeUrl(env)
})
this.dbClient = new DeepBookClient({
address: this.getActiveAddress(),
env: env,
client: this.suiClient,
});
}

getSignerFromPK = (privateKey: string): Ed25519Keypair => {
const { schema, secretKey } = decodeSuiPrivateKey(privateKey);
if (schema === 'ED25519') return Ed25519Keypair.fromSecretKey(secretKey);

throw new Error(`Unsupported schema: ${schema}`);
};

getActiveAddress() {
return this.keypair.toSuiAddress();
}
}

Keys: Coin, Pool, and Manager

Functions that require the input of a coin, pool, or a manager require the key of any such object as the parameter. The SDK manages a key:value relationship of this data in memory. Some default data comes with the SDK (as seen in utils/constants.ts). Coins are stored in a CoinMap and pools in a PoolMap in the config.

Balance manager

Before placing any trade, you must supply a balance manager address to the client. The manager key points to an object defined by the BalanceManager interface in the client. BalanceManager docs. Initialize the balance manager with the client. If you don't create a balance manager, you can rely on the client to create one, but then the user must reinitialize the client.

Example using an existing balance manager:

import { SuiClient, getFullnodeUrl } from "@mysten/sui/client";
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
import { decodeSuiPrivateKey } from "@mysten/sui/cryptography";
import { config } from 'dotenv';
config();

import { DeepBookClient } from "../src";
import { BalanceManager } from "./types";

// Used wherever balance manager key is required
const BALANCE_MANAGER_KEY = 'MANAGER_1';

class DeepBookMarketMaker {
dbClient: DeepBookClient; // For building transactions
suiClient: SuiClient; // For executing transactions
keypair: Ed25519Keypair; // For signing transactions
env: 'testnet' | 'mainnet';

constructor(privateKey: string, env: 'testnet' | 'mainnet') {
this.env = env;
this.keypair = this.getSignerFromPK(privateKey);
this.suiClient = new SuiClient({
url: getFullnodeUrl(env)
})
this.dbClient = new DeepBookClient({
address: this.getActiveAddress(),
env: env,
client: this.suiClient,
balanceManagers: this.getBalanceManagers()
});
}

getSignerFromPK = (privateKey: string): Ed25519Keypair => {
const { schema, secretKey } = decodeSuiPrivateKey(privateKey);
if (schema === 'ED25519') return Ed25519Keypair.fromSecretKey(secretKey);

throw new Error(`Unsupported schema: ${schema}`);
};

getActiveAddress() {
return this.keypair.toSuiAddress();
}

getBalanceManagers(): { [key: string]: BalanceManager } {
// Used wherever balance manager key is required
const balanceManagerAddress = process.env.BALANCE_MANAGER_ADDRESS;
const balanceManagerTradeCap = process.env.BALANCE_MANAGER_TRADE_CAP;
if (!balanceManagerAddress) {
throw new Error('No balance manager address found');
}
return {
[BALANCE_MANAGER_KEY]: {
address: balanceManagerAddress,
tradeCap: balanceManagerTradeCap
}
}
}
}

Example creating a balance manager:

import { SuiClient, getFullnodeUrl } from "@mysten/sui/client";
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
import { decodeSuiPrivateKey } from "@mysten/sui/cryptography";

import { DeepBookClient } from "../src";
import { Transaction } from "@mysten/sui/transactions";
import { BalanceManager } from "./types";

// Used wherever balance manager key is required
const BALANCE_MANAGER_KEY = 'MANAGER_1';

class DeepBookMarketMaker {
dbClient: DeepBookClient; // For building transactions
suiClient: SuiClient; // For executing transactions
keypair: Ed25519Keypair; // For signing transactions
env: 'testnet' | 'mainnet';

constructor(privateKey: string, env: 'testnet' | 'mainnet') {
this.env = env;
this.keypair = this.getSignerFromPK(privateKey);
this.suiClient = new SuiClient({
url: getFullnodeUrl(env)
})
this.dbClient = new DeepBookClient({
address: this.getActiveAddress(),
env: env,
client: this.suiClient,
});
}

getSignerFromPK = (privateKey: string): Ed25519Keypair => {
const { schema, secretKey } = decodeSuiPrivateKey(privateKey);
if (schema === 'ED25519') return Ed25519Keypair.fromSecretKey(secretKey);

throw new Error(`Unsupported schema: ${schema}`);
};

getActiveAddress() {
return this.keypair.toSuiAddress();
}

async createBalanceManagerAndReinitialize() {
let tx = new Transaction();
tx.add(this.dbClient.balanceManager.createAndShareBalanceManager());

const res = await this.suiClient.signAndExecuteTransaction({
transaction: tx,
signer: this.keypair,
options: {
showEffects: true,
showObjectChanges: true,
},
})

// @ts-ignore
const balanceManagerAddress = res.objectChanges?.find((change) => {
return change.type === 'created' && change.objectType.includes('BalanceManager');
})?.['objectId'];

const balanceManagers: { [key: string]: BalanceManager } = {
[BALANCE_MANAGER_KEY]: {
address: balanceManagerAddress,
tradeCap: undefined,
}
}

this.dbClient = new DeepBookClient({
address: this.getActiveAddress(),
env: this.env,
client: this.suiClient,
balanceManagers: balanceManagers,
})
}
}

Coin

The SDK comes with four default coins on Testnet and five default coins on Mainnet.

Default Testnet coins

  • DEEP
  • SUI
  • DBUSDC
  • DBUSDT

Default Mainnet coins

  • DEEP
  • SUI
  • USDC
  • USDT
  • WETH

You can also initialize the SDK with custom coins to interact with pools that are not supported by default. To do this, create a CoinMap object and pass it to the constructor of the client.

Pool

Similar to coins, the SDK comes with default pools. You can provide a PoolMap during construction to override this behavior.

import { decodeSuiPrivateKey } from '@mysten/sui.js/cryptography';
import { getFullnodeUrl, SuiClient } from '@mysten/sui/client';
import type { Keypair } from '@mysten/sui/cryptography';
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
import type { Transaction } from '@mysten/sui/transactions';

import { DeepBookClient } from '../src/index.js'; // Adjust path according to new structure
import type { BalanceManager } from '../src/types/index.js';

export class DeepBookMarketMaker extends DeepBookClient {
keypair: Keypair;
suiClient: SuiClient;

constructor(
keypair: string | Keypair,
env: 'testnet' | 'mainnet',
balanceManagers?: { [key: string]: BalanceManager },
adminCap?: string,
) {
let resolvedKeypair: Keypair;

if (typeof keypair === 'string') {
resolvedKeypair = DeepBookMarketMaker.#getSignerFromPK(keypair);
} else {
resolvedKeypair = keypair;
}

const address = resolvedKeypair.toSuiAddress();

super({
address: address,
env: env,
client: new SuiClient({
url: getFullnodeUrl(env),
}),
balanceManagers: balanceManagers,
adminCap: adminCap,
});

this.keypair = resolvedKeypair;
this.suiClient = new SuiClient({
url: getFullnodeUrl(env),
});
}

static #getSignerFromPK = (privateKey: string) => {
const { schema, secretKey } = decodeSuiPrivateKey(privateKey);
if (schema === 'ED25519') return Ed25519Keypair.fromSecretKey(secretKey);

throw new Error(`Unsupported schema: ${schema}`);
};

signAndExecute = async (tx: Transaction) => {
// remove arguments
return this.suiClient.signAndExecuteTransaction({
transaction: tx,
signer: this.keypair,
options: {
showEffects: true,
showObjectChanges: true,
},
});
};

getActiveAddress() {
return this.keypair.getPublicKey().toSuiAddress();
}
}

Example setup

The following example uses the default pools and coins provided.

import { Transaction } from '@mysten/sui/transactions';
import { DeepBookMarketMaker } from './deepbookMarketMaker.js';

(async () => {
const privateKey = ''; // Can encapsalate this in a .env file

// Initialize with balance managers if created
const balanceManagers = {
MANAGER_1: {
address: '',
tradeCap: '',
},
};
const mmClient = new DeepBookMarketMaker(
privateKey,
'testnet',
balanceManagers,
);

const tx = new Transaction();

// Read only call
console.log(await mmClient.checkManagerBalance('MANAGER_1', 'SUI'));
console.log(await mmClient.getLevel2Range('SUI_DBUSDC', 0.1, 100, true));

// Balance manager contract call
mmClient.balanceManager.depositIntoManager('MANAGER_1', 'DBUSDT', 10000)(tx);
mmClient.balanceManager.withdrawAllFromManager(
'MANAGER_1',
'DBUSDT',
mmClient.getActiveAddress(),
)(tx);

// Example custom PTB call in DeepBookMarketMaker class
mmClient.placeLimitOrderExample(tx);
mmClient.flashLoanExample(tx);

let res = await mmClient.signAndExecute(tx);

console.dir(res, { depth: null });
})();