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, 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 });
})();
DeepBookV3 SDK node package

The DeepBookV3 SDK node package on NPM.

DeepBook Margin package

The DeepBook Margin package on GitHub.