@cetusprotocol/aggregator-sdk 0.0.1

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.
Files changed (66) hide show
  1. package/.env.example +4 -0
  2. package/README.md +128 -0
  3. package/bun.lockb +0 -0
  4. package/dist/index.d.mts +266 -0
  5. package/dist/index.d.ts +266 -0
  6. package/dist/index.js +6817 -0
  7. package/dist/index.mjs +6738 -0
  8. package/dist/src/client.d.ts +87 -0
  9. package/dist/src/config.d.ts +26 -0
  10. package/dist/src/const.d.ts +75 -0
  11. package/dist/src/errors.d.ts +31 -0
  12. package/dist/src/index.d.ts +5 -0
  13. package/dist/src/math.d.ts +5 -0
  14. package/dist/src/test_data.test.d.ts +8 -0
  15. package/dist/src/transaction/aftermath.d.ts +24 -0
  16. package/dist/src/transaction/cetus.d.ts +39 -0
  17. package/dist/src/transaction/common.d.ts +12 -0
  18. package/dist/src/transaction/deepbook.d.ts +21 -0
  19. package/dist/src/transaction/flowx.d.ts +20 -0
  20. package/dist/src/transaction/index.d.ts +1 -0
  21. package/dist/src/transaction/kriya.d.ts +21 -0
  22. package/dist/src/transaction/router.d.ts +6 -0
  23. package/dist/src/transaction/swap.d.ts +5 -0
  24. package/dist/src/transaction/turbos.d.ts +22 -0
  25. package/dist/src/types/CoinAssist.d.ts +122 -0
  26. package/dist/src/types/sui.d.ts +112 -0
  27. package/dist/src/utils/account_cap.d.ts +7 -0
  28. package/dist/src/utils/coin.d.ts +4 -0
  29. package/dist/src/utils/coin.spec.d.ts +1 -0
  30. package/dist/src/utils/contracts.d.ts +16 -0
  31. package/dist/src/utils/index.d.ts +1 -0
  32. package/dist/src/utils/transaction.d.ts +3 -0
  33. package/dist/tests/router.test.d.ts +2 -0
  34. package/dist/tests/wallet.test.d.ts +1 -0
  35. package/jest.config.mjs +13 -0
  36. package/package.json +41 -0
  37. package/src/client.ts +383 -0
  38. package/src/config.ts +65 -0
  39. package/src/const.ts +126 -0
  40. package/src/errors.ts +44 -0
  41. package/src/index.ts +5 -0
  42. package/src/math.ts +37 -0
  43. package/src/test_data.test.ts +17 -0
  44. package/src/transaction/aftermath.ts +143 -0
  45. package/src/transaction/cetus.ts +282 -0
  46. package/src/transaction/common.ts +169 -0
  47. package/src/transaction/deepbook.ts +126 -0
  48. package/src/transaction/flowx.ts +98 -0
  49. package/src/transaction/index.ts +1 -0
  50. package/src/transaction/kriya.ts +77 -0
  51. package/src/transaction/router.ts +345 -0
  52. package/src/transaction/swap.ts +163 -0
  53. package/src/transaction/turbos.ts +114 -0
  54. package/src/types/CoinAssist.ts +217 -0
  55. package/src/types/sui.ts +148 -0
  56. package/src/utils/account_cap.ts +62 -0
  57. package/src/utils/coin.spec.ts +10 -0
  58. package/src/utils/coin.ts +61 -0
  59. package/src/utils/contracts.ts +136 -0
  60. package/src/utils/index.ts +1 -0
  61. package/src/utils/transaction.ts +20 -0
  62. package/tests/router.test.ts +249 -0
  63. package/tests/wallet.test.ts +17 -0
  64. package/tsconfig.json +22 -0
  65. package/tsup.config.ts +23 -0
  66. package/version.mjs +28 -0
