@bolt-liquidity-hq/sui-client 0.1.0-beta.10
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/LICENSE +201 -0
- package/README.md +52 -0
- package/dist/index.cjs +836 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +371 -0
- package/dist/index.d.ts +371 -0
- package/dist/index.js +815 -0
- package/dist/index.js.map +1 -0
- package/package.json +85 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,815 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
|
|
5
|
+
// src/lib/client.ts
|
|
6
|
+
import { BaseClient } from "@bolt-liquidity-hq/core";
|
|
7
|
+
import { SuiClient } from "@mysten/sui/client";
|
|
8
|
+
|
|
9
|
+
// src/config/mainnet.ts
|
|
10
|
+
var MainnetChainConfig = {
|
|
11
|
+
name: "Sui",
|
|
12
|
+
id: "101",
|
|
13
|
+
rpcEndpoint: "https://fullnode.mainnet.sui.io:443"
|
|
14
|
+
};
|
|
15
|
+
var MainnetContracts = {
|
|
16
|
+
oracle: "0x...",
|
|
17
|
+
router: "0x..."
|
|
18
|
+
};
|
|
19
|
+
var MainnetPackageId = "0x...";
|
|
20
|
+
var MainnetAssets = {
|
|
21
|
+
"0x2::sui::SUI": {
|
|
22
|
+
symbol: "SUI",
|
|
23
|
+
name: "Sui",
|
|
24
|
+
chainId: "101",
|
|
25
|
+
denom: "0x2::sui::SUI",
|
|
26
|
+
decimals: 9,
|
|
27
|
+
logo: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/sui/info/logo.png",
|
|
28
|
+
coingeckoId: "sui"
|
|
29
|
+
},
|
|
30
|
+
"0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC": {
|
|
31
|
+
symbol: "USDC",
|
|
32
|
+
name: "Circle USDC",
|
|
33
|
+
chainId: "101",
|
|
34
|
+
denom: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC",
|
|
35
|
+
decimals: 6,
|
|
36
|
+
logo: "https://raw.githubusercontent.com/cosmos/chain-registry/master/noble/images/USDCoin.png",
|
|
37
|
+
coingeckoId: "usd-coin"
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/config/testnet.ts
|
|
42
|
+
var TestnetChainConfig = {
|
|
43
|
+
name: "Sui Testnet",
|
|
44
|
+
id: "103",
|
|
45
|
+
rpcEndpoint: "https://fullnode.testnet.sui.io:443"
|
|
46
|
+
};
|
|
47
|
+
var TestnetContracts = {
|
|
48
|
+
oracle: "0xecece01cfb23b5439e04b18fe656eaf2746b9087cf68f1d48797c8f71a3dd93b",
|
|
49
|
+
router: "0x3881fdcb4a7fbcda8edc230e6f92eb57b24c0be6b44af0b5e1d0b45564f3ed00"
|
|
50
|
+
};
|
|
51
|
+
var TestnetPackageId = "0x22384b1841229e2be878bb7e88833c03e23ff5dc39accd050fb932120602f85e";
|
|
52
|
+
var TestnetAssets = {
|
|
53
|
+
"0x2::sui::SUI": {
|
|
54
|
+
symbol: "SUI",
|
|
55
|
+
name: "Sui",
|
|
56
|
+
chainId: "103",
|
|
57
|
+
denom: "0x2::sui::SUI",
|
|
58
|
+
decimals: 9,
|
|
59
|
+
logo: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/sui/info/logo.png",
|
|
60
|
+
coingeckoId: "sui"
|
|
61
|
+
},
|
|
62
|
+
"0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC": {
|
|
63
|
+
symbol: "USDC",
|
|
64
|
+
name: "Circle USDC",
|
|
65
|
+
chainId: "103",
|
|
66
|
+
denom: "0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC",
|
|
67
|
+
decimals: 6,
|
|
68
|
+
logo: "https://raw.githubusercontent.com/cosmos/chain-registry/master/noble/images/USDCoin.png",
|
|
69
|
+
coingeckoId: "usd-coin"
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// src/lib/oracle/get-asset-pairs.ts
|
|
74
|
+
import { bcs as bcs6 } from "@mysten/bcs";
|
|
75
|
+
|
|
76
|
+
// src/lib/constants/defaults.ts
|
|
77
|
+
var DEFAULT_PAGINATION_LIMIT = 50;
|
|
78
|
+
|
|
79
|
+
// src/lib/constants/sui-objects.ts
|
|
80
|
+
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
81
|
+
var PRICE_ORACLE_MODULE = "price_oracle";
|
|
82
|
+
var ROUTER_MODULE = "router";
|
|
83
|
+
var POOL_MODULE = "settlement";
|
|
84
|
+
|
|
85
|
+
// src/lib/helpers/bcs-parse.ts
|
|
86
|
+
import { InvalidObjectError, ParseError } from "@bolt-liquidity-hq/core";
|
|
87
|
+
import { bcs } from "@mysten/bcs";
|
|
88
|
+
var extractBytes = (result, resultIndex = 0, returnValueIndex = 0) => {
|
|
89
|
+
const returnValues = result.results?.[resultIndex]?.returnValues;
|
|
90
|
+
if (!returnValues || !returnValues[returnValueIndex]) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
const [bytes] = returnValues[returnValueIndex];
|
|
94
|
+
return new Uint8Array(bytes);
|
|
95
|
+
};
|
|
96
|
+
var parseDevInspectResult = (result, bcsType, resultIndex = 0, returnValueIndex = 0) => {
|
|
97
|
+
const bytes = extractBytes(result, resultIndex, returnValueIndex);
|
|
98
|
+
if (!bytes) {
|
|
99
|
+
throw new InvalidObjectError("When trying to parse result, no bytes found", {
|
|
100
|
+
bcsType,
|
|
101
|
+
resultIndex,
|
|
102
|
+
returnValueIndex
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
return bcsType.parse(bytes);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
throw new ParseError("DevInspectResult", "from bcs to a typescript type", {
|
|
109
|
+
error,
|
|
110
|
+
result,
|
|
111
|
+
bcsType,
|
|
112
|
+
resultIndex,
|
|
113
|
+
returnValueIndex
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
var parseMultipleResults = (info, schema) => {
|
|
118
|
+
return schema.map((bcsType, index) => parseDevInspectResult(info, bcsType, 0, index));
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// src/lib/helpers/queries.ts
|
|
122
|
+
import { TransactionFailedError, UnexpectedError } from "@bolt-liquidity-hq/core";
|
|
123
|
+
import { Transaction } from "@mysten/sui/transactions";
|
|
124
|
+
var queryDevInspect = async (suiClient, target, args, typeArguments, senderAddress) => {
|
|
125
|
+
const tx = new Transaction();
|
|
126
|
+
const targetString = Array.isArray(target) ? `${target[0]}::${target[1]}::${target[2]}` : target;
|
|
127
|
+
const txArgs = args?.map(
|
|
128
|
+
(item) => typeof item === "string" ? tx.object(item) : tx.pure(item.toBytes())
|
|
129
|
+
);
|
|
130
|
+
tx.moveCall({
|
|
131
|
+
target: targetString,
|
|
132
|
+
arguments: txArgs,
|
|
133
|
+
typeArguments
|
|
134
|
+
});
|
|
135
|
+
try {
|
|
136
|
+
const result = await suiClient.devInspectTransactionBlock({
|
|
137
|
+
transactionBlock: tx,
|
|
138
|
+
sender: senderAddress ?? ZERO_ADDRESS
|
|
139
|
+
});
|
|
140
|
+
if (result.effects.status.status === "success") {
|
|
141
|
+
return result;
|
|
142
|
+
} else {
|
|
143
|
+
throw new TransactionFailedError("N/A", "Failed to query smart contract", { result });
|
|
144
|
+
}
|
|
145
|
+
} catch (error) {
|
|
146
|
+
throw UnexpectedError.from(error, "Failed to query smart contract", {
|
|
147
|
+
target: targetString,
|
|
148
|
+
args,
|
|
149
|
+
typeArguments
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// src/lib/oracle/parsers.ts
|
|
155
|
+
import { InvalidObjectError as InvalidObjectError2 } from "@bolt-liquidity-hq/core";
|
|
156
|
+
import { BigNumber } from "bignumber.js";
|
|
157
|
+
var parseOracleConfigStructOutput = (output) => {
|
|
158
|
+
return {
|
|
159
|
+
admin: output.admin,
|
|
160
|
+
priceThresholdRatio: output.price_threshold_ratio,
|
|
161
|
+
priceExpireTime: {
|
|
162
|
+
secs: Number(output.default_price_expiry_seconds),
|
|
163
|
+
nanos: 0
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
var parseAssetPairStructOutput = (output) => {
|
|
168
|
+
return {
|
|
169
|
+
base: {
|
|
170
|
+
name: output.base_symbol,
|
|
171
|
+
symbol: output.base_symbol,
|
|
172
|
+
precision: output.base_precision
|
|
173
|
+
},
|
|
174
|
+
quote: {
|
|
175
|
+
name: output.quote_symbol,
|
|
176
|
+
symbol: output.quote_symbol,
|
|
177
|
+
precision: output.quote_precision
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
var parsePriceDataStructOutput = (response, baseDenom, quoteDenom) => {
|
|
182
|
+
return {
|
|
183
|
+
assetPair: `${baseDenom}:${quoteDenom}`,
|
|
184
|
+
price: response.price,
|
|
185
|
+
expiryTime: BigNumber(response.expiry_time_ms).times(1e6).toFixed(),
|
|
186
|
+
isInverse: false
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
var parsePriceResponseStructOutput = (response, baseDenom, quoteDenom) => {
|
|
190
|
+
if (!response.pair_data) {
|
|
191
|
+
throw new InvalidObjectError2("Can't find pair data price");
|
|
192
|
+
}
|
|
193
|
+
return parsePriceDataStructOutput(response.pair_data, baseDenom, quoteDenom);
|
|
194
|
+
};
|
|
195
|
+
var parseAssetPairsResponsePaginatedStructOutput = (output) => {
|
|
196
|
+
return output.asset_pairs.map((item) => parseAssetPairStructOutput(item));
|
|
197
|
+
};
|
|
198
|
+
var parsePricesResponsePaginatedStructOutput = (output) => {
|
|
199
|
+
return output.prices.map((item) => parsePriceDataStructOutput(item, "", ""));
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// src/types/bcs.ts
|
|
203
|
+
import { bcs as bcs2, BcsType } from "@mysten/bcs";
|
|
204
|
+
var PaginationStruct = {
|
|
205
|
+
total_count: bcs2.u64(),
|
|
206
|
+
has_next_page: bcs2.bool(),
|
|
207
|
+
next_cursor: bcs2.option(bcs2.string())
|
|
208
|
+
};
|
|
209
|
+
var BcsAddressType = new BcsType({
|
|
210
|
+
name: "address",
|
|
211
|
+
read(reader) {
|
|
212
|
+
const bytes = new Uint8Array(32);
|
|
213
|
+
for (let i = 0; i < 32; i++) {
|
|
214
|
+
bytes[i] = reader.read8();
|
|
215
|
+
}
|
|
216
|
+
return "0x" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
217
|
+
},
|
|
218
|
+
write(value, writer) {
|
|
219
|
+
const hex = value.startsWith("0x") ? value.slice(2) : value;
|
|
220
|
+
const paddedHex = hex.padStart(64, "0");
|
|
221
|
+
for (let i = 0; i < 32; i++) {
|
|
222
|
+
const byte = parseInt(paddedHex.substr(i * 2, 2), 16);
|
|
223
|
+
writer.write8(byte);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// src/types/oracle.ts
|
|
229
|
+
import { bcs as bcs3 } from "@mysten/bcs";
|
|
230
|
+
var OracleConfigStruct = bcs3.struct("Config", {
|
|
231
|
+
admin: BcsAddressType,
|
|
232
|
+
price_threshold_ratio: bcs3.u64(),
|
|
233
|
+
default_price_expiry_seconds: bcs3.u64()
|
|
234
|
+
});
|
|
235
|
+
var AssetPairStruct = bcs3.struct("AssetPair", {
|
|
236
|
+
base_symbol: bcs3.string(),
|
|
237
|
+
quote_symbol: bcs3.string(),
|
|
238
|
+
base_precision: bcs3.u8(),
|
|
239
|
+
quote_precision: bcs3.u8()
|
|
240
|
+
});
|
|
241
|
+
var AssetPairsResponseStruct = bcs3.struct("AssetPairsResponse", {
|
|
242
|
+
asset_pairs: bcs3.vector(AssetPairStruct)
|
|
243
|
+
});
|
|
244
|
+
var AssetPairsResponsePaginatedStruct = bcs3.struct("AssetPairsResponsePaginated", {
|
|
245
|
+
asset_pairs: bcs3.vector(AssetPairStruct),
|
|
246
|
+
...PaginationStruct
|
|
247
|
+
});
|
|
248
|
+
var PriceDataStruct = bcs3.struct("PriceData", {
|
|
249
|
+
price: bcs3.u128(),
|
|
250
|
+
expiry_time_ms: bcs3.u64(),
|
|
251
|
+
last_updated_ms: bcs3.u64(),
|
|
252
|
+
updater: BcsAddressType
|
|
253
|
+
});
|
|
254
|
+
var PriceResponseStruct = bcs3.struct("PriceResponse", {
|
|
255
|
+
pair_data: bcs3.option(PriceDataStruct)
|
|
256
|
+
});
|
|
257
|
+
var PricesResponsePaginatedStruct = bcs3.struct("PricesResponsePaginated", {
|
|
258
|
+
prices: bcs3.vector(PriceDataStruct),
|
|
259
|
+
...PaginationStruct
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// src/types/router.ts
|
|
263
|
+
import { bcs as bcs4 } from "@mysten/bcs";
|
|
264
|
+
var RouterConfigStruct = bcs4.struct("Config", {
|
|
265
|
+
admin: BcsAddressType,
|
|
266
|
+
default_price_oracle_contract: BcsAddressType,
|
|
267
|
+
default_protocol_fee_recipient: BcsAddressType,
|
|
268
|
+
default_protocol_fee: bcs4.u64(),
|
|
269
|
+
default_lp_fee: bcs4.u64()
|
|
270
|
+
});
|
|
271
|
+
var MarketStruct = bcs4.struct("Market", {
|
|
272
|
+
base_asset_symbol: bcs4.string(),
|
|
273
|
+
quote_assets_symbols: bcs4.vector(bcs4.string()),
|
|
274
|
+
market_address: bcs4.string(),
|
|
275
|
+
is_permissioned: bcs4.bool(),
|
|
276
|
+
created_at_ms: bcs4.u64()
|
|
277
|
+
});
|
|
278
|
+
var MarketResponseStruct = bcs4.struct("MarketResponse", {
|
|
279
|
+
market: bcs4.option(MarketStruct)
|
|
280
|
+
});
|
|
281
|
+
var MarketsResponseStruct = bcs4.struct("MarketsResponse", {
|
|
282
|
+
markets: bcs4.vector(MarketStruct)
|
|
283
|
+
});
|
|
284
|
+
var MarketsResponsePaginatedStruct = bcs4.struct("MarketsResponsePaginated", {
|
|
285
|
+
markets: bcs4.vector(MarketStruct),
|
|
286
|
+
...PaginationStruct
|
|
287
|
+
});
|
|
288
|
+
var BaseLiquidityResponseStruct = bcs4.struct("BaseLiquidityResponse", {
|
|
289
|
+
base_assets: bcs4.vector(bcs4.string()),
|
|
290
|
+
...PaginationStruct
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
// src/types/pool.ts
|
|
294
|
+
import { bcs as bcs5 } from "@mysten/bcs";
|
|
295
|
+
var GetPoolInfoResponseStruct = [
|
|
296
|
+
bcs5.u64(),
|
|
297
|
+
bcs5.u128(),
|
|
298
|
+
BcsAddressType,
|
|
299
|
+
bcs5.bool()
|
|
300
|
+
];
|
|
301
|
+
var GetFeesResponseStruct = [bcs5.u64(), bcs5.u64(), bcs5.u64()];
|
|
302
|
+
|
|
303
|
+
// src/lib/oracle/get-asset-pairs.ts
|
|
304
|
+
var getAssetPairs = async (client) => {
|
|
305
|
+
const ASSET_PAIRS_PAGINATED_FUNCTION = "asset_pairs_paginated";
|
|
306
|
+
const result = [];
|
|
307
|
+
let currentCursor = null;
|
|
308
|
+
let hasNextPage = true;
|
|
309
|
+
while (hasNextPage) {
|
|
310
|
+
const response = await queryDevInspect(
|
|
311
|
+
client.suiClient,
|
|
312
|
+
[client.packageId, PRICE_ORACLE_MODULE, ASSET_PAIRS_PAGINATED_FUNCTION],
|
|
313
|
+
[
|
|
314
|
+
client.contracts.oracle,
|
|
315
|
+
bcs6.option(bcs6.u64()).serialize(DEFAULT_PAGINATION_LIMIT),
|
|
316
|
+
bcs6.option(bcs6.string()).serialize(currentCursor)
|
|
317
|
+
]
|
|
318
|
+
);
|
|
319
|
+
const output = parseDevInspectResult(response, AssetPairsResponsePaginatedStruct);
|
|
320
|
+
const assetPairs = parseAssetPairsResponsePaginatedStructOutput(output);
|
|
321
|
+
result.push(...assetPairs);
|
|
322
|
+
currentCursor = output.next_cursor;
|
|
323
|
+
hasNextPage = output.has_next_page;
|
|
324
|
+
}
|
|
325
|
+
return result;
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
// src/lib/oracle/get-assets.ts
|
|
329
|
+
var getAssets = async (client) => {
|
|
330
|
+
const assetPairs = await client.getAllOracleAssetPairs();
|
|
331
|
+
const uniqueOracleAssets = {};
|
|
332
|
+
for (const item of assetPairs) {
|
|
333
|
+
uniqueOracleAssets[item.base.symbol] = item.base;
|
|
334
|
+
uniqueOracleAssets[item.quote.symbol] = item.quote;
|
|
335
|
+
}
|
|
336
|
+
return Object.values(uniqueOracleAssets).map(
|
|
337
|
+
(item) => client.assetsConfig[item.symbol] ?? // Fallback to minimal asset data from oracle
|
|
338
|
+
{
|
|
339
|
+
symbol: item.name,
|
|
340
|
+
name: item.name,
|
|
341
|
+
chainId: client.chainConfig.id,
|
|
342
|
+
denom: item.symbol,
|
|
343
|
+
decimals: item.precision,
|
|
344
|
+
logo: void 0,
|
|
345
|
+
coingeckoId: void 0
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
// src/lib/oracle/get-oracle-config.ts
|
|
351
|
+
var getOracleConfig = async (client) => {
|
|
352
|
+
const CONFIG_FUNCTION = "config";
|
|
353
|
+
const response = await queryDevInspect(
|
|
354
|
+
client.suiClient,
|
|
355
|
+
[client.packageId, PRICE_ORACLE_MODULE, CONFIG_FUNCTION],
|
|
356
|
+
[client.contracts.oracle]
|
|
357
|
+
);
|
|
358
|
+
const output = parseDevInspectResult(response, OracleConfigStruct);
|
|
359
|
+
return parseOracleConfigStructOutput(output);
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
// src/lib/oracle/get-price.ts
|
|
363
|
+
import { bcs as bcs7 } from "@mysten/bcs";
|
|
364
|
+
import { SUI_CLOCK_OBJECT_ID } from "@mysten/sui/utils";
|
|
365
|
+
var getPrice = async (client, baseDenom, quoteDenom) => {
|
|
366
|
+
const GET_PRICE_FUNCTION = "get_price";
|
|
367
|
+
const response = await queryDevInspect(
|
|
368
|
+
client.suiClient,
|
|
369
|
+
[client.packageId, PRICE_ORACLE_MODULE, GET_PRICE_FUNCTION],
|
|
370
|
+
[
|
|
371
|
+
client.contracts.oracle,
|
|
372
|
+
bcs7.string().serialize(baseDenom),
|
|
373
|
+
bcs7.string().serialize(quoteDenom),
|
|
374
|
+
SUI_CLOCK_OBJECT_ID
|
|
375
|
+
]
|
|
376
|
+
);
|
|
377
|
+
const output = parseDevInspectResult(response, PriceResponseStruct);
|
|
378
|
+
return parsePriceResponseStructOutput(output, baseDenom, quoteDenom);
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// src/lib/oracle/get-prices.ts
|
|
382
|
+
import { bcs as bcs8 } from "@mysten/bcs";
|
|
383
|
+
var getPrices = async (client) => {
|
|
384
|
+
const GET_PRICES_PAGINATED_FUNCTION = "get_prices_paginated";
|
|
385
|
+
const result = [];
|
|
386
|
+
let currentCursor = null;
|
|
387
|
+
let hasNextPage = true;
|
|
388
|
+
while (hasNextPage) {
|
|
389
|
+
const response = await queryDevInspect(
|
|
390
|
+
client.suiClient,
|
|
391
|
+
[client.packageId, PRICE_ORACLE_MODULE, GET_PRICES_PAGINATED_FUNCTION],
|
|
392
|
+
[
|
|
393
|
+
client.contracts.oracle,
|
|
394
|
+
bcs8.option(bcs8.u64()).serialize(DEFAULT_PAGINATION_LIMIT),
|
|
395
|
+
bcs8.option(bcs8.string()).serialize(currentCursor)
|
|
396
|
+
]
|
|
397
|
+
);
|
|
398
|
+
const output = parseDevInspectResult(response, PricesResponsePaginatedStruct);
|
|
399
|
+
const assetPairs = parsePricesResponsePaginatedStructOutput(output);
|
|
400
|
+
result.push(...assetPairs);
|
|
401
|
+
currentCursor = output.next_cursor;
|
|
402
|
+
hasNextPage = output.has_next_page;
|
|
403
|
+
}
|
|
404
|
+
return result;
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
// src/lib/router/get-all-base-liquidity.ts
|
|
408
|
+
import { bcs as bcs9 } from "@mysten/bcs";
|
|
409
|
+
|
|
410
|
+
// src/lib/router/parsers.ts
|
|
411
|
+
import { NotFoundError } from "@bolt-liquidity-hq/core";
|
|
412
|
+
var parseMarketStructOutput = (output) => {
|
|
413
|
+
return {
|
|
414
|
+
poolAddress: output.market_address,
|
|
415
|
+
baseDenom: output.base_asset_symbol,
|
|
416
|
+
quoteDenoms: output.quote_assets_symbols
|
|
417
|
+
};
|
|
418
|
+
};
|
|
419
|
+
var parseMarketResponseStructOutput = (response) => {
|
|
420
|
+
if (!response.market) {
|
|
421
|
+
throw new NotFoundError("Market", void 0, { response });
|
|
422
|
+
}
|
|
423
|
+
return parseMarketStructOutput(response.market);
|
|
424
|
+
};
|
|
425
|
+
var parseMarketsResponsePaginatedStructOutput = (response) => {
|
|
426
|
+
return response.markets.map((item) => parseMarketStructOutput(item));
|
|
427
|
+
};
|
|
428
|
+
var parseRouterConfigStructOutput = (output) => {
|
|
429
|
+
return {
|
|
430
|
+
admin: output.admin,
|
|
431
|
+
defaultPriceOracleContract: output.default_price_oracle_contract,
|
|
432
|
+
defaultProtocolFeeRecipient: output.default_protocol_fee_recipient,
|
|
433
|
+
defaultProtocolFee: output.default_protocol_fee,
|
|
434
|
+
defaultLpFee: output.default_lp_fee
|
|
435
|
+
};
|
|
436
|
+
};
|
|
437
|
+
var parseBaseLiquidityResponseStructOutput = (output) => {
|
|
438
|
+
return output.base_assets.map((item) => ({
|
|
439
|
+
baseLiquidity: {
|
|
440
|
+
denom: item,
|
|
441
|
+
amount: "10"
|
|
442
|
+
},
|
|
443
|
+
totalShares: "10"
|
|
444
|
+
}));
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
// src/lib/router/get-all-base-liquidity.ts
|
|
448
|
+
var getAllBaseLiquidity = async (client) => {
|
|
449
|
+
const BASE_LIQUIDITY_ALL_PAGINATED_FUNCTION = "base_liquidity_all_paginated";
|
|
450
|
+
const result = {};
|
|
451
|
+
let currentCursor = null;
|
|
452
|
+
let hasNextPage = true;
|
|
453
|
+
while (hasNextPage) {
|
|
454
|
+
const response = await queryDevInspect(
|
|
455
|
+
client.suiClient,
|
|
456
|
+
[client.packageId, ROUTER_MODULE, BASE_LIQUIDITY_ALL_PAGINATED_FUNCTION],
|
|
457
|
+
[
|
|
458
|
+
client.contracts.router,
|
|
459
|
+
bcs9.option(bcs9.u64()).serialize(DEFAULT_PAGINATION_LIMIT),
|
|
460
|
+
bcs9.option(bcs9.string()).serialize(currentCursor)
|
|
461
|
+
]
|
|
462
|
+
);
|
|
463
|
+
const output = parseDevInspectResult(response, BaseLiquidityResponseStruct);
|
|
464
|
+
const baseLiquidities = parseBaseLiquidityResponseStructOutput(output);
|
|
465
|
+
for (const item of baseLiquidities) {
|
|
466
|
+
result[item.baseLiquidity.denom] = item;
|
|
467
|
+
}
|
|
468
|
+
currentCursor = output.next_cursor;
|
|
469
|
+
hasNextPage = output.has_next_page;
|
|
470
|
+
}
|
|
471
|
+
return result;
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
// src/lib/router/get-all-quotes-for-user.ts
|
|
475
|
+
import { bcs as bcs10 } from "@mysten/bcs";
|
|
476
|
+
var getAllQuotesForUser = async (client, lpAddress) => {
|
|
477
|
+
const QUOTES_FOR_USER_ALL_FUNCTION = "quotes_for_user_all";
|
|
478
|
+
const response = await queryDevInspect(
|
|
479
|
+
client.suiClient,
|
|
480
|
+
[client.packageId, ROUTER_MODULE, QUOTES_FOR_USER_ALL_FUNCTION],
|
|
481
|
+
[client.contracts.router, bcs10.string().serialize(lpAddress)]
|
|
482
|
+
);
|
|
483
|
+
console.log(response);
|
|
484
|
+
return {};
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// src/lib/router/get-pool-for-base.ts
|
|
488
|
+
import { bcs as bcs11 } from "@mysten/bcs";
|
|
489
|
+
var getPoolForBase = async (client, baseDenom) => {
|
|
490
|
+
const MARKET_FOR_BASE_FUNCTION = "market_for_base";
|
|
491
|
+
const response = await queryDevInspect(
|
|
492
|
+
client.suiClient,
|
|
493
|
+
[client.packageId, ROUTER_MODULE, MARKET_FOR_BASE_FUNCTION],
|
|
494
|
+
[client.contracts.router, bcs11.string().serialize(baseDenom)]
|
|
495
|
+
);
|
|
496
|
+
const output = parseDevInspectResult(response, MarketResponseStruct);
|
|
497
|
+
return parseMarketResponseStructOutput(output);
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
// src/lib/router/get-pools.ts
|
|
501
|
+
import { bcs as bcs12 } from "@mysten/bcs";
|
|
502
|
+
var getPools = async (client) => {
|
|
503
|
+
const MARKETS_PAGINATED_FUNCTION = "markets_paginated";
|
|
504
|
+
const result = [];
|
|
505
|
+
let currentCursor = null;
|
|
506
|
+
let hasNextPage = true;
|
|
507
|
+
while (hasNextPage) {
|
|
508
|
+
const response = await queryDevInspect(
|
|
509
|
+
client.suiClient,
|
|
510
|
+
[client.packageId, ROUTER_MODULE, MARKETS_PAGINATED_FUNCTION],
|
|
511
|
+
[
|
|
512
|
+
client.contracts.router,
|
|
513
|
+
bcs12.option(bcs12.u64()).serialize(DEFAULT_PAGINATION_LIMIT),
|
|
514
|
+
bcs12.option(bcs12.string()).serialize(currentCursor)
|
|
515
|
+
]
|
|
516
|
+
);
|
|
517
|
+
const output = parseDevInspectResult(response, MarketsResponsePaginatedStruct);
|
|
518
|
+
const pools = parseMarketsResponsePaginatedStructOutput(output);
|
|
519
|
+
result.push(...pools);
|
|
520
|
+
currentCursor = output.next_cursor;
|
|
521
|
+
hasNextPage = output.has_next_page;
|
|
522
|
+
}
|
|
523
|
+
return result;
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
// src/lib/router/get-router-config.ts
|
|
527
|
+
var getRouterConfig = async (client) => {
|
|
528
|
+
const CONFIG_FUNCTION = "config";
|
|
529
|
+
const response = await queryDevInspect(
|
|
530
|
+
client.suiClient,
|
|
531
|
+
[client.packageId, ROUTER_MODULE, CONFIG_FUNCTION],
|
|
532
|
+
[client.contracts.router]
|
|
533
|
+
);
|
|
534
|
+
const output = parseDevInspectResult(response, RouterConfigStruct);
|
|
535
|
+
return parseRouterConfigStructOutput(output);
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
// src/lib/router/swap-exact-in.ts
|
|
539
|
+
var swapExactIn = async (client, signer, { assetIn, amountIn, assetOut, minimumAmountOut, receiver }) => {
|
|
540
|
+
console.log(client, signer, assetIn, amountIn, assetOut, minimumAmountOut, receiver);
|
|
541
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
542
|
+
return {};
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
// src/lib/settlement/get-pool-info.ts
|
|
546
|
+
import { SUI_TYPE_ARG } from "@mysten/sui/utils";
|
|
547
|
+
|
|
548
|
+
// src/lib/settlement/parsers.ts
|
|
549
|
+
var parseSettlementConfigStructOutput = (_poolInfoOutput, feesOutput) => {
|
|
550
|
+
return {
|
|
551
|
+
priceOracleContract: "0x",
|
|
552
|
+
// Should come from poolInfoOutput
|
|
553
|
+
protocolFeeRecipient: "0x",
|
|
554
|
+
// Should be feesOutput[1]
|
|
555
|
+
protocolFee: feesOutput[0],
|
|
556
|
+
// Protocol fee percentage
|
|
557
|
+
lpFee: feesOutput[2],
|
|
558
|
+
// LP fee percentage
|
|
559
|
+
allowanceMode: "allow",
|
|
560
|
+
// Should come from poolInfoOutput
|
|
561
|
+
lps: ["0x"],
|
|
562
|
+
// Should come from poolInfoOutput
|
|
563
|
+
minBaseOut: "1"
|
|
564
|
+
// Should come from poolInfoOutput
|
|
565
|
+
};
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
// src/lib/settlement/get-pool-info.ts
|
|
569
|
+
var getPoolInfo = async (client, contractAddress) => {
|
|
570
|
+
const GET_POOL_INFO = "get_pool_info";
|
|
571
|
+
const GET_FEES_FUNCTION = "get_fees";
|
|
572
|
+
const [info, fees] = await Promise.all([
|
|
573
|
+
// Query pool information (LP configuration, allowance mode)
|
|
574
|
+
queryDevInspect(
|
|
575
|
+
client.suiClient,
|
|
576
|
+
[client.packageId, POOL_MODULE, GET_POOL_INFO],
|
|
577
|
+
[contractAddress],
|
|
578
|
+
// TODO: get the base token of the pool to pass it here instead of hardcoded SUI token
|
|
579
|
+
[SUI_TYPE_ARG]
|
|
580
|
+
),
|
|
581
|
+
// Query fee structure (protocol fee, LP fee, recipients)
|
|
582
|
+
queryDevInspect(
|
|
583
|
+
client.suiClient,
|
|
584
|
+
[client.packageId, POOL_MODULE, GET_FEES_FUNCTION],
|
|
585
|
+
[contractAddress],
|
|
586
|
+
// TODO: get the base token of the pool to pass it here instead of hardcoded SUI token
|
|
587
|
+
[SUI_TYPE_ARG]
|
|
588
|
+
)
|
|
589
|
+
]);
|
|
590
|
+
const infoOutput = parseMultipleResults(info, GetPoolInfoResponseStruct);
|
|
591
|
+
const feesOutput = parseMultipleResults(fees, GetFeesResponseStruct);
|
|
592
|
+
return parseSettlementConfigStructOutput(infoOutput, feesOutput);
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
// src/tests/constants/sui-objects.ts
|
|
596
|
+
var TEST_POOL = "0xdd05c1caea7b6725da3f67e30e99872033fc5d3a610a4f72ac1c434bc81c3c0d";
|
|
597
|
+
|
|
598
|
+
// src/lib/settlement/get-pool-info-for-base.ts
|
|
599
|
+
var getPoolInfoForBase = async (client, baseDenom) => {
|
|
600
|
+
const pool = await getPoolForBase(client, baseDenom && "SUI");
|
|
601
|
+
return await getPoolInfo(client, pool.poolAddress || TEST_POOL);
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
// src/lib/client.ts
|
|
605
|
+
var BoltSuiClient = class extends BaseClient {
|
|
606
|
+
/**
|
|
607
|
+
* Creates a new instance of the BoltSuiClient.
|
|
608
|
+
*
|
|
609
|
+
* The client automatically configures itself based on the specified chain and environment,
|
|
610
|
+
* loading the appropriate contract addresses, chain configuration, and assets from configuration files.
|
|
611
|
+
*
|
|
612
|
+
* @param config - (Optional) Configuration for the client
|
|
613
|
+
* @param config.environment - (Optional) The deployment environment ('mainnet' or 'testnet'). Defaults to 'mainnet'
|
|
614
|
+
* @param config.customOverride - (Optional) Custom overrides for chain configuration, contracts, and assets
|
|
615
|
+
* @param config.customOverride.chainConfig - (Optional) Override chain configuration
|
|
616
|
+
* @param config.customOverride.chainConfig.id - (Optional) Custom chain ID
|
|
617
|
+
* @param config.customOverride.chainConfig.name - (Optional) Custom chain name
|
|
618
|
+
* @param config.customOverride.chainConfig.rpcEndpoint - (Optional) Custom RPC endpoint URL
|
|
619
|
+
* @param config.customOverride.packageId - (Optional) Custom package ID for Bolt contracts
|
|
620
|
+
* @param config.customOverride.contracts - (Optional) Override contract addresses
|
|
621
|
+
* @param config.customOverride.contracts.oracle - (Optional) Custom oracle contract address
|
|
622
|
+
* @param config.customOverride.contracts.router - (Optional) Custom router contract address
|
|
623
|
+
* @param config.customOverride.assetsConfig - (Optional) Custom asset configurations indexed by denom
|
|
624
|
+
* @param config.suiClient - (Optional) Pre-existing SuiClient to use for blockchain queries
|
|
625
|
+
*
|
|
626
|
+
* @throws {InvalidObjectError} Thrown when required configuration fields are missing
|
|
627
|
+
*
|
|
628
|
+
* @example
|
|
629
|
+
* ```typescript
|
|
630
|
+
* // Use default configuration (Sui mainnet)
|
|
631
|
+
* const client = new BoltSuiClient();
|
|
632
|
+
*
|
|
633
|
+
* // Use testnet configuration
|
|
634
|
+
* const testnetClient = new BoltSuiClient({
|
|
635
|
+
* environment: 'testnet'
|
|
636
|
+
* });
|
|
637
|
+
*
|
|
638
|
+
* // Use custom chain configuration
|
|
639
|
+
* const customClient = new BoltSuiClient({
|
|
640
|
+
* customOverride: {
|
|
641
|
+
* chainConfig: {
|
|
642
|
+
* id: 'sui-custom',
|
|
643
|
+
* name: 'Sui Custom',
|
|
644
|
+
* rpcEndpoint: 'https://custom-rpc.example.com'
|
|
645
|
+
* },
|
|
646
|
+
* packageId: '0xcustom_package_id...',
|
|
647
|
+
* contracts: {
|
|
648
|
+
* oracle: '0xcustom_oracle...',
|
|
649
|
+
* router: '0xcustom_router...'
|
|
650
|
+
* },
|
|
651
|
+
* assetsConfig: {
|
|
652
|
+
* '0x2::sui::SUI': {
|
|
653
|
+
* symbol: 'SUI',
|
|
654
|
+
* name: 'Sui',
|
|
655
|
+
* chainId: 'sui-custom',
|
|
656
|
+
* denom: '0x2::sui::SUI',
|
|
657
|
+
* decimals: 9,
|
|
658
|
+
* logo: 'https://example.com/sui.png',
|
|
659
|
+
* coingeckoId: 'sui'
|
|
660
|
+
* }
|
|
661
|
+
* }
|
|
662
|
+
* }
|
|
663
|
+
* });
|
|
664
|
+
*
|
|
665
|
+
* // Use pre-existing Sui client
|
|
666
|
+
* const clientWithCustomClient = new BoltSuiClient({
|
|
667
|
+
* suiClient: mySuiClient
|
|
668
|
+
* });
|
|
669
|
+
* ```
|
|
670
|
+
*/
|
|
671
|
+
constructor(config) {
|
|
672
|
+
const { environment = "mainnet", customOverride, suiClient } = config ?? {};
|
|
673
|
+
const defaultChainConfig = environment === "mainnet" ? MainnetChainConfig : TestnetChainConfig;
|
|
674
|
+
const defaultContracts = environment === "mainnet" ? MainnetContracts : TestnetContracts;
|
|
675
|
+
const defaultPackageId = environment === "mainnet" ? MainnetPackageId : TestnetPackageId;
|
|
676
|
+
const assetsConfig = environment === "mainnet" ? MainnetAssets : TestnetAssets;
|
|
677
|
+
const chainConfig = {
|
|
678
|
+
id: customOverride?.chainConfig?.id ?? defaultChainConfig.id,
|
|
679
|
+
name: customOverride?.chainConfig?.name ?? defaultChainConfig.name,
|
|
680
|
+
rpcEndpoint: customOverride?.chainConfig?.rpcEndpoint ?? defaultChainConfig.rpcEndpoint
|
|
681
|
+
};
|
|
682
|
+
const packageId = customOverride?.packageId ?? defaultPackageId;
|
|
683
|
+
const contracts = {
|
|
684
|
+
oracle: customOverride?.contracts?.oracle ?? defaultContracts.oracle,
|
|
685
|
+
router: customOverride?.contracts?.router ?? defaultContracts.router
|
|
686
|
+
};
|
|
687
|
+
for (const item of Object.values(customOverride?.assetsConfig ?? {})) {
|
|
688
|
+
assetsConfig[item.denom] = item;
|
|
689
|
+
}
|
|
690
|
+
super({
|
|
691
|
+
customOverride: {
|
|
692
|
+
chainConfig,
|
|
693
|
+
contracts,
|
|
694
|
+
assetsConfig
|
|
695
|
+
}
|
|
696
|
+
});
|
|
697
|
+
/**
|
|
698
|
+
* The Sui-specific chain configuration including RPC endpoint
|
|
699
|
+
*/
|
|
700
|
+
__publicField(this, "chainConfig");
|
|
701
|
+
/**
|
|
702
|
+
* Package Id for the deployed Bolt contracts on Sui
|
|
703
|
+
*/
|
|
704
|
+
__publicField(this, "packageId");
|
|
705
|
+
/**
|
|
706
|
+
* Instance of the Sui client to interact with the blockchain
|
|
707
|
+
*/
|
|
708
|
+
__publicField(this, "suiClient");
|
|
709
|
+
this.chainConfig = chainConfig;
|
|
710
|
+
this.packageId = packageId;
|
|
711
|
+
this.suiClient = suiClient ?? new SuiClient({ url: chainConfig.rpcEndpoint });
|
|
712
|
+
}
|
|
713
|
+
// The following methods inherit their documentation from BaseClient
|
|
714
|
+
// Only add documentation here if you need to override or add implementation-specific details
|
|
715
|
+
/** @inheritdoc */
|
|
716
|
+
async getOracleConfig() {
|
|
717
|
+
return await getOracleConfig(this);
|
|
718
|
+
}
|
|
719
|
+
/** @inheritdoc */
|
|
720
|
+
async getAllOracleAssetPairs() {
|
|
721
|
+
return await getAssetPairs(this);
|
|
722
|
+
}
|
|
723
|
+
/** @inheritdoc */
|
|
724
|
+
async getPrice(baseDenom, quoteDenom) {
|
|
725
|
+
return await getPrice(this, baseDenom, quoteDenom);
|
|
726
|
+
}
|
|
727
|
+
/** @inheritdoc */
|
|
728
|
+
async getAllPrices() {
|
|
729
|
+
return await getPrices(this);
|
|
730
|
+
}
|
|
731
|
+
/** @inheritdoc */
|
|
732
|
+
async getRouterConfig() {
|
|
733
|
+
return await getRouterConfig(this);
|
|
734
|
+
}
|
|
735
|
+
/** @inheritdoc */
|
|
736
|
+
async getAllBaseAssetsLiquidity() {
|
|
737
|
+
return await getAllBaseLiquidity(this);
|
|
738
|
+
}
|
|
739
|
+
/** @inheritdoc */
|
|
740
|
+
async getAllQuotesByUser(address) {
|
|
741
|
+
return await getAllQuotesForUser(this, address);
|
|
742
|
+
}
|
|
743
|
+
/** @inheritdoc */
|
|
744
|
+
async getPoolByBaseAsset(baseDenom) {
|
|
745
|
+
return await getPoolForBase(this, baseDenom);
|
|
746
|
+
}
|
|
747
|
+
/** @inheritdoc */
|
|
748
|
+
async getAllPools() {
|
|
749
|
+
return await getPools(this);
|
|
750
|
+
}
|
|
751
|
+
// Satisfy the base class requirement
|
|
752
|
+
async getPoolConfig(poolContractAddress) {
|
|
753
|
+
return await getPoolInfo(this, poolContractAddress);
|
|
754
|
+
}
|
|
755
|
+
/** @inheritdoc */
|
|
756
|
+
async getAssets() {
|
|
757
|
+
return await getAssets(this);
|
|
758
|
+
}
|
|
759
|
+
/** @inheritdoc */
|
|
760
|
+
async getPoolConfigByBaseAsset(baseDenom) {
|
|
761
|
+
return await getPoolInfoForBase(this, baseDenom);
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* @inheritdoc
|
|
765
|
+
*
|
|
766
|
+
* @example
|
|
767
|
+
* ```typescript
|
|
768
|
+
* // Get signer from wallet (e.g., Sui Wallet, Suiet, etc.)
|
|
769
|
+
* const signer = // ... obtain signer from wallet
|
|
770
|
+
*
|
|
771
|
+
* // Execute swap: 1 SUI for USDC
|
|
772
|
+
* const result = await client.swap(signer, {
|
|
773
|
+
* assetIn: "0x2::sui::SUI",
|
|
774
|
+
* amountIn: "1000000000", // 1 SUI (9 decimals)
|
|
775
|
+
* assetOut: "0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN", // USDC address
|
|
776
|
+
* minimumAmountOut: "1950000", // Minimum 1.95 USDC expected (6 decimals)
|
|
777
|
+
* receiver: "0x..." // Optional custom receiver address
|
|
778
|
+
* });
|
|
779
|
+
*
|
|
780
|
+
* console.log(`Swap successful!`);
|
|
781
|
+
* console.log(`Transaction digest: ${result.txHash}`);
|
|
782
|
+
* console.log(`Received: ${result.amountOut} ${result.assetOut}`);
|
|
783
|
+
* console.log(`Gas cost: ${result.txOutput.effects.gasUsed.computationCost}`);
|
|
784
|
+
* console.log(`Status: ${result.txOutput.effects.status.status}`);
|
|
785
|
+
* ```
|
|
786
|
+
*
|
|
787
|
+
* @remarks
|
|
788
|
+
* This implementation returns a SuiTransactionBlockResponse as the transaction output,
|
|
789
|
+
* which includes details like gas costs, transaction effects, object changes, and events.
|
|
790
|
+
*/
|
|
791
|
+
async swap(signer, params) {
|
|
792
|
+
return await swapExactIn(this, signer, params);
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
export {
|
|
796
|
+
AssetPairStruct,
|
|
797
|
+
AssetPairsResponsePaginatedStruct,
|
|
798
|
+
AssetPairsResponseStruct,
|
|
799
|
+
BaseLiquidityResponseStruct,
|
|
800
|
+
BcsAddressType,
|
|
801
|
+
BoltSuiClient,
|
|
802
|
+
GetFeesResponseStruct,
|
|
803
|
+
GetPoolInfoResponseStruct,
|
|
804
|
+
MarketResponseStruct,
|
|
805
|
+
MarketStruct,
|
|
806
|
+
MarketsResponsePaginatedStruct,
|
|
807
|
+
MarketsResponseStruct,
|
|
808
|
+
OracleConfigStruct,
|
|
809
|
+
PaginationStruct,
|
|
810
|
+
PriceDataStruct,
|
|
811
|
+
PriceResponseStruct,
|
|
812
|
+
PricesResponsePaginatedStruct,
|
|
813
|
+
RouterConfigStruct
|
|
814
|
+
};
|
|
815
|
+
//# sourceMappingURL=index.js.map
|