DeepBook Margin SDK
The DeepBook Margin TypeScript SDK abstracts away the transaction calls, allowing for direct interactions with the DeepBook Margin package for leveraged trading.
Install
To use the SDK in your projects, install the @mysten/deepbook-v3 package, which includes the margin trading functionality.
- npm
- Yarn
- pnpm
npm install @mysten/deepbook-v3
yarn add @mysten/deepbook-v3
pnpm add @mysten/deepbook-v3
Constants
The DeepBook SDK includes a constants file (/utils/constants.ts) that maintains the latest deployed addresses for DeepBook Margin, as well as margin pools and configurations.
constants.ts
constants.tsDeepBookClient
To work with DeepBook Margin, 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 { DeepBookClient } from '@mysten/deepbook-v3';
import { getFullnodeUrl, SuiClient } from '@mysten/sui/client';
import { decodeSuiPrivateKey } from '@mysten/sui/cryptography';
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
class DeepBookMarginTrader {
	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 MarginManager
Functions that require the input of a coin, pool, or a margin 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, pools in a PoolMap, and margin managers in a MarginManagerMap in the config.
Margin manager
Before placing any margin trade, you must supply a margin manager address to the client. The manager key points to an object defined by the MarginManager interface in the client. MarginManager docs. Initialize the margin manager with the client. If you don't create a margin manager, you can rely on the client to create one, but then the user must reinitialize the client.
Example using an existing margin manager:
import { getFullnodeUrl, SuiClient } from '@mysten/sui/client';
import { decodeSuiPrivateKey } from '@mysten/sui/cryptography';
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
import { config } from 'dotenv';
import { DeepBookClient } from '../src';
import { MarginManager } from './types';
config();
// Used wherever margin manager key is required
const MARGIN_MANAGER_KEY = 'MARGIN_MANAGER_1';
class DeepBookMarginTrader {
	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,
			marginManagers: this.getMarginManagers(),
		});
	}
	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();
	}
	getMarginManagers(): { [key: string]: MarginManager } {
		// Used wherever margin manager key is required
		const marginManagerAddress = process.env.MARGIN_MANAGER_ADDRESS;
		const poolKey = process.env.POOL_KEY || 'SUI_DBUSDC';
		if (!marginManagerAddress) {
			throw new Error('No margin manager address found');
		}
		return {
			[MARGIN_MANAGER_KEY]: {
				address: marginManagerAddress,
				poolKey: poolKey,
			},
		};
	}
}
Example creating a margin manager:
import { getFullnodeUrl, SuiClient } from '@mysten/sui/client';
import { decodeSuiPrivateKey } from '@mysten/sui/cryptography';
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
import { Transaction } from '@mysten/sui/transactions';
import { DeepBookClient } from '../src';
import { MarginManager } from './types';
// Used wherever margin manager key is required
const MARGIN_MANAGER_KEY = 'MARGIN_MANAGER_1';
class DeepBookMarginTrader {
	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 createMarginManagerAndReinitialize() {
		let tx = new Transaction();
		const poolKey = 'SUI_DBUSDC';
		tx.add(this.dbClient.marginManager.newMarginManager(poolKey));
		const res = await this.suiClient.signAndExecuteTransaction({
			transaction: tx,
			signer: this.keypair,
			options: {
				showEffects: true,
				showObjectChanges: true,
			},
		});
		// @ts-ignore
		const marginManagerAddress = res.objectChanges?.find((change) => {
			return change.type === 'created' && change.objectType.includes('MarginManager');
		})?.['objectId'];
		const marginManagers: { [key: string]: MarginManager } = {
			[MARGIN_MANAGER_KEY]: {
				address: marginManagerAddress,
				poolKey: poolKey,
			},
		};
		this.dbClient = new DeepBookClient({
			address: this.getActiveAddress(),
			env: this.env,
			client: this.suiClient,
			marginManagers: marginManagers,
		});
	}
}
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 margin 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 { MarginManager } from '../src/types/index.js';
export class DeepBookMarginTrader extends DeepBookClient {
	keypair: Keypair;
	suiClient: SuiClient;
	constructor(
		keypair: string | Keypair,
		env: 'testnet' | 'mainnet',
		marginManagers?: { [key: string]: MarginManager },
		maintainerCap?: string,
	) {
		let resolvedKeypair: Keypair;
		if (typeof keypair === 'string') {
			resolvedKeypair = DeepBookMarginTrader.#getSignerFromPK(keypair);
		} else {
			resolvedKeypair = keypair;
		}
		const address = resolvedKeypair.toSuiAddress();
		super({
			address: address,
			env: env,
			client: new SuiClient({
				url: getFullnodeUrl(env),
			}),
			marginManagers: marginManagers,
			marginMaintainerCap: maintainerCap,
		});
		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) => {
		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, and demonstrates margin trading operations.
import { Transaction } from '@mysten/sui/transactions';
import { DeepBookMarginTrader } from './deepbookMarginTrader.js';
(async () => {
	const privateKey = ''; // Can encapsulate this in a .env file
	// Initialize with margin managers if created
	const marginManagers = {
		MARGIN_MANAGER_1: {
			address: '',
			poolKey: 'SUI_DBUSDC',
		},
	};
	const traderClient = new DeepBookMarginTrader(privateKey, 'testnet', marginManagers);
	const tx = new Transaction();
	// Margin manager contract calls
	traderClient.marginManager.deposit('MARGIN_MANAGER_1', 'DBUSDC', 10000)(tx);
	traderClient.marginManager.borrowBase('MARGIN_MANAGER_1', 'SUI_DBUSDC', 100)(tx);
	// Place leveraged orders
	traderClient.poolProxy.placeLimitOrder({
		poolKey: 'SUI_DBUSDC',
		marginManagerKey: 'MARGIN_MANAGER_1',
		clientOrderId: '12345',
		price: 2.5,
		quantity: 100,
		isBid: true,
		payWithDeep: true,
	})(tx);
	// Margin pool operations
	const supplierCap = tx.add(traderClient.marginPool.mintSupplierCap());
	traderClient.marginPool.supplyToMarginPool('DBUSDC', supplierCap, 5000)(tx);
	let res = await traderClient.signAndExecute(tx);
	console.dir(res, { depth: null });
})();
Related links
The DeepBookV3 SDK node package on NPM.
The DeepBook Margin package on GitHub.