@cetusprotocol/aggregator-sdk 0.0.0-experimental-20240719182939

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 +0 -0
  3. package/bun.lockb +0 -0
  4. package/dist/index.d.mts +267 -0
  5. package/dist/index.d.ts +267 -0
  6. package/dist/index.js +6824 -0
  7. package/dist/index.mjs +6745 -0
  8. package/dist/src/client.d.ts +88 -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 +393 -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 +142 -0
  45. package/src/transaction/cetus.ts +281 -0
  46. package/src/transaction/common.ts +169 -0
  47. package/src/transaction/deepbook.ts +126 -0
  48. package/src/transaction/flowx.ts +97 -0
  49. package/src/transaction/index.ts +1 -0
  50. package/src/transaction/kriya.ts +77 -0
  51. package/src/transaction/router.ts +341 -0
  52. package/src/transaction/swap.ts +164 -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 +255 -0
  63. package/tests/wallet.test.ts +21 -0
  64. package/tsconfig.json +22 -0
  65. package/tsup.config.ts +23 -0
  66. package/version.mjs +28 -0
package/src/errors.ts ADDED
@@ -0,0 +1,44 @@
1
+ export enum TypesErrorCode {
2
+ InvalidType = `InvalidType`,
3
+ }
4
+
5
+ export enum ConfigErrorCode {
6
+ MissAggregatorPackage = `MissAggregatorPackage`,
7
+ MissGlobalConfig = `MissGlobalConfig`,
8
+ InvalidWallet = `InvalidWallet`,
9
+ SimulateError = `SimulateError`,
10
+ }
11
+
12
+ export enum TransactionErrorCode {
13
+ InsufficientBalance = `InsufficientBalance`,
14
+ SimulateEventError = `simulateEventError`,
15
+ CannotGetDecimals = `CannotGetDecimals`,
16
+ MissCoinA = `MissCoinA`,
17
+ MissCoinB = `MissCoinB`,
18
+ MissTurbosFeeType = `MissTurbosFeeType`,
19
+ MissAftermathLpSupplyType = `MissAftermathLpSupplyType`,
20
+ }
21
+
22
+ export type AggregatorErrorCode = TypesErrorCode
23
+
24
+ /**
25
+ * AggregatorError is a custom error class that extends the built-in Error class. It is used to represent errors that occur during aggregation operations.
26
+ * The key functionality of this code includes:
27
+ * - Defining the AggregatorError class that represents an error during aggregation. It includes a message property and an optional errorCode property.
28
+ * - Providing a static method isAggregatorErrorCode() that checks if a given error instance is an instance of AggregatorError and has a specific error code.
29
+ */
30
+ export class AggregatorError extends Error {
31
+ override message: string
32
+
33
+ errorCode?: AggregatorErrorCode
34
+
35
+ constructor(message: string, errorCode?: AggregatorErrorCode) {
36
+ super(message)
37
+ this.message = message
38
+ this.errorCode = errorCode
39
+ }
40
+
41
+ static isAggregatorErrorCode(e: any, code: AggregatorErrorCode): boolean {
42
+ return e instanceof AggregatorError && e.errorCode === code
43
+ }
44
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './client'
2
+ export * from './transaction'
3
+ export * from './config'
4
+ export * from './utils'
5
+ export * from './const'
package/src/math.ts ADDED
@@ -0,0 +1,37 @@
1
+ // Calculate amount limit.
2
+ // If byAmountIn is true, the expectAmount means amountOut, otherwise means amountIn.
3
+ // `byAmountIn` means fixed amount in or out.
4
+
5
+ import BN from "bn.js"
6
+ import { ZERO } from "./const"
7
+ import Decimal from "decimal.js"
8
+
9
+ // `slippage` is a percentage, for example, 0.01 means 1%.
10
+ export function CalculateAmountLimit(expectAmount: BN, byAmountIn: boolean, slippage: number): number {
11
+ let amountLimit = ZERO
12
+ if (byAmountIn) {
13
+ amountLimit = expectAmount.muln(1 - slippage)
14
+ } else {
15
+ amountLimit = expectAmount.muln(1 + slippage)
16
+ }
17
+
18
+ return Number(amountLimit.toString())
19
+ }
20
+
21
+ const MAX_SQER_PRICE_X64 = '79226673515401279992447579055'
22
+ const MIN_SQER_PRICE_X64 = '4295048016'
23
+
24
+ export function GetDefaultSqrtPriceLimit(a2b: boolean): BN {
25
+ if (a2b) {
26
+ return new BN(MIN_SQER_PRICE_X64)
27
+ } else {
28
+ return new BN(MAX_SQER_PRICE_X64)
29
+ }
30
+ }
31
+
32
+ export function sqrtPriceX64ToPrice(sqrtPriceStr: string, decimalsA: number, decimalsB: number): Decimal {
33
+ const sqrtPriceX64 = new Decimal(sqrtPriceStr).mul(Decimal.pow(2, -64))
34
+ return sqrtPriceX64
35
+ .pow(2)
36
+ .mul(Decimal.pow(10, decimalsA - decimalsB))
37
+ }
@@ -0,0 +1,17 @@
1
+ // Testnet
2
+ export const T_USDC = ""
3
+
4
+ // Mainnet
5
+ export const M_USDC =
6
+ "0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN"
7
+ export const M_CETUS =
8
+ "0x06864a6f921804860930db6ddbe2e16acdf8504495ea7481637a1c8b9a8fe54b::cetus::CETUS"
9
+ export const M_NAVI =
10
+ "0xa99b8952d4f7d947ea77fe0ecdcc9e5fc0bcab2841d6e2a5aa00c3044e5544b5::navx::NAVX"
11
+ export const M_SUI = "0x2::sui::SUI"
12
+ export const M_VSUI =
13
+ "0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT"
14
+ export const M_VAPOR =
15
+ "0xa1f2c11169f32165ad4efb4468ec5bdfc880cd66b22094024b32ab7b76d14d30::vapor::VAPOR"
16
+ export const M_HASUI =
17
+ "0xbde4ba4c2e274a60ce15c1cfff9e5c42e41654ac8b6d906a57efa4bd3c29f47d::hasui::HASUI"
@@ -0,0 +1,142 @@
1
+ import {
2
+ TransactionArgument,
3
+ Transaction,
4
+ TransactionObjectArgument,
5
+ } from "@mysten/sui/transactions"
6
+ import { AggregatorConfig, ENV } from "../config"
7
+ import {
8
+ AFTERMATH_MODULE,
9
+ AGGREGATOR,
10
+ MAINNET_AFTERMATH_INSURANCE_FUND_ID,
11
+ MAINNET_AFTERMATH_PROTOCOL_FEE_VAULT_ID,
12
+ MAINNET_AFTERMATH_REFERRAL_VAULT_ID,
13
+ MAINNET_AFTERMATH_REGISTRY_ID,
14
+ MAINNET_AFTERMATH_TREASURY_ID,
15
+ SWAP_A2B_FUNC,
16
+ SWAP_B2A_FUNC,
17
+ TESTNET_AFTERMATH_INSURANCE_FUND_ID,
18
+ TESTNET_AFTERMATH_PROTOCOL_FEE_VAULT_ID,
19
+ TESTNET_AFTERMATH_REFERRAL_VAULT_ID,
20
+ TESTNET_AFTERMATH_REGISTRY_ID,
21
+ TESTNET_AFTERMATH_TREASURY_ID,
22
+ } from "../const"
23
+ import { ConfigErrorCode, TransactionErrorCode } from "../errors"
24
+ import { createTarget } from "../utils"
25
+
26
+ export type AftermathSwapParams = {
27
+ poolId: string
28
+ amount: TransactionArgument
29
+ amountOut: number
30
+ amountLimit: number
31
+ a2b: boolean
32
+ byAmountIn: boolean
33
+ coinA?: TransactionObjectArgument
34
+ coinB?: TransactionObjectArgument
35
+ useFullInputCoinAmount: boolean
36
+ coinAType: string
37
+ coinBType: string
38
+ slippage: number
39
+ lpSupplyType: string
40
+ }
41
+
42
+ export type AftermathSwapResult = {
43
+ targetCoin: TransactionObjectArgument
44
+ amountIn: TransactionArgument
45
+ amountOut: TransactionArgument
46
+ txb: Transaction
47
+ }
48
+
49
+ export async function AftermathAmmSwapMovecall(
50
+ swapParams: AftermathSwapParams,
51
+ txb: Transaction,
52
+ config: AggregatorConfig
53
+ ): Promise<AftermathSwapResult> {
54
+ const aggregatorPackage = config.getPackage(AGGREGATOR)
55
+ if (aggregatorPackage == null) {
56
+ throw new AggregateError(
57
+ "Aggregator package not set",
58
+ ConfigErrorCode.MissAggregatorPackage
59
+ )
60
+ }
61
+ const aggregatorPublishedAt = aggregatorPackage.publishedAt
62
+
63
+ if (swapParams.a2b) {
64
+ if (swapParams.coinA == null) {
65
+ throw new AggregateError(
66
+ "coinA is required",
67
+ TransactionErrorCode.MissCoinA
68
+ )
69
+ }
70
+ } else {
71
+ if (swapParams.coinB == null) {
72
+ throw new AggregateError(
73
+ "coinB is required",
74
+ TransactionErrorCode.MissCoinB
75
+ )
76
+ }
77
+ }
78
+
79
+ const poolRegistryID =
80
+ config.getENV() === ENV.MAINNET
81
+ ? MAINNET_AFTERMATH_REGISTRY_ID
82
+ : TESTNET_AFTERMATH_REGISTRY_ID
83
+
84
+ const vaultID =
85
+ config.getENV() === ENV.MAINNET
86
+ ? MAINNET_AFTERMATH_PROTOCOL_FEE_VAULT_ID
87
+ : TESTNET_AFTERMATH_PROTOCOL_FEE_VAULT_ID
88
+
89
+ const treasuryID =
90
+ config.getENV() === ENV.MAINNET
91
+ ? MAINNET_AFTERMATH_TREASURY_ID
92
+ : TESTNET_AFTERMATH_TREASURY_ID
93
+
94
+ const insuranceFundID =
95
+ config.getENV() === ENV.MAINNET
96
+ ? MAINNET_AFTERMATH_INSURANCE_FUND_ID
97
+ : TESTNET_AFTERMATH_INSURANCE_FUND_ID
98
+
99
+ const referrealVaultID =
100
+ config.getENV() === ENV.MAINNET
101
+ ? MAINNET_AFTERMATH_REFERRAL_VAULT_ID
102
+ : TESTNET_AFTERMATH_REFERRAL_VAULT_ID
103
+
104
+ const swapCoin = swapParams.a2b ? swapParams.coinA! : swapParams.coinB!
105
+
106
+ const slippageArg = (1 - swapParams.slippage) * 1000000000000000000
107
+
108
+ const args = [
109
+ txb.object(swapParams.poolId),
110
+ txb.object(poolRegistryID),
111
+ txb.object(vaultID),
112
+ txb.object(treasuryID),
113
+ txb.object(insuranceFundID),
114
+ txb.object(referrealVaultID),
115
+ swapParams.amount,
116
+ txb.pure.u64(swapParams.amountLimit),
117
+ txb.pure.u64(swapParams.amountOut),
118
+ txb.pure.u64(slippageArg),
119
+ swapCoin,
120
+ txb.pure.bool(swapParams.useFullInputCoinAmount),
121
+ ]
122
+
123
+ const func = swapParams.a2b ? SWAP_A2B_FUNC : SWAP_B2A_FUNC
124
+
125
+ const target = createTarget(aggregatorPublishedAt, AFTERMATH_MODULE, func)
126
+
127
+ const res = txb.moveCall({
128
+ target,
129
+ typeArguments: [
130
+ swapParams.coinAType,
131
+ swapParams.coinBType,
132
+ swapParams.lpSupplyType,
133
+ ],
134
+ arguments: args,
135
+ })
136
+ return {
137
+ targetCoin: res[0],
138
+ amountIn: res[1],
139
+ amountOut: res[2],
140
+ txb,
141
+ }
142
+ }
@@ -0,0 +1,281 @@
1
+ import {
2
+ Transaction,
3
+ TransactionArgument,
4
+ TransactionObjectArgument,
5
+ } from "@mysten/sui/transactions"
6
+ import { AggregatorConfig, ENV } from "../config"
7
+ import {
8
+ AGGREGATOR,
9
+ CLOCK_ADDRESS,
10
+ CETUS_MODULE,
11
+ FlashSwapA2BFunc,
12
+ MAINNET_CETUS_GLOBAL_CONFIG_ID,
13
+ TESTNET_CETUS_GLOBAL_CONFIG_ID,
14
+ FlashSwapWithPartnerA2BFunc,
15
+ FlashSwapWithPartnerB2AFunc,
16
+ FlashSwapB2AFunc,
17
+ REPAY_FLASH_SWAP_WITH_PARTNER_A2B_FUNC,
18
+ REPAY_FLASH_SWAP_WITH_PARTNER_B2A_FUNC,
19
+ REPAY_FLASH_SWAP_A2B_FUNC,
20
+ REPAY_FLASH_SWAP_B2A_FUNC,
21
+ } from "../const"
22
+ import { ConfigErrorCode, TransactionErrorCode } from "../errors"
23
+ import BN from "bn.js"
24
+ import { createTarget } from "../utils"
25
+
26
+ export type CetusSwapParams = {
27
+ poolId: string
28
+ amount: TransactionArgument
29
+ amountLimit: string
30
+ a2b: boolean
31
+ byAmountIn: boolean
32
+ sqrtPriceLimit: BN
33
+ partner?: string
34
+ coinAType: string
35
+ coinBType: string
36
+ }
37
+
38
+ export type CetusFlashSwapResult = {
39
+ targetCoin: TransactionObjectArgument
40
+ flashReceipt: TransactionObjectArgument
41
+ payAmount: TransactionArgument
42
+ swapedAmount: TransactionArgument
43
+ txb: Transaction
44
+ }
45
+
46
+ export function cetusFlashSwapMovecall(
47
+ swapParams: CetusSwapParams,
48
+ txb: Transaction,
49
+ config: AggregatorConfig
50
+ ): CetusFlashSwapResult {
51
+ const aggregatorPackage = config.getPackage(AGGREGATOR)
52
+ if (aggregatorPackage == null) {
53
+ throw new AggregateError(
54
+ "Aggregator package not set",
55
+ ConfigErrorCode.MissAggregatorPackage
56
+ )
57
+ }
58
+ const aggregatorPublishedAt = aggregatorPackage.publishedAt
59
+
60
+ const globalConfigId =
61
+ config.getENV() === ENV.MAINNET
62
+ ? MAINNET_CETUS_GLOBAL_CONFIG_ID
63
+ : TESTNET_CETUS_GLOBAL_CONFIG_ID
64
+
65
+ const hasPartner = swapParams.partner != null && swapParams.partner.length > 0
66
+
67
+ const args = hasPartner
68
+ ? [
69
+ txb.object(globalConfigId),
70
+ txb.object(swapParams.poolId),
71
+ swapParams.amount,
72
+ txb.pure.u64(swapParams.amountLimit),
73
+ txb.pure.bool(swapParams.byAmountIn),
74
+ txb.pure.u128(swapParams.sqrtPriceLimit.toString()),
75
+ txb.object(swapParams.partner!.toString()),
76
+ txb.object(CLOCK_ADDRESS),
77
+ ]
78
+ : [
79
+ txb.object(globalConfigId),
80
+ txb.object(swapParams.poolId),
81
+ swapParams.amount,
82
+ txb.pure.u64(swapParams.amountLimit),
83
+ txb.pure.bool(swapParams.byAmountIn),
84
+ txb.pure.u128(swapParams.sqrtPriceLimit.toString()),
85
+ txb.object(CLOCK_ADDRESS),
86
+ ]
87
+
88
+ let func
89
+ if (hasPartner) {
90
+ if (swapParams.a2b) {
91
+ func = FlashSwapWithPartnerA2BFunc
92
+ } else {
93
+ func = FlashSwapWithPartnerB2AFunc
94
+ }
95
+ } else {
96
+ if (swapParams.a2b) {
97
+ func = FlashSwapA2BFunc
98
+ } else {
99
+ func = FlashSwapB2AFunc
100
+ }
101
+ }
102
+
103
+ const target = createTarget(aggregatorPublishedAt, CETUS_MODULE, func)
104
+
105
+ const moveCallRes = txb.moveCall({
106
+ target,
107
+ typeArguments: [swapParams.coinAType, swapParams.coinBType],
108
+ arguments: args,
109
+ })
110
+
111
+ return {
112
+ targetCoin: moveCallRes[0],
113
+ flashReceipt: moveCallRes[1],
114
+ payAmount: moveCallRes[2],
115
+ swapedAmount: moveCallRes[3],
116
+ txb,
117
+ }
118
+ }
119
+
120
+ export type repayParams = {
121
+ poolId: string
122
+ a2b: boolean
123
+ coinA?: TransactionObjectArgument
124
+ coinB?: TransactionObjectArgument
125
+ receipt: TransactionObjectArgument
126
+ coinAType: string
127
+ coinBType: string
128
+ partner?: string
129
+ }
130
+
131
+ export type SwapResult = {
132
+ repayTargetCoin: TransactionObjectArgument
133
+ nextInputAmount?: TransactionArgument
134
+ flashTargetCoin?: TransactionObjectArgument
135
+ }
136
+
137
+ export async function cetusRepayFlashSwapMovecall(
138
+ repayParams: repayParams,
139
+ txb: Transaction,
140
+ config: AggregatorConfig
141
+ ): Promise<SwapResult> {
142
+ const aggregatorPackage = config.getPackage(AGGREGATOR)
143
+ if (aggregatorPackage == null) {
144
+ throw new AggregateError(
145
+ "Aggregator package not set",
146
+ ConfigErrorCode.MissAggregatorPackage
147
+ )
148
+ }
149
+ const aggregatorPublishedAt = aggregatorPackage.publishedAt
150
+
151
+ const globalConfigId =
152
+ config.getENV() === ENV.MAINNET
153
+ ? MAINNET_CETUS_GLOBAL_CONFIG_ID
154
+ : TESTNET_CETUS_GLOBAL_CONFIG_ID
155
+
156
+ const hasPartner =
157
+ repayParams.partner != null && repayParams.partner.length > 0
158
+
159
+ if (repayParams.a2b) {
160
+ if (repayParams.coinA == null) {
161
+ throw new AggregateError(
162
+ "coinA is required",
163
+ TransactionErrorCode.MissCoinA
164
+ )
165
+ }
166
+ } else {
167
+ if (repayParams.coinB == null) {
168
+ throw new AggregateError(
169
+ "coinB is required",
170
+ TransactionErrorCode.MissCoinB
171
+ )
172
+ }
173
+ }
174
+
175
+ let args
176
+ if (hasPartner) {
177
+ if (repayParams.a2b) {
178
+ args = [
179
+ txb.object(globalConfigId),
180
+ txb.object(repayParams.poolId),
181
+ repayParams.coinA!,
182
+ repayParams.receipt,
183
+ txb.object(repayParams.partner!),
184
+ ]
185
+ } else {
186
+ args = [
187
+ txb.object(globalConfigId),
188
+ txb.object(repayParams.poolId),
189
+ repayParams.coinB!,
190
+ repayParams.receipt,
191
+ txb.object(repayParams.partner!),
192
+ ]
193
+ }
194
+ } else {
195
+ if (repayParams.a2b) {
196
+ args = [
197
+ txb.object(globalConfigId),
198
+ txb.object(repayParams.poolId),
199
+ repayParams.coinA!,
200
+ repayParams.receipt,
201
+ ]
202
+ } else {
203
+ args = [
204
+ txb.object(globalConfigId),
205
+ txb.object(repayParams.poolId),
206
+ repayParams.coinB!,
207
+ repayParams.receipt,
208
+ ]
209
+ }
210
+ }
211
+
212
+ let func
213
+ if (hasPartner) {
214
+ if (repayParams.a2b) {
215
+ func = REPAY_FLASH_SWAP_WITH_PARTNER_A2B_FUNC
216
+ } else {
217
+ func = REPAY_FLASH_SWAP_WITH_PARTNER_B2A_FUNC
218
+ }
219
+ } else {
220
+ if (repayParams.a2b) {
221
+ func = REPAY_FLASH_SWAP_A2B_FUNC
222
+ } else {
223
+ func = REPAY_FLASH_SWAP_B2A_FUNC
224
+ }
225
+ }
226
+
227
+ const target = createTarget(aggregatorPublishedAt, CETUS_MODULE, func)
228
+
229
+ const res: TransactionObjectArgument[] = txb.moveCall({
230
+ target,
231
+ typeArguments: [repayParams.coinAType, repayParams.coinBType],
232
+ arguments: args,
233
+ })
234
+
235
+ return {
236
+ repayTargetCoin: res[0],
237
+ }
238
+ }
239
+
240
+ export async function cetusSwapWithOutLimit(
241
+ swapParams: CetusSwapParams,
242
+ fromCoin: TransactionObjectArgument,
243
+ txb: Transaction,
244
+ config: AggregatorConfig
245
+ ): Promise<SwapResult> {
246
+ const flashResult = cetusFlashSwapMovecall(swapParams, txb, config)
247
+
248
+ const repayCoinA = swapParams.a2b ? fromCoin : undefined
249
+ const repayCoinB = swapParams.a2b ? undefined : fromCoin
250
+
251
+ const repayParams = {
252
+ poolId: swapParams.poolId,
253
+ a2b: swapParams.a2b,
254
+ coinA: repayCoinA,
255
+ coinB: repayCoinB,
256
+ receipt: flashResult.flashReceipt,
257
+ coinAType: swapParams.coinAType,
258
+ coinBType: swapParams.coinBType,
259
+ partner: swapParams.partner,
260
+ }
261
+
262
+ let nextInputAmount: TransactionArgument
263
+
264
+ if (swapParams.byAmountIn) {
265
+ nextInputAmount = flashResult.swapedAmount
266
+ } else {
267
+ nextInputAmount = flashResult.payAmount
268
+ }
269
+
270
+ const repayResult = await cetusRepayFlashSwapMovecall(
271
+ repayParams,
272
+ txb,
273
+ config
274
+ )
275
+
276
+ return {
277
+ flashTargetCoin: flashResult.targetCoin,
278
+ repayTargetCoin: repayResult.repayTargetCoin,
279
+ nextInputAmount,
280
+ }
281
+ }
@@ -0,0 +1,169 @@
1
+ import {
2
+ AGGREGATOR,
3
+ CHECK_COINS_THRESHOLD_FUNC,
4
+ JOIN_FUNC,
5
+ PAY_MODULE,
6
+ SuiZeroCoinFn,
7
+ TRANSFER_OR_DESTORY_COIN_FUNC,
8
+ UTILS_MODULE,
9
+ } from "../const"
10
+ import { CoinAsset } from "../types/sui"
11
+ import { CoinUtils } from "../types/CoinAssist"
12
+ import { ConfigErrorCode, TransactionErrorCode } from "../errors"
13
+ import { createTarget } from "../utils"
14
+ import { AggregatorConfig } from "../config"
15
+ import {
16
+ Transaction,
17
+ TransactionArgument,
18
+ TransactionObjectArgument,
19
+ } from "@mysten/sui/transactions"
20
+ import { SUI_FRAMEWORK_ADDRESS } from "@mysten/sui/utils"
21
+
22
+ export function mintZeroCoin(
23
+ txb: Transaction,
24
+ coinType: string
25
+ ): TransactionObjectArgument {
26
+ return txb.moveCall({
27
+ target: SuiZeroCoinFn,
28
+ typeArguments: [coinType],
29
+ })
30
+ }
31
+
32
+ export type BuildCoinResult = {
33
+ targetCoin: TransactionObjectArgument
34
+ isMintZeroCoin: boolean
35
+ targetCoinAmount: number
36
+ }
37
+
38
+ export function buildInputCoin(
39
+ txb: Transaction,
40
+ allCoins: CoinAsset[],
41
+ amount: bigint,
42
+ coinType: string
43
+ ): BuildCoinResult {
44
+ const usedCoinAsests = CoinUtils.getCoinAssets(coinType, allCoins)
45
+ if (amount === BigInt(0) && usedCoinAsests.length === 0) {
46
+ const zeroCoin = mintZeroCoin(txb, coinType)
47
+ return {
48
+ targetCoin: zeroCoin,
49
+ isMintZeroCoin: true,
50
+ targetCoinAmount: 0,
51
+ }
52
+ }
53
+
54
+ if (CoinUtils.isSuiCoin(coinType)) {
55
+ const resultCoin = txb.splitCoins(txb.gas, [
56
+ txb.pure.u64(amount.toString()),
57
+ ])
58
+ return {
59
+ targetCoin: resultCoin,
60
+ isMintZeroCoin: true,
61
+ targetCoinAmount: Number(amount.toString()),
62
+ }
63
+ }
64
+
65
+ let totalCoinBalance = CoinUtils.calculateTotalBalance(usedCoinAsests)
66
+ if (totalCoinBalance < amount) {
67
+ throw new AggregateError(
68
+ "Insufficient balance when build merge coin",
69
+ TransactionErrorCode.InsufficientBalance
70
+ )
71
+ }
72
+
73
+ // sort used coin by amount, asc
74
+ let sortCoinAssets = CoinUtils.sortByBalance(usedCoinAsests)
75
+
76
+ // find first three coin if greater than amount
77
+ let totalThreeCoinBalance = sortCoinAssets
78
+ .slice(0, 3)
79
+ .reduce((acc, coin) => acc + coin.balance, BigInt(0))
80
+ if (totalThreeCoinBalance < BigInt(amount)) {
81
+ sortCoinAssets = CoinUtils.sortByBalanceDes(usedCoinAsests)
82
+ }
83
+
84
+ let selectedCoinResult = CoinUtils.selectCoinObjectIdGreaterThanOrEqual(
85
+ sortCoinAssets,
86
+ amount
87
+ )
88
+ const [masterCoin, ...mergedCoin] = selectedCoinResult.objectArray
89
+
90
+ if (mergedCoin.length > 0) {
91
+ txb.mergeCoins(
92
+ masterCoin,
93
+ mergedCoin.map((coin) => txb.object(coin))
94
+ )
95
+ }
96
+
97
+ return {
98
+ targetCoin: txb.object(masterCoin),
99
+ isMintZeroCoin: false,
100
+ targetCoinAmount: Number(amount.toString()),
101
+ }
102
+ }
103
+
104
+ export function transferOrDestoryCoin(
105
+ txb: Transaction,
106
+ coinObject: TransactionObjectArgument,
107
+ coinType: string,
108
+ config: AggregatorConfig
109
+ ) {
110
+ const aggregatorPackage = config.getPackage(AGGREGATOR)
111
+ if (aggregatorPackage == null) {
112
+ throw new AggregateError(
113
+ "Aggregator package not set",
114
+ ConfigErrorCode.MissAggregatorPackage
115
+ )
116
+ }
117
+ const aggregatorPublishedAt = aggregatorPackage.publishedAt
118
+
119
+ txb.moveCall({
120
+ target: createTarget(
121
+ aggregatorPublishedAt,
122
+ UTILS_MODULE,
123
+ TRANSFER_OR_DESTORY_COIN_FUNC
124
+ ),
125
+ typeArguments: [coinType],
126
+ arguments: [coinObject],
127
+ })
128
+ }
129
+
130
+ export function checkCoinThresholdAndMergeCoin(
131
+ txb: Transaction,
132
+ coins: TransactionObjectArgument[],
133
+ coinType: string,
134
+ amountLimit: number,
135
+ config: AggregatorConfig
136
+ ): TransactionArgument {
137
+ const aggregatorPackage = config.getPackage(AGGREGATOR)
138
+ if (aggregatorPackage == null) {
139
+ throw new AggregateError(
140
+ "Aggregator package not set",
141
+ ConfigErrorCode.MissAggregatorPackage
142
+ )
143
+ }
144
+ const aggregatorPublishedAt = aggregatorPackage.publishedAt
145
+
146
+ const vec = txb.makeMoveVec({
147
+ elements: coins,
148
+ })
149
+
150
+ txb.moveCall({
151
+ target: createTarget(
152
+ aggregatorPublishedAt,
153
+ UTILS_MODULE,
154
+ CHECK_COINS_THRESHOLD_FUNC
155
+ ),
156
+ typeArguments: [coinType],
157
+ arguments: [vec, txb.pure.u64(amountLimit)],
158
+ })
159
+
160
+ const zeroCoin = mintZeroCoin(txb, coinType)
161
+
162
+ txb.moveCall({
163
+ target: createTarget(SUI_FRAMEWORK_ADDRESS, PAY_MODULE, JOIN_FUNC),
164
+ typeArguments: [coinType],
165
+ arguments: [zeroCoin, vec],
166
+ })
167
+
168
+ return zeroCoin
169
+ }