@haneullabs/deepbook 0.1.0
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/CHANGELOG.md +974 -0
- package/README.md +11 -0
- package/dist/cjs/client.d.ts +198 -0
- package/dist/cjs/client.js +630 -0
- package/dist/cjs/client.js.map +7 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +19 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/package.json +4 -0
- package/dist/cjs/types/bcs.d.ts +11 -0
- package/dist/cjs/types/bcs.js +36 -0
- package/dist/cjs/types/bcs.js.map +7 -0
- package/dist/cjs/types/index.d.ts +51 -0
- package/dist/cjs/types/index.js +38 -0
- package/dist/cjs/types/index.js.map +7 -0
- package/dist/cjs/utils/constants.d.ts +7 -0
- package/dist/cjs/utils/constants.js +38 -0
- package/dist/cjs/utils/constants.js.map +7 -0
- package/dist/cjs/utils/index.d.ts +1 -0
- package/dist/cjs/utils/index.js +19 -0
- package/dist/cjs/utils/index.js.map +7 -0
- package/dist/esm/client.d.ts +198 -0
- package/dist/esm/client.js +623 -0
- package/dist/esm/client.js.map +7 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +7 -0
- package/dist/esm/package.json +4 -0
- package/dist/esm/types/bcs.d.ts +11 -0
- package/dist/esm/types/bcs.js +16 -0
- package/dist/esm/types/bcs.js.map +7 -0
- package/dist/esm/types/index.d.ts +51 -0
- package/dist/esm/types/index.js +17 -0
- package/dist/esm/types/index.js.map +7 -0
- package/dist/esm/utils/constants.d.ts +7 -0
- package/dist/esm/utils/constants.js +18 -0
- package/dist/esm/utils/constants.js.map +7 -0
- package/dist/esm/utils/index.d.ts +1 -0
- package/dist/esm/utils/index.js +2 -0
- package/dist/esm/utils/index.js.map +7 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +56 -0
- package/src/client.ts +786 -0
- package/src/index.ts +4 -0
- package/src/types/bcs.ts +16 -0
- package/src/types/index.ts +71 -0
- package/src/utils/constants.ts +18 -0
- package/src/utils/index.ts +4 -0
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
var __typeError = (msg) => {
|
|
2
|
+
throw TypeError(msg);
|
|
3
|
+
};
|
|
4
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
5
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
6
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
7
|
+
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
8
|
+
var _poolTypeArgsCache, _DeepBookClient_instances, checkAccountCap_fn, checkAddress_fn, nextClientOrderId_fn;
|
|
9
|
+
import { bcs } from "@haneullabs/haneul/bcs";
|
|
10
|
+
import { getFullnodeUrl, HaneulClient } from "@haneullabs/haneul/client";
|
|
11
|
+
import { Transaction } from "@haneullabs/haneul/transactions";
|
|
12
|
+
import {
|
|
13
|
+
normalizeStructTag,
|
|
14
|
+
normalizeHaneulAddress,
|
|
15
|
+
normalizeHaneulObjectId,
|
|
16
|
+
parseStructTag,
|
|
17
|
+
HANEUL_CLOCK_OBJECT_ID
|
|
18
|
+
} from "@haneullabs/haneul/utils";
|
|
19
|
+
import { BcsOrder } from "./types/bcs.js";
|
|
20
|
+
import { LimitOrderType, SelfMatchingPreventionStyle } from "./types/index.js";
|
|
21
|
+
import {
|
|
22
|
+
CREATION_FEE,
|
|
23
|
+
MODULE_CLOB,
|
|
24
|
+
MODULE_CUSTODIAN,
|
|
25
|
+
NORMALIZED_HANEUL_COIN_TYPE,
|
|
26
|
+
ORDER_DEFAULT_EXPIRATION_IN_MS,
|
|
27
|
+
PACKAGE_ID
|
|
28
|
+
} from "./utils/index.js";
|
|
29
|
+
const DUMMY_ADDRESS = normalizeHaneulAddress("0x0");
|
|
30
|
+
class DeepBookClient {
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
|
+
* @param haneulClient connection to fullnode
|
|
34
|
+
* @param accountCap (optional) only required for wrting operations
|
|
35
|
+
* @param currentAddress (optional) address of the current user (default: DUMMY_ADDRESS)
|
|
36
|
+
*/
|
|
37
|
+
constructor(haneulClient = new HaneulClient({ url: getFullnodeUrl("testnet") }), accountCap = void 0, currentAddress = DUMMY_ADDRESS, clientOrderId = 0) {
|
|
38
|
+
this.haneulClient = haneulClient;
|
|
39
|
+
this.accountCap = accountCap;
|
|
40
|
+
this.currentAddress = currentAddress;
|
|
41
|
+
this.clientOrderId = clientOrderId;
|
|
42
|
+
__privateAdd(this, _DeepBookClient_instances);
|
|
43
|
+
__privateAdd(this, _poolTypeArgsCache, /* @__PURE__ */ new Map());
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* @param cap set the account cap for interacting with DeepBook
|
|
47
|
+
*/
|
|
48
|
+
async setAccountCap(cap) {
|
|
49
|
+
this.accountCap = cap;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* @description Create pool for trading pair
|
|
53
|
+
* @param baseAssetType Full coin type of the base asset, eg: "0x3d0d0ce17dcd3b40c2d839d96ce66871ffb40e1154a8dd99af72292b3d10d7fc::wbtc::WBTC"
|
|
54
|
+
* @param quoteAssetType Full coin type of quote asset, eg: "0x3d0d0ce17dcd3b40c2d839d96ce66871ffb40e1154a8dd99af72292b3d10d7fc::usdt::USDT"
|
|
55
|
+
* @param tickSize Minimal Price Change Accuracy of this pool, eg: 10000000. The number must be an integer float scaled by `FLOAT_SCALING_FACTOR`.
|
|
56
|
+
* @param lotSize Minimal Lot Change Accuracy of this pool, eg: 10000.
|
|
57
|
+
*/
|
|
58
|
+
createPool(baseAssetType, quoteAssetType, tickSize, lotSize) {
|
|
59
|
+
const tx = new Transaction();
|
|
60
|
+
const [coin] = tx.splitCoins(tx.gas, [CREATION_FEE]);
|
|
61
|
+
tx.moveCall({
|
|
62
|
+
typeArguments: [baseAssetType, quoteAssetType],
|
|
63
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::create_pool`,
|
|
64
|
+
arguments: [tx.pure.u64(tickSize), tx.pure.u64(lotSize), coin]
|
|
65
|
+
});
|
|
66
|
+
return tx;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* @description Create pool for trading pair
|
|
70
|
+
* @param baseAssetType Full coin type of the base asset, eg: "0x3d0d0ce17dcd3b40c2d839d96ce66871ffb40e1154a8dd99af72292b3d10d7fc::wbtc::WBTC"
|
|
71
|
+
* @param quoteAssetType Full coin type of quote asset, eg: "0x3d0d0ce17dcd3b40c2d839d96ce66871ffb40e1154a8dd99af72292b3d10d7fc::usdt::USDT"
|
|
72
|
+
* @param tickSize Minimal Price Change Accuracy of this pool, eg: 10000000. The number must be an interger float scaled by `FLOAT_SCALING_FACTOR`.
|
|
73
|
+
* @param lotSize Minimal Lot Change Accuracy of this pool, eg: 10000.
|
|
74
|
+
* @param takerFeeRate Customized taker fee rate, float scaled by `FLOAT_SCALING_FACTOR`, Taker_fee_rate of 0.25% should be 2_500_000 for example
|
|
75
|
+
* @param makerRebateRate Customized maker rebate rate, float scaled by `FLOAT_SCALING_FACTOR`, should be less than or equal to the taker_rebate_rate
|
|
76
|
+
*/
|
|
77
|
+
createCustomizedPool(baseAssetType, quoteAssetType, tickSize, lotSize, takerFeeRate, makerRebateRate) {
|
|
78
|
+
const tx = new Transaction();
|
|
79
|
+
const [coin] = tx.splitCoins(tx.gas, [CREATION_FEE]);
|
|
80
|
+
tx.moveCall({
|
|
81
|
+
typeArguments: [baseAssetType, quoteAssetType],
|
|
82
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::create_customized_pool`,
|
|
83
|
+
arguments: [
|
|
84
|
+
tx.pure.u64(tickSize),
|
|
85
|
+
tx.pure.u64(lotSize),
|
|
86
|
+
tx.pure.u64(takerFeeRate),
|
|
87
|
+
tx.pure.u64(makerRebateRate),
|
|
88
|
+
coin
|
|
89
|
+
]
|
|
90
|
+
});
|
|
91
|
+
return tx;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* @description Create Account Cap
|
|
95
|
+
* @param tx
|
|
96
|
+
*/
|
|
97
|
+
createAccountCap(tx) {
|
|
98
|
+
const [cap] = tx.moveCall({
|
|
99
|
+
typeArguments: [],
|
|
100
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::create_account`,
|
|
101
|
+
arguments: []
|
|
102
|
+
});
|
|
103
|
+
return cap;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* @description Create and Transfer custodian account to user
|
|
107
|
+
* @param currentAddress current address of the user
|
|
108
|
+
* @param tx
|
|
109
|
+
*/
|
|
110
|
+
createAccount(currentAddress = this.currentAddress, tx = new Transaction()) {
|
|
111
|
+
const cap = this.createAccountCap(tx);
|
|
112
|
+
tx.transferObjects([cap], __privateMethod(this, _DeepBookClient_instances, checkAddress_fn).call(this, currentAddress));
|
|
113
|
+
return tx;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* @description Create and Transfer custodian account to user
|
|
117
|
+
* @param currentAddress: current user address, eg: "0xbddc9d4961b46a130c2e1f38585bbc6fa8077ce54bcb206b26874ac08d607966"
|
|
118
|
+
* @param accountCap: Object id of Account Capacity under user address, created after invoking createAccount, eg: "0x6f699fef193723277559c8f499ca3706121a65ac96d273151b8e52deb29135d3"
|
|
119
|
+
*/
|
|
120
|
+
createChildAccountCap(currentAddress = this.currentAddress, accountCap = this.accountCap) {
|
|
121
|
+
const tx = new Transaction();
|
|
122
|
+
const [childCap] = tx.moveCall({
|
|
123
|
+
typeArguments: [],
|
|
124
|
+
target: `${PACKAGE_ID}::${MODULE_CUSTODIAN}::create_child_account_cap`,
|
|
125
|
+
arguments: [tx.object(__privateMethod(this, _DeepBookClient_instances, checkAccountCap_fn).call(this, accountCap))]
|
|
126
|
+
});
|
|
127
|
+
tx.transferObjects([childCap], __privateMethod(this, _DeepBookClient_instances, checkAddress_fn).call(this, currentAddress));
|
|
128
|
+
return tx;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* @description construct transaction for depositing asset into a pool.
|
|
132
|
+
* @param poolId the pool id for the deposit
|
|
133
|
+
* @param coinId the coin used for the deposit. You can omit this argument if you are depositing SUI, in which case
|
|
134
|
+
* gas coin will be used
|
|
135
|
+
* @param amount the amount of coin to deposit. If omitted, the entire balance of the coin will be deposited
|
|
136
|
+
*/
|
|
137
|
+
async deposit(poolId, coinId = void 0, quantity = void 0) {
|
|
138
|
+
const tx = new Transaction();
|
|
139
|
+
const [baseAsset, quoteAsset] = await this.getPoolTypeArgs(poolId);
|
|
140
|
+
const hasSui = baseAsset === NORMALIZED_HANEUL_COIN_TYPE || quoteAsset === NORMALIZED_HANEUL_COIN_TYPE;
|
|
141
|
+
if (coinId === void 0 && !hasSui) {
|
|
142
|
+
throw new Error("coinId must be specified if neither baseAsset nor quoteAsset is SUI");
|
|
143
|
+
}
|
|
144
|
+
const inputCoin = coinId ? tx.object(coinId) : tx.gas;
|
|
145
|
+
const [coin] = quantity ? tx.splitCoins(inputCoin, [quantity]) : [inputCoin];
|
|
146
|
+
const coinType = coinId ? await this.getCoinType(coinId) : NORMALIZED_HANEUL_COIN_TYPE;
|
|
147
|
+
if (coinType !== baseAsset && coinType !== quoteAsset) {
|
|
148
|
+
throw new Error(
|
|
149
|
+
`coin ${coinId} of ${coinType} type is not a valid asset for pool ${poolId}, which supports ${baseAsset} and ${quoteAsset}`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
const functionName = coinType === baseAsset ? "deposit_base" : "deposit_quote";
|
|
153
|
+
tx.moveCall({
|
|
154
|
+
typeArguments: [baseAsset, quoteAsset],
|
|
155
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::${functionName}`,
|
|
156
|
+
arguments: [tx.object(poolId), coin, tx.object(__privateMethod(this, _DeepBookClient_instances, checkAccountCap_fn).call(this))]
|
|
157
|
+
});
|
|
158
|
+
return tx;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* @description construct transaction for withdrawing asset from a pool.
|
|
162
|
+
* @param poolId the pool id for the withdraw
|
|
163
|
+
* @param amount the amount of coin to withdraw
|
|
164
|
+
* @param assetType Base or Quote
|
|
165
|
+
* @param recipientAddress the address to receive the withdrawn asset. If omitted, `this.currentAddress` will be used. The function
|
|
166
|
+
* will throw if the `recipientAddress === DUMMY_ADDRESS`
|
|
167
|
+
*/
|
|
168
|
+
async withdraw(poolId, quantity, assetType, recipientAddress = this.currentAddress) {
|
|
169
|
+
const tx = new Transaction();
|
|
170
|
+
const functionName = assetType === "base" ? "withdraw_base" : "withdraw_quote";
|
|
171
|
+
const [withdraw] = tx.moveCall({
|
|
172
|
+
typeArguments: await this.getPoolTypeArgs(poolId),
|
|
173
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::${functionName}`,
|
|
174
|
+
arguments: [tx.object(poolId), tx.pure.u64(quantity), tx.object(__privateMethod(this, _DeepBookClient_instances, checkAccountCap_fn).call(this))]
|
|
175
|
+
});
|
|
176
|
+
tx.transferObjects([withdraw], __privateMethod(this, _DeepBookClient_instances, checkAddress_fn).call(this, recipientAddress));
|
|
177
|
+
return tx;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* @description place a limit order
|
|
181
|
+
* @param poolId Object id of pool, created after invoking createPool, eg: "0xcaee8e1c046b58e55196105f1436a2337dcaa0c340a7a8c8baf65e4afb8823a4"
|
|
182
|
+
* @param price: price of the limit order. The number must be an interger float scaled by `FLOAT_SCALING_FACTOR`.
|
|
183
|
+
* @param quantity: quantity of the limit order in BASE ASSET, eg: 100000000.
|
|
184
|
+
* @param orderType: bid for buying base with quote, ask for selling base for quote
|
|
185
|
+
* @param expirationTimestamp: expiration timestamp of the limit order in ms, eg: 1620000000000. If omitted, the order will expire in 1 day
|
|
186
|
+
* from the time this function is called(not the time the transaction is executed)
|
|
187
|
+
* @param restriction restrictions on limit orders, explain in doc for more details, eg: 0
|
|
188
|
+
* @param clientOrderId a client side defined order number for bookkeeping purpose, e.g., "1", "2", etc. If omitted, the sdk will
|
|
189
|
+
* assign a increasing number starting from 0. But this number might be duplicated if you are using multiple sdk instances
|
|
190
|
+
* @param selfMatchingPrevention: Options for self-match prevention. Right now only support `CANCEL_OLDEST`
|
|
191
|
+
*/
|
|
192
|
+
async placeLimitOrder(poolId, price, quantity, orderType, expirationTimestamp = Date.now() + ORDER_DEFAULT_EXPIRATION_IN_MS, restriction = LimitOrderType.NO_RESTRICTION, clientOrderId = void 0, selfMatchingPrevention = SelfMatchingPreventionStyle.CANCEL_OLDEST) {
|
|
193
|
+
const tx = new Transaction();
|
|
194
|
+
const args = [
|
|
195
|
+
tx.object(poolId),
|
|
196
|
+
tx.pure.u64(clientOrderId ?? __privateMethod(this, _DeepBookClient_instances, nextClientOrderId_fn).call(this)),
|
|
197
|
+
tx.pure.u64(price),
|
|
198
|
+
tx.pure.u64(quantity),
|
|
199
|
+
tx.pure.u8(selfMatchingPrevention),
|
|
200
|
+
tx.pure.bool(orderType === "bid"),
|
|
201
|
+
tx.pure.u64(expirationTimestamp),
|
|
202
|
+
tx.pure.u8(restriction),
|
|
203
|
+
tx.object(HANEUL_CLOCK_OBJECT_ID),
|
|
204
|
+
tx.object(__privateMethod(this, _DeepBookClient_instances, checkAccountCap_fn).call(this))
|
|
205
|
+
];
|
|
206
|
+
tx.moveCall({
|
|
207
|
+
typeArguments: await this.getPoolTypeArgs(poolId),
|
|
208
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::place_limit_order`,
|
|
209
|
+
arguments: args
|
|
210
|
+
});
|
|
211
|
+
return tx;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* @description place a market order
|
|
215
|
+
* @param poolId Object id of pool, created after invoking createPool, eg: "0xcaee8e1c046b58e55196105f1436a2337dcaa0c340a7a8c8baf65e4afb8823a4"
|
|
216
|
+
* @param quantity Amount of quote asset to swap in base asset
|
|
217
|
+
* @param orderType bid for buying base with quote, ask for selling base for quote
|
|
218
|
+
* @param baseCoin the objectId or the coin object of the base coin
|
|
219
|
+
* @param quoteCoin the objectId or the coin object of the quote coin
|
|
220
|
+
* @param clientOrderId a client side defined order id for bookkeeping purpose. eg: "1" , "2", ... If omitted, the sdk will
|
|
221
|
+
* assign an increasing number starting from 0. But this number might be duplicated if you are using multiple sdk instances
|
|
222
|
+
* @param accountCap
|
|
223
|
+
* @param recipientAddress the address to receive the swapped asset. If omitted, `this.currentAddress` will be used. The function
|
|
224
|
+
* @param tx
|
|
225
|
+
*/
|
|
226
|
+
async placeMarketOrder(accountCap, poolId, quantity, orderType, baseCoin = void 0, quoteCoin = void 0, clientOrderId = void 0, recipientAddress = this.currentAddress, tx = new Transaction()) {
|
|
227
|
+
const [baseAssetType, quoteAssetType] = await this.getPoolTypeArgs(poolId);
|
|
228
|
+
if (!baseCoin && orderType === "ask") {
|
|
229
|
+
throw new Error("Must specify a valid base coin for an ask order");
|
|
230
|
+
} else if (!quoteCoin && orderType === "bid") {
|
|
231
|
+
throw new Error("Must specify a valid quote coin for a bid order");
|
|
232
|
+
}
|
|
233
|
+
const emptyCoin = tx.moveCall({
|
|
234
|
+
typeArguments: [baseCoin ? quoteAssetType : baseAssetType],
|
|
235
|
+
target: `0x2::coin::zero`,
|
|
236
|
+
arguments: []
|
|
237
|
+
});
|
|
238
|
+
const [base_coin_ret, quote_coin_ret] = tx.moveCall({
|
|
239
|
+
typeArguments: [baseAssetType, quoteAssetType],
|
|
240
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::place_market_order`,
|
|
241
|
+
arguments: [
|
|
242
|
+
tx.object(poolId),
|
|
243
|
+
typeof accountCap === "string" ? tx.object(__privateMethod(this, _DeepBookClient_instances, checkAccountCap_fn).call(this, accountCap)) : accountCap,
|
|
244
|
+
tx.pure.u64(clientOrderId ?? __privateMethod(this, _DeepBookClient_instances, nextClientOrderId_fn).call(this)),
|
|
245
|
+
tx.pure.u64(quantity),
|
|
246
|
+
tx.pure.bool(orderType === "bid"),
|
|
247
|
+
baseCoin ? tx.object(baseCoin) : emptyCoin,
|
|
248
|
+
quoteCoin ? tx.object(quoteCoin) : emptyCoin,
|
|
249
|
+
tx.object(HANEUL_CLOCK_OBJECT_ID)
|
|
250
|
+
]
|
|
251
|
+
});
|
|
252
|
+
const recipient = __privateMethod(this, _DeepBookClient_instances, checkAddress_fn).call(this, recipientAddress);
|
|
253
|
+
tx.transferObjects([base_coin_ret], recipient);
|
|
254
|
+
tx.transferObjects([quote_coin_ret], recipient);
|
|
255
|
+
return tx;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* @description swap exact quote for base
|
|
259
|
+
* @param poolId Object id of pool, created after invoking createPool, eg: "0xcaee8e1c046b58e55196105f1436a2337dcaa0c340a7a8c8baf65e4afb8823a4"
|
|
260
|
+
* @param tokenObjectIn Object id of the token to swap: eg: "0x6e566fec4c388eeb78a7dab832c9f0212eb2ac7e8699500e203def5b41b9c70d"
|
|
261
|
+
* @param amountIn amount of token to buy or sell, eg: 10000000.
|
|
262
|
+
* @param currentAddress current user address, eg: "0xbddc9d4961b46a130c2e1f38585bbc6fa8077ce54bcb206b26874ac08d607966"
|
|
263
|
+
* @param clientOrderId a client side defined order id for bookkeeping purpose, eg: "1" , "2", ... If omitted, the sdk will
|
|
264
|
+
* assign an increasing number starting from 0. But this number might be duplicated if you are using multiple sdk instances
|
|
265
|
+
* @param tx
|
|
266
|
+
*/
|
|
267
|
+
async swapExactQuoteForBase(poolId, tokenObjectIn, amountIn, currentAddress, clientOrderId, tx = new Transaction()) {
|
|
268
|
+
const [base_coin_ret, quote_coin_ret, _amount] = tx.moveCall({
|
|
269
|
+
typeArguments: await this.getPoolTypeArgs(poolId),
|
|
270
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::swap_exact_quote_for_base`,
|
|
271
|
+
arguments: [
|
|
272
|
+
tx.object(poolId),
|
|
273
|
+
tx.pure.u64(clientOrderId ?? __privateMethod(this, _DeepBookClient_instances, nextClientOrderId_fn).call(this)),
|
|
274
|
+
tx.object(__privateMethod(this, _DeepBookClient_instances, checkAccountCap_fn).call(this)),
|
|
275
|
+
tx.pure.u64(String(amountIn)),
|
|
276
|
+
tx.object(HANEUL_CLOCK_OBJECT_ID),
|
|
277
|
+
tx.object(tokenObjectIn)
|
|
278
|
+
]
|
|
279
|
+
});
|
|
280
|
+
tx.transferObjects([base_coin_ret], currentAddress);
|
|
281
|
+
tx.transferObjects([quote_coin_ret], currentAddress);
|
|
282
|
+
return tx;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* @description swap exact base for quote
|
|
286
|
+
* @param poolId Object id of pool, created after invoking createPool, eg: "0xcaee8e1c046b58e55196105f1436a2337dcaa0c340a7a8c8baf65e4afb8823a4"
|
|
287
|
+
* @param tokenObjectIn Object id of the token to swap: eg: "0x6e566fec4c388eeb78a7dab832c9f0212eb2ac7e8699500e203def5b41b9c70d"
|
|
288
|
+
* @param amountIn amount of token to buy or sell, eg: 10000000
|
|
289
|
+
* @param currentAddress current user address, eg: "0xbddc9d4961b46a130c2e1f38585bbc6fa8077ce54bcb206b26874ac08d607966"
|
|
290
|
+
* @param clientOrderId a client side defined order number for bookkeeping purpose. eg: "1" , "2", ...
|
|
291
|
+
*/
|
|
292
|
+
async swapExactBaseForQuote(poolId, tokenObjectIn, amountIn, currentAddress, clientOrderId = void 0) {
|
|
293
|
+
const tx = new Transaction();
|
|
294
|
+
const [baseAsset, quoteAsset] = await this.getPoolTypeArgs(poolId);
|
|
295
|
+
const [base_coin_ret, quote_coin_ret, _amount] = tx.moveCall({
|
|
296
|
+
typeArguments: [baseAsset, quoteAsset],
|
|
297
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::swap_exact_base_for_quote`,
|
|
298
|
+
arguments: [
|
|
299
|
+
tx.object(poolId),
|
|
300
|
+
tx.pure.u64(clientOrderId ?? __privateMethod(this, _DeepBookClient_instances, nextClientOrderId_fn).call(this)),
|
|
301
|
+
tx.object(__privateMethod(this, _DeepBookClient_instances, checkAccountCap_fn).call(this)),
|
|
302
|
+
tx.object(String(amountIn)),
|
|
303
|
+
tx.object(tokenObjectIn),
|
|
304
|
+
tx.moveCall({
|
|
305
|
+
typeArguments: [quoteAsset],
|
|
306
|
+
target: `0x2::coin::zero`,
|
|
307
|
+
arguments: []
|
|
308
|
+
}),
|
|
309
|
+
tx.object(HANEUL_CLOCK_OBJECT_ID)
|
|
310
|
+
]
|
|
311
|
+
});
|
|
312
|
+
tx.transferObjects([base_coin_ret], currentAddress);
|
|
313
|
+
tx.transferObjects([quote_coin_ret], currentAddress);
|
|
314
|
+
return tx;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* @description cancel an order
|
|
318
|
+
* @param poolId Object id of pool, created after invoking createPool, eg: "0xcaee8e1c046b58e55196105f1436a2337dcaa0c340a7a8c8baf65e4afb8823a4"
|
|
319
|
+
* @param orderId orderId of a limit order, you can find them through function query.list_open_orders eg: "0"
|
|
320
|
+
*/
|
|
321
|
+
async cancelOrder(poolId, orderId) {
|
|
322
|
+
const tx = new Transaction();
|
|
323
|
+
tx.moveCall({
|
|
324
|
+
typeArguments: await this.getPoolTypeArgs(poolId),
|
|
325
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::cancel_order`,
|
|
326
|
+
arguments: [tx.object(poolId), tx.pure.u64(orderId), tx.object(__privateMethod(this, _DeepBookClient_instances, checkAccountCap_fn).call(this))]
|
|
327
|
+
});
|
|
328
|
+
return tx;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* @description Cancel all limit orders under a certain account capacity
|
|
332
|
+
* @param poolId Object id of pool, created after invoking createPool, eg: "0xcaee8e1c046b58e55196105f1436a2337dcaa0c340a7a8c8baf65e4afb8823a4"
|
|
333
|
+
*/
|
|
334
|
+
async cancelAllOrders(poolId) {
|
|
335
|
+
const tx = new Transaction();
|
|
336
|
+
tx.moveCall({
|
|
337
|
+
typeArguments: await this.getPoolTypeArgs(poolId),
|
|
338
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::cancel_all_orders`,
|
|
339
|
+
arguments: [tx.object(poolId), tx.object(__privateMethod(this, _DeepBookClient_instances, checkAccountCap_fn).call(this))]
|
|
340
|
+
});
|
|
341
|
+
return tx;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* @description batch cancel order
|
|
345
|
+
* @param poolId Object id of pool, created after invoking createPool, eg: "0xcaee8e1c046b58e55196105f1436a2337dcaa0c340a7a8c8baf65e4afb8823a4"
|
|
346
|
+
* @param orderIds array of order ids you want to cancel, you can find your open orders by query.list_open_orders eg: ["0", "1", "2"]
|
|
347
|
+
*/
|
|
348
|
+
async batchCancelOrder(poolId, orderIds) {
|
|
349
|
+
const tx = new Transaction();
|
|
350
|
+
tx.moveCall({
|
|
351
|
+
typeArguments: await this.getPoolTypeArgs(poolId),
|
|
352
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::batch_cancel_order`,
|
|
353
|
+
arguments: [
|
|
354
|
+
tx.object(poolId),
|
|
355
|
+
bcs.vector(bcs.U64).serialize(orderIds),
|
|
356
|
+
tx.object(__privateMethod(this, _DeepBookClient_instances, checkAccountCap_fn).call(this))
|
|
357
|
+
]
|
|
358
|
+
});
|
|
359
|
+
return tx;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* @param poolId Object id of pool, created after invoking createPool, eg: "0xcaee8e1c046b58e55196105f1436a2337dcaa0c340a7a8c8baf65e4afb8823a4"
|
|
363
|
+
* @param orderIds array of expired order ids to clean, eg: ["0", "1", "2"]
|
|
364
|
+
* @param orderOwners array of Order owners, should be the owner addresses from the account capacities which placed the orders
|
|
365
|
+
*/
|
|
366
|
+
async cleanUpExpiredOrders(poolId, orderIds, orderOwners) {
|
|
367
|
+
const tx = new Transaction();
|
|
368
|
+
tx.moveCall({
|
|
369
|
+
typeArguments: await this.getPoolTypeArgs(poolId),
|
|
370
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::clean_up_expired_orders`,
|
|
371
|
+
arguments: [
|
|
372
|
+
tx.object(poolId),
|
|
373
|
+
tx.object(HANEUL_CLOCK_OBJECT_ID),
|
|
374
|
+
bcs.vector(bcs.U64).serialize(orderIds),
|
|
375
|
+
bcs.vector(bcs.Address).serialize(orderOwners)
|
|
376
|
+
]
|
|
377
|
+
});
|
|
378
|
+
return tx;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* @description returns paginated list of pools created in DeepBook by querying for the
|
|
382
|
+
* `PoolCreated` event. Warning: this method can return incomplete results if the upstream data source
|
|
383
|
+
* is pruned.
|
|
384
|
+
*/
|
|
385
|
+
async getAllPools(input) {
|
|
386
|
+
const resp = await this.haneulClient.queryEvents({
|
|
387
|
+
query: { MoveEventType: `${PACKAGE_ID}::${MODULE_CLOB}::PoolCreated` },
|
|
388
|
+
...input
|
|
389
|
+
});
|
|
390
|
+
const pools = resp.data.map((event) => {
|
|
391
|
+
const rawEvent = event.parsedJson;
|
|
392
|
+
return {
|
|
393
|
+
poolId: rawEvent.pool_id,
|
|
394
|
+
baseAsset: normalizeStructTag(rawEvent.base_asset.name),
|
|
395
|
+
quoteAsset: normalizeStructTag(rawEvent.quote_asset.name)
|
|
396
|
+
};
|
|
397
|
+
});
|
|
398
|
+
return {
|
|
399
|
+
data: pools,
|
|
400
|
+
nextCursor: resp.nextCursor,
|
|
401
|
+
hasNextPage: resp.hasNextPage
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* @description Fetch metadata for a pool
|
|
406
|
+
* @param poolId object id of the pool
|
|
407
|
+
* @returns Metadata for the Pool
|
|
408
|
+
*/
|
|
409
|
+
async getPoolInfo(poolId) {
|
|
410
|
+
const resp = await this.haneulClient.getObject({
|
|
411
|
+
id: poolId,
|
|
412
|
+
options: { showContent: true }
|
|
413
|
+
});
|
|
414
|
+
if (resp?.data?.content?.dataType !== "moveObject") {
|
|
415
|
+
throw new Error(`pool ${poolId} does not exist`);
|
|
416
|
+
}
|
|
417
|
+
const [baseAsset, quoteAsset] = parseStructTag(resp.data.content.type).typeParams.map(
|
|
418
|
+
(t) => normalizeStructTag(t)
|
|
419
|
+
);
|
|
420
|
+
return {
|
|
421
|
+
poolId,
|
|
422
|
+
baseAsset,
|
|
423
|
+
quoteAsset
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
async getPoolTypeArgs(poolId) {
|
|
427
|
+
if (!__privateGet(this, _poolTypeArgsCache).has(poolId)) {
|
|
428
|
+
const { baseAsset, quoteAsset } = await this.getPoolInfo(poolId);
|
|
429
|
+
const typeArgs = [baseAsset, quoteAsset];
|
|
430
|
+
__privateGet(this, _poolTypeArgsCache).set(poolId, typeArgs);
|
|
431
|
+
}
|
|
432
|
+
return __privateGet(this, _poolTypeArgsCache).get(poolId);
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* @description get the order status
|
|
436
|
+
* @param poolId: the pool id, eg: 0xcaee8e1c046b58e55196105f1436a2337dcaa0c340a7a8c8baf65e4afb8823a4
|
|
437
|
+
* @param orderId the order id, eg: "1"
|
|
438
|
+
*/
|
|
439
|
+
async getOrderStatus(poolId, orderId, accountCap = this.accountCap) {
|
|
440
|
+
const tx = new Transaction();
|
|
441
|
+
const cap = __privateMethod(this, _DeepBookClient_instances, checkAccountCap_fn).call(this, accountCap);
|
|
442
|
+
tx.moveCall({
|
|
443
|
+
typeArguments: await this.getPoolTypeArgs(poolId),
|
|
444
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::get_order_status`,
|
|
445
|
+
arguments: [tx.object(poolId), tx.pure.u64(orderId), tx.object(cap)]
|
|
446
|
+
});
|
|
447
|
+
const results = (await this.haneulClient.devInspectTransactionBlock({
|
|
448
|
+
transactionBlock: tx,
|
|
449
|
+
sender: this.currentAddress
|
|
450
|
+
})).results;
|
|
451
|
+
if (!results) {
|
|
452
|
+
return void 0;
|
|
453
|
+
}
|
|
454
|
+
return BcsOrder.parse(Uint8Array.from(results[0].returnValues[0][0]));
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* @description get the base and quote token in custodian account
|
|
458
|
+
* @param poolId the pool id, eg: 0xcaee8e1c046b58e55196105f1436a2337dcaa0c340a7a8c8baf65e4afb8823a4
|
|
459
|
+
* @param accountCap your accountCap, eg: 0x6f699fef193723277559c8f499ca3706121a65ac96d273151b8e52deb29135d3. If not provided, `this.accountCap` will be used.
|
|
460
|
+
*/
|
|
461
|
+
async getUserPosition(poolId, accountCap = void 0) {
|
|
462
|
+
const tx = new Transaction();
|
|
463
|
+
const cap = __privateMethod(this, _DeepBookClient_instances, checkAccountCap_fn).call(this, accountCap);
|
|
464
|
+
tx.moveCall({
|
|
465
|
+
typeArguments: await this.getPoolTypeArgs(poolId),
|
|
466
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::account_balance`,
|
|
467
|
+
arguments: [tx.object(normalizeHaneulObjectId(poolId)), tx.object(cap)]
|
|
468
|
+
});
|
|
469
|
+
const [availableBaseAmount, lockedBaseAmount, availableQuoteAmount, lockedQuoteAmount] = (await this.haneulClient.devInspectTransactionBlock({
|
|
470
|
+
transactionBlock: tx,
|
|
471
|
+
sender: this.currentAddress
|
|
472
|
+
})).results[0].returnValues.map(([bytes, _]) => BigInt(bcs.U64.parse(Uint8Array.from(bytes))));
|
|
473
|
+
return {
|
|
474
|
+
availableBaseAmount,
|
|
475
|
+
lockedBaseAmount,
|
|
476
|
+
availableQuoteAmount,
|
|
477
|
+
lockedQuoteAmount
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* @description get the open orders of the current user
|
|
482
|
+
* @param poolId the pool id, eg: 0xcaee8e1c046b58e55196105f1436a2337dcaa0c340a7a8c8baf65e4afb8823a4
|
|
483
|
+
* @param accountCap your accountCap, eg: 0x6f699fef193723277559c8f499ca3706121a65ac96d273151b8e52deb29135d3. If not provided, `this.accountCap` will be used.
|
|
484
|
+
*/
|
|
485
|
+
async listOpenOrders(poolId, accountCap = void 0) {
|
|
486
|
+
const tx = new Transaction();
|
|
487
|
+
const cap = __privateMethod(this, _DeepBookClient_instances, checkAccountCap_fn).call(this, accountCap);
|
|
488
|
+
tx.moveCall({
|
|
489
|
+
typeArguments: await this.getPoolTypeArgs(poolId),
|
|
490
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::list_open_orders`,
|
|
491
|
+
arguments: [tx.object(poolId), tx.object(cap)]
|
|
492
|
+
});
|
|
493
|
+
const results = (await this.haneulClient.devInspectTransactionBlock({
|
|
494
|
+
transactionBlock: tx,
|
|
495
|
+
sender: this.currentAddress
|
|
496
|
+
})).results;
|
|
497
|
+
if (!results) {
|
|
498
|
+
return [];
|
|
499
|
+
}
|
|
500
|
+
return bcs.vector(BcsOrder).parse(Uint8Array.from(results[0].returnValues[0][0]));
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* @description get the market price {bestBidPrice, bestAskPrice}
|
|
504
|
+
* @param poolId the pool id, eg: 0xcaee8e1c046b58e55196105f1436a2337dcaa0c340a7a8c8baf65e4afb8823a4
|
|
505
|
+
*/
|
|
506
|
+
async getMarketPrice(poolId) {
|
|
507
|
+
const tx = new Transaction();
|
|
508
|
+
tx.moveCall({
|
|
509
|
+
typeArguments: await this.getPoolTypeArgs(poolId),
|
|
510
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::get_market_price`,
|
|
511
|
+
arguments: [tx.object(poolId)]
|
|
512
|
+
});
|
|
513
|
+
const resp = (await this.haneulClient.devInspectTransactionBlock({
|
|
514
|
+
transactionBlock: tx,
|
|
515
|
+
sender: this.currentAddress
|
|
516
|
+
})).results[0].returnValues.map(([bytes, _]) => {
|
|
517
|
+
const opt = bcs.option(bcs.U64).parse(Uint8Array.from(bytes));
|
|
518
|
+
return opt == null ? void 0 : BigInt(opt);
|
|
519
|
+
});
|
|
520
|
+
return { bestBidPrice: resp[0], bestAskPrice: resp[1] };
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* @description get level2 book status
|
|
524
|
+
* @param poolId the pool id, eg: 0xcaee8e1c046b58e55196105f1436a2337dcaa0c340a7a8c8baf65e4afb8823a4
|
|
525
|
+
* @param lowerPrice lower price you want to query in the level2 book, eg: 18000000000. The number must be an integer float scaled by `FLOAT_SCALING_FACTOR`.
|
|
526
|
+
* @param higherPrice higher price you want to query in the level2 book, eg: 20000000000. The number must be an integer float scaled by `FLOAT_SCALING_FACTOR`.
|
|
527
|
+
* @param side { 'bid' | 'ask' | 'both' } bid or ask or both sides.
|
|
528
|
+
*/
|
|
529
|
+
async getLevel2BookStatus(poolId, lowerPrice, higherPrice, side) {
|
|
530
|
+
const tx = new Transaction();
|
|
531
|
+
if (side === "both") {
|
|
532
|
+
tx.moveCall({
|
|
533
|
+
typeArguments: await this.getPoolTypeArgs(poolId),
|
|
534
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::get_level2_book_status_bid_side`,
|
|
535
|
+
arguments: [
|
|
536
|
+
tx.object(poolId),
|
|
537
|
+
tx.pure.u64(lowerPrice),
|
|
538
|
+
tx.pure.u64(higherPrice),
|
|
539
|
+
tx.object(HANEUL_CLOCK_OBJECT_ID)
|
|
540
|
+
]
|
|
541
|
+
});
|
|
542
|
+
tx.moveCall({
|
|
543
|
+
typeArguments: await this.getPoolTypeArgs(poolId),
|
|
544
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::get_level2_book_status_ask_side`,
|
|
545
|
+
arguments: [
|
|
546
|
+
tx.object(poolId),
|
|
547
|
+
tx.pure.u64(lowerPrice),
|
|
548
|
+
tx.pure.u64(higherPrice),
|
|
549
|
+
tx.object(HANEUL_CLOCK_OBJECT_ID)
|
|
550
|
+
]
|
|
551
|
+
});
|
|
552
|
+
} else {
|
|
553
|
+
tx.moveCall({
|
|
554
|
+
typeArguments: await this.getPoolTypeArgs(poolId),
|
|
555
|
+
target: `${PACKAGE_ID}::${MODULE_CLOB}::get_level2_book_status_${side}_side`,
|
|
556
|
+
arguments: [
|
|
557
|
+
tx.object(poolId),
|
|
558
|
+
tx.pure.u64(lowerPrice),
|
|
559
|
+
tx.pure.u64(higherPrice),
|
|
560
|
+
tx.object(HANEUL_CLOCK_OBJECT_ID)
|
|
561
|
+
]
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
const results = await this.haneulClient.devInspectTransactionBlock({
|
|
565
|
+
transactionBlock: tx,
|
|
566
|
+
sender: this.currentAddress
|
|
567
|
+
});
|
|
568
|
+
if (side === "both") {
|
|
569
|
+
const bidSide = results.results[0].returnValues.map(
|
|
570
|
+
([bytes, _]) => bcs.vector(bcs.U64).parse(Uint8Array.from(bytes)).map((s) => BigInt(s))
|
|
571
|
+
);
|
|
572
|
+
const askSide = results.results[1].returnValues.map(
|
|
573
|
+
([bytes, _]) => bcs.vector(bcs.U64).parse(Uint8Array.from(bytes)).map((s) => BigInt(s))
|
|
574
|
+
);
|
|
575
|
+
return [
|
|
576
|
+
bidSide[0].map((price, i) => ({ price, depth: bidSide[1][i] })),
|
|
577
|
+
askSide[0].map((price, i) => ({ price, depth: askSide[1][i] }))
|
|
578
|
+
];
|
|
579
|
+
} else {
|
|
580
|
+
const result = results.results[0].returnValues.map(
|
|
581
|
+
([bytes, _]) => bcs.vector(bcs.U64).parse(Uint8Array.from(bytes)).map((s) => BigInt(s))
|
|
582
|
+
);
|
|
583
|
+
return result[0].map((price, i) => ({ price, depth: result[1][i] }));
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
async getCoinType(coinId) {
|
|
587
|
+
const resp = await this.haneulClient.getObject({
|
|
588
|
+
id: coinId,
|
|
589
|
+
options: { showType: true }
|
|
590
|
+
});
|
|
591
|
+
const parsed = resp.data?.type != null ? parseStructTag(resp.data.type) : null;
|
|
592
|
+
if (parsed?.address === NORMALIZED_HANEUL_COIN_TYPE.split("::")[0] && parsed.module === "coin" && parsed.name === "Coin" && parsed.typeParams.length > 0) {
|
|
593
|
+
const firstTypeParam = parsed.typeParams[0];
|
|
594
|
+
return typeof firstTypeParam === "object" ? firstTypeParam.address + "::" + firstTypeParam.module + "::" + firstTypeParam.name : null;
|
|
595
|
+
} else {
|
|
596
|
+
return null;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
_poolTypeArgsCache = new WeakMap();
|
|
601
|
+
_DeepBookClient_instances = new WeakSet();
|
|
602
|
+
checkAccountCap_fn = function(accountCap = void 0) {
|
|
603
|
+
const cap = accountCap ?? this.accountCap;
|
|
604
|
+
if (cap === void 0) {
|
|
605
|
+
throw new Error("accountCap is undefined, please call setAccountCap() first");
|
|
606
|
+
}
|
|
607
|
+
return normalizeHaneulObjectId(cap);
|
|
608
|
+
};
|
|
609
|
+
checkAddress_fn = function(recipientAddress) {
|
|
610
|
+
if (recipientAddress === DUMMY_ADDRESS) {
|
|
611
|
+
throw new Error("Current address cannot be DUMMY_ADDRESS");
|
|
612
|
+
}
|
|
613
|
+
return normalizeHaneulAddress(recipientAddress);
|
|
614
|
+
};
|
|
615
|
+
nextClientOrderId_fn = function() {
|
|
616
|
+
const id = this.clientOrderId;
|
|
617
|
+
this.clientOrderId += 1;
|
|
618
|
+
return id;
|
|
619
|
+
};
|
|
620
|
+
export {
|
|
621
|
+
DeepBookClient
|
|
622
|
+
};
|
|
623
|
+
//# sourceMappingURL=client.js.map
|