@scallop-io/scallop-deepbook-kit 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +360 -0
- package/dist/index.d.mts +80 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/package.json +95 -0
- package/src/config.ts +130 -0
- package/src/examples/margin-pool-demo.ts +15 -0
- package/src/examples/toolkit-demo.ts +308 -0
- package/src/index.ts +1 -0
- package/src/testnet-config.ts +229 -0
- package/src/toolkit/DeepBookMarginPool.ts +440 -0
- package/src/toolkit/DeepBookMarginToolkit.ts +453 -0
- package/src/toolkit/index.ts +28 -0
- package/src/toolkit/types.ts +73 -0
- package/src/utils/env-manager.ts +357 -0
- package/src/utils/private-key.ts +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# Scallop DeepBook Kit
|
|
2
|
+
|
|
3
|
+
A comprehensive toolkit for interacting with DeepBook V3 Margin Pools on the Sui blockchain.
|
|
4
|
+
一個在 Sui 區塊鏈上與 DeepBook V3 Margin Pools 互動的完整工具套件。
|
|
5
|
+
|
|
6
|
+
## Features | 功能特色
|
|
7
|
+
|
|
8
|
+
- **DeepBook V3 Integration** | **DeepBook V3 整合**
|
|
9
|
+
Complete integration with DeepBook V3 Margin Pool system
|
|
10
|
+
完整整合 DeepBook V3 Margin Pool 系統
|
|
11
|
+
|
|
12
|
+
- **Simplified API** | **簡化的 API**
|
|
13
|
+
Clean and intuitive API for complex margin operations
|
|
14
|
+
簡潔直觀的 API,處理複雜的 margin 操作
|
|
15
|
+
|
|
16
|
+
- **Supplier Cap Management** | **Supplier Cap 管理**
|
|
17
|
+
Automatic creation and management of Supplier Credentials
|
|
18
|
+
自動創建和管理供應者憑證
|
|
19
|
+
|
|
20
|
+
- **Referral System** | **推薦系統**
|
|
21
|
+
Built-in referral creation and fee withdrawal support
|
|
22
|
+
內建推薦系統創建和費用提取支援
|
|
23
|
+
|
|
24
|
+
- **Balance Tracking** | **餘額追蹤**
|
|
25
|
+
Query wallet and margin pool balances in real-time
|
|
26
|
+
即時查詢錢包和 margin pool 餘額
|
|
27
|
+
|
|
28
|
+
- **TypeScript Support** | **TypeScript 支援**
|
|
29
|
+
Full TypeScript support with comprehensive type definitions
|
|
30
|
+
完整的 TypeScript 支援與詳盡的型別定義
|
|
31
|
+
|
|
32
|
+
- **Environment Management** | **環境管理**
|
|
33
|
+
Easy-to-use environment variable management utilities
|
|
34
|
+
易於使用的環境變數管理工具
|
|
35
|
+
|
|
36
|
+
## Prerequisites | 環境需求
|
|
37
|
+
|
|
38
|
+
- **Node.js** >= 18.0.0
|
|
39
|
+
- **pnpm** >= 9.0.0
|
|
40
|
+
- **Sui Testnet Account** with SUI and DBUSDC balance
|
|
41
|
+
**Sui 測試網帳戶**,需包含 SUI 和 DBUSDC 餘額
|
|
42
|
+
|
|
43
|
+
## Installation | 安裝
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Clone the repository | 克隆儲存庫
|
|
47
|
+
git clone https://github.com/your-username/scallop-deepbook-kit.git
|
|
48
|
+
cd scallop-deepbook-kit
|
|
49
|
+
|
|
50
|
+
# Install dependencies | 安裝依賴
|
|
51
|
+
pnpm install
|
|
52
|
+
|
|
53
|
+
# Setup environment variables | 設定環境變數
|
|
54
|
+
cp .env.example .env
|
|
55
|
+
# Edit .env and add your PRIVATE_KEY | 編輯 .env 並新增您的 PRIVATE_KEY
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Quick Start | 快速開始
|
|
59
|
+
|
|
60
|
+
### 1. Configure Environment | 配置環境
|
|
61
|
+
|
|
62
|
+
Create a `.env` file in the project root:
|
|
63
|
+
在專案根目錄建立 `.env` 檔案:
|
|
64
|
+
|
|
65
|
+
```env
|
|
66
|
+
# Required: Your wallet private key (hex format, without 0x prefix)
|
|
67
|
+
# 必需:您的錢包私鑰(hex 格式,不含 0x 前綴)
|
|
68
|
+
PRIVATE_KEY=your_private_key_here
|
|
69
|
+
|
|
70
|
+
# Optional: These will be auto-generated and saved
|
|
71
|
+
# 可選:這些會自動產生並儲存
|
|
72
|
+
# SUPPLIER_CAP_ID=
|
|
73
|
+
# SUI_REFERRAL_ID=
|
|
74
|
+
# DBUSDC_REFERRAL_ID=
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 2. Run the Demo | 執行示範
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Run the complete toolkit demo | 執行完整的 toolkit 示範
|
|
81
|
+
pnpm example:toolkit
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The demo will:
|
|
85
|
+
示範程式將會:
|
|
86
|
+
|
|
87
|
+
- Create or load Supplier Cap | 創建或載入 Supplier Cap
|
|
88
|
+
- Create referrals for SUI and DBUSDC | 為 SUI 和 DBUSDC 創建 referrals
|
|
89
|
+
- Withdraw all existing supplies | 提取所有現有的供應
|
|
90
|
+
- Supply 0.1 SUI and 10 DBUSDC to margin pools | 供應 0.1 SUI 和 10 DBUSDC 到 margin pools
|
|
91
|
+
- Track and display balance changes | 追蹤並顯示餘額變化
|
|
92
|
+
|
|
93
|
+
### 3. Use the Toolkit in Your Code | 在程式碼中使用 Toolkit
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { DeepBookMarginToolkit } from './toolkit';
|
|
97
|
+
|
|
98
|
+
// Initialize the toolkit | 初始化 toolkit
|
|
99
|
+
const toolkit = new DeepBookMarginToolkit({
|
|
100
|
+
network: 'testnet',
|
|
101
|
+
privateKey: process.env.PRIVATE_KEY!,
|
|
102
|
+
supplierCapId: process.env.SUPPLIER_CAP_ID, // Optional | 可選
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Initialize (creates Supplier Cap if needed) | 初始化(需要時創建 Supplier Cap)
|
|
106
|
+
await toolkit.initialize();
|
|
107
|
+
|
|
108
|
+
// Create a referral | 創建 referral
|
|
109
|
+
const referralId = await toolkit.createSupplyReferral('SUI');
|
|
110
|
+
|
|
111
|
+
// Supply to margin pool | 供應到 margin pool
|
|
112
|
+
await toolkit.supplyToMarginPool('SUI', 0.1, referralId);
|
|
113
|
+
|
|
114
|
+
// Get balance | 查詢餘額
|
|
115
|
+
const balance = await toolkit.getBalance('SUI');
|
|
116
|
+
console.log(`Supply amount: ${balance.userSupplyAmount}`);
|
|
117
|
+
console.log(`Wallet balance: ${balance.walletBalance}`);
|
|
118
|
+
|
|
119
|
+
// Withdraw from margin pool | 從 margin pool 提取
|
|
120
|
+
await toolkit.withdrawFromMarginPool('SUI'); // Withdraws all | 提取全部
|
|
121
|
+
|
|
122
|
+
// Withdraw referral fees | 提取 referral 費用
|
|
123
|
+
await toolkit.withdrawReferralFees('SUI', referralId);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## API Reference | API 參考
|
|
127
|
+
|
|
128
|
+
### DeepBookMarginToolkit
|
|
129
|
+
|
|
130
|
+
#### Constructor | 建構函式
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
new DeepBookMarginToolkit(config: ToolkitConfig)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Parameters | 參數:**
|
|
137
|
+
|
|
138
|
+
- `config.network`: `'testnet' | 'mainnet'` - Network type | 網路類型
|
|
139
|
+
- `config.privateKey`: `string` - Private key (hex, no 0x prefix) | 私鑰(hex 格式,無 0x 前綴)
|
|
140
|
+
- `config.supplierCapId?`: `string` - Optional existing Supplier Cap ID | 可選的現有 Supplier Cap ID
|
|
141
|
+
|
|
142
|
+
#### Methods | 方法
|
|
143
|
+
|
|
144
|
+
##### `initialize(): Promise<string>`
|
|
145
|
+
|
|
146
|
+
Initialize the toolkit and create Supplier Cap if needed.
|
|
147
|
+
初始化 toolkit 並在需要時創建 Supplier Cap。
|
|
148
|
+
|
|
149
|
+
**Returns | 返回:** Supplier Cap ID
|
|
150
|
+
|
|
151
|
+
##### `createSupplyReferral(coin: MarginCoinType): Promise<string | null>`
|
|
152
|
+
|
|
153
|
+
Create a supply referral for the specified coin.
|
|
154
|
+
為指定的幣種創建供應 referral。
|
|
155
|
+
|
|
156
|
+
**Parameters | 參數:**
|
|
157
|
+
|
|
158
|
+
- `coin`: `'SUI' | 'DBUSDC'` - Coin type | 幣種
|
|
159
|
+
|
|
160
|
+
**Returns | 返回:** Referral ID or null
|
|
161
|
+
|
|
162
|
+
##### `supplyToMarginPool(coin: MarginCoinType, amount: number, referralId?: string): Promise<boolean>`
|
|
163
|
+
|
|
164
|
+
Supply funds to the margin pool.
|
|
165
|
+
供應資金到 margin pool。
|
|
166
|
+
|
|
167
|
+
**Parameters | 參數:**
|
|
168
|
+
|
|
169
|
+
- `coin`: `'SUI' | 'DBUSDC'` - Coin type | 幣種
|
|
170
|
+
- `amount`: `number` - Amount in human-readable units | 人類可讀單位的金額
|
|
171
|
+
- `referralId?`: `string` - Optional referral ID | 可選的 referral ID
|
|
172
|
+
|
|
173
|
+
**Returns | 返回:** Success status
|
|
174
|
+
|
|
175
|
+
##### `withdrawFromMarginPool(coin: MarginCoinType, amount?: number): Promise<boolean>`
|
|
176
|
+
|
|
177
|
+
Withdraw funds from the margin pool.
|
|
178
|
+
從 margin pool 提取資金。
|
|
179
|
+
|
|
180
|
+
**Parameters | 參數:**
|
|
181
|
+
|
|
182
|
+
- `coin`: `'SUI' | 'DBUSDC'` - Coin type | 幣種
|
|
183
|
+
- `amount?`: `number` - Optional amount, omit to withdraw all | 可選的金額,省略則提取全部
|
|
184
|
+
|
|
185
|
+
**Returns | 返回:** Success status
|
|
186
|
+
|
|
187
|
+
##### `withdrawReferralFees(coin: MarginCoinType, referralId: string): Promise<boolean>`
|
|
188
|
+
|
|
189
|
+
Withdraw accumulated referral fees.
|
|
190
|
+
提取累積的 referral 費用。
|
|
191
|
+
|
|
192
|
+
**Parameters | 參數:**
|
|
193
|
+
|
|
194
|
+
- `coin`: `'SUI' | 'DBUSDC'` - Coin type | 幣種
|
|
195
|
+
- `referralId`: `string` - Referral Object ID | Referral 物件 ID
|
|
196
|
+
|
|
197
|
+
**Returns | 返回:** Success status
|
|
198
|
+
|
|
199
|
+
##### `getBalance(coin: MarginCoinType): Promise<MarginBalance>`
|
|
200
|
+
|
|
201
|
+
Query margin balance for a coin.
|
|
202
|
+
查詢幣種的 margin 餘額。
|
|
203
|
+
|
|
204
|
+
**Parameters | 參數:**
|
|
205
|
+
|
|
206
|
+
- `coin`: `'SUI' | 'DBUSDC'` - Coin type | 幣種
|
|
207
|
+
|
|
208
|
+
**Returns | 返回:** Balance information with `userSupplyAmount` and `walletBalance`
|
|
209
|
+
|
|
210
|
+
##### `getAddress(): string`
|
|
211
|
+
|
|
212
|
+
Get the wallet address.
|
|
213
|
+
獲取錢包地址。
|
|
214
|
+
|
|
215
|
+
**Returns | 返回:** Wallet address
|
|
216
|
+
|
|
217
|
+
##### `getSupplierCapId(): string | undefined`
|
|
218
|
+
|
|
219
|
+
Get the Supplier Cap ID.
|
|
220
|
+
獲取 Supplier Cap ID。
|
|
221
|
+
|
|
222
|
+
**Returns | 返回:** Supplier Cap ID or undefined
|
|
223
|
+
|
|
224
|
+
## Development Commands | 開發指令
|
|
225
|
+
|
|
226
|
+
### Build | 建置
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
pnpm build # Compile TypeScript | 編譯 TypeScript
|
|
230
|
+
pnpm build:watch # Watch mode compilation | 監聽模式編譯
|
|
231
|
+
pnpm clean # Remove build artifacts | 清除建置檔案
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Code Quality | 程式碼品質
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
pnpm lint # Check code style with ESLint | 使用 ESLint 檢查程式碼風格
|
|
238
|
+
pnpm lint:fix # Auto-fix ESLint issues | 自動修正 ESLint 問題
|
|
239
|
+
pnpm format # Format code with Prettier | 使用 Prettier 格式化程式碼
|
|
240
|
+
pnpm format:check # Check code formatting | 檢查程式碼格式
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Testing | 測試
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
pnpm test # Run tests | 執行測試
|
|
247
|
+
pnpm test:watch # Run tests in watch mode | 監聽模式執行測試
|
|
248
|
+
pnpm test:coverage # Generate coverage report | 產生覆蓋率報告
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Examples | 範例
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
pnpm example:toolkit # Run the DeepBook Margin Toolkit demo | 執行 DeepBook Margin Toolkit 示範
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Project Structure | 專案結構
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
.
|
|
261
|
+
├── src/
|
|
262
|
+
│ ├── toolkit/ # Core toolkit implementation | 核心 toolkit 實作
|
|
263
|
+
│ │ ├── DeepBookMarginToolkit.ts # Main toolkit class | 主要 toolkit 類別
|
|
264
|
+
│ │ ├── types.ts # Type definitions | 型別定義
|
|
265
|
+
│ │ └── index.ts # Exports | 匯出
|
|
266
|
+
│ ├── examples/ # Example scripts | 範例程式
|
|
267
|
+
│ │ └── toolkit-demo.ts # Complete demo | 完整示範
|
|
268
|
+
│ ├── utils/ # Utility functions | 工具函式
|
|
269
|
+
│ │ └── env-manager.ts # Environment variable management | 環境變數管理
|
|
270
|
+
│ ├── config.ts # Configuration loader | 配置載入器
|
|
271
|
+
│ └── testnet-config.ts # Testnet constants | 測試網常數
|
|
272
|
+
├── tests/ # Test files | 測試檔案
|
|
273
|
+
├── dist/ # Build output (git-ignored) | 建置輸出(git 忽略)
|
|
274
|
+
└── .env # Environment variables (git-ignored) | 環境變數(git 忽略)
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Tech Stack | 技術堆疊
|
|
278
|
+
|
|
279
|
+
### Core Dependencies | 核心依賴
|
|
280
|
+
|
|
281
|
+
- **[@mysten/sui](https://www.npmjs.com/package/@mysten/sui)** ^1.44.0 - Sui blockchain SDK | Sui 區塊鏈 SDK
|
|
282
|
+
- **[@mysten/deepbook-v3](https://www.npmjs.com/package/@mysten/deepbook-v3)** ^0.20.2 - DeepBook V3 SDK
|
|
283
|
+
- **[dotenv](https://www.npmjs.com/package/dotenv)** ^17.2.3 - Environment variable management | 環境變數管理
|
|
284
|
+
|
|
285
|
+
### Development Tools | 開發工具
|
|
286
|
+
|
|
287
|
+
- **[TypeScript](https://www.typescriptlang.org/)** ^5.9.3 - Type-safe JavaScript | 型別安全的 JavaScript
|
|
288
|
+
- **[Jest](https://jestjs.io/)** ^30.2.0 - Testing framework | 測試框架
|
|
289
|
+
- **[ESLint](https://eslint.org/)** ^9.39.1 - Code linting | 程式碼檢查
|
|
290
|
+
- **[Prettier](https://prettier.io/)** ^3.6.2 - Code formatting | 程式碼格式化
|
|
291
|
+
- **[tsx](https://www.npmjs.com/package/tsx)** ^4.19.2 - TypeScript execution | TypeScript 執行工具
|
|
292
|
+
|
|
293
|
+
### Package Manager | 套件管理器
|
|
294
|
+
|
|
295
|
+
- **[pnpm](https://pnpm.io/)** ^10.21.0 - Fast, disk space efficient package manager | 快速、節省磁碟空間的套件管理器
|
|
296
|
+
|
|
297
|
+
## Configuration | 配置
|
|
298
|
+
|
|
299
|
+
### Testnet Configuration | 測試網配置
|
|
300
|
+
|
|
301
|
+
The toolkit uses predefined testnet configurations for:
|
|
302
|
+
toolkit 使用預定義的測試網配置:
|
|
303
|
+
|
|
304
|
+
- **Coins | 幣種**: SUI, DBUSDC, DEEP
|
|
305
|
+
- **Pools | 池子**: SUI/DBUSDC trading pool
|
|
306
|
+
- **Margin Pools | Margin 池子**: SUI and DBUSDC margin pools
|
|
307
|
+
|
|
308
|
+
These configurations are defined in `src/testnet-config.ts`.
|
|
309
|
+
這些配置定義於 `src/testnet-config.ts`。
|
|
310
|
+
|
|
311
|
+
## Environment Variables | 環境變數
|
|
312
|
+
|
|
313
|
+
| Variable | Description | Required | Auto-generated |
|
|
314
|
+
| -------------------- | ------------------------------- | -------- | -------------- |
|
|
315
|
+
| `PRIVATE_KEY` | Wallet private key (hex, no 0x) | ✅ Yes | ❌ No |
|
|
316
|
+
| `SUPPLIER_CAP_ID` | Supplier Cap Object ID | ❌ No | ✅ Yes |
|
|
317
|
+
| `SUI_REFERRAL_ID` | SUI Supply Referral ID | ❌ No | ✅ Yes |
|
|
318
|
+
| `DBUSDC_REFERRAL_ID` | DBUSDC Supply Referral ID | ❌ No | ✅ Yes |
|
|
319
|
+
|
|
320
|
+
| 變數 | 說明 | 必需 | 自動產生 |
|
|
321
|
+
| -------------------- | ----------------------- | ----- | -------- |
|
|
322
|
+
| `PRIVATE_KEY` | 錢包私鑰(hex,無 0x) | ✅ 是 | ❌ 否 |
|
|
323
|
+
| `SUPPLIER_CAP_ID` | Supplier Cap 物件 ID | ❌ 否 | ✅ 是 |
|
|
324
|
+
| `SUI_REFERRAL_ID` | SUI 供應 Referral ID | ❌ 否 | ✅ 是 |
|
|
325
|
+
| `DBUSDC_REFERRAL_ID` | DBUSDC 供應 Referral ID | ❌ 否 | ✅ 是 |
|
|
326
|
+
|
|
327
|
+
## Troubleshooting | 疑難排解
|
|
328
|
+
|
|
329
|
+
### Common Issues | 常見問題
|
|
330
|
+
|
|
331
|
+
**Issue | 問題:** "Supplier Cap not initialized"
|
|
332
|
+
**Solution | 解決方法:** Call `await toolkit.initialize()` before using other methods | 在使用其他方法前呼叫 `await toolkit.initialize()`
|
|
333
|
+
|
|
334
|
+
**Issue | 問題:** Transaction fails due to insufficient balance
|
|
335
|
+
**Solution | 解決方法:** Ensure you have enough SUI and DBUSDC in your wallet | 確保錢包中有足夠的 SUI 和 DBUSDC
|
|
336
|
+
|
|
337
|
+
**Issue | 問題:** "Failed to create Supplier Cap"
|
|
338
|
+
**Solution | 解決方法:** Check network connectivity and wallet balance | 檢查網路連線和錢包餘額
|
|
339
|
+
|
|
340
|
+
## Contributing | 貢獻
|
|
341
|
+
|
|
342
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
343
|
+
歡迎貢獻!請隨時提交 Pull Request。
|
|
344
|
+
|
|
345
|
+
## License | 授權
|
|
346
|
+
|
|
347
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
348
|
+
MIT 授權 - 詳情請見 [LICENSE](LICENSE) 檔案。
|
|
349
|
+
|
|
350
|
+
## Links | 連結
|
|
351
|
+
|
|
352
|
+
- [DeepBook Documentation](https://docs.sui.io/standards/deepbookv3-sdk)
|
|
353
|
+
- [Sui Documentation](https://docs.sui.io/)
|
|
354
|
+
- [DeepBook V3 SDK](https://www.npmjs.com/package/@mysten/deepbook-v3)
|
|
355
|
+
- [Sui TypeScript SDK](https://www.npmjs.com/package/@mysten/sui)
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
**Made with ❤️ for the Sui and DeepBook community**
|
|
360
|
+
**用 ❤️ 為 Sui 和 DeepBook 社群打造**
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as _mysten_deepbook_v3 from '@mysten/deepbook-v3';
|
|
2
|
+
import { MarginPoolContract, DeepBookConfig } from '@mysten/deepbook-v3';
|
|
3
|
+
import { SuiClient } from '@mysten/sui/client';
|
|
4
|
+
import { Transaction } from '@mysten/sui/transactions';
|
|
5
|
+
|
|
6
|
+
type NetworkType = 'testnet' | 'mainnet';
|
|
7
|
+
type MarginCoinType = 'SUI' | 'DBUSDC';
|
|
8
|
+
interface ToolkitConfig {
|
|
9
|
+
network: NetworkType;
|
|
10
|
+
privateKey: string;
|
|
11
|
+
supplierCapId?: string;
|
|
12
|
+
fullnodeUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
interface TransactionResult {
|
|
15
|
+
digest: string;
|
|
16
|
+
status: string;
|
|
17
|
+
objectId?: string;
|
|
18
|
+
}
|
|
19
|
+
interface MarginBalance {
|
|
20
|
+
userSupplyAmount: number;
|
|
21
|
+
walletBalance: number;
|
|
22
|
+
}
|
|
23
|
+
interface ReferralInfo {
|
|
24
|
+
referralId: string;
|
|
25
|
+
coin: MarginCoinType;
|
|
26
|
+
owner: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
declare class DeepBookMarginToolkit {
|
|
30
|
+
#private;
|
|
31
|
+
private suiClient;
|
|
32
|
+
private keypair;
|
|
33
|
+
private address;
|
|
34
|
+
private marginPoolContract;
|
|
35
|
+
private supplierCapId?;
|
|
36
|
+
constructor(config: ToolkitConfig);
|
|
37
|
+
initialize(): Promise<string>;
|
|
38
|
+
createSupplierCap(): Promise<string | null>;
|
|
39
|
+
createSupplyReferral(coin: MarginCoinType): Promise<string | null>;
|
|
40
|
+
supplyToMarginPool(coin: MarginCoinType, amount: number, referralId?: string): Promise<boolean>;
|
|
41
|
+
withdrawFromMarginPool(coin: MarginCoinType, amount?: number): Promise<boolean>;
|
|
42
|
+
withdrawReferralFees(coin: MarginCoinType, referralId: string): Promise<boolean>;
|
|
43
|
+
getBalance(coin: MarginCoinType): Promise<MarginBalance>;
|
|
44
|
+
getSupplierCapId(): string | undefined;
|
|
45
|
+
getAddress(): string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
declare const MARGIN_POOL_PARAM_KEYS: readonly ["supplyCap", "maxUtilizationRate", "protocolSpread", "minBorrow", "interestRate", "totalSupply", "supplyShares", "totalBorrow", "borrowShares", "lastUpdateTimestamp"];
|
|
49
|
+
declare const MARGIN_POOL_W_SUPPLIER_CAP_PARAM_KEYS: readonly ["userSupplyShares", "userSupplyAmount"];
|
|
50
|
+
|
|
51
|
+
type MarginPoolParamKey = (typeof MARGIN_POOL_PARAM_KEYS)[number];
|
|
52
|
+
type MarginPoolWithSupplierCapParamKey = (typeof MARGIN_POOL_W_SUPPLIER_CAP_PARAM_KEYS)[number];
|
|
53
|
+
type InterestConfig = {
|
|
54
|
+
midKink: number;
|
|
55
|
+
highKink: number;
|
|
56
|
+
baseBorrowApr: number;
|
|
57
|
+
midBorrowApr: number;
|
|
58
|
+
highBorrowApr: number;
|
|
59
|
+
maxBorrowApr: number;
|
|
60
|
+
borrowApr: number;
|
|
61
|
+
};
|
|
62
|
+
type MarginPoolParams = Record<MarginPoolParamKey | MarginPoolWithSupplierCapParamKey, number> & InterestConfig & {
|
|
63
|
+
address: string;
|
|
64
|
+
type: string;
|
|
65
|
+
scalar: number;
|
|
66
|
+
decimals: number;
|
|
67
|
+
};
|
|
68
|
+
declare class DeepBookMarginPool {
|
|
69
|
+
#private;
|
|
70
|
+
readonly suiClient: SuiClient;
|
|
71
|
+
marginPoolContract: MarginPoolContract;
|
|
72
|
+
dbConfig: DeepBookConfig;
|
|
73
|
+
constructor(env?: NetworkType, address?: string, suiClient?: SuiClient, dbConfig?: DeepBookConfig);
|
|
74
|
+
get env(): _mysten_deepbook_v3.Environment;
|
|
75
|
+
getPoolParameters(coinKey: string, supplierCapId?: string, tx?: Transaction): Promise<MarginPoolParams>;
|
|
76
|
+
getPoolParameters(coinKey: string, supplierCapId: string | undefined, tx: Transaction, inspect: true): Promise<MarginPoolParams>;
|
|
77
|
+
getPoolParameters(coinKey: string, supplierCapId: string | undefined, tx: Transaction, inspect: false): Promise<Transaction>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export { DeepBookMarginPool, DeepBookMarginToolkit, type MarginBalance, type MarginCoinType, type MarginPoolParams, type NetworkType, type ReferralInfo, type ToolkitConfig, type TransactionResult };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as _mysten_deepbook_v3 from '@mysten/deepbook-v3';
|
|
2
|
+
import { MarginPoolContract, DeepBookConfig } from '@mysten/deepbook-v3';
|
|
3
|
+
import { SuiClient } from '@mysten/sui/client';
|
|
4
|
+
import { Transaction } from '@mysten/sui/transactions';
|
|
5
|
+
|
|
6
|
+
type NetworkType = 'testnet' | 'mainnet';
|
|
7
|
+
type MarginCoinType = 'SUI' | 'DBUSDC';
|
|
8
|
+
interface ToolkitConfig {
|
|
9
|
+
network: NetworkType;
|
|
10
|
+
privateKey: string;
|
|
11
|
+
supplierCapId?: string;
|
|
12
|
+
fullnodeUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
interface TransactionResult {
|
|
15
|
+
digest: string;
|
|
16
|
+
status: string;
|
|
17
|
+
objectId?: string;
|
|
18
|
+
}
|
|
19
|
+
interface MarginBalance {
|
|
20
|
+
userSupplyAmount: number;
|
|
21
|
+
walletBalance: number;
|
|
22
|
+
}
|
|
23
|
+
interface ReferralInfo {
|
|
24
|
+
referralId: string;
|
|
25
|
+
coin: MarginCoinType;
|
|
26
|
+
owner: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
declare class DeepBookMarginToolkit {
|
|
30
|
+
#private;
|
|
31
|
+
private suiClient;
|
|
32
|
+
private keypair;
|
|
33
|
+
private address;
|
|
34
|
+
private marginPoolContract;
|
|
35
|
+
private supplierCapId?;
|
|
36
|
+
constructor(config: ToolkitConfig);
|
|
37
|
+
initialize(): Promise<string>;
|
|
38
|
+
createSupplierCap(): Promise<string | null>;
|
|
39
|
+
createSupplyReferral(coin: MarginCoinType): Promise<string | null>;
|
|
40
|
+
supplyToMarginPool(coin: MarginCoinType, amount: number, referralId?: string): Promise<boolean>;
|
|
41
|
+
withdrawFromMarginPool(coin: MarginCoinType, amount?: number): Promise<boolean>;
|
|
42
|
+
withdrawReferralFees(coin: MarginCoinType, referralId: string): Promise<boolean>;
|
|
43
|
+
getBalance(coin: MarginCoinType): Promise<MarginBalance>;
|
|
44
|
+
getSupplierCapId(): string | undefined;
|
|
45
|
+
getAddress(): string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
declare const MARGIN_POOL_PARAM_KEYS: readonly ["supplyCap", "maxUtilizationRate", "protocolSpread", "minBorrow", "interestRate", "totalSupply", "supplyShares", "totalBorrow", "borrowShares", "lastUpdateTimestamp"];
|
|
49
|
+
declare const MARGIN_POOL_W_SUPPLIER_CAP_PARAM_KEYS: readonly ["userSupplyShares", "userSupplyAmount"];
|
|
50
|
+
|
|
51
|
+
type MarginPoolParamKey = (typeof MARGIN_POOL_PARAM_KEYS)[number];
|
|
52
|
+
type MarginPoolWithSupplierCapParamKey = (typeof MARGIN_POOL_W_SUPPLIER_CAP_PARAM_KEYS)[number];
|
|
53
|
+
type InterestConfig = {
|
|
54
|
+
midKink: number;
|
|
55
|
+
highKink: number;
|
|
56
|
+
baseBorrowApr: number;
|
|
57
|
+
midBorrowApr: number;
|
|
58
|
+
highBorrowApr: number;
|
|
59
|
+
maxBorrowApr: number;
|
|
60
|
+
borrowApr: number;
|
|
61
|
+
};
|
|
62
|
+
type MarginPoolParams = Record<MarginPoolParamKey | MarginPoolWithSupplierCapParamKey, number> & InterestConfig & {
|
|
63
|
+
address: string;
|
|
64
|
+
type: string;
|
|
65
|
+
scalar: number;
|
|
66
|
+
decimals: number;
|
|
67
|
+
};
|
|
68
|
+
declare class DeepBookMarginPool {
|
|
69
|
+
#private;
|
|
70
|
+
readonly suiClient: SuiClient;
|
|
71
|
+
marginPoolContract: MarginPoolContract;
|
|
72
|
+
dbConfig: DeepBookConfig;
|
|
73
|
+
constructor(env?: NetworkType, address?: string, suiClient?: SuiClient, dbConfig?: DeepBookConfig);
|
|
74
|
+
get env(): _mysten_deepbook_v3.Environment;
|
|
75
|
+
getPoolParameters(coinKey: string, supplierCapId?: string, tx?: Transaction): Promise<MarginPoolParams>;
|
|
76
|
+
getPoolParameters(coinKey: string, supplierCapId: string | undefined, tx: Transaction, inspect: true): Promise<MarginPoolParams>;
|
|
77
|
+
getPoolParameters(coinKey: string, supplierCapId: string | undefined, tx: Transaction, inspect: false): Promise<Transaction>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export { DeepBookMarginPool, DeepBookMarginToolkit, type MarginBalance, type MarginCoinType, type MarginPoolParams, type NetworkType, type ReferralInfo, type ToolkitConfig, type TransactionResult };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';var client=require('@mysten/sui/client'),ed25519=require('@mysten/sui/keypairs/ed25519'),transactions=require('@mysten/sui/transactions'),deepbookV3=require('@mysten/deepbook-v3'),cryptography=require('@mysten/sui/cryptography'),bcs$1=require('@mysten/bcs'),bcs=require('@mysten/sui/bcs'),bignumber_js=require('bignumber.js');var D={MARGIN_INITIAL_PACKAGE_ID:"0x7f2d8f15343f210e813595a8798d6197d152061d0a35be938372f4b1cd66f209"},c={DEEP:{address:"0x36dbef866a1d62bf7328989a10fb2f07d769f4ee587c0de4a0a256e57e0a58a8",type:"0x36dbef866a1d62bf7328989a10fb2f07d769f4ee587c0de4a0a256e57e0a58a8::deep::DEEP",scalar:1e6,decimals:6},SUI:{address:"0x0000000000000000000000000000000000000000000000000000000000000002",type:"0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI",scalar:1e9,decimals:9},DBUSDC:{address:"0xf7152c05930480cd740d7311b5b8b45c6f488e3a53a11c3f74a6fac36a52e0d7",type:"0xf7152c05930480cd740d7311b5b8b45c6f488e3a53a11c3f74a6fac36a52e0d7::DBUSDC::DBUSDC",scalar:1e6,decimals:6},DBUSDT:{address:"0xf7152c05930480cd740d7311b5b8b45c6f488e3a53a11c3f74a6fac36a52e0d7",type:"0xf7152c05930480cd740d7311b5b8b45c6f488e3a53a11c3f74a6fac36a52e0d7::DBUSDT::DBUSDT",scalar:1e6,decimals:6},WAL:{address:"0x9ef7676a9f81937a52ae4b2af8d511a28a0b080477c0c2db40b0ab8882240d76",type:"0x9ef7676a9f81937a52ae4b2af8d511a28a0b080477c0c2db40b0ab8882240d76::wal::WAL",scalar:1e9,decimals:9}},f={DEEP_SUI:{address:"0x48c95963e9eac37a316b7ae04a0deb761bcdcc2b67912374d6036e7f0e9bae9f",baseCoin:"DEEP",quoteCoin:"SUI",lotSize:1e6,tickSize:1e6},SUI_DBUSDC:{address:"0x1c19362ca52b8ffd7a33cee805a67d40f31e6ba303753fd3a4cfdfacea7163a5",baseCoin:"SUI",quoteCoin:"DBUSDC",lotSize:1e6,tickSize:1e3},DEEP_DBUSDC:{address:"0xe86b991f8632217505fd859445f9803967ac84a9d4a1219065bf191fcb74b622",baseCoin:"DEEP",quoteCoin:"DBUSDC",lotSize:1e6,tickSize:1e3},DBUSDT_DBUSDC:{address:"0x83970bb02e3636efdff8c141ab06af5e3c9a22e2f74d7f02a9c3430d0d10c1ca",baseCoin:"DBUSDT",quoteCoin:"DBUSDC",lotSize:1e6,tickSize:1e3},WAL_DBUSDC:{address:"0xeb524b6aea0ec4b494878582e0b78924208339d360b62aec4a8ecd4031520dbb",baseCoin:"WAL",quoteCoin:"DBUSDC",lotSize:1e6,tickSize:1e3},WAL_SUI:{address:"0x8c1c1b186c4fddab1ebd53e0895a36c1d1b3b9a77cd34e607bef49a38af0150a",baseCoin:"WAL",quoteCoin:"SUI",lotSize:1e6,tickSize:1e6}},d={SUI:{address:"0xe620d6a5390e57e88baff18af89383130d4210eb496a024edcd62f270a655af7",coinType:"0x2::sui::SUI"},DBUSDC:{address:"0xfd0dc290a120ad6c534507614d4dc0b2e78baab649c35bfacbaec2ce18140b69",coinType:"0xf7152c05930480cd740d7311b5b8b45c6f488e3a53a11c3f74a6fac36a52e0d7::DBUSDC::DBUSDC"}};var P=["supplyCap","maxUtilizationRate","protocolSpread","minBorrow","interestRate","totalSupply","supplyShares","totalBorrow","borrowShares","lastUpdateTimestamp"],b=["userSupplyShares","userSupplyAmount"],B={supplyCap:"U64",maxUtilizationRate:"U64",protocolSpread:"U64",minBorrow:"U64",interestRate:"U64",totalSupply:"U64",supplyShares:"U64",totalBorrow:"U64",borrowShares:"U64",lastUpdateTimestamp:"U64",userSupplyShares:"U64",userSupplyAmount:"U64"};var k=n=>/^0x[0-9a-fA-F]+$|^[0-9a-fA-F]+$/.test(n),L=n=>/^[a-zA-Z0-9+/]+={0,2}$/g.test(n),x=n=>{if(k(n))return bcs$1.fromHex(n);if(L(n))return bcs$1.fromBase64(n);throw new Error("The string is not a valid hex or base64 string.")},_=n=>{if(n.length===cryptography.LEGACY_PRIVATE_KEY_SIZE)return n.slice(0,cryptography.PRIVATE_KEY_SIZE);if(n.length===cryptography.PRIVATE_KEY_SIZE+1&&n[0]===0)return n.slice(1);if(n.length===cryptography.PRIVATE_KEY_SIZE)return n;throw new Error("invalid secret key")};var w=class{suiClient;keypair;address;marginPoolContract;supplierCapId;constructor(r){let a=r.fullnodeUrl??client.getFullnodeUrl(r.network);this.suiClient=new client.SuiClient({url:a}),this.keypair=this.#r(r.privateKey),this.address=this.keypair.getPublicKey().toSuiAddress(),this.supplierCapId=r.supplierCapId;let e={DEEP:{address:c.DEEP.address,type:c.DEEP.type,scalar:c.DEEP.scalar},SUI:{address:c.SUI.address,type:c.SUI.type,scalar:c.SUI.scalar},DBUSDC:{address:c.DBUSDC.address,type:c.DBUSDC.type,scalar:c.DBUSDC.scalar}},t={SUI_DBUSDC:{address:f.SUI_DBUSDC.address,baseCoin:f.SUI_DBUSDC.baseCoin,quoteCoin:f.SUI_DBUSDC.quoteCoin}},i={SUI:{address:d.SUI.address,type:d.SUI.coinType},DBUSDC:{address:d.DBUSDC.address,type:d.DBUSDC.coinType}},o=new deepbookV3.DeepBookConfig({address:this.address,env:r.network,coins:e,pools:t,marginPools:i});this.marginPoolContract=new deepbookV3.MarginPoolContract(o);}#r(r){if(r.startsWith(cryptography.SUI_PRIVATE_KEY_PREFIX)){let{secretKey:a}=cryptography.decodeSuiPrivateKey(r);return ed25519.Ed25519Keypair.fromSecretKey(_(a))}return ed25519.Ed25519Keypair.fromSecretKey(_(x(r)))}async#e(){let r=`${D.MARGIN_INITIAL_PACKAGE_ID}::margin_pool::SupplierCap`;return (await this.suiClient.getOwnedObjects({owner:this.address,filter:{StructType:r},options:{showType:true}})).data?.[0]?.data?.objectId}async initialize(){if(this.supplierCapId)return this.supplierCapId;let r=await this.#e();if(r)return this.supplierCapId=r,r;let a=await this.createSupplierCap();if(!a)throw new Error("Failed to create Supplier Cap");return this.supplierCapId=a,a}async createSupplierCap(){try{let r=new transactions.Transaction,a=this.marginPoolContract.mintSupplierCap()(r);r.transferObjects([a],this.address);let e=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:r,options:{showEffects:!0,showObjectChanges:!0}});if(e.errors&&e.errors.length>0)throw new Error(`Transaction failed with errors: ${e.errors.map(t=>t.toString()).join(", ")}`);if(e.objectChanges){for(let t of e.objectChanges)if(t.type==="created"&&t.objectType.includes("SupplierCap"))return t.objectId}return null}catch(r){throw new Error(`Failed to create Supplier Cap: ${r.message||r}`)}}async createSupplyReferral(r){try{let a=new transactions.Transaction;this.marginPoolContract.mintSupplyReferral(r)(a);let e=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:a,options:{showEffects:!0,showObjectChanges:!0}});if(e.errors&&e.errors.length>0)throw new Error(`Transaction failed with errors: ${e.errors.map(t=>t.toString()).join(", ")}`);if(e.objectChanges){for(let t of e.objectChanges)if(t.type==="created"&&t.objectType.includes("SupplyReferral"))return t.objectId}return null}catch(a){throw new Error(`Failed to create Supply Referral: ${a.message||a}`)}}async supplyToMarginPool(r,a,e){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let t=new transactions.Transaction;t.setSender(this.address);let i=t.object(this.supplierCapId);t.add(this.marginPoolContract.supplyToMarginPool(r,i,a,e));let{errors:o}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:t,options:{showEffects:!0,showObjectChanges:!0}});if(o&&o.length>0)throw new Error(`Transaction failed with errors: ${o.map(s=>s.toString()).join(", ")}`);return !0}catch(t){throw new Error(`Failed to supply to margin pool: ${t.message||t}`)}}async withdrawFromMarginPool(r,a){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let e=new transactions.Transaction,t=e.object(this.supplierCapId),o=this.marginPoolContract.withdrawFromMarginPool(r,t,a)(e);e.transferObjects([o],this.address);let{errors:s}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:e,options:{showEffects:!0,showObjectChanges:!0}});if(s&&s.length>0)throw new Error(`Transaction failed with errors: ${s.map(l=>l.toString()).join(", ")}`);return !0}catch(e){throw new Error(`Failed to withdraw from margin pool: ${e.message||e}`)}}async withdrawReferralFees(r,a){try{let e=new transactions.Transaction;e.add(this.marginPoolContract.withdrawReferralFees(r,a));let{errors:t}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:e,options:{showEffects:!0,showObjectChanges:!0,showBalanceChanges:!0}});if(t&&t.length>0)throw new Error(`Transaction failed with errors: ${t.map(i=>i.toString()).join(", ")}`);return !0}catch(e){throw new Error(`Failed to withdraw referral fees: ${e.message||e}`)}}async getBalance(r){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let a=new transactions.Transaction;a.add(this.marginPoolContract.userSupplyAmount(r,this.supplierCapId));let e=await this.suiClient.devInspectTransactionBlock({sender:this.address,transactionBlock:a}),t=0;if(e&&e.results&&e.results[0]&&e.results[0].returnValues){let p=e.results[0].returnValues[0];if(p&&p[0]){let m=Buffer.from(p[0]).readBigUInt64LE(),C=r==="SUI"?c.SUI.scalar:c.DBUSDC.scalar;t=Number(m)/C;}}let i=r==="SUI"?c.SUI.type:c.DBUSDC.type,o=await this.suiClient.getBalance({owner:this.address,coinType:i}),s=r==="SUI"?c.SUI.scalar:c.DBUSDC.scalar,l=Number(o.totalBalance)/s;return {userSupplyAmount:t,walletBalance:l}}catch(a){throw new Error(`Failed to get balance: ${a.message||a}`)}}getSupplierCapId(){return this.supplierCapId}getAddress(){return this.address}};var X=new Set(b),J=n=>X.has(n),I=class{constructor(r="testnet",a="",e=new client.SuiClient({url:client.getFullnodeUrl(r)}),t){this.suiClient=e;this.dbConfig=t??new deepbookV3.DeepBookConfig({env:r,address:a,coins:c,pools:f,marginPools:{SUI:{address:d.SUI.address,type:d.SUI.coinType},DBUSDC:{address:d.DBUSDC.address,type:d.DBUSDC.coinType}}}),this.marginPoolContract=new deepbookV3.MarginPoolContract(this.dbConfig);}marginPoolContract;dbConfig;get env(){return this.dbConfig.env}#r(r,a,e,t){if(J(a)){let i=this.marginPoolContract[a];if(t==null)throw new Error(`supplierCap is required for '${a}'.`);r.add(i(e,t));}else {let i=this.marginPoolContract[a];r.add(i(e));}}#e(r,a){let e=r.results;return e?a.reduce((t,i,o)=>{let s=e[o]?.returnValues?.[0]?.[0];if(!s)return t;let l=bcs.bcs[B[i]];return t[i]=l.parse(new Uint8Array(s)),t},{}):{}}#t(r,a){let e=this.dbConfig.getCoin(a),t={supplyCap:0,maxUtilizationRate:0,protocolSpread:0,minBorrow:0,interestRate:0,totalSupply:0,supplyShares:0,totalBorrow:0,borrowShares:0,lastUpdateTimestamp:0,userSupplyShares:0,userSupplyAmount:0,decimals:0,midKink:0,highKink:0,baseBorrowApr:0,midBorrowApr:0,highBorrowApr:0,maxBorrowApr:0,borrowApr:0,...e};if(!e)return t;let i=new Set(["interestRate","maxUtilizationRate","protocolSpread"]);for(let[o,s]of Object.entries(r))o==="lastUpdateTimestamp"?t[o]=Number(s):i.has(o)?t[o]=new bignumber_js.BigNumber(s).dividedBy(deepbookV3.FLOAT_SCALAR).toNumber():t[o]=new bignumber_js.BigNumber(s).dividedBy(e.scalar).toNumber();return t}#a(r,a){let e=BigInt(a.base_rate),t=BigInt(a.base_slope),i=BigInt(a.excess_slope),o=BigInt(a.optimal_utilization),s=r<0n?0n:r>BigInt(deepbookV3.FLOAT_SCALAR)?BigInt(deepbookV3.FLOAT_SCALAR):BigInt(r);return s<=o?e+t*s/o:e+t+i*(s-o)/(BigInt(deepbookV3.FLOAT_SCALAR)-o)}#o(r,a,e){let t=BigInt(r.base_rate),i=BigInt(r.base_slope),o=BigInt(r.excess_slope),s=BigInt(r.optimal_utilization),l=BigInt(a.max_utilization_rate),p=s,m=l,C=t,E=t+i,T=t+i+o*(l-s)/(1000000000n-s),A=t+i+o,U=this.#a(BigInt(bignumber_js.BigNumber(e.total_borrow).dividedBy(e.total_supply).shiftedBy(9).decimalPlaces(0).toString()),r),u=M=>bignumber_js.BigNumber(M).dividedBy(deepbookV3.FLOAT_SCALAR).toNumber();return {raw:{midKink:p,highKink:m,baseBorrowApr:C,midBorrowApr:E,highBorrowApr:T,maxBorrowApr:A,borrowApr:U},normalized:{midKink:u(p),highKink:u(m),baseBorrowApr:u(C),midBorrowApr:u(E),highBorrowApr:u(T),maxBorrowApr:u(A),borrowApr:u(U)}}}async#i(r){let{address:a}=this.dbConfig.getMarginPool(r),t=((await this.suiClient.getObject({id:a,options:{showContent:true}})).data?.content).fields,i=t.config.fields,o=i.interest_config.fields,s=i.margin_pool_config.fields,l=t.state.fields,{normalized:p}=this.#o(o,s,l);return p}async getPoolParameters(r,a,e=new transactions.Transaction,t=true){if(P.forEach(p=>this.#r(e,p,r)),a&&b.forEach(p=>this.#r(e,p,r,a)),!t)return e;let i=[...P,...b],o=await this.suiClient.devInspectTransactionBlock({transactionBlock:e,sender:this.dbConfig.address}),s=await this.#i(r);return {...this.#t(this.#e(o,i),r),...s}}};exports.DeepBookMarginPool=I;exports.DeepBookMarginToolkit=w;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {getFullnodeUrl,SuiClient}from'@mysten/sui/client';import {Ed25519Keypair}from'@mysten/sui/keypairs/ed25519';import {Transaction}from'@mysten/sui/transactions';import {DeepBookConfig,MarginPoolContract,FLOAT_SCALAR}from'@mysten/deepbook-v3';import {SUI_PRIVATE_KEY_PREFIX,decodeSuiPrivateKey,LEGACY_PRIVATE_KEY_SIZE,PRIVATE_KEY_SIZE}from'@mysten/sui/cryptography';import {fromHex,fromBase64}from'@mysten/bcs';import {bcs}from'@mysten/sui/bcs';import {BigNumber}from'bignumber.js';var D={MARGIN_INITIAL_PACKAGE_ID:"0x7f2d8f15343f210e813595a8798d6197d152061d0a35be938372f4b1cd66f209"},c={DEEP:{address:"0x36dbef866a1d62bf7328989a10fb2f07d769f4ee587c0de4a0a256e57e0a58a8",type:"0x36dbef866a1d62bf7328989a10fb2f07d769f4ee587c0de4a0a256e57e0a58a8::deep::DEEP",scalar:1e6,decimals:6},SUI:{address:"0x0000000000000000000000000000000000000000000000000000000000000002",type:"0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI",scalar:1e9,decimals:9},DBUSDC:{address:"0xf7152c05930480cd740d7311b5b8b45c6f488e3a53a11c3f74a6fac36a52e0d7",type:"0xf7152c05930480cd740d7311b5b8b45c6f488e3a53a11c3f74a6fac36a52e0d7::DBUSDC::DBUSDC",scalar:1e6,decimals:6},DBUSDT:{address:"0xf7152c05930480cd740d7311b5b8b45c6f488e3a53a11c3f74a6fac36a52e0d7",type:"0xf7152c05930480cd740d7311b5b8b45c6f488e3a53a11c3f74a6fac36a52e0d7::DBUSDT::DBUSDT",scalar:1e6,decimals:6},WAL:{address:"0x9ef7676a9f81937a52ae4b2af8d511a28a0b080477c0c2db40b0ab8882240d76",type:"0x9ef7676a9f81937a52ae4b2af8d511a28a0b080477c0c2db40b0ab8882240d76::wal::WAL",scalar:1e9,decimals:9}},f={DEEP_SUI:{address:"0x48c95963e9eac37a316b7ae04a0deb761bcdcc2b67912374d6036e7f0e9bae9f",baseCoin:"DEEP",quoteCoin:"SUI",lotSize:1e6,tickSize:1e6},SUI_DBUSDC:{address:"0x1c19362ca52b8ffd7a33cee805a67d40f31e6ba303753fd3a4cfdfacea7163a5",baseCoin:"SUI",quoteCoin:"DBUSDC",lotSize:1e6,tickSize:1e3},DEEP_DBUSDC:{address:"0xe86b991f8632217505fd859445f9803967ac84a9d4a1219065bf191fcb74b622",baseCoin:"DEEP",quoteCoin:"DBUSDC",lotSize:1e6,tickSize:1e3},DBUSDT_DBUSDC:{address:"0x83970bb02e3636efdff8c141ab06af5e3c9a22e2f74d7f02a9c3430d0d10c1ca",baseCoin:"DBUSDT",quoteCoin:"DBUSDC",lotSize:1e6,tickSize:1e3},WAL_DBUSDC:{address:"0xeb524b6aea0ec4b494878582e0b78924208339d360b62aec4a8ecd4031520dbb",baseCoin:"WAL",quoteCoin:"DBUSDC",lotSize:1e6,tickSize:1e3},WAL_SUI:{address:"0x8c1c1b186c4fddab1ebd53e0895a36c1d1b3b9a77cd34e607bef49a38af0150a",baseCoin:"WAL",quoteCoin:"SUI",lotSize:1e6,tickSize:1e6}},d={SUI:{address:"0xe620d6a5390e57e88baff18af89383130d4210eb496a024edcd62f270a655af7",coinType:"0x2::sui::SUI"},DBUSDC:{address:"0xfd0dc290a120ad6c534507614d4dc0b2e78baab649c35bfacbaec2ce18140b69",coinType:"0xf7152c05930480cd740d7311b5b8b45c6f488e3a53a11c3f74a6fac36a52e0d7::DBUSDC::DBUSDC"}};var P=["supplyCap","maxUtilizationRate","protocolSpread","minBorrow","interestRate","totalSupply","supplyShares","totalBorrow","borrowShares","lastUpdateTimestamp"],b=["userSupplyShares","userSupplyAmount"],B={supplyCap:"U64",maxUtilizationRate:"U64",protocolSpread:"U64",minBorrow:"U64",interestRate:"U64",totalSupply:"U64",supplyShares:"U64",totalBorrow:"U64",borrowShares:"U64",lastUpdateTimestamp:"U64",userSupplyShares:"U64",userSupplyAmount:"U64"};var k=n=>/^0x[0-9a-fA-F]+$|^[0-9a-fA-F]+$/.test(n),L=n=>/^[a-zA-Z0-9+/]+={0,2}$/g.test(n),x=n=>{if(k(n))return fromHex(n);if(L(n))return fromBase64(n);throw new Error("The string is not a valid hex or base64 string.")},_=n=>{if(n.length===LEGACY_PRIVATE_KEY_SIZE)return n.slice(0,PRIVATE_KEY_SIZE);if(n.length===PRIVATE_KEY_SIZE+1&&n[0]===0)return n.slice(1);if(n.length===PRIVATE_KEY_SIZE)return n;throw new Error("invalid secret key")};var w=class{suiClient;keypair;address;marginPoolContract;supplierCapId;constructor(r){let a=r.fullnodeUrl??getFullnodeUrl(r.network);this.suiClient=new SuiClient({url:a}),this.keypair=this.#r(r.privateKey),this.address=this.keypair.getPublicKey().toSuiAddress(),this.supplierCapId=r.supplierCapId;let e={DEEP:{address:c.DEEP.address,type:c.DEEP.type,scalar:c.DEEP.scalar},SUI:{address:c.SUI.address,type:c.SUI.type,scalar:c.SUI.scalar},DBUSDC:{address:c.DBUSDC.address,type:c.DBUSDC.type,scalar:c.DBUSDC.scalar}},t={SUI_DBUSDC:{address:f.SUI_DBUSDC.address,baseCoin:f.SUI_DBUSDC.baseCoin,quoteCoin:f.SUI_DBUSDC.quoteCoin}},i={SUI:{address:d.SUI.address,type:d.SUI.coinType},DBUSDC:{address:d.DBUSDC.address,type:d.DBUSDC.coinType}},o=new DeepBookConfig({address:this.address,env:r.network,coins:e,pools:t,marginPools:i});this.marginPoolContract=new MarginPoolContract(o);}#r(r){if(r.startsWith(SUI_PRIVATE_KEY_PREFIX)){let{secretKey:a}=decodeSuiPrivateKey(r);return Ed25519Keypair.fromSecretKey(_(a))}return Ed25519Keypair.fromSecretKey(_(x(r)))}async#e(){let r=`${D.MARGIN_INITIAL_PACKAGE_ID}::margin_pool::SupplierCap`;return (await this.suiClient.getOwnedObjects({owner:this.address,filter:{StructType:r},options:{showType:true}})).data?.[0]?.data?.objectId}async initialize(){if(this.supplierCapId)return this.supplierCapId;let r=await this.#e();if(r)return this.supplierCapId=r,r;let a=await this.createSupplierCap();if(!a)throw new Error("Failed to create Supplier Cap");return this.supplierCapId=a,a}async createSupplierCap(){try{let r=new Transaction,a=this.marginPoolContract.mintSupplierCap()(r);r.transferObjects([a],this.address);let e=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:r,options:{showEffects:!0,showObjectChanges:!0}});if(e.errors&&e.errors.length>0)throw new Error(`Transaction failed with errors: ${e.errors.map(t=>t.toString()).join(", ")}`);if(e.objectChanges){for(let t of e.objectChanges)if(t.type==="created"&&t.objectType.includes("SupplierCap"))return t.objectId}return null}catch(r){throw new Error(`Failed to create Supplier Cap: ${r.message||r}`)}}async createSupplyReferral(r){try{let a=new Transaction;this.marginPoolContract.mintSupplyReferral(r)(a);let e=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:a,options:{showEffects:!0,showObjectChanges:!0}});if(e.errors&&e.errors.length>0)throw new Error(`Transaction failed with errors: ${e.errors.map(t=>t.toString()).join(", ")}`);if(e.objectChanges){for(let t of e.objectChanges)if(t.type==="created"&&t.objectType.includes("SupplyReferral"))return t.objectId}return null}catch(a){throw new Error(`Failed to create Supply Referral: ${a.message||a}`)}}async supplyToMarginPool(r,a,e){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let t=new Transaction;t.setSender(this.address);let i=t.object(this.supplierCapId);t.add(this.marginPoolContract.supplyToMarginPool(r,i,a,e));let{errors:o}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:t,options:{showEffects:!0,showObjectChanges:!0}});if(o&&o.length>0)throw new Error(`Transaction failed with errors: ${o.map(s=>s.toString()).join(", ")}`);return !0}catch(t){throw new Error(`Failed to supply to margin pool: ${t.message||t}`)}}async withdrawFromMarginPool(r,a){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let e=new Transaction,t=e.object(this.supplierCapId),o=this.marginPoolContract.withdrawFromMarginPool(r,t,a)(e);e.transferObjects([o],this.address);let{errors:s}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:e,options:{showEffects:!0,showObjectChanges:!0}});if(s&&s.length>0)throw new Error(`Transaction failed with errors: ${s.map(l=>l.toString()).join(", ")}`);return !0}catch(e){throw new Error(`Failed to withdraw from margin pool: ${e.message||e}`)}}async withdrawReferralFees(r,a){try{let e=new Transaction;e.add(this.marginPoolContract.withdrawReferralFees(r,a));let{errors:t}=await this.suiClient.signAndExecuteTransaction({signer:this.keypair,transaction:e,options:{showEffects:!0,showObjectChanges:!0,showBalanceChanges:!0}});if(t&&t.length>0)throw new Error(`Transaction failed with errors: ${t.map(i=>i.toString()).join(", ")}`);return !0}catch(e){throw new Error(`Failed to withdraw referral fees: ${e.message||e}`)}}async getBalance(r){try{if(!this.supplierCapId)throw new Error("Supplier Cap not initialized. Call initialize() first.");let a=new Transaction;a.add(this.marginPoolContract.userSupplyAmount(r,this.supplierCapId));let e=await this.suiClient.devInspectTransactionBlock({sender:this.address,transactionBlock:a}),t=0;if(e&&e.results&&e.results[0]&&e.results[0].returnValues){let p=e.results[0].returnValues[0];if(p&&p[0]){let m=Buffer.from(p[0]).readBigUInt64LE(),C=r==="SUI"?c.SUI.scalar:c.DBUSDC.scalar;t=Number(m)/C;}}let i=r==="SUI"?c.SUI.type:c.DBUSDC.type,o=await this.suiClient.getBalance({owner:this.address,coinType:i}),s=r==="SUI"?c.SUI.scalar:c.DBUSDC.scalar,l=Number(o.totalBalance)/s;return {userSupplyAmount:t,walletBalance:l}}catch(a){throw new Error(`Failed to get balance: ${a.message||a}`)}}getSupplierCapId(){return this.supplierCapId}getAddress(){return this.address}};var X=new Set(b),J=n=>X.has(n),I=class{constructor(r="testnet",a="",e=new SuiClient({url:getFullnodeUrl(r)}),t){this.suiClient=e;this.dbConfig=t??new DeepBookConfig({env:r,address:a,coins:c,pools:f,marginPools:{SUI:{address:d.SUI.address,type:d.SUI.coinType},DBUSDC:{address:d.DBUSDC.address,type:d.DBUSDC.coinType}}}),this.marginPoolContract=new MarginPoolContract(this.dbConfig);}marginPoolContract;dbConfig;get env(){return this.dbConfig.env}#r(r,a,e,t){if(J(a)){let i=this.marginPoolContract[a];if(t==null)throw new Error(`supplierCap is required for '${a}'.`);r.add(i(e,t));}else {let i=this.marginPoolContract[a];r.add(i(e));}}#e(r,a){let e=r.results;return e?a.reduce((t,i,o)=>{let s=e[o]?.returnValues?.[0]?.[0];if(!s)return t;let l=bcs[B[i]];return t[i]=l.parse(new Uint8Array(s)),t},{}):{}}#t(r,a){let e=this.dbConfig.getCoin(a),t={supplyCap:0,maxUtilizationRate:0,protocolSpread:0,minBorrow:0,interestRate:0,totalSupply:0,supplyShares:0,totalBorrow:0,borrowShares:0,lastUpdateTimestamp:0,userSupplyShares:0,userSupplyAmount:0,decimals:0,midKink:0,highKink:0,baseBorrowApr:0,midBorrowApr:0,highBorrowApr:0,maxBorrowApr:0,borrowApr:0,...e};if(!e)return t;let i=new Set(["interestRate","maxUtilizationRate","protocolSpread"]);for(let[o,s]of Object.entries(r))o==="lastUpdateTimestamp"?t[o]=Number(s):i.has(o)?t[o]=new BigNumber(s).dividedBy(FLOAT_SCALAR).toNumber():t[o]=new BigNumber(s).dividedBy(e.scalar).toNumber();return t}#a(r,a){let e=BigInt(a.base_rate),t=BigInt(a.base_slope),i=BigInt(a.excess_slope),o=BigInt(a.optimal_utilization),s=r<0n?0n:r>BigInt(FLOAT_SCALAR)?BigInt(FLOAT_SCALAR):BigInt(r);return s<=o?e+t*s/o:e+t+i*(s-o)/(BigInt(FLOAT_SCALAR)-o)}#o(r,a,e){let t=BigInt(r.base_rate),i=BigInt(r.base_slope),o=BigInt(r.excess_slope),s=BigInt(r.optimal_utilization),l=BigInt(a.max_utilization_rate),p=s,m=l,C=t,E=t+i,T=t+i+o*(l-s)/(1000000000n-s),A=t+i+o,U=this.#a(BigInt(BigNumber(e.total_borrow).dividedBy(e.total_supply).shiftedBy(9).decimalPlaces(0).toString()),r),u=M=>BigNumber(M).dividedBy(FLOAT_SCALAR).toNumber();return {raw:{midKink:p,highKink:m,baseBorrowApr:C,midBorrowApr:E,highBorrowApr:T,maxBorrowApr:A,borrowApr:U},normalized:{midKink:u(p),highKink:u(m),baseBorrowApr:u(C),midBorrowApr:u(E),highBorrowApr:u(T),maxBorrowApr:u(A),borrowApr:u(U)}}}async#i(r){let{address:a}=this.dbConfig.getMarginPool(r),t=((await this.suiClient.getObject({id:a,options:{showContent:true}})).data?.content).fields,i=t.config.fields,o=i.interest_config.fields,s=i.margin_pool_config.fields,l=t.state.fields,{normalized:p}=this.#o(o,s,l);return p}async getPoolParameters(r,a,e=new Transaction,t=true){if(P.forEach(p=>this.#r(e,p,r)),a&&b.forEach(p=>this.#r(e,p,r,a)),!t)return e;let i=[...P,...b],o=await this.suiClient.devInspectTransactionBlock({transactionBlock:e,sender:this.dbConfig.address}),s=await this.#i(r);return {...this.#t(this.#e(o,i),r),...s}}};export{I as DeepBookMarginPool,w as DeepBookMarginToolkit};
|
package/package.json
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@scallop-io/scallop-deepbook-kit",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "A toolkit for integrating Scallop with DeepBook functionality",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"scallop",
|
|
7
|
+
"deepbook",
|
|
8
|
+
"sui",
|
|
9
|
+
"defi",
|
|
10
|
+
"blockchain",
|
|
11
|
+
"dex"
|
|
12
|
+
],
|
|
13
|
+
"author": "team@scallop.io",
|
|
14
|
+
"homepage": "https://github.com/scallop-io/scallop-deepbook-kit#readme",
|
|
15
|
+
"bugs": "https://github.com/scallop-io/scallop-deepbook-kit/issues",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/scallop-io/scallop-deepbook-kit.git"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"main": "dist/index.js",
|
|
25
|
+
"module": "dist/index.mjs",
|
|
26
|
+
"types": "dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"source": "./src/index.ts",
|
|
30
|
+
"import": "./dist/index.mjs",
|
|
31
|
+
"require": "./dist/index.js",
|
|
32
|
+
"default": "./dist/index.js"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"src"
|
|
38
|
+
],
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/jest": "^30.0.0",
|
|
41
|
+
"@types/node": "^24.10.0",
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "^8.46.4",
|
|
43
|
+
"@typescript-eslint/parser": "^8.46.4",
|
|
44
|
+
"eslint": "^9.39.1",
|
|
45
|
+
"eslint-config-prettier": "^10.1.8",
|
|
46
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
47
|
+
"husky": "^8.0.3",
|
|
48
|
+
"jest": "^30.2.0",
|
|
49
|
+
"prettier": "^3.6.2",
|
|
50
|
+
"ts-jest": "^29.4.5",
|
|
51
|
+
"tsup": "^8.5.1",
|
|
52
|
+
"tsx": "^4.19.2",
|
|
53
|
+
"typescript": "^5.9.3"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@mysten/bcs": "^1.9.2",
|
|
57
|
+
"@mysten/deepbook-v3": "^0.21.0",
|
|
58
|
+
"@mysten/sui": "^1.45.0",
|
|
59
|
+
"bignumber.js": "^9.3.1",
|
|
60
|
+
"dotenv": "^17.2.3"
|
|
61
|
+
},
|
|
62
|
+
"lint-staged": {
|
|
63
|
+
"**/*.ts": [
|
|
64
|
+
"pnpm run format:fix"
|
|
65
|
+
],
|
|
66
|
+
"**/*.json|md": [
|
|
67
|
+
"pnpm run format:fix"
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
"husky": {
|
|
71
|
+
"hooks": {
|
|
72
|
+
"pre-commit": "lint-staged"
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"engines": {
|
|
76
|
+
"node": ">=18.0.0",
|
|
77
|
+
"pnpm": ">=9.0.0"
|
|
78
|
+
},
|
|
79
|
+
"scripts": {
|
|
80
|
+
"build": "npm run build:tsup",
|
|
81
|
+
"build:prod": "tsup --env.NODE_ENV production",
|
|
82
|
+
"build:tsup": "tsup",
|
|
83
|
+
"build:watch": "tsc --watch",
|
|
84
|
+
"example:toolkit": "tsx src/examples/toolkit-demo.ts",
|
|
85
|
+
"clean": "rm -rf dist",
|
|
86
|
+
"lint": "eslint src --ext .ts",
|
|
87
|
+
"format:fix": "prettier --ignore-path 'dist/* docs/*' --write '**/*.{ts,json,md}'",
|
|
88
|
+
"lint:fix": "eslint src --ext .ts --fix",
|
|
89
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
90
|
+
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
91
|
+
"test": "jest",
|
|
92
|
+
"test:watch": "jest --watch",
|
|
93
|
+
"test:coverage": "jest --coverage"
|
|
94
|
+
}
|
|
95
|
+
}
|