@@ -0,0 +1,163 @@
1
+ import { Transaction } from "@mysten/sui/transactions"
2
+ import { SwapInPoolsParams } from "~/client"
3
+ import { AggregatorConfig } from "~/config"
4
+ import { compareCoins, completionCoin } from "~/utils/coin"
5
+ import {
6
+ CETUS_DEX,
7
+ INTEGRATE,
8
+ RouterData,
9
+ SwapInPoolsResult,
10
+ U64_MAX_BN,
11
+ ZERO,
12
+ } from ".."
13
+ import { ConfigErrorCode, TransactionErrorCode } from "~/errors"
14
+ import { checkInvalidSuiAddress } from "~/utils/transaction"
15
+ import { SuiClient } from "@mysten/sui/client"
16
+ import { BN } from "bn.js"
17
+ import { sqrtPriceX64ToPrice } from "~/math"
18
+
19
+ export async function swapInPools(
20
+ client: SuiClient,
21
+ params: SwapInPoolsParams,
22
+ config: AggregatorConfig
23
+ ): Promise<SwapInPoolsResult> {
24
+ const { from, target, amount, byAmountIn, pools } = params
25
+ const fromCoin = completionCoin(from)
26
+ const targetCoin = completionCoin(target)
27
+
28
+ const tx = new Transaction()
29
+ const a2b = compareCoins(fromCoin, targetCoin)
30
+
31
+ const integratePackage = config.getPackage(INTEGRATE)
32
+ if (integratePackage == null) {
33
+ throw new AggregateError(
34
+ "Aggregator package not set",
35
+ ConfigErrorCode.MissAggregatorPackage
36
+ )
37
+ }
38
+ const integratePublishedAt = integratePackage.publishedAt
39
+
40
+ const coinA = a2b ? fromCoin : targetCoin
41
+ const coinB = a2b ? targetCoin : fromCoin
42
+
43
+ const typeArguments = [coinA, coinB]
44
+ for (let i = 0; i < pools.length; i++) {
45
+ const args = [
46
+ tx.object(pools[i]),
47
+ tx.pure.bool(a2b),
48
+ tx.pure.bool(byAmountIn),
49
+ tx.pure.u64(amount.toString()),
50
+ ]
51
+ tx.moveCall({
52
+ target: `${integratePublishedAt}::fetcher_script::calculate_swap_result`,
53
+ arguments: args,
54
+ typeArguments,
55
+ })
56
+ }
57
+
58
+ if (!checkInvalidSuiAddress(config.getWallet())) {
59
+ throw new AggregateError(
60
+ "Aggregator package not set",
61
+ ConfigErrorCode.InvalidWallet
62
+ )
63
+ }
64
+
65
+ const simulateRes = await client.devInspectTransactionBlock({
66
+ transactionBlock: tx,
67
+ sender: config.getWallet(),
68
+ })
69
+ if (simulateRes.error != null) {
70
+ throw new AggregateError(
71
+ "Aggregator package not set",
72
+ ConfigErrorCode.SimulateError
73
+ )
74
+ }
75
+
76
+ const valueData: any = simulateRes.events?.filter((item: any) => {
77
+ return item.type.includes("CalculatedSwapResultEvent")
78
+ })
79
+
80
+ if (valueData.length === 0 || valueData.length !== pools.length) {
81
+ throw new AggregateError(
82
+ "Simulate event result error",
83
+ TransactionErrorCode.SimulateEventError
84
+ )
85
+ }
86
+
87
+ let tempMaxAmount = byAmountIn ? ZERO : U64_MAX_BN
88
+ let tempIndex = 0
89
+ for (let i = 0; i < valueData.length; i += 1) {
90
+ if (valueData[i].parsedJson.data.is_exceed) {
91
+ continue
92
+ }
93
+
94
+ if (params.byAmountIn) {
95
+ const amount = new BN(valueData[i].parsedJson.data.amount_out)
96
+ if (amount.gt(tempMaxAmount)) {
97
+ tempIndex = i
98
+ tempMaxAmount = amount
99
+ }
100
+ } else {
101
+ const amount = new BN(valueData[i].parsedJson.data.amount_out)
102
+ if (amount.lt(tempMaxAmount)) {
103
+ tempIndex = i
104
+ tempMaxAmount = amount
105
+ }
106
+ }
107
+ }
108
+
109
+ const event = valueData[tempIndex].parsedJson.data
110
+ const currentSqrtPrice = event.step_results[0].current_sqrt_price
111
+
112
+ const [decimalA, decimalB] = await Promise.all([
113
+ client
114
+ .getCoinMetadata({ coinType: coinA })
115
+ .then((metadata) => metadata?.decimals),
116
+ client
117
+ .getCoinMetadata({ coinType: coinB })
118
+ .then((metadata) => metadata?.decimals),
119
+ ])
120
+
121
+ if (decimalA == null || decimalB == null) {
122
+ throw new AggregateError(
123
+ "Simulate event result error",
124
+ TransactionErrorCode.CannotGetDecimals
125
+ )
126
+ }
127
+ const initialPrice = sqrtPriceX64ToPrice(
128
+ currentSqrtPrice,
129
+ decimalA!,
130
+ decimalB!
131
+ )
132
+
133
+ const routeData = {
134
+ amountIn: new BN(event.amount_in ?? 0),
135
+ amountOut: new BN(event.amount_out ?? 0),
136
+ routes: [
137
+ {
138
+ path: [
139
+ {
140
+ id: pools[tempIndex],
141
+ a2b,
142
+ provider: CETUS_DEX,
143
+ from: fromCoin,
144
+ target: targetCoin,
145
+ feeRate: 0,
146
+ amountIn: 0,
147
+ amountOut: 0,
148
+ },
149
+ ],
150
+ amountIn: new BN(event.amount_in ?? 0),
151
+ amountOut: new BN(event.amount_out ?? 0),
152
+ initialPrice,
153
+ },
154
+ ],
155
+ }
156
+
157
+ const result = {
158
+ isExceed: event.is_exceed,
159
+ routeData,
160
+ }
161
+
162
+ return result
163
+ }
@@ -0,0 +1,114 @@
1
+ import {
2
+ TransactionArgument,
3
+ Transaction,
4
+ TransactionObjectArgument,
5
+ } from "@mysten/sui/transactions"
6
+ import { AggregatorConfig } from "../config"
7
+ import {
8
+ AGGREGATOR,
9
+ CLOCK_ADDRESS,
10
+ SWAP_A2B_FUNC,
11
+ SWAP_B2A_FUNC,
12
+ TURBOS_MODULE,
13
+ TURBOS_VERSIONED,
14
+ } from "../const"
15
+ import { ConfigErrorCode, TransactionErrorCode } from "../errors"
16
+ import { createTarget } from "../utils"
17
+
18
+ export type TurbosSwapParams = {
19
+ poolId: string
20
+ amount: TransactionArgument
21
+ amountLimit: number
22
+ a2b: boolean
23
+ byAmountIn: boolean
24
+ coinA?: TransactionObjectArgument
25
+ coinB?: TransactionObjectArgument
26
+ useFullInputCoinAmount: boolean
27
+ coinAType: string
28
+ coinBType: string
29
+ feeType: string
30
+ }
31
+
32
+ export type TurbosSwapResult = {
33
+ targetCoin: TransactionObjectArgument
34
+ amountIn: TransactionArgument
35
+ amountOut: TransactionArgument
36
+ txb: Transaction
37
+ }
38
+
39
+ export async function turbosSwapMovecall(
40
+ swapParams: TurbosSwapParams,
41
+ txb: Transaction,
42
+ config: AggregatorConfig
43
+ ): Promise<TurbosSwapResult> {
44
+ const aggregatorPackage = config.getPackage(AGGREGATOR)
45
+ if (aggregatorPackage == null) {
46
+ throw new AggregateError(
47
+ "Aggregator package not set",
48
+ ConfigErrorCode.MissAggregatorPackage
49
+ )
50
+ }
51
+ const aggregatorPublishedAt = aggregatorPackage.publishedAt
52
+
53
+ if (swapParams.a2b) {
54
+ if (swapParams.coinA == null) {
55
+ throw new AggregateError(
56
+ "coinA is required",
57
+ TransactionErrorCode.MissCoinA
58
+ )
59
+ }
60
+ } else {
61
+ if (swapParams.coinB == null) {
62
+ throw new AggregateError(
63
+ "coinB is required",
64
+ TransactionErrorCode.MissCoinB
65
+ )
66
+ }
67
+ }
68
+
69
+ const sqrtPriceLimit = swapParams.a2b
70
+ ? "4295048016"
71
+ : "79226673515401279992447579055"
72
+
73
+ const args = swapParams.a2b
74
+ ? [
75
+ txb.object(swapParams.poolId),
76
+ swapParams.amount,
77
+ txb.pure.u64(swapParams.amountLimit),
78
+ swapParams.coinA!,
79
+ txb.pure.bool(swapParams.useFullInputCoinAmount),
80
+ txb.pure.u128(sqrtPriceLimit),
81
+ txb.object(CLOCK_ADDRESS),
82
+ txb.object(TURBOS_VERSIONED),
83
+ ]
84
+ : [
85
+ txb.object(swapParams.poolId),
86
+ swapParams.amount,
87
+ txb.pure.u64(swapParams.amountLimit),
88
+ swapParams.coinB!,
89
+ txb.pure.bool(swapParams.useFullInputCoinAmount),
90
+ txb.pure.u128(sqrtPriceLimit),
91
+ txb.object(CLOCK_ADDRESS),
92
+ txb.object(TURBOS_VERSIONED),
93
+ ]
94
+
95
+ const func = swapParams.a2b ? SWAP_A2B_FUNC : SWAP_B2A_FUNC
96
+
97
+ const target = createTarget(aggregatorPublishedAt, TURBOS_MODULE, func)
98
+
99
+ const res = txb.moveCall({
100
+ target,
101
+ typeArguments: [
102
+ swapParams.coinAType,
103
+ swapParams.coinBType,
104
+ swapParams.feeType,
105
+ ],
106
+ arguments: args,
107
+ })
108
+ return {
109
+ targetCoin: res[0],
110
+ amountIn: res[1],
111
+ amountOut: res[2],
112
+ txb,
113
+ }
114
+ }
@@ -0,0 +1,217 @@
1
+ import type { SuiMoveObject } from '@mysten/sui/client'
2
+ import type { CoinAsset, SuiAddress } from './sui'
3
+ import { extractStructTagFromType, normalizeCoinType } from '../utils/contracts'
4
+
5
+ const COIN_TYPE = '0x2::coin::Coin'
6
+ const COIN_TYPE_ARG_REGEX = /^0x2::coin::Coin<(.+)>$/
7
+
8
+ export const DEFAULT_GAS_BUDGET_FOR_SPLIT = 1000
9
+ export const DEFAULT_GAS_BUDGET_FOR_MERGE = 500
10
+ export const DEFAULT_GAS_BUDGET_FOR_TRANSFER = 100
11
+ export const DEFAULT_GAS_BUDGET_FOR_TRANSFER_SUI = 100
12
+ export const DEFAULT_GAS_BUDGET_FOR_STAKE = 1000
13
+ export const GAS_TYPE_ARG = '0x2::sui::SUI'
14
+ export const GAS_TYPE_ARG_LONG = '0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI'
15
+ export const GAS_SYMBOL = 'SUI'
16
+ export const DEFAULT_NFT_TRANSFER_GAS_FEE = 450
17
+ export const SUI_SYSTEM_STATE_OBJECT_ID = '0x0000000000000000000000000000000000000005'
18
+
19
+ /**
20
+ * This class provides helper methods for working with coins.
21
+ */
22
+ export class CoinUtils {
23
+ /**
24
+ * Get the coin type argument from a SuiMoveObject.
25
+ *
26
+ * @param obj The SuiMoveObject to get the coin type argument from.
27
+ * @returns The coin type argument, or null if it is not found.
28
+ */
29
+ public static getCoinTypeArg(obj: SuiMoveObject) {
30
+ const res = obj.type.match(COIN_TYPE_ARG_REGEX)
31
+ return res ? res[1] : null
32
+ }
33
+
34
+ /**
35
+ * Get whether a SuiMoveObject is a SUI coin.
36
+ *
37
+ * @param obj The SuiMoveObject to check.
38
+ * @returns Whether the SuiMoveObject is a SUI coin.
39
+ */
40
+ public static isSUI(obj: SuiMoveObject) {
41
+ const arg = CoinUtils.getCoinTypeArg(obj)
42
+ return arg ? CoinUtils.getCoinSymbol(arg) === 'SUI' : false
43
+ }
44
+
45
+ /**
46
+ * Get the coin symbol from a coin type argument.
47
+ *
48
+ * @param coinTypeArg The coin type argument to get the symbol from.
49
+ * @returns The coin symbol.
50
+ */
51
+ public static getCoinSymbol(coinTypeArg: string) {
52
+ return coinTypeArg.substring(coinTypeArg.lastIndexOf(':') + 1)
53
+ }
54
+
55
+ /**
56
+ * Get the balance of a SuiMoveObject.
57
+ *
58
+ * @param obj The SuiMoveObject to get the balance from.
59
+ * @returns The balance of the SuiMoveObject.
60
+ */
61
+ public static getBalance(obj: SuiMoveObject): bigint {
62
+ return BigInt((obj.fields as any).balance)
63
+ }
64
+
65
+ /**
66
+ * Get the total balance of a list of CoinAsset objects for a given coin address.
67
+ *
68
+ * @param objs The list of CoinAsset objects to get the total balance for.
69
+ * @param coinAddress The coin address to get the total balance for.
70
+ * @returns The total balance of the CoinAsset objects for the given coin address.
71
+ */
72
+ public static totalBalance(objs: CoinAsset[], coinAddress: SuiAddress): bigint {
73
+ let balanceTotal = BigInt(0)
74
+ objs.forEach((obj) => {
75
+ if (coinAddress === obj.coinAddress) {
76
+ balanceTotal += BigInt(obj.balance)
77
+ }
78
+ })
79
+ return balanceTotal
80
+ }
81
+
82
+ /**
83
+ * Get the ID of a SuiMoveObject.
84
+ *
85
+ * @param obj The SuiMoveObject to get the ID from.
86
+ * @returns The ID of the SuiMoveObject.
87
+ */
88
+ public static getID(obj: SuiMoveObject): string {
89
+ return (obj.fields as any).id.id
90
+ }
91
+
92
+ /**
93
+ * Get the coin type from a coin type argument.
94
+ *
95
+ * @param coinTypeArg The coin type argument to get the coin type from.
96
+ * @returns The coin type.
97
+ */
98
+ public static getCoinTypeFromArg(coinTypeArg: string) {
99
+ return `${COIN_TYPE}<${coinTypeArg}>`
100
+ }
101
+
102
+ /**
103
+ * Get the CoinAsset objects for a given coin type.
104
+ *
105
+ * @param coinType The coin type to get the CoinAsset objects for.
106
+ * @param allSuiObjects The list of all SuiMoveObjects.
107
+ * @returns The CoinAsset objects for the given coin type.
108
+ */
109
+ public static getCoinAssets(coinType: string, allSuiObjects: CoinAsset[]): CoinAsset[] {
110
+ const coins: CoinAsset[] = []
111
+ allSuiObjects.forEach((anObj) => {
112
+ if (normalizeCoinType(anObj.coinAddress) === normalizeCoinType(coinType)) {
113
+ coins.push(anObj)
114
+ }
115
+ })
116
+ return coins
117
+ }
118
+
119
+ /**
120
+ * Get whether a coin address is a SUI coin.
121
+ *
122
+ * @param coinAddress The coin address to check.
123
+ * @returns Whether the coin address is a SUI coin.
124
+ */
125
+ public static isSuiCoin(coinAddress: SuiAddress) {
126
+ return extractStructTagFromType(coinAddress).full_address === GAS_TYPE_ARG
127
+ }
128
+
129
+ /**
130
+ * Select the CoinAsset objects from a list of CoinAsset objects that have a balance greater than or equal to a given amount.
131
+ *
132
+ * @param coins The list of CoinAsset objects to select from.
133
+ * @param amount The amount to select CoinAsset objects with a balance greater than or equal to.
134
+ * @param exclude A list of CoinAsset objects to exclude from the selection.
135
+ * @returns The CoinAsset objects that have a balance greater than or equal to the given amount.
136
+ */
137
+ static selectCoinObjectIdGreaterThanOrEqual(
138
+ coins: CoinAsset[],
139
+ amount: bigint,
140
+ exclude: string[] = []
141
+ ): { objectArray: string[]; remainCoins: CoinAsset[]; amountArray: string[] } {
142
+ const selectedResult = CoinUtils.selectCoinAssetGreaterThanOrEqual(coins, amount, exclude)
143
+ const objectArray = selectedResult.selectedCoins.map((item) => item.coinObjectId)
144
+ const remainCoins = selectedResult.remainingCoins
145
+ const amountArray = selectedResult.selectedCoins.map((item) => item.balance.toString())
146
+ return { objectArray, remainCoins, amountArray }
147
+ }
148
+
149
+ /**
150
+ * Select the CoinAsset objects from a list of CoinAsset objects that have a balance greater than or equal to a given amount.
151
+ *
152
+ * @param coins The list of CoinAsset objects to select from.
153
+ * @param amount The amount to select CoinAsset objects with a balance greater than or equal to.
154
+ * @param exclude A list of CoinAsset objects to exclude from the selection.
155
+ * @returns The CoinAsset objects that have a balance greater than or equal to the given amount.
156
+ */
157
+ static selectCoinAssetGreaterThanOrEqual(
158
+ coins: CoinAsset[],
159
+ amount: bigint,
160
+ exclude: string[] = []
161
+ ): { selectedCoins: CoinAsset[]; remainingCoins: CoinAsset[] } {
162
+ const sortedCoins = CoinUtils.sortByBalance(coins.filter((c) => !exclude.includes(c.coinObjectId)))
163
+
164
+ const total = CoinUtils.calculateTotalBalance(sortedCoins)
165
+
166
+ if (total < amount) {
167
+ return { selectedCoins: [], remainingCoins: sortedCoins }
168
+ }
169
+ if (total === amount) {
170
+ return { selectedCoins: sortedCoins, remainingCoins: [] }
171
+ }
172
+
173
+ let sum = BigInt(0)
174
+ const selectedCoins = []
175
+ const remainingCoins = [...sortedCoins]
176
+ while (sum < total) {
177
+ const target = amount - sum
178
+ const coinWithSmallestSufficientBalanceIndex = remainingCoins.findIndex((c) => c.balance >= target)
179
+ if (coinWithSmallestSufficientBalanceIndex !== -1) {
180
+ selectedCoins.push(remainingCoins[coinWithSmallestSufficientBalanceIndex])
181
+ remainingCoins.splice(coinWithSmallestSufficientBalanceIndex, 1)
182
+ break
183
+ }
184
+
185
+ const coinWithLargestBalance = remainingCoins.pop()!
186
+ if (coinWithLargestBalance.balance > 0) {
187
+ selectedCoins.push(coinWithLargestBalance)
188
+ sum += coinWithLargestBalance.balance
189
+ }
190
+ }
191
+ return { selectedCoins: CoinUtils.sortByBalance(selectedCoins), remainingCoins: CoinUtils.sortByBalance(remainingCoins) }
192
+ }
193
+
194
+ /**
195
+ * Sort the CoinAsset objects by their balance.
196
+ *
197
+ * @param coins The CoinAsset objects to sort.
198
+ * @returns The sorted CoinAsset objects.
199
+ */
200
+ static sortByBalance(coins: CoinAsset[]): CoinAsset[] {
201
+ return coins.sort((a, b) => (a.balance < b.balance ? -1 : a.balance > b.balance ? 1 : 0))
202
+ }
203
+
204
+ static sortByBalanceDes(coins: CoinAsset[]): CoinAsset[] {
205
+ return coins.sort((a, b) => (a.balance > b.balance ? -1 : a.balance < b.balance ? 0 : 1))
206
+ }
207
+
208
+ /**
209
+ * Calculate the total balance of a list of CoinAsset objects.
210
+ *
211
+ * @param coins The list of CoinAsset objects to calculate the total balance for.
212
+ * @returns The total balance of the CoinAsset objects.
213
+ */
214
+ static calculateTotalBalance(coins: CoinAsset[]): bigint {
215
+ return coins.reduce((partialSum, c) => partialSum + c.balance, BigInt(0))
216
+ }
217
+ }
@@ -0,0 +1,148 @@
1
+ import type { TransactionArgument } from '@mysten/sui/transactions'
2
+ import Decimal from 'decimal.js'
3
+ import { TypesErrorCode } from '../errors'
4
+
5
+ /**
6
+ * Represents a SUI address, which is a string.
7
+ */
8
+ export type SuiAddress = string
9
+
10
+ /**
11
+ * Represents a SUI object identifier, which is a string.
12
+ */
13
+ export type SuiObjectIdType = string
14
+
15
+ /**
16
+ * Represents a BigNumber, which can be a Decimal.Value, number, or string.
17
+ */
18
+ export type BigNumber = Decimal.Value | number | string
19
+
20
+
21
+ /**
22
+ * Represents a SUI resource, which can be of any type.
23
+ */
24
+ export type SuiResource = any
25
+
26
+ /**
27
+ * Represents a Non-Fungible Token (NFT) with associated metadata.
28
+ */
29
+ export type NFT = {
30
+ /**
31
+ * The address or identifier of the creator of the NFT.
32
+ */
33
+ creator: string
34
+
35
+ /**
36
+ * A description providing additional information about the NFT.
37
+ */
38
+ description: string
39
+
40
+ /**
41
+ * The URL to the image representing the NFT visually.
42
+ */
43
+ image_url: string
44
+
45
+ /**
46
+ * A link associated with the NFT, providing more details or interactions.
47
+ */
48
+ link: string
49
+
50
+ /**
51
+ * The name or title of the NFT.
52
+ */
53
+ name: string
54
+
55
+ /**
56
+ * The URL to the project or collection associated with the NFT.
57
+ */
58
+ project_url: string
59
+ }
60
+
61
+ /**
62
+ * Represents a SUI struct tag.
63
+ */
64
+ export type SuiStructTag = {
65
+ /**
66
+ * The full address of the struct.
67
+ */
68
+ full_address: string
69
+
70
+ /**
71
+ * The source address of the struct.
72
+ */
73
+ source_address: string
74
+
75
+ /**
76
+ * The address of the struct.
77
+ */
78
+ address: SuiAddress
79
+
80
+ /**
81
+ * The module to which the struct belongs.
82
+ */
83
+ module: string
84
+
85
+ /**
86
+ * The name of the struct.
87
+ */
88
+ name: string
89
+
90
+ /**
91
+ * An array of type arguments (SUI addresses) for the struct.
92
+ */
93
+ type_arguments: SuiAddress[]
94
+ }
95
+
96
+ /**
97
+ * Represents basic SUI data types.
98
+ */
99
+ export type SuiBasicTypes = 'address' | 'bool' | 'u8' | 'u16' | 'u32' | 'u64' | 'u128' | 'u256'
100
+
101
+ /**
102
+ * Represents a SUI transaction argument, which can be of various types.
103
+ */
104
+ export type SuiTxArg = TransactionArgument | string | number | bigint | boolean
105
+
106
+ /**
107
+ * Represents input types for SUI data.
108
+ */
109
+ export type SuiInputTypes = 'object' | SuiBasicTypes
110
+
111
+ /**
112
+ * Gets the default SUI input type based on the provided value.
113
+ * @param value - The value to determine the default input type for.
114
+ * @returns The default SUI input type.
115
+ * @throws Error if the type of the value is unknown.
116
+ */
117
+ export const getDefaultSuiInputType = (value: any): SuiInputTypes => {
118
+ if (typeof value === 'string' && value.startsWith('0x')) {
119
+ return 'object'
120
+ }
121
+ if (typeof value === 'number' || typeof value === 'bigint') {
122
+ return 'u64'
123
+ }
124
+ if (typeof value === 'boolean') {
125
+ return 'bool'
126
+ }
127
+ throw new AggregateError(`Unknown type for value: ${value}`, TypesErrorCode.InvalidType)
128
+ }
129
+
130
+ /**
131
+ * Represents a coin asset with address, object ID, and balance information.
132
+ */
133
+ export type CoinAsset = {
134
+ /**
135
+ * The address type of the coin asset.
136
+ */
137
+ coinAddress: SuiAddress
138
+
139
+ /**
140
+ * The object identifier of the coin asset.
141
+ */
142
+ coinObjectId: SuiObjectIdType
143
+
144
+ /**
145
+ * The balance amount of the coin asset.
146
+ */
147
+ balance: bigint
148
+ }
@@ -0,0 +1,62 @@
1
+ import { SuiClient } from "@mysten/sui/client"
2
+ import { DEEPBOOK_CLOB_V2_MODULE, DEEPBOOK_CUSTODIAN_V2_MODULE, DEEPBOOK_PACKAGE_ID, DEEPBOOK_PUBLISHED_AT } from "../const"
3
+ import { Transaction, TransactionObjectArgument } from "@mysten/sui/transactions"
4
+
5
+ export type GetOrCreateAccountCapResult = {
6
+ accountCap: TransactionObjectArgument,
7
+ isCreate: boolean
8
+ }
9
+
10
+ export async function getOrCreateAccountCap(txb: Transaction, client: SuiClient, owner: string): Promise<GetOrCreateAccountCapResult> {
11
+ let accountCapStr = await getAccountCap(client, owner)
12
+ if (accountCapStr !== null) {
13
+ return {
14
+ accountCap: txb.object(accountCapStr),
15
+ isCreate: false,
16
+ }
17
+ }
18
+
19
+ const accountCap = txb.moveCall({
20
+ target: `${DEEPBOOK_PUBLISHED_AT}::${DEEPBOOK_CLOB_V2_MODULE}::create_account`,
21
+ typeArguments: [],
22
+ arguments: [],
23
+ })
24
+
25
+ return {
26
+ accountCap,
27
+ isCreate: true,
28
+ }
29
+ }
30
+
31
+ async function getAccountCap(client: SuiClient, owner: string): Promise<string | null> {
32
+ let limit = 50;
33
+ let cursor = null;
34
+
35
+ while (true) {
36
+ const ownedObjects: any = client.getOwnedObjects({
37
+ owner,
38
+ cursor,
39
+ limit,
40
+ filter: {
41
+ MoveModule: {
42
+ package: DEEPBOOK_PACKAGE_ID,
43
+ module: DEEPBOOK_CUSTODIAN_V2_MODULE,
44
+ }
45
+ }
46
+ })
47
+
48
+ if (ownedObjects != null && ownedObjects.data != null) {
49
+ if (ownedObjects.data.length !== 0) {
50
+ return ownedObjects.data[0].data.objectId
51
+ }
52
+
53
+ if (ownedObjects.data.length < 50) {
54
+ break
55
+ }
56
+ } else {
57
+ break
58
+ }
59
+ }
60
+
61
+ return null
62
+ }
@@ -0,0 +1,10 @@
1
+ import { parseTurbosPoolFeeType } from "./coin"
2
+
3
+ describe("Coin Utils", () => {
4
+ it("should fetch token infos by URL and return data", async () => {
5
+ const typeDate =
6
+ "0x91bfbc386a41afcfd9b2533058d7e915a1d3829089cc268ff4333d54d6339ca1::pool::Pool<0xc91acfb75009c5ff2fd57c54f3caaee12ad1fbe997681334adc0b574fc277a07::icorgi::ICORGI, 0x2::sui::SUI, 0x91bfbc386a41afcfd9b2533058d7e915a1d3829089cc268ff4333d54d6339ca1::fee10000bps::FEE10000BPS>"
7
+ const result = parseTurbosPoolFeeType(typeDate)
8
+ console.log("parse turbos pool type", result)
9
+ })
10
+ })