@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.
- package/.env.example +4 -0
- package/README.md +0 -0
- package/bun.lockb +0 -0
- package/dist/index.d.mts +267 -0
- package/dist/index.d.ts +267 -0
- package/dist/index.js +6824 -0
- package/dist/index.mjs +6745 -0
- package/dist/src/client.d.ts +88 -0
- package/dist/src/config.d.ts +26 -0
- package/dist/src/const.d.ts +75 -0
- package/dist/src/errors.d.ts +31 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/math.d.ts +5 -0
- package/dist/src/test_data.test.d.ts +8 -0
- package/dist/src/transaction/aftermath.d.ts +24 -0
- package/dist/src/transaction/cetus.d.ts +39 -0
- package/dist/src/transaction/common.d.ts +12 -0
- package/dist/src/transaction/deepbook.d.ts +21 -0
- package/dist/src/transaction/flowx.d.ts +20 -0
- package/dist/src/transaction/index.d.ts +1 -0
- package/dist/src/transaction/kriya.d.ts +21 -0
- package/dist/src/transaction/router.d.ts +6 -0
- package/dist/src/transaction/swap.d.ts +5 -0
- package/dist/src/transaction/turbos.d.ts +22 -0
- package/dist/src/types/CoinAssist.d.ts +122 -0
- package/dist/src/types/sui.d.ts +112 -0
- package/dist/src/utils/account_cap.d.ts +7 -0
- package/dist/src/utils/coin.d.ts +4 -0
- package/dist/src/utils/coin.spec.d.ts +1 -0
- package/dist/src/utils/contracts.d.ts +16 -0
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/transaction.d.ts +3 -0
- package/dist/tests/router.test.d.ts +2 -0
- package/dist/tests/wallet.test.d.ts +1 -0
- package/jest.config.mjs +13 -0
- package/package.json +41 -0
- package/src/client.ts +393 -0
- package/src/config.ts +65 -0
- package/src/const.ts +126 -0
- package/src/errors.ts +44 -0
- package/src/index.ts +5 -0
- package/src/math.ts +37 -0
- package/src/test_data.test.ts +17 -0
- package/src/transaction/aftermath.ts +142 -0
- package/src/transaction/cetus.ts +281 -0
- package/src/transaction/common.ts +169 -0
- package/src/transaction/deepbook.ts +126 -0
- package/src/transaction/flowx.ts +97 -0
- package/src/transaction/index.ts +1 -0
- package/src/transaction/kriya.ts +77 -0
- package/src/transaction/router.ts +341 -0
- package/src/transaction/swap.ts +164 -0
- package/src/transaction/turbos.ts +114 -0
- package/src/types/CoinAssist.ts +217 -0
- package/src/types/sui.ts +148 -0
- package/src/utils/account_cap.ts +62 -0
- package/src/utils/coin.spec.ts +10 -0
- package/src/utils/coin.ts +61 -0
- package/src/utils/contracts.ts +136 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/transaction.ts +20 -0
- package/tests/router.test.ts +255 -0
- package/tests/wallet.test.ts +21 -0
- package/tsconfig.json +22 -0
- package/tsup.config.ts +23 -0
- 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
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
|
+
}
|