@mmt-finance/amm-sui-sdk 0.0.1-beta
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/.eslintrc.json +22 -0
- package/.husky/commit-msg +4 -0
- package/.prettierrc +7 -0
- package/README.md +206 -0
- package/bun.lock +937 -0
- package/commitlint.config.js +3 -0
- package/package.json +40 -0
- package/src/index.ts +7 -0
- package/src/sdk/dex.ts +423 -0
- package/src/sdk/sdkBase.ts +199 -0
- package/src/utils/constants.ts +150 -0
- package/src/utils/types.ts +155 -0
- package/src/utils/utils.ts +308 -0
- package/tsconfig.json +18 -0
- package/tsup.config.ts +12 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
export class DexConstants {
|
|
2
|
+
// Legacy constants for backward compat if needed, but we will mostly use NETWORK_CONFIG
|
|
3
|
+
public static readonly packageId =
|
|
4
|
+
'0xcf1fc98b09bc29b7747412ca3bbf36e63f0f213a485db7fe19c8500d4b3d9bab';
|
|
5
|
+
public static readonly packageIdV1 =
|
|
6
|
+
'0xcf1fc98b09bc29b7747412ca3bbf36e63f0f213a485db7fe19c8500d4b3d9bab';
|
|
7
|
+
public static readonly farmPackageId =
|
|
8
|
+
'0x88701243d0445aa38c0a13f02a9af49a58092dfadb93af9754edb41c52f40085';
|
|
9
|
+
public static readonly suiPackageId =
|
|
10
|
+
'0x0000000000000000000000000000000000000000000000000000000000000002';
|
|
11
|
+
|
|
12
|
+
public static readonly suiCoinType =
|
|
13
|
+
'0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI';
|
|
14
|
+
|
|
15
|
+
public static readonly functions = {
|
|
16
|
+
swapX: 'swap_token_x',
|
|
17
|
+
swapY: 'swap_token_y',
|
|
18
|
+
createPool: 'create_pool_',
|
|
19
|
+
createPoolInternal: 'create_pool',
|
|
20
|
+
createPoolAndAddLiquidity: 'create_pool_and_add_liquidity',
|
|
21
|
+
addLiquidityInternal: 'add_liquidity',
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const NETWORK_CONFIG = {
|
|
26
|
+
mainnet: {
|
|
27
|
+
packageId: '0xcf1fc98b09bc29b7747412ca3bbf36e63f0f213a485db7fe19c8500d4b3d9bab',
|
|
28
|
+
packageIdV1: '0xcf1fc98b09bc29b7747412ca3bbf36e63f0f213a485db7fe19c8500d4b3d9bab',
|
|
29
|
+
farmPackageId: '0x88701243d0445aa38c0a13f02a9af49a58092dfadb93af9754edb41c52f40085',
|
|
30
|
+
protocolConfigs: '0x...', // TODO: Add Mainnet ProtocolConfigs ID
|
|
31
|
+
},
|
|
32
|
+
testnet: {
|
|
33
|
+
packageId: '0xaee0193a13a2ff9e4d20360789aa9132a3a97cd1d92e641c96f28a07e97c7375',
|
|
34
|
+
packageIdV1: '0xaee0193a13a2ff9e4d20360789aa9132a3a97cd1d92e641c96f28a07e97c7375', // TODO: What's this? Do we really need it?
|
|
35
|
+
farmPackageId: '0x88701243d0445aa38c0a13f02a9af49a58092dfadb93af9754edb41c52f40085', // TODO: What's this? Do we really need it?
|
|
36
|
+
protocolConfigs: '0xc0e50d862bc57afc72edac15cde58e8f8cc3ed2517d8521dfb295f8d083c5a47',
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const TEMP_POOL_DATA: Record<
|
|
41
|
+
string,
|
|
42
|
+
{
|
|
43
|
+
upsaclingFactor: number;
|
|
44
|
+
baseToken: string;
|
|
45
|
+
amountUpscalingFactor: number;
|
|
46
|
+
tickSize: number;
|
|
47
|
+
minAmount: number;
|
|
48
|
+
lotSize: number;
|
|
49
|
+
}
|
|
50
|
+
> = {
|
|
51
|
+
//V2 pools
|
|
52
|
+
'0xc0833efe1d86978ebf57a3ce4a41b2c2b9e20faf802305f1eda306c8fc64ee40': {
|
|
53
|
+
upsaclingFactor: 1e13,
|
|
54
|
+
amountUpscalingFactor: 1e5,
|
|
55
|
+
baseToken: 'FUD',
|
|
56
|
+
tickSize: 100,
|
|
57
|
+
minAmount: 100,
|
|
58
|
+
lotSize: 100000000000,
|
|
59
|
+
},
|
|
60
|
+
'0x4405b50d791fd3346754e8171aaab6bc2ed26c2c46efdd033c14b30ae507ac33': {
|
|
61
|
+
upsaclingFactor: 1e6,
|
|
62
|
+
amountUpscalingFactor: 1e9,
|
|
63
|
+
baseToken: 'SUI',
|
|
64
|
+
tickSize: 100,
|
|
65
|
+
minAmount: 0.1,
|
|
66
|
+
lotSize: 100000000,
|
|
67
|
+
},
|
|
68
|
+
'0x6e417ee1c12ad5f2600a66bc80c7bd52ff3cb7c072d508700d17cf1325324527': {
|
|
69
|
+
upsaclingFactor: 1e7,
|
|
70
|
+
baseToken: 'WETH',
|
|
71
|
+
amountUpscalingFactor: 1e8,
|
|
72
|
+
tickSize: 1000000,
|
|
73
|
+
minAmount: 0.0001,
|
|
74
|
+
lotSize: 10000,
|
|
75
|
+
},
|
|
76
|
+
'0x31d1790e617eef7f516555124155b28d663e5c600317c769a75ee6336a54c07f': {
|
|
77
|
+
upsaclingFactor: 1e7,
|
|
78
|
+
baseToken: 'WBTC',
|
|
79
|
+
tickSize: 1000000,
|
|
80
|
+
minAmount: 0.00001,
|
|
81
|
+
lotSize: 1000,
|
|
82
|
+
amountUpscalingFactor: 1e8,
|
|
83
|
+
},
|
|
84
|
+
'0xd1f0a9baacc1864ab19534e2d4c5d6c14f2e071a1f075e8e7f9d51f2c17dc238': {
|
|
85
|
+
upsaclingFactor: 1e9,
|
|
86
|
+
baseToken: 'USDT',
|
|
87
|
+
tickSize: 100000,
|
|
88
|
+
minAmount: 0.1,
|
|
89
|
+
lotSize: 100000,
|
|
90
|
+
amountUpscalingFactor: 1e6,
|
|
91
|
+
},
|
|
92
|
+
//v1 pools
|
|
93
|
+
'0x7f526b1263c4b91b43c9e646419b5696f424de28dda3c1e6658cc0a54558baa7': {
|
|
94
|
+
upsaclingFactor: 1e6,
|
|
95
|
+
amountUpscalingFactor: 1e9,
|
|
96
|
+
baseToken: 'SUI',
|
|
97
|
+
tickSize: 100,
|
|
98
|
+
minAmount: 0.1,
|
|
99
|
+
lotSize: 100000000,
|
|
100
|
+
},
|
|
101
|
+
'0xd9e45ab5440d61cc52e3b2bd915cdd643146f7593d587c715bc7bfa48311d826': {
|
|
102
|
+
upsaclingFactor: 1e7,
|
|
103
|
+
baseToken: 'WETH',
|
|
104
|
+
amountUpscalingFactor: 1e8,
|
|
105
|
+
tickSize: 1000000,
|
|
106
|
+
minAmount: 0.0001,
|
|
107
|
+
lotSize: 10000,
|
|
108
|
+
},
|
|
109
|
+
'0xf0f663cf87f1eb124da2fc9be813e0ce262146f3df60bc2052d738eb41a25899': {
|
|
110
|
+
upsaclingFactor: 1e7,
|
|
111
|
+
baseToken: 'WBTC',
|
|
112
|
+
tickSize: 1000000,
|
|
113
|
+
minAmount: 0.00001,
|
|
114
|
+
lotSize: 1000,
|
|
115
|
+
amountUpscalingFactor: 1e8,
|
|
116
|
+
},
|
|
117
|
+
'0x5deafda22b6b86127ea4299503362638bea0ca33bb212ea3a67b029356b8b955': {
|
|
118
|
+
upsaclingFactor: 1e9,
|
|
119
|
+
baseToken: 'USDC',
|
|
120
|
+
tickSize: 100000,
|
|
121
|
+
minAmount: 0.1,
|
|
122
|
+
lotSize: 100000,
|
|
123
|
+
amountUpscalingFactor: 1e6,
|
|
124
|
+
},
|
|
125
|
+
// testnet pools
|
|
126
|
+
'0xb288337ce29aff7fbce8827ba16e74f0f4c1c0b312873464bd220f2eb771edc6': {
|
|
127
|
+
upsaclingFactor: 1e7,
|
|
128
|
+
baseToken: 'WBTC',
|
|
129
|
+
tickSize: 1000000,
|
|
130
|
+
minAmount: 0.00001,
|
|
131
|
+
lotSize: 1000,
|
|
132
|
+
amountUpscalingFactor: 1e6,
|
|
133
|
+
},
|
|
134
|
+
'0x715a62958fba1e7c8d61d849fdd0b60c734a24a6e78fbefd8049b0f7e41b7204': {
|
|
135
|
+
upsaclingFactor: 1e7,
|
|
136
|
+
baseToken: 'WBTC',
|
|
137
|
+
tickSize: 1000000,
|
|
138
|
+
minAmount: 0.00001,
|
|
139
|
+
lotSize: 1000,
|
|
140
|
+
amountUpscalingFactor: 1e8,
|
|
141
|
+
},
|
|
142
|
+
'0x22b276b1f0e2dca4e7483f7da035e7f99d8831aa9cbec131058b6bb5768f998d': {
|
|
143
|
+
upsaclingFactor: 1e7,
|
|
144
|
+
baseToken: 'WBTC',
|
|
145
|
+
tickSize: 1000000,
|
|
146
|
+
minAmount: 0.00001,
|
|
147
|
+
lotSize: 1000,
|
|
148
|
+
amountUpscalingFactor: 1e8,
|
|
149
|
+
},
|
|
150
|
+
};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Transaction, TransactionArgument } from '@mysten/sui/transactions';
|
|
2
|
+
|
|
3
|
+
export interface Pool {
|
|
4
|
+
objectId: string;
|
|
5
|
+
tokenXType: string;
|
|
6
|
+
tokenYType: string;
|
|
7
|
+
isStable?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface Farm {
|
|
11
|
+
objectId: string;
|
|
12
|
+
tokenXType: string;
|
|
13
|
+
tokenYType: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface GetExactCoinByAmountOptions {
|
|
17
|
+
coinType: string;
|
|
18
|
+
coins: { objectId: string; balance: bigint }[];
|
|
19
|
+
amount: bigint;
|
|
20
|
+
txb: Transaction;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface SwapOptions {
|
|
24
|
+
pool: Pool;
|
|
25
|
+
inputCoinType: string;
|
|
26
|
+
inputCoinAmount: bigint | TransactionArgument;
|
|
27
|
+
inputCoin: string | TransactionArgument;
|
|
28
|
+
minReceived: bigint;
|
|
29
|
+
txb: Transaction;
|
|
30
|
+
transferToAddress?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface SwapWithRouteOptions {
|
|
34
|
+
pools: Pool[];
|
|
35
|
+
inputCoinType: string;
|
|
36
|
+
inputCoinAmount: bigint | TransactionArgument;
|
|
37
|
+
inputCoin: string | TransactionArgument;
|
|
38
|
+
minReceived: bigint;
|
|
39
|
+
txb: Transaction;
|
|
40
|
+
transferToAddress?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface RemoveLiquidityOptions {
|
|
44
|
+
pool: Pool;
|
|
45
|
+
amount: bigint | TransactionArgument;
|
|
46
|
+
mmtLpToken: string | TransactionArgument;
|
|
47
|
+
txb: Transaction;
|
|
48
|
+
transferToAddress?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface AddLiquidityOptions {
|
|
52
|
+
pool: Pool;
|
|
53
|
+
amountX: bigint | TransactionArgument;
|
|
54
|
+
amountY: bigint | TransactionArgument;
|
|
55
|
+
minAddAmountX: bigint;
|
|
56
|
+
minAddAmountY: bigint;
|
|
57
|
+
coinX: string | TransactionArgument;
|
|
58
|
+
coinY: string | TransactionArgument;
|
|
59
|
+
txb: Transaction;
|
|
60
|
+
transferToAddress?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface AddLiquiditySingleSidedOptions {
|
|
64
|
+
pool: Pool;
|
|
65
|
+
inputCoinType: string;
|
|
66
|
+
inputCoinAmount: bigint;
|
|
67
|
+
inputCoin: string | TransactionArgument;
|
|
68
|
+
tokenInDecimals: number;
|
|
69
|
+
tokenOutDecimals: number;
|
|
70
|
+
swapSlippageTolerance: number;
|
|
71
|
+
txb: Transaction;
|
|
72
|
+
transferToAddress?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface GetUserLpPositionsOptions {
|
|
76
|
+
pool: Pool;
|
|
77
|
+
userAddress: string;
|
|
78
|
+
maxIter?: number;
|
|
79
|
+
cursor?: string | null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface GetSwapAmountStableOptions {
|
|
83
|
+
reserveA: bigint;
|
|
84
|
+
reserveB: bigint;
|
|
85
|
+
scaleA: bigint;
|
|
86
|
+
scaleB: bigint;
|
|
87
|
+
amount: bigint;
|
|
88
|
+
totalFeeRate?: bigint;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface GetSwapAmountUncorrelatedOptions {
|
|
92
|
+
reserveA: bigint;
|
|
93
|
+
reserveB: bigint;
|
|
94
|
+
amount: bigint;
|
|
95
|
+
totalFeeRate?: bigint;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface GetLpAmountInOptions {
|
|
99
|
+
amountX: bigint;
|
|
100
|
+
amountY: bigint;
|
|
101
|
+
lspSupply: bigint;
|
|
102
|
+
reserveX: bigint;
|
|
103
|
+
reserveY: bigint;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface GetLpAmountOutOptions {
|
|
107
|
+
lspAmount: bigint;
|
|
108
|
+
lspSupply: bigint;
|
|
109
|
+
reserveX: bigint;
|
|
110
|
+
reserveY: bigint;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface MergeLpsTxOptions {
|
|
114
|
+
txb: Transaction;
|
|
115
|
+
lps: string[];
|
|
116
|
+
typeX: string;
|
|
117
|
+
typeY: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface SplitLpsTxOptions {
|
|
121
|
+
txb: Transaction;
|
|
122
|
+
lp: string | TransactionArgument;
|
|
123
|
+
amount: number;
|
|
124
|
+
typeX: string;
|
|
125
|
+
typeY: string;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface CreatePoolOptions {
|
|
129
|
+
isStable: boolean;
|
|
130
|
+
decimalsX: number;
|
|
131
|
+
decimalsY: number;
|
|
132
|
+
txb: Transaction;
|
|
133
|
+
typeX: string;
|
|
134
|
+
typeY: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface CreatePoolAndAddLiquidityOptions {
|
|
138
|
+
isStable: boolean;
|
|
139
|
+
decimalsX: number;
|
|
140
|
+
decimalsY: number;
|
|
141
|
+
txb: Transaction;
|
|
142
|
+
typeX: string;
|
|
143
|
+
typeY: string;
|
|
144
|
+
minAddAmountX: bigint;
|
|
145
|
+
minAddAmountY: bigint;
|
|
146
|
+
coinX: string | TransactionArgument;
|
|
147
|
+
coinY: string | TransactionArgument;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export type Network = 'mainnet' | 'testnet';
|
|
151
|
+
|
|
152
|
+
export interface SdkOptions {
|
|
153
|
+
network?: Network;
|
|
154
|
+
rpcEndpoint: string;
|
|
155
|
+
}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { SuiClient } from "@mysten/sui/client";
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
|
|
4
|
+
const FEE_SCALING = BigInt(1000000);
|
|
5
|
+
/// We take 10^8 as we expect most of the coins to have 6-8 decimals.
|
|
6
|
+
const ONE_E_8 = BigInt(100000000);
|
|
7
|
+
|
|
8
|
+
const coingeckoID = (ticker: string) => {
|
|
9
|
+
switch (ticker) {
|
|
10
|
+
case "SUI":
|
|
11
|
+
return "sui";
|
|
12
|
+
case "USDC":
|
|
13
|
+
case "USDCeth":
|
|
14
|
+
case "USDCbnb":
|
|
15
|
+
return "usd-coin";
|
|
16
|
+
case "WETH":
|
|
17
|
+
return "ethereum";
|
|
18
|
+
case "SPEPE":
|
|
19
|
+
return "suipepe";
|
|
20
|
+
case "MOVE":
|
|
21
|
+
return "bluemove";
|
|
22
|
+
case "USDT":
|
|
23
|
+
return "tether";
|
|
24
|
+
case "WBTC":
|
|
25
|
+
case "BTC":
|
|
26
|
+
return "bitcoin";
|
|
27
|
+
default:
|
|
28
|
+
return "";
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/// Get output price for uncorrelated curve x*y = k
|
|
33
|
+
const getPriceUncorrelated = (
|
|
34
|
+
input_amount: bigint,
|
|
35
|
+
input_reserve: bigint,
|
|
36
|
+
output_reserve: bigint,
|
|
37
|
+
fee_percent: bigint,
|
|
38
|
+
) => {
|
|
39
|
+
let input_amount_with_fee = input_amount * (FEE_SCALING - fee_percent);
|
|
40
|
+
let numerator = input_amount_with_fee * output_reserve;
|
|
41
|
+
let denominator = input_reserve * FEE_SCALING + input_amount_with_fee;
|
|
42
|
+
|
|
43
|
+
return numerator / denominator;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const getPriceStable = (
|
|
47
|
+
input_amount: bigint,
|
|
48
|
+
input_reserve: bigint,
|
|
49
|
+
output_reserve: bigint,
|
|
50
|
+
fee_percent: bigint,
|
|
51
|
+
input_scale: bigint,
|
|
52
|
+
output_scale: bigint,
|
|
53
|
+
) => {
|
|
54
|
+
let u2561e8 = ONE_E_8;
|
|
55
|
+
|
|
56
|
+
let xy = lp_value(input_reserve, input_scale, output_reserve, output_scale);
|
|
57
|
+
|
|
58
|
+
let reserve_in_u256 = (input_reserve * u2561e8) / input_scale;
|
|
59
|
+
let reserve_out_u256 = (output_reserve * u2561e8) / output_scale;
|
|
60
|
+
let amount_in = (input_amount * u2561e8) / input_scale;
|
|
61
|
+
let amount_in_with_fees_scaling =
|
|
62
|
+
(amount_in * (FEE_SCALING - fee_percent)) / FEE_SCALING;
|
|
63
|
+
let total_reserve = amount_in_with_fees_scaling + reserve_in_u256;
|
|
64
|
+
let y = reserve_out_u256 - get_y(total_reserve, xy, reserve_out_u256);
|
|
65
|
+
|
|
66
|
+
let r = (y * output_scale) / u2561e8;
|
|
67
|
+
|
|
68
|
+
return r;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/// Get LP value for stable curve: x^3*y + x*y^3
|
|
72
|
+
/// * `x_coin` - reserves of coin X.
|
|
73
|
+
/// * `x_scale` - 10 pow X coin decimals amount.
|
|
74
|
+
/// * `y_coin` - reserves of coin Y.
|
|
75
|
+
/// * `y_scale` - 10 pow Y coin decimals amount.
|
|
76
|
+
const lp_value = (
|
|
77
|
+
x_coin: bigint,
|
|
78
|
+
x_scale: bigint,
|
|
79
|
+
y_coin: bigint,
|
|
80
|
+
y_scale: bigint,
|
|
81
|
+
) => {
|
|
82
|
+
let _x = (x_coin * ONE_E_8) / x_scale;
|
|
83
|
+
let _y = (y_coin * ONE_E_8) / y_scale;
|
|
84
|
+
|
|
85
|
+
let xy = _x * _y;
|
|
86
|
+
let x2_y2 = _x * _x + _y * _y;
|
|
87
|
+
|
|
88
|
+
return xy * x2_y2;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/// get value of reserve_y - output_y
|
|
92
|
+
/// * `x0` = reserve_x + input_x = total x reserve after adding input
|
|
93
|
+
/// * `xy` - original value of x^3*y + x*y^3
|
|
94
|
+
/// * `y` - reserve_y - initial guess is reserve_y
|
|
95
|
+
/// calculate 255 iterations of Newton's method for x^3*y + x*y^3
|
|
96
|
+
const get_y = (x0: bigint, xy: bigint, y: bigint) => {
|
|
97
|
+
let i = 0;
|
|
98
|
+
|
|
99
|
+
let one_u256 = BigInt(1);
|
|
100
|
+
|
|
101
|
+
while (i < 255) {
|
|
102
|
+
let k = f(x0, y);
|
|
103
|
+
|
|
104
|
+
let _dy = BigInt(0);
|
|
105
|
+
if (xy > k) {
|
|
106
|
+
_dy = (xy - k) / d(x0, y) + one_u256; // Round up
|
|
107
|
+
y = y + _dy;
|
|
108
|
+
} else {
|
|
109
|
+
_dy = (k - xy) / d(x0, y) + one_u256;
|
|
110
|
+
y = y - _dy;
|
|
111
|
+
}
|
|
112
|
+
if (_dy <= one_u256) {
|
|
113
|
+
return y;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
i = i + 1;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return y;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/// Implements x0*y^3 + x0^3*y = x0*(y*y/1e18*y/1e18)/1e18+(x0*x0/1e18*x0/1e18)*y/1e18
|
|
123
|
+
const f = (x0_u256: bigint, y_u256: bigint) => {
|
|
124
|
+
// x0*(y*y/1e18*y/1e18)/1e18
|
|
125
|
+
let yy = y_u256 * y_u256;
|
|
126
|
+
let yyy = yy * y_u256;
|
|
127
|
+
|
|
128
|
+
let a = x0_u256 * yyy;
|
|
129
|
+
|
|
130
|
+
//(x0*x0/1e18*x0/1e18)*y/1e18
|
|
131
|
+
let xx = x0_u256 * x0_u256;
|
|
132
|
+
let xxx = xx * x0_u256;
|
|
133
|
+
let b = xxx * y_u256;
|
|
134
|
+
|
|
135
|
+
// a + b
|
|
136
|
+
return a + b;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/// Implements 3 * x0 * y^2 + x0^3 = 3 * x0 * (y * y / 1e8) / 1e8 + (x0 * x0 / 1e8 * x0) / 1e8
|
|
140
|
+
const d = (x0_u256: bigint, y_u256: bigint) => {
|
|
141
|
+
let three_u256 = BigInt(3);
|
|
142
|
+
|
|
143
|
+
// 3 * x0 * (y * y / 1e8) / 1e8
|
|
144
|
+
let x3 = three_u256 * x0_u256;
|
|
145
|
+
let yy = y_u256 * y_u256;
|
|
146
|
+
let xyy3 = x3 * yy;
|
|
147
|
+
let xx = x0_u256 * x0_u256;
|
|
148
|
+
|
|
149
|
+
// x0 * x0 / 1e8 * x0 / 1e8
|
|
150
|
+
let xxx = xx * x0_u256;
|
|
151
|
+
|
|
152
|
+
return xyy3 + xxx;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const bigIntMax = (args: bigint[]) => args.reduce((m, e) => (e > m ? e : m));
|
|
156
|
+
const bigIntMin = (args: bigint[]) => args.reduce((m, e) => (e < m ? e : m));
|
|
157
|
+
|
|
158
|
+
const queryAllUserEvents = async (address: string, provider: SuiClient) => {
|
|
159
|
+
let cursor: { txDigest: string; eventSeq: string } | null | undefined = null;
|
|
160
|
+
let data: any[] = [];
|
|
161
|
+
let iter = 0;
|
|
162
|
+
do {
|
|
163
|
+
try {
|
|
164
|
+
const res: any = await provider.queryEvents({
|
|
165
|
+
query: {
|
|
166
|
+
Sender: address,
|
|
167
|
+
},
|
|
168
|
+
limit: 100,
|
|
169
|
+
cursor: cursor as { txDigest: string; eventSeq: string } | null,
|
|
170
|
+
});
|
|
171
|
+
data = [...data, ...res.data];
|
|
172
|
+
cursor = res.nextCursor;
|
|
173
|
+
if (!res.hasNextPage) {
|
|
174
|
+
cursor = null;
|
|
175
|
+
}
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.log(error);
|
|
178
|
+
cursor = null;
|
|
179
|
+
}
|
|
180
|
+
iter++;
|
|
181
|
+
} while (cursor !== null && iter < 2);
|
|
182
|
+
return data;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const fetchTokenDataCoingecko = async (ticker: string) => {
|
|
186
|
+
try {
|
|
187
|
+
const coingeckoId = coingeckoID(ticker);
|
|
188
|
+
if (coingeckoId !== "") {
|
|
189
|
+
const response = await axios.get(
|
|
190
|
+
`https://api.coingecko.com/api/v3/coins/${coingeckoId}`,
|
|
191
|
+
);
|
|
192
|
+
const jsonData = response.data;
|
|
193
|
+
return {
|
|
194
|
+
price: jsonData.market_data["current_price"]["usd"] as number,
|
|
195
|
+
high24: jsonData.market_data["high_24h"]["usd"] as number,
|
|
196
|
+
low24: jsonData.market_data["low_24h"]["usd"] as number,
|
|
197
|
+
change: jsonData.market_data["price_change_percentage_24h"] as number,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
} catch (e) {
|
|
201
|
+
console.log(e);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const babylonianSqrt = (y: number): number => {
|
|
206
|
+
let x: number, z: number;
|
|
207
|
+
if (y > 3) {
|
|
208
|
+
z = y;
|
|
209
|
+
x = y / 2 + 1;
|
|
210
|
+
while (x < z) {
|
|
211
|
+
z = x;
|
|
212
|
+
x = (y / x + x) / 2;
|
|
213
|
+
}
|
|
214
|
+
return z;
|
|
215
|
+
} else if (y != 0) {
|
|
216
|
+
z = 1;
|
|
217
|
+
return z;
|
|
218
|
+
}
|
|
219
|
+
return 0;
|
|
220
|
+
};
|
|
221
|
+
const calculateStableSwapAmount = (
|
|
222
|
+
totalAmount: number,
|
|
223
|
+
tokenXReserve: number,
|
|
224
|
+
tokenYReserve: number,
|
|
225
|
+
isX: boolean,
|
|
226
|
+
): number => {
|
|
227
|
+
const ratio = tokenXReserve / tokenYReserve;
|
|
228
|
+
let swapAmount: number;
|
|
229
|
+
|
|
230
|
+
if (!isX) {
|
|
231
|
+
swapAmount = totalAmount / (1 + 1 / ratio);
|
|
232
|
+
} else {
|
|
233
|
+
swapAmount = totalAmount - totalAmount / (1 + 1 / ratio);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return swapAmount;
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const getOptimalLpSwapAmount = async (
|
|
240
|
+
inputAmt: bigint,
|
|
241
|
+
poolId: string,
|
|
242
|
+
isXtoY: boolean,
|
|
243
|
+
client: SuiClient, // Changed from instantiating Dex to passing Client
|
|
244
|
+
isStable?: boolean,
|
|
245
|
+
): Promise<bigint> => {
|
|
246
|
+
const txn = await client.getObject({
|
|
247
|
+
id: poolId,
|
|
248
|
+
options: { showContent: true },
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
252
|
+
const content = txn.data?.content as any;
|
|
253
|
+
const tokenReserve = isXtoY
|
|
254
|
+
? Number(content.fields.token_x)
|
|
255
|
+
: Number(content.fields.token_y);
|
|
256
|
+
|
|
257
|
+
if (!isStable && tokenReserve) {
|
|
258
|
+
const swapAmt =
|
|
259
|
+
(babylonianSqrt(
|
|
260
|
+
tokenReserve * (tokenReserve * 3992004 + Number(inputAmt) * 3992000),
|
|
261
|
+
) -
|
|
262
|
+
tokenReserve * 1998) /
|
|
263
|
+
1996;
|
|
264
|
+
return BigInt(Math.round(swapAmt));
|
|
265
|
+
} else {
|
|
266
|
+
const swapAmtStable = calculateStableSwapAmount(
|
|
267
|
+
Number(inputAmt),
|
|
268
|
+
Number(content.fields.token_x),
|
|
269
|
+
Number(content.fields.token_y),
|
|
270
|
+
isXtoY,
|
|
271
|
+
);
|
|
272
|
+
return BigInt(Math.round(swapAmtStable));
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const fetchCoinPrice = async (coinType: string) => {
|
|
277
|
+
const BIRDEYE_API_KEY = "";
|
|
278
|
+
try {
|
|
279
|
+
const response = await axios.get(
|
|
280
|
+
`https://public-api.birdeye.so/defi/price?address=${coinType.replace(
|
|
281
|
+
/^\s+/g,
|
|
282
|
+
"",
|
|
283
|
+
)}&address_type=token`,
|
|
284
|
+
{
|
|
285
|
+
headers: {
|
|
286
|
+
"x-chain": "sui",
|
|
287
|
+
"X-API-KEY": BIRDEYE_API_KEY,
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
return response.data.data.value;
|
|
293
|
+
} catch (err) {
|
|
294
|
+
throw new Error(`Failed to fetch price for ${coinType}`);
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
export {
|
|
299
|
+
getPriceStable,
|
|
300
|
+
coingeckoID,
|
|
301
|
+
bigIntMax,
|
|
302
|
+
bigIntMin,
|
|
303
|
+
getPriceUncorrelated,
|
|
304
|
+
queryAllUserEvents,
|
|
305
|
+
fetchTokenDataCoingecko,
|
|
306
|
+
getOptimalLpSwapAmount,
|
|
307
|
+
fetchCoinPrice,
|
|
308
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ESNext", "DOM"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"outDir": "./dist",
|
|
13
|
+
"rootDir": "./src",
|
|
14
|
+
"types": ["bun-types"]
|
|
15
|
+
},
|
|
16
|
+
"include": ["src", "test"],
|
|
17
|
+
"exclude": ["node_modules", "dist"]
|
|
18
|
+
}
|
package/tsup.config.ts
ADDED