Skip to main content

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 install @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.

DeepBookClient

To work with DeepBook Margin, use the client extension to add DeepBook functionality to a Sui client. The Sui TypeScript SDK provides the SuiGrpcClient and key functionality necessary to process transactions. The following example imports those libraries, as well.

import { deepbook, type DeepBookClient } from '@mysten/deepbook-v3';
import type { ClientWithExtensions } from '@mysten/sui/client';
import { decodeSuiPrivateKey } from '@mysten/sui/cryptography';
import { SuiGrpcClient } from '@mysten/sui/grpc';
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';

class DeepBookMarginTrader {
client: ClientWithExtensions<{ deepbook: DeepBookClient }>;
keypair: Ed25519Keypair;

constructor(privateKey: string, env: 'testnet' | 'mainnet') {
this.keypair = this.getSignerFromPK(privateKey);
this.client = new SuiGrpcClient({
network: env,
baseUrl:
env === 'mainnet'
? 'https://fullnode.mainnet.sui.io:443'
: 'https://fullnode.testnet.sui.io:443',
}).$extend(
deepbook({
address: this.getActiveAddress(),
}),
);
}

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

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

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 { deepbook, type DeepBookClient } from '@mysten/deepbook-v3';
import type { MarginManager } from '@mysten/deepbook-v3';
import type { ClientWithExtensions } from '@mysten/sui/client';
import { decodeSuiPrivateKey } from '@mysten/sui/cryptography';
import { SuiGrpcClient } from '@mysten/sui/grpc';
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
import { config } from 'dotenv';

config();

const MARGIN_MANAGER_KEY = 'MARGIN_MANAGER_1';

class DeepBookMarginTrader {
client: ClientWithExtensions<{ deepbook: DeepBookClient }>;
keypair: Ed25519Keypair;

constructor(privateKey: string, env: 'testnet' | 'mainnet') {
this.keypair = this.getSignerFromPK(privateKey);
this.client = new SuiGrpcClient({
network: env,
baseUrl:
env === 'mainnet'
? 'https://fullnode.mainnet.sui.io:443'
: 'https://fullnode.testnet.sui.io:443',
}).$extend(
deepbook({
address: this.getActiveAddress(),
marginManagers: this.getMarginManagers(),
}),
);
}

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

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

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

getMarginManagers(): { [key: string]: MarginManager } {
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 { deepbook, type DeepBookClient } from '@mysten/deepbook-v3';
import type { MarginManager } from '@mysten/deepbook-v3';
import type { ClientWithExtensions } from '@mysten/sui/client';
import { decodeSuiPrivateKey } from '@mysten/sui/cryptography';
import { SuiGrpcClient } from '@mysten/sui/grpc';
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
import { Transaction } from '@mysten/sui/transactions';

const MARGIN_MANAGER_KEY = 'MARGIN_MANAGER_1';

class DeepBookMarginTrader {
client: ClientWithExtensions<{ deepbook: DeepBookClient }>;
keypair: Ed25519Keypair;
env: 'testnet' | 'mainnet';

constructor(privateKey: string, env: 'testnet' | 'mainnet') {
this.env = env;
this.keypair = this.getSignerFromPK(privateKey);
this.client = this.#createClient(env);
}

#createClient(env: 'testnet' | 'mainnet', marginManagers?: { [key: string]: MarginManager }) {
return new SuiGrpcClient({
network: env,
baseUrl:
env === 'mainnet'
? 'https://fullnode.mainnet.sui.io:443'
: 'https://fullnode.testnet.sui.io:443',
}).$extend(
deepbook({
address: this.getActiveAddress(),
marginManagers,
}),
);
}

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

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

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

async createMarginManagerAndReinitialize() {
let tx = new Transaction();
const poolKey = 'SUI_DBUSDC';
tx.add(this.client.deepbook.marginManager.newMarginManager(poolKey));

const result = await this.client.core.signAndExecuteTransaction({
transaction: tx,
signer: this.keypair,
include: { effects: true, objectTypes: true },
});

if (result.$kind === 'FailedTransaction') {
throw new Error('Transaction failed');
}

const objectTypes = result.Transaction?.objectTypes ?? {};
const marginManagerAddress = result.Transaction?.effects?.changedObjects?.find(
(obj) =>
obj.idOperation === 'Created' && objectTypes[obj.objectId]?.includes('MarginManager'),
)?.objectId;

if (!marginManagerAddress) {
throw new Error('Failed to create margin manager');
}

const marginManagers: { [key: string]: MarginManager } = {
[MARGIN_MANAGER_KEY]: {
address: marginManagerAddress,
poolKey: poolKey,
},
};

this.client = this.#createClient(this.env, 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 { deepbook, type DeepBookClient } from '@mysten/deepbook-v3';
import type { MarginManager } from '@mysten/deepbook-v3';
import type { ClientWithExtensions } from '@mysten/sui/client';
import { decodeSuiPrivateKey } from '@mysten/sui/cryptography';
import type { Keypair } from '@mysten/sui/cryptography';
import { SuiGrpcClient } from '@mysten/sui/grpc';
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
import type { Transaction } from '@mysten/sui/transactions';

export class DeepBookMarginTrader {
keypair: Keypair;
client: ClientWithExtensions<{ deepbook: DeepBookClient }>;

constructor(
keypair: string | Keypair,
env: 'testnet' | 'mainnet',
marginManagers?: { [key: string]: MarginManager },
maintainerCap?: string,
) {
if (typeof keypair === 'string') {
this.keypair = DeepBookMarginTrader.#getSignerFromPK(keypair);
} else {
this.keypair = keypair;
}

this.client = new SuiGrpcClient({
network: env,
baseUrl:
env === 'mainnet'
? 'https://fullnode.mainnet.sui.io:443'
: 'https://fullnode.testnet.sui.io:443',
}).$extend(
deepbook({
address: this.getActiveAddress(),
marginManagers,
marginMaintainerCap: maintainerCap,
}),
);
}

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

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

signAndExecute = async (tx: Transaction) => {
const result = await this.client.core.signAndExecuteTransaction({
transaction: tx,
signer: this.keypair,
include: { effects: true },
});
if (result.$kind === 'FailedTransaction') {
throw new Error('Transaction failed');
}
return result.Transaction;
};

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.client.deepbook.marginManager.deposit('MARGIN_MANAGER_1', 'DBUSDC', 10000)(tx);
traderClient.client.deepbook.marginManager.borrowBase('MARGIN_MANAGER_1', 'SUI_DBUSDC', 100)(tx);

// Place leveraged orders
traderClient.client.deepbook.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.client.deepbook.marginPool.mintSupplierCap());
traderClient.client.deepbook.marginPool.supplyToMarginPool('DBUSDC', supplierCap, 5000)(tx);

let res = await traderClient.signAndExecute(tx);

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

Margin manager referral functions

The SDK provides functions for managing referrals with margin managers. Referrals are pool-specific and must first be minted using the core DeepBook SDK before they can be associated with a margin manager.

// Set a referral for a margin manager (pool-specific)
// The referral must be a DeepBookPoolReferral minted for the pool the margin manager is associated with
traderClient.client.deepbook.marginManager.setMarginManagerReferral(
'MARGIN_MANAGER_1',
referralId,
)(tx);

// Unset the referral for a margin manager for a specific pool
traderClient.client.deepbook.marginManager.unsetMarginManagerReferral(
'MARGIN_MANAGER_1',
'SUI_DBUSDC',
)(tx);
info

To mint a referral, use the core DeepBook SDK's mintReferral function. See the DeepBookV3 SDK documentation for more details on minting and managing referrals.

DeepBookV3 SDK node package

The DeepBookV3 SDK node package on NPM.

DeepBook Margin package

The DeepBook Margin package on GitHub.