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
- Yarn
- pnpm
npm install @mysten/deepbook-v3
yarn add @mysten/deepbook-v3
pnpm add @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
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";
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 });
})();