본문으로 건너뛰기

DeepBook Margin SDK

DeepBook Margin TypeScript SDK는 transaction call을 추상화하여 leveraged trading을 위한 DeepBook Margin package와 직접 상호작용할 수 있게 한다.

Install

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

npm install @mysten/deepbook-v3

Constants

DeepBook SDK에는 DeepBook Margin의 최신 배포 address와 margin pool 및 configuration을 유지하는 constants file(/utils/constants.ts)이 포함된다.

DeepBookClient

DeepBook Margin으로 작업하려면, client extension을 사용해 Sui client에 DeepBook 기능을 추가한다. Sui TypeScript SDK는 transaction을 처리하는 데 필요한 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

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

Margin manager

margin trade를 배치하기 전에, client에 margin manager address를 제공해야 한다. manager key는 client에서 MarginManager interface로 정의된 object를 가리킨다. 마진 매니저를 참고한다. client로 margin manager를 initialize한다. margin manager를 생성하지 않으면 client가 margin manager를 생성하도록 의존할 수 있지만, 이 경우 사용자는 client를 다시 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에서 네 개의 default coin과 Mainnet에서 다섯 개의 default coin이 포함된다.

Default Testnet coins

  • DEEP
  • SUI
  • DBUSDC
  • DBUSDT

Default Mainnet coins

  • DEEP
  • SUI
  • USDC
  • USDT
  • WETH

또한 default로 지원되지 않는 margin pool과 상호작용하기 위해 custom coin으로 SDK를 initialize할 수도 있다. 이를 위해 CoinMap object를 생성하고 client constructor에 전달한다.

Pool

coin과 유사하게, SDK에는 default pool이 포함된다. 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();
}
}

Example setup

다음 예시는 제공되는 default pool과 coin을 사용하며, margin trading 작업을 시연한다.

import { Transaction } from '@mysten/sui/transactions';

import { DeepBookMarginTrader } from './deepbookMarginTrader.js';

(async () => {
const privateKey = ''; // 이를 .env 파일에 넣을 수 있다

// 생성된 margin managers가 있으면 함께 초기화한다
const marginManagers = {
MARGIN_MANAGER_1: {
address: '',
poolKey: 'SUI_DBUSDC',
},
};
const traderClient = new DeepBookMarginTrader(privateKey, 'testnet', marginManagers);

const tx = new Transaction();

// Margin manager contract 호출
traderClient.client.deepbook.marginManager.deposit('MARGIN_MANAGER_1', 'DBUSDC', 10000)(tx);
traderClient.client.deepbook.marginManager.borrowBase('MARGIN_MANAGER_1', 'SUI_DBUSDC', 100)(tx);

// leveraged order를 넣는다
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 작업
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

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

// margin manager에 referral을 설정한다(pool-specific)
// referral은 margin manager가 연결된 pool용으로 mint된 DeepBookPoolReferral이어야 한다
traderClient.client.deepbook.marginManager.setMarginManagerReferral(
'MARGIN_MANAGER_1',
referralId,
)(tx);

// 특정 pool에 대한 margin manager의 referral 설정을 해제한다
traderClient.client.deepbook.marginManager.unsetMarginManagerReferral(
'MARGIN_MANAGER_1',
'SUI_DBUSDC',
)(tx);
정보

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