@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,126 @@
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
+ DEEPBOOK_MODULE,
11
+ SWAP_A2B_FUNC,
12
+ SWAP_B2A_FUNC,
13
+ TRANSFER_ACCOUNT_CAP,
14
+ } from "../const"
15
+ import { ConfigErrorCode, TransactionErrorCode } from "../errors"
16
+ import { createTarget } from "../utils"
17
+ import { getOrCreateAccountCap } from "../utils/account_cap"
18
+ import { SuiClient } from "@mysten/sui/client"
19
+
20
+ export type DeepbookSwapParams = {
21
+ poolId: string
22
+ a2b: boolean
23
+ amount: TransactionArgument
24
+ amountLimit: number
25
+ coinA?: TransactionObjectArgument
26
+ coinB?: TransactionObjectArgument
27
+ useFullInputCoinAmount: boolean
28
+ coinAType: string
29
+ coinBType: string
30
+ }
31
+
32
+ export type DeepbookSwapResult = {
33
+ targetCoin: TransactionObjectArgument
34
+ amountIn: TransactionArgument
35
+ amountOut: TransactionArgument
36
+ txb: Transaction
37
+ }
38
+
39
+ export async function deepbookSwapMovecall(
40
+ swapParams: DeepbookSwapParams,
41
+ client: SuiClient,
42
+ txb: Transaction,
43
+ config: AggregatorConfig
44
+ ): Promise<DeepbookSwapResult> {
45
+ const accountCapRes = await getOrCreateAccountCap(
46
+ txb,
47
+ client,
48
+ config.getWallet()
49
+ )
50
+ const accountCap = accountCapRes.accountCap
51
+
52
+ const aggregatorPackage = config.getPackage(AGGREGATOR)
53
+ if (aggregatorPackage == null) {
54
+ throw new AggregateError(
55
+ "Aggregator package not set",
56
+ ConfigErrorCode.MissAggregatorPackage
57
+ )
58
+ }
59
+ const aggregatorPublishedAt = aggregatorPackage.publishedAt
60
+
61
+ if (swapParams.a2b) {
62
+ if (swapParams.coinA == null) {
63
+ throw new AggregateError(
64
+ "coinA is required",
65
+ TransactionErrorCode.MissCoinA
66
+ )
67
+ }
68
+ } else {
69
+ if (swapParams.coinB == null) {
70
+ throw new AggregateError(
71
+ "coinB is required",
72
+ TransactionErrorCode.MissCoinB
73
+ )
74
+ }
75
+ }
76
+
77
+ const args = swapParams.a2b
78
+ ? [
79
+ txb.object(swapParams.poolId),
80
+ swapParams.amount,
81
+ txb.pure.u64(swapParams.amountLimit),
82
+ swapParams.coinA!,
83
+ accountCap,
84
+ txb.pure.bool(swapParams.useFullInputCoinAmount),
85
+ txb.object(CLOCK_ADDRESS),
86
+ ]
87
+ : [
88
+ txb.object(swapParams.poolId),
89
+ swapParams.amount,
90
+ txb.pure.u64(swapParams.amountLimit),
91
+ swapParams.coinB!,
92
+ accountCap,
93
+ txb.pure.bool(swapParams.useFullInputCoinAmount),
94
+ txb.object(CLOCK_ADDRESS),
95
+ ]
96
+
97
+ let func = swapParams.a2b ? SWAP_A2B_FUNC : SWAP_B2A_FUNC
98
+ const target = createTarget(aggregatorPublishedAt, DEEPBOOK_MODULE, func)
99
+
100
+ const res = txb.moveCall({
101
+ target,
102
+ typeArguments: [swapParams.coinAType, swapParams.coinBType],
103
+ arguments: args,
104
+ })
105
+
106
+ if (accountCapRes.isCreate) {
107
+ const target = createTarget(
108
+ aggregatorPublishedAt,
109
+ DEEPBOOK_MODULE,
110
+ TRANSFER_ACCOUNT_CAP
111
+ )
112
+
113
+ const res = txb.moveCall({
114
+ target,
115
+ typeArguments: [],
116
+ arguments: [accountCap],
117
+ })
118
+ }
119
+
120
+ return {
121
+ targetCoin: res[0],
122
+ amountIn: res[1],
123
+ amountOut: res[2],
124
+ txb,
125
+ }
126
+ }
@@ -0,0 +1,98 @@
1
+ import {
2
+ TransactionArgument,
3
+ Transaction,
4
+ TransactionObjectArgument,
5
+ } from "@mysten/sui/transactions"
6
+ import { AggregatorConfig, ENV } from "../config"
7
+ import {
8
+ AGGREGATOR,
9
+ FLOWX_AMM_MODULE,
10
+ MAINNET_FLOWX_AMM_CONTAINER_ID,
11
+ SWAP_A2B_FUNC,
12
+ SWAP_B2A_FUNC,
13
+ TESTNET_FLOWX_AMM_CONTAINER_ID,
14
+ } from "../const"
15
+ import { ConfigErrorCode, TransactionErrorCode } from "../errors"
16
+ import { createTarget } from "../utils"
17
+
18
+ export type FlowxSwapParams = {
19
+ amount: TransactionArgument
20
+ amountLimit: number
21
+ a2b: boolean
22
+ byAmountIn: boolean
23
+ coinA?: TransactionObjectArgument
24
+ coinB?: TransactionObjectArgument
25
+ useFullInputCoinAmount: boolean
26
+ coinAType: string
27
+ coinBType: string
28
+ }
29
+
30
+ export type FlowxSwapResult = {
31
+ targetCoin: TransactionObjectArgument
32
+ amountIn: TransactionArgument
33
+ amountOut: TransactionArgument
34
+ txb: Transaction
35
+ }
36
+
37
+ export async function flowxAmmSwapMovecall(
38
+ swapParams: FlowxSwapParams,
39
+ txb: Transaction,
40
+ config: AggregatorConfig
41
+ ): Promise<FlowxSwapResult> {
42
+ console.log("flowx amm swap param", swapParams)
43
+ const aggregatorPackage = config.getPackage(AGGREGATOR)
44
+ if (aggregatorPackage == null) {
45
+ throw new AggregateError(
46
+ "Aggregator package not set",
47
+ ConfigErrorCode.MissAggregatorPackage
48
+ )
49
+ }
50
+ const aggregatorPublishedAt = aggregatorPackage.publishedAt
51
+
52
+ if (swapParams.a2b) {
53
+ if (swapParams.coinA == null) {
54
+ throw new AggregateError(
55
+ "coinA is required",
56
+ TransactionErrorCode.MissCoinA
57
+ )
58
+ }
59
+ } else {
60
+ if (swapParams.coinB == null) {
61
+ throw new AggregateError(
62
+ "coinB is required",
63
+ TransactionErrorCode.MissCoinB
64
+ )
65
+ }
66
+ }
67
+
68
+ const containerID =
69
+ config.getENV() === ENV.MAINNET
70
+ ? MAINNET_FLOWX_AMM_CONTAINER_ID
71
+ : TESTNET_FLOWX_AMM_CONTAINER_ID
72
+
73
+ const swapCoin = swapParams.a2b ? swapParams.coinA! : swapParams.coinB!
74
+
75
+ const args = [
76
+ txb.object(containerID),
77
+ swapParams.amount,
78
+ txb.pure.u64(swapParams.amountLimit),
79
+ swapCoin,
80
+ txb.pure.bool(swapParams.useFullInputCoinAmount),
81
+ ]
82
+
83
+ const func = swapParams.a2b ? SWAP_A2B_FUNC : SWAP_B2A_FUNC
84
+
85
+ const target = createTarget(aggregatorPublishedAt, FLOWX_AMM_MODULE, func)
86
+
87
+ const res = txb.moveCall({
88
+ target,
89
+ typeArguments: [swapParams.coinAType, swapParams.coinBType],
90
+ arguments: args,
91
+ })
92
+ return {
93
+ targetCoin: res[0],
94
+ amountIn: res[1],
95
+ amountOut: res[2],
96
+ txb,
97
+ }
98
+ }
@@ -0,0 +1 @@
1
+ export * from "./router"
@@ -0,0 +1,77 @@
1
+ import { TransactionArgument, Transaction, TransactionObjectArgument } from "@mysten/sui/transactions"
2
+ import { AggregatorConfig } from "../config"
3
+ import { AGGREGATOR, KRIYA_MODULE, SWAP_A2B_FUNC, SWAP_B2A_FUNC } from "../const"
4
+ import { ConfigErrorCode, TransactionErrorCode } from "../errors"
5
+ import { createTarget } from "../utils"
6
+
7
+ export type KriyaSwapParams = {
8
+ poolId: string
9
+ amount: TransactionArgument
10
+ amountLimit: number
11
+ a2b: boolean
12
+ byAmountIn: boolean
13
+ coinA?: TransactionObjectArgument
14
+ coinB?: TransactionObjectArgument
15
+ useFullInputCoinAmount: boolean
16
+ coinAType: string
17
+ coinBType: string
18
+ }
19
+
20
+ export type KriyaSwapResult = {
21
+ targetCoin: TransactionObjectArgument
22
+ amountIn: TransactionArgument
23
+ amountOut: TransactionArgument
24
+ txb: Transaction
25
+ }
26
+
27
+ export async function kriyaSwapMovecall(
28
+ swapParams: KriyaSwapParams,
29
+ txb: Transaction,
30
+ config: AggregatorConfig,
31
+ ): Promise<KriyaSwapResult> {
32
+ const aggregatorPackage = config.getPackage(AGGREGATOR)
33
+ if (aggregatorPackage == null) {
34
+ throw new AggregateError("Aggregator package not set", ConfigErrorCode.MissAggregatorPackage)
35
+ }
36
+ const aggregatorPublishedAt = aggregatorPackage.publishedAt
37
+
38
+ if (swapParams.a2b) {
39
+ if (swapParams.coinA == null) {
40
+ throw new AggregateError("coinA is required", TransactionErrorCode.MissCoinA)
41
+ }
42
+ } else {
43
+ if (swapParams.coinB == null) {
44
+ throw new AggregateError("coinB is required", TransactionErrorCode.MissCoinB)
45
+ }
46
+ }
47
+
48
+ const args = swapParams.a2b ? [
49
+ txb.object(swapParams.poolId),
50
+ swapParams.amount,
51
+ txb.pure.u64(swapParams.amountLimit),
52
+ swapParams.coinA!,
53
+ txb.pure.bool(swapParams.useFullInputCoinAmount)
54
+ ] : [
55
+ txb.object(swapParams.poolId),
56
+ swapParams.amount,
57
+ txb.pure.u64(swapParams.amountLimit),
58
+ swapParams.coinB!,
59
+ txb.pure.bool(swapParams.useFullInputCoinAmount)
60
+ ]
61
+
62
+ const func = swapParams.a2b ? SWAP_A2B_FUNC : SWAP_B2A_FUNC
63
+
64
+ const target = createTarget(aggregatorPublishedAt, KRIYA_MODULE, func)
65
+
66
+ const res = txb.moveCall({
67
+ target,
68
+ typeArguments: [swapParams.coinAType, swapParams.coinBType],
69
+ arguments: args,
70
+ })
71
+ return {
72
+ targetCoin: res[0],
73
+ amountIn: res[1],
74
+ amountOut: res[2],
75
+ txb
76
+ }
77
+ }
@@ -0,0 +1,345 @@
1
+ import {
2
+ TransactionArgument,
3
+ Transaction,
4
+ TransactionObjectArgument,
5
+ } from "@mysten/sui/transactions"
6
+ import type { BuildRouterSwapParams } from "../client"
7
+ import { AggregatorConfig } from "../config"
8
+ import {
9
+ AFTERMATH_AMM,
10
+ CETUS_DEX,
11
+ DEEPBOOK_DEX,
12
+ FLOWX_AMM,
13
+ KRIYA_DEX,
14
+ TURBOS_DEX,
15
+ U64_MAX,
16
+ } from "../const"
17
+ import { deepbookSwapMovecall } from "./deepbook"
18
+ import { SuiClient } from "@mysten/sui/client"
19
+ import { kriyaSwapMovecall } from "./kriya"
20
+ import {
21
+ cetusFlashSwapMovecall,
22
+ cetusRepayFlashSwapMovecall,
23
+ cetusSwapWithOutLimit,
24
+ } from "./cetus"
25
+ import { transferOrDestoryCoin } from "./common"
26
+ import { GetDefaultSqrtPriceLimit } from "../math"
27
+ import { flowxAmmSwapMovecall } from "./flowx"
28
+ import { turbosSwapMovecall } from "./turbos"
29
+ import { parseAftermathFeeType, parseTurbosPoolFeeType } from "~/utils/coin"
30
+ import { AftermathAmmSwapMovecall } from "./aftermath"
31
+ import { TransactionErrorCode } from "~/errors"
32
+
33
+ export async function expectInputRouterSwap(
34
+ client: SuiClient,
35
+ params: BuildRouterSwapParams,
36
+ txb: Transaction,
37
+ fromCoin: TransactionObjectArgument,
38
+ config: AggregatorConfig,
39
+ partner?: string
40
+ ): Promise<TransactionObjectArgument[]> {
41
+ const splitAmounts = params.routers.map((router) =>
42
+ router.amountIn.toString()
43
+ )
44
+ const targetCoins = []
45
+ const fromCoins = txb.splitCoins(fromCoin, splitAmounts)
46
+
47
+ for (let i = 0; i < params.routers.length; i++) {
48
+ const router = params.routers[i]
49
+ let intermediateTargetCoin: TransactionObjectArgument
50
+ let nextFromCoin = fromCoins[i] as TransactionObjectArgument
51
+
52
+ let nextFlashAmount: TransactionArgument = txb.pure.u64(splitAmounts[i])
53
+
54
+ for (let j = 0; j < router.path.length; j++) {
55
+ const firstPathPool = j === 0
56
+ const path = router.path[j]
57
+
58
+ if (path.provider === CETUS_DEX) {
59
+ const swapParams = {
60
+ poolId: path.id,
61
+ amount: nextFlashAmount,
62
+ amountLimit: "0",
63
+ a2b: path.a2b,
64
+ byAmountIn: true,
65
+ sqrtPriceLimit: GetDefaultSqrtPriceLimit(path.a2b),
66
+ partner: partner!,
67
+ coinAType: path.a2b ? path.from : path.target,
68
+ coinBType: path.a2b ? path.target : path.from,
69
+ }
70
+
71
+ const returnPayAmount = firstPathPool && router.path.length > 1
72
+ const swapResult = await cetusSwapWithOutLimit(
73
+ swapParams,
74
+ nextFromCoin,
75
+ txb,
76
+ config,
77
+ returnPayAmount
78
+ )
79
+
80
+ transferOrDestoryCoin(
81
+ txb,
82
+ swapResult.repayTargetCoin,
83
+ path.from,
84
+ config
85
+ )
86
+
87
+ intermediateTargetCoin = swapResult.flashTargetCoin!
88
+ nextFromCoin = intermediateTargetCoin
89
+ nextFlashAmount = returnPayAmount
90
+ ? swapResult.nextInputAmount!
91
+ : txb.pure.u64(0)
92
+ }
93
+
94
+ if (path.provider === DEEPBOOK_DEX) {
95
+ const coinA = path.a2b ? nextFromCoin : undefined
96
+ const coinB = path.a2b ? undefined : nextFromCoin
97
+
98
+ const swapParams = {
99
+ poolId: path.id,
100
+ a2b: path.a2b,
101
+ amount: nextFlashAmount,
102
+ amountLimit: 0,
103
+ coinA,
104
+ coinB,
105
+ useFullInputCoinAmount: !firstPathPool,
106
+ coinAType: path.a2b ? path.from : path.target,
107
+ coinBType: path.a2b ? params.targetCoinType : path.from,
108
+ }
109
+ const deepbookSwapResult = await deepbookSwapMovecall(
110
+ swapParams,
111
+ client,
112
+ txb,
113
+ config
114
+ )
115
+
116
+ intermediateTargetCoin = deepbookSwapResult.targetCoin
117
+ nextFromCoin = intermediateTargetCoin
118
+ nextFlashAmount = deepbookSwapResult.amountOut
119
+ }
120
+
121
+ if (path.provider === KRIYA_DEX) {
122
+ const coinA = path.a2b ? nextFromCoin : undefined
123
+ const coinB = path.a2b ? undefined : nextFromCoin
124
+
125
+ const swapParams = {
126
+ poolId: path.id,
127
+ amount: nextFlashAmount,
128
+ amountLimit: 0,
129
+ a2b: path.a2b,
130
+ byAmountIn: true,
131
+ coinA,
132
+ coinB,
133
+ useFullInputCoinAmount: !firstPathPool,
134
+ coinAType: path.a2b ? path.from : path.target,
135
+ coinBType: path.a2b ? path.target : path.from,
136
+ }
137
+
138
+ const swapResult = await kriyaSwapMovecall(swapParams, txb, config)
139
+
140
+ intermediateTargetCoin = swapResult.targetCoin
141
+ nextFromCoin = intermediateTargetCoin
142
+ nextFlashAmount = swapResult.amountOut
143
+ }
144
+
145
+ if (path.provider === FLOWX_AMM) {
146
+ const coinA = path.a2b ? nextFromCoin : undefined
147
+ const coinB = path.a2b ? undefined : nextFromCoin
148
+
149
+ const swapParams = {
150
+ amount: nextFlashAmount,
151
+ amountLimit: 0,
152
+ a2b: path.a2b,
153
+ byAmountIn: true,
154
+ coinA,
155
+ coinB,
156
+ useFullInputCoinAmount: !firstPathPool,
157
+ coinAType: path.a2b ? path.from : path.target,
158
+ coinBType: path.a2b ? path.target : path.from,
159
+ }
160
+
161
+ const swapResult = await flowxAmmSwapMovecall(swapParams, txb, config)
162
+
163
+ intermediateTargetCoin = swapResult.targetCoin
164
+ nextFromCoin = intermediateTargetCoin
165
+ nextFlashAmount = swapResult.amountOut
166
+ }
167
+
168
+ if (path.provider === TURBOS_DEX) {
169
+ const coinA = path.a2b ? nextFromCoin : undefined
170
+ const coinB = path.a2b ? undefined : nextFromCoin
171
+
172
+ let feeType = ""
173
+ if (
174
+ path.extendedDetails != null &&
175
+ path.extendedDetails.turbosFeeType != null
176
+ ) {
177
+ feeType = path.extendedDetails.turbosFeeType
178
+ } else {
179
+ throw new AggregateError(
180
+ "Build turbos swap movecall error: ",
181
+ TransactionErrorCode.MissTurbosFeeType
182
+ )
183
+ }
184
+
185
+ const swapParams = {
186
+ poolId: path.id,
187
+ amount: nextFlashAmount,
188
+ amountLimit: 0,
189
+ a2b: path.a2b,
190
+ byAmountIn: true,
191
+ coinA,
192
+ coinB,
193
+ useFullInputCoinAmount: !firstPathPool,
194
+ coinAType: path.a2b ? path.from : path.target,
195
+ coinBType: path.a2b ? path.target : path.from,
196
+ feeType,
197
+ }
198
+
199
+ const swapResult = await turbosSwapMovecall(swapParams, txb, config)
200
+
201
+ intermediateTargetCoin = swapResult.targetCoin
202
+ nextFromCoin = intermediateTargetCoin
203
+ nextFlashAmount = swapResult.amountOut
204
+ }
205
+
206
+ if (path.provider === AFTERMATH_AMM) {
207
+ const coinA = path.a2b ? nextFromCoin : undefined
208
+ const coinB = path.a2b ? undefined : nextFromCoin
209
+
210
+ let lpSupplyType = ""
211
+
212
+ if (
213
+ path.extendedDetails != null &&
214
+ path.extendedDetails.aftermathLpSupplyType != null
215
+ ) {
216
+ lpSupplyType = path.extendedDetails.aftermathLpSupplyType
217
+ } else {
218
+ throw new AggregateError(
219
+ "Build aftermath swap movecall error: ",
220
+ TransactionErrorCode.MissAftermathLpSupplyType
221
+ )
222
+ }
223
+
224
+ const swapParams = {
225
+ poolId: path.id,
226
+ amount: nextFlashAmount,
227
+ amountOut: path.amountOut,
228
+ amountLimit: 0,
229
+ a2b: path.a2b,
230
+ byAmountIn: true,
231
+ coinA,
232
+ coinB,
233
+ useFullInputCoinAmount: !firstPathPool,
234
+ coinAType: path.a2b ? path.from : path.target,
235
+ coinBType: path.a2b ? path.target : path.from,
236
+ slippage: params.slippage,
237
+ lpSupplyType,
238
+ }
239
+
240
+ const swapResult = await AftermathAmmSwapMovecall(
241
+ swapParams,
242
+ txb,
243
+ config
244
+ )
245
+
246
+ intermediateTargetCoin = swapResult.targetCoin
247
+ nextFromCoin = intermediateTargetCoin
248
+ nextFlashAmount = swapResult.amountOut
249
+ }
250
+ }
251
+ targetCoins.push(nextFromCoin)
252
+ }
253
+
254
+ transferOrDestoryCoin(txb, fromCoin, params.fromCoinType, config)
255
+
256
+ return targetCoins
257
+ }
258
+
259
+ export async function expectOutputRouterSwap(
260
+ params: BuildRouterSwapParams,
261
+ txb: Transaction,
262
+ fromCoin: TransactionObjectArgument,
263
+ config: AggregatorConfig,
264
+ partner?: string
265
+ ): Promise<TransactionObjectArgument[]> {
266
+ const splitAmounts = params.routers.map((router) =>
267
+ router.amountOut.toString()
268
+ )
269
+
270
+ const returnCoins: TransactionObjectArgument[] = []
271
+ const receipts: TransactionObjectArgument[] = []
272
+
273
+ const targetCoins = []
274
+
275
+ for (let i = 0; i < params.routers.length; i++) {
276
+ const router = params.routers[i]
277
+
278
+ let nextFlashAmount: TransactionArgument = txb.pure.u64(splitAmounts[i])
279
+ for (let j = router.path.length - 1; j >= 0; j--) {
280
+ const path = router.path[j]
281
+
282
+ const coinAType = path.a2b ? path.from : path.target
283
+ const coinBType = path.a2b ? path.target : path.from
284
+
285
+ const swapParams = {
286
+ poolId: path.id,
287
+ amount: nextFlashAmount,
288
+ amountLimit: U64_MAX,
289
+ a2b: path.a2b,
290
+ byAmountIn: false,
291
+ sqrtPriceLimit: GetDefaultSqrtPriceLimit(path.a2b), //
292
+ partner,
293
+ coinAType,
294
+ coinBType,
295
+ }
296
+
297
+ const flashSwapResult = cetusFlashSwapMovecall(swapParams, txb, config)
298
+ nextFlashAmount = flashSwapResult.payAmount
299
+ returnCoins.unshift(flashSwapResult.targetCoin)
300
+ receipts.unshift(flashSwapResult.flashReceipt)
301
+ }
302
+
303
+ let nextRepayCoin = fromCoin
304
+ for (let j = 0; j < router.path.length; j++) {
305
+ const path = router.path[j]
306
+
307
+ const coinAType = path.a2b ? path.from : path.target
308
+ const coinBType = path.a2b ? path.target : path.from
309
+
310
+ const repayParams = {
311
+ poolId: path.id,
312
+ a2b: path.a2b,
313
+ partner: partner,
314
+ coinA: path.a2b ? nextRepayCoin : undefined,
315
+ coinB: path.a2b ? undefined : nextRepayCoin,
316
+ receipt: receipts[j],
317
+ coinAType,
318
+ coinBType,
319
+ }
320
+ const repayResult = await cetusRepayFlashSwapMovecall(
321
+ repayParams,
322
+ txb,
323
+ config
324
+ )
325
+ nextRepayCoin = returnCoins[j]
326
+ if (j === 0) {
327
+ fromCoin = repayResult.repayTargetCoin
328
+ } else {
329
+ transferOrDestoryCoin(
330
+ txb,
331
+ repayResult.repayTargetCoin,
332
+ path.from,
333
+ config
334
+ )
335
+ }
336
+ if (j === router.path.length - 1) {
337
+ targetCoins.push(nextRepayCoin)
338
+ }
339
+ }
340
+ }
341
+
342
+ transferOrDestoryCoin(txb, fromCoin, params.fromCoinType, config)
343
+
344
+ return targetCoins
345
+ }