본문으로 건너뛰기

DeepBook Margin SDK

DeepBook Margin TypeScript SDK는 트랜잭션 call을 추상화하여 leveraged trading을 위한 DeepBook Margin 패키지와 직접 상호작용할 수 있게 한다.

설치

프로젝트에서 SDK를 사용하려면, margin trading 기능을 포함하는 @mysten/deepbook-v3 패키지를 설치한다.

npm install @mysten/deepbook-v3

constant

DeepBook SDK에는 DeepBook Margin의 최신 배포 주소와 마진 풀 및 configuration을 유지하는 constants file(/utils/constants.ts)이 포함된다.

DeepBookClient

DeepBook Margin으로 작업하려면, 클라이언트 extension을 사용해 Sui 클라이언트에 DeepBook 기능을 추가한다. Sui TypeScript SDK는 트랜잭션을 처리하는 데 필요한 SuiGrpcClient와 핵심 기능을 제공한다. 다음 예시는 이 라이브러리도 함께 import한다.

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

코인, 풀, 또는 margin manager의 입력을 요구하는 함수는 파라미터로 해당 객체의 key를 요구한다. SDK는 이 데이터를 메모리에서 key:value 관계로 관리한다. 일부 기본 데이터는 SDK와 함께 제공된다(utils/constants.ts 참조). 코인은 CoinMap에 저장되고, 풀은 PoolMap에 저장되며, margin manager는 config의 MarginManagerMap에 저장된다.

margin manager

margin trade를 배치하기 전에, 클라이언트에 margin manager 주소를 제공해야 한다. manager key는 클라이언트에서 MarginManager interface로 정의된 객체를 가리킨다. 마진 매니저를 참고한다. 클라이언트로 margin manager를 initialize한다. margin manager를 생성하지 않으면 클라이언트가 margin manager를 생성하도록 의존할 수 있지만, 이 경우 사용자는 클라이언트를 다시 initialize해야 한다.

기존 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,
},
};
}
}

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

SDK에는 Testnet에서 네 개의 기본 코인과 Mainnet에서 다섯 개의 기본 코인이 포함된다.

Default Testnet 코인

  • DEEP
  • SUI
  • DBUSDC
  • DBUSDT

Default Mainnet 코인

  • DEEP
  • SUI
  • USDC
  • USDT
  • WETH

또한 기본적으로 지원되지 않는 마진 풀과 상호작용하기 위해 custom 코인으로 SDK를 initialize할 수도 있다. 이를 위해 CoinMap 객체를 생성하고 클라이언트 constructor에 전달한다.

코인과 유사하게, SDK에는 기본 풀이 포함된다. construction 시 PoolMap을 제공하여 이 동작을 override할 수 있다.

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();
}
}

예시 setup

다음 예시는 제공되는 기본 풀과 코인을 사용하며, margin trading 작업을 시연한다.

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 함수

SDK는 margin manager와 함께 referral을 관리하기 위한 함수를 제공한다. referral은 풀-specific이며, margin manager와 연결되기 전에 먼저 core DeepBook SDK를 사용해 민트해야 한다.

// 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);
정보

referral을 민트하려면, core DeepBook SDK의 mintReferral 함수를 사용한다. referral의 민트 및 관리에 대한 자세한 내용은 DeepBookV3 SDK documentation을 참조한다.