@alphafi/alphafi-sdk 0.0.2

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 (46) hide show
  1. package/.babelrc +6 -0
  2. package/.eslintrc.json +30 -0
  3. package/README.md +1 -0
  4. package/dist/common/cetus_mainnet_config.d.ts +3 -0
  5. package/dist/common/cetus_mainnet_config.d.ts.map +1 -0
  6. package/dist/common/coins.d.ts +11 -0
  7. package/dist/common/coins.d.ts.map +1 -0
  8. package/dist/common/constants.d.ts +294 -0
  9. package/dist/common/constants.d.ts.map +1 -0
  10. package/dist/common/maps.d.ts +30 -0
  11. package/dist/common/maps.d.ts.map +1 -0
  12. package/dist/common/pyth.d.ts +7 -0
  13. package/dist/common/pyth.d.ts.map +1 -0
  14. package/dist/common/types.d.ts +331 -0
  15. package/dist/common/types.d.ts.map +1 -0
  16. package/dist/functions.d.ts +20 -0
  17. package/dist/functions.d.ts.map +1 -0
  18. package/dist/getVaultBalances.d.ts +5 -0
  19. package/dist/getVaultBalances.d.ts.map +1 -0
  20. package/dist/getVaults.d.ts +3 -0
  21. package/dist/getVaults.d.ts.map +1 -0
  22. package/dist/index.d.ts +4 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +3 -0
  25. package/dist/index.js.LICENSE.txt +28 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/portfolioAmount.d.ts +36 -0
  28. package/dist/portfolioAmount.d.ts.map +1 -0
  29. package/dist/price.d.ts +19 -0
  30. package/dist/price.d.ts.map +1 -0
  31. package/jest.config.js +14 -0
  32. package/package.json +51 -0
  33. package/src/common/cetus_mainnet_config.ts +72 -0
  34. package/src/common/coins.ts +126 -0
  35. package/src/common/constants.ts +820 -0
  36. package/src/common/maps.ts +200 -0
  37. package/src/common/pyth.ts +23 -0
  38. package/src/common/types.ts +446 -0
  39. package/src/functions.ts +299 -0
  40. package/src/getVaultBalances.ts +128 -0
  41. package/src/getVaults.ts +63 -0
  42. package/src/index.ts +13 -0
  43. package/src/portfolioAmount.ts +365 -0
  44. package/src/price.ts +397 -0
  45. package/tsconfig.json +21 -0
  46. package/webpack.config.js +59 -0
package/src/price.ts ADDED
@@ -0,0 +1,397 @@
1
+ import BN from "bn.js";
2
+ import { coins } from "./common/coins";
3
+ import CetusClmmSDK, {
4
+ SdkOptions,
5
+ Pool,
6
+ Percentage,
7
+ adjustForSlippage,
8
+ CalculateRatesResult,
9
+ ClmmPoolUtil,
10
+ TickMath,
11
+ d,
12
+ } from "@cetusprotocol/cetus-sui-clmm-sdk";
13
+ import {
14
+ CetusSwapOptions,
15
+ Coin,
16
+ CreatePoolOptions,
17
+ SimpleCache,
18
+ } from "./common/types";
19
+ import { Transaction } from "@mysten/sui/transactions";
20
+ import { cetusMainnetSDKOptions } from "./common/cetus_mainnet_config";
21
+ import axios from "axios";
22
+ import { PythPriceIdPair } from "./common/pyth";
23
+
24
+ export async function getLatestPrice(
25
+ pair: PythPriceIdPair,
26
+ ): Promise<string | undefined> {
27
+ let price: string | undefined = undefined;
28
+
29
+ if (pair === ("ALPHA/USD" as PythPriceIdPair)) {
30
+ const alphaPrice = await getAlphaPrice();
31
+ if (alphaPrice) {
32
+ price = `${alphaPrice}`;
33
+ }
34
+ } else if (pair === ("USDY/USD" as PythPriceIdPair)) {
35
+ const usdyPrice = await getUSDYPrice();
36
+ if (usdyPrice) {
37
+ price = `${usdyPrice}`;
38
+ }
39
+ } else {
40
+ try {
41
+ price = await fetchPriceFromAlphaAPI(pair);
42
+ if (!price) {
43
+ console.error(`Failed to get price for pair ${pair}`);
44
+ }
45
+ } catch (error) {
46
+ console.error(`Error in getPrice for pair ${pair}:`, error);
47
+ }
48
+ }
49
+ return price;
50
+ }
51
+
52
+ interface PythPricePair {
53
+ pair: PythPriceIdPair;
54
+ price: string;
55
+ }
56
+
57
+ async function fetchPriceFromAlphaAPI(
58
+ pair: string,
59
+ ): Promise<string | undefined> {
60
+ let pythPricePair: PythPricePair | undefined = undefined;
61
+ const cachedPromise = axios
62
+ .get<PythPricePair>(`https://api.alphafi.xyz/alpha/fetchPrice?pair=${pair}`)
63
+ .then((response) => {
64
+ const data = response.data;
65
+ return data;
66
+ })
67
+ .catch((error) => {
68
+ throw error;
69
+ });
70
+ pythPricePair = await cachedPromise;
71
+
72
+ if (pythPricePair) {
73
+ return pythPricePair.price;
74
+ } else {
75
+ throw new Error(`Price not found for pair: ${pair}`);
76
+ }
77
+ }
78
+
79
+ const alphaPricePromiseCache = new SimpleCache<Promise<number>>(60000);
80
+ const alphaPriceCache = new SimpleCache<number>(60000);
81
+
82
+ export async function getAlphaPrice(
83
+ ignoreCache: boolean = false,
84
+ ): Promise<number | undefined> {
85
+ const cacheKey = `getAlphaPrice`;
86
+ if (ignoreCache) {
87
+ alphaPriceCache.delete(cacheKey);
88
+ alphaPricePromiseCache.delete(cacheKey);
89
+ }
90
+ const cachedResponse = alphaPriceCache.get(cacheKey);
91
+
92
+ if (cachedResponse) {
93
+ return cachedResponse;
94
+ }
95
+ let alphaPrice = 0;
96
+ let cachedPromise = alphaPricePromiseCache.get(cacheKey);
97
+ if (!cachedPromise) {
98
+ cachedPromise = (async (): Promise<number> => {
99
+ const cetusGateway = new CetusGateway(cetusMainnetSDKOptions);
100
+ const swapOption: CetusSwapOptions = {
101
+ pair: { coinA: coins.ALPHA, coinB: coins.SUI },
102
+ senderAddress:
103
+ "0x4260738f0f7341adc79a8edaa62f8a4681ebd27c595aecab1f322f47bfc52c5e",
104
+ slippage: 1,
105
+ inAmount: new BN(1_000_000_000),
106
+ };
107
+ const res = await cetusGateway.getPrice(swapOption);
108
+ const latestSuiPrice = await getLatestPrice("SUI/USD");
109
+ if (latestSuiPrice) {
110
+ alphaPrice =
111
+ res.estimatedAmountOut.toNumber() * Number(latestSuiPrice) * 1e-9;
112
+ alphaPriceCache.set(cacheKey, alphaPrice);
113
+ alphaPricePromiseCache.delete(cacheKey); // Remove the promise from cache
114
+ }
115
+ return alphaPrice;
116
+ })().catch((error) => {
117
+ alphaPricePromiseCache.delete(cacheKey); // Remove the promise from cache
118
+ throw error;
119
+ });
120
+
121
+ alphaPricePromiseCache.set(cacheKey, cachedPromise);
122
+ }
123
+
124
+ return cachedPromise;
125
+ }
126
+
127
+ export async function getUSDYPrice(): Promise<number | undefined> {
128
+ const cetusGateway = new CetusGateway(cetusMainnetSDKOptions);
129
+ const swapOption: CetusSwapOptions = {
130
+ pair: { coinA: coins.USDY, coinB: coins.USDC },
131
+ senderAddress:
132
+ "0x4260738f0f7341adc79a8edaa62f8a4681ebd27c595aecab1f322f47bfc52c5e",
133
+ slippage: 1,
134
+ inAmount: new BN(1_000_000),
135
+ };
136
+ const res = await cetusGateway.getPrice(swapOption);
137
+ const latestSuiPrice = await getLatestPrice("USDC/USD");
138
+ if (latestSuiPrice) {
139
+ return res.estimatedAmountOut.toNumber() * Number(latestSuiPrice) * 1e-6;
140
+ }
141
+ }
142
+
143
+ interface PoolData {
144
+ pair: string;
145
+ id: string;
146
+ a2b: boolean;
147
+ }
148
+
149
+ const poolData: { [key: string]: PoolData } = {
150
+ "SUI/USDC": {
151
+ pair: "SUI/USDC",
152
+ id: "0xcf994611fd4c48e277ce3ffd4d4364c914af2c3cbb05f7bf6facd371de688630",
153
+ a2b: false,
154
+ },
155
+ "USDC/SUI": {
156
+ pair: "USDC/SUI",
157
+ id: "0xcf994611fd4c48e277ce3ffd4d4364c914af2c3cbb05f7bf6facd371de688630",
158
+ a2b: true,
159
+ },
160
+ "SUI/USDT": {
161
+ pair: "SUI/USDT",
162
+ id: "0x06d8af9e6afd27262db436f0d37b304a041f710c3ea1fa4c3a9bab36b3569ad3",
163
+ a2b: false,
164
+ },
165
+ "USDT/SUI": {
166
+ pair: "USDT/SUI",
167
+ id: "0x06d8af9e6afd27262db436f0d37b304a041f710c3ea1fa4c3a9bab36b3569ad3",
168
+ a2b: true,
169
+ },
170
+ "USDC/USDT": {
171
+ pair: "USDC/USDT",
172
+ id: "0xc8d7a1503dc2f9f5b05449a87d8733593e2f0f3e7bffd90541252782e4d2ca20",
173
+ a2b: false,
174
+ },
175
+ "USDT/USDC": {
176
+ pair: "USDT/USDC",
177
+ id: "0xc8d7a1503dc2f9f5b05449a87d8733593e2f0f3e7bffd90541252782e4d2ca20",
178
+ a2b: true,
179
+ },
180
+ "SUI/VSUI": {
181
+ pair: "SUI/VSUI",
182
+ id: "0x6c545e78638c8c1db7a48b282bb8ca79da107993fcb185f75cedc1f5adb2f535",
183
+ a2b: false,
184
+ },
185
+ "VSUI/SUI": {
186
+ pair: "VSUI/SUI",
187
+ id: "0x6c545e78638c8c1db7a48b282bb8ca79da107993fcb185f75cedc1f5adb2f535",
188
+ a2b: true,
189
+ },
190
+ "SUI/NAVX": {
191
+ pair: "SUI/NAVX",
192
+ id: "0x0254747f5ca059a1972cd7f6016485d51392a3fde608107b93bbaebea550f703",
193
+ a2b: false,
194
+ },
195
+ "NAVX/SUI": {
196
+ pair: "NAVX/SUI",
197
+ id: "0x0254747f5ca059a1972cd7f6016485d51392a3fde608107b93bbaebea550f703",
198
+ a2b: true,
199
+ },
200
+ "ALPHA/SUI": {
201
+ pair: "ALPHA/SUI",
202
+ id: "0xda7347c3192a27ddac32e659c9d9cbed6f8c9d1344e605c71c8886d7b787d720",
203
+ a2b: true,
204
+ },
205
+ "SUI/ALPHA": {
206
+ pair: "ALPHA/SUI",
207
+ id: "0xda7347c3192a27ddac32e659c9d9cbed6f8c9d1344e605c71c8886d7b787d720",
208
+ a2b: false,
209
+ },
210
+ "USDY/USDC": {
211
+ pair: "USDY/USDC",
212
+ id: "0x0e809689d04d87f4bd4e660cd1b84bf5448c5a7997e3d22fc480e7e5e0b3f58d",
213
+ a2b: true,
214
+ },
215
+ "USDC/USDY": {
216
+ pair: "USDY/USDC",
217
+ id: "0x0e809689d04d87f4bd4e660cd1b84bf5448c5a7997e3d22fc480e7e5e0b3f58d",
218
+ a2b: false,
219
+ },
220
+ };
221
+
222
+ export class CetusGateway {
223
+ private cetusSDK: CetusClmmSDK;
224
+
225
+ constructor(sdkOptions: SdkOptions) {
226
+ this.cetusSDK = new CetusClmmSDK(sdkOptions);
227
+ this.cetusSDK.senderAddress = sdkOptions.simulationAccount.address;
228
+ }
229
+
230
+ async getPools(pairs: { coinA?: Coin; coinB?: Coin }[]) {
231
+ const allPools = await this.cetusSDK.Pool.getPoolsWithPage([]);
232
+ const matchedPools: Pool[] = [];
233
+
234
+ pairs.forEach((pair) => {
235
+ const filteredPools: Pool[] = allPools.filter((pool) => {
236
+ if (pair.coinA && pair.coinB) {
237
+ return (
238
+ (pool.coinTypeA === pair.coinA.type &&
239
+ pool.coinTypeB === pair.coinB.type) ||
240
+ (pool.coinTypeA === pair.coinB.type &&
241
+ pool.coinTypeB === pair.coinA.type)
242
+ );
243
+ } else if (pair.coinA && !pair.coinB) {
244
+ return (
245
+ pool.coinTypeA === pair.coinA.type ||
246
+ pool.coinTypeB === pair.coinA.type
247
+ );
248
+ } else if (!pair.coinA && pair.coinB) {
249
+ return (
250
+ pool.coinTypeB === pair.coinB.type ||
251
+ pool.coinTypeB === pair.coinB.type
252
+ );
253
+ }
254
+ });
255
+ matchedPools.push(...filteredPools);
256
+ });
257
+
258
+ return matchedPools;
259
+ }
260
+
261
+ async getPrice(options: CetusSwapOptions): Promise<CalculateRatesResult> {
262
+ const { pair, inAmount, outAmount } = options;
263
+ const poolDatum = poolData[pair.coinA.name + "/" + pair.coinB.name];
264
+ let amount: BN = new BN(0);
265
+ let byAmountIn: boolean = true;
266
+ if (inAmount) {
267
+ byAmountIn = true;
268
+ amount = inAmount;
269
+ } else if (outAmount) {
270
+ byAmountIn = false;
271
+ amount = outAmount;
272
+ }
273
+
274
+ const pool = await this.cetusSDK.Pool.getPool(poolDatum.id);
275
+
276
+ const swapTicks = await this.cetusSDK.Pool.fetchTicks({
277
+ pool_id: pool.poolAddress,
278
+ coinTypeA: pool.coinTypeA,
279
+ coinTypeB: pool.coinTypeB,
280
+ });
281
+
282
+ const res = this.cetusSDK.Swap.calculateRates({
283
+ decimalsA: pair.coinA.expo,
284
+ decimalsB: pair.coinB.expo,
285
+ a2b: poolDatum.a2b,
286
+ byAmountIn,
287
+ amount,
288
+ swapTicks,
289
+ currentPool: pool,
290
+ });
291
+
292
+ return res;
293
+ }
294
+
295
+ async getTransaction(options: CetusSwapOptions): Promise<Transaction> {
296
+ const res = await this.getPrice(options);
297
+
298
+ const { pair, senderAddress, slippage, inAmount, outAmount } = options;
299
+ const poolDatum = poolData[pair.coinA.name + "/" + pair.coinB.name];
300
+ const poolID = poolDatum.id;
301
+ const pool = await this.cetusSDK.Pool.getPool(poolID);
302
+
303
+ let byAmountIn: boolean = true;
304
+ if (inAmount) {
305
+ byAmountIn = true;
306
+ } else if (outAmount) {
307
+ byAmountIn = false;
308
+ }
309
+
310
+ const slippagePercentage = new Percentage(
311
+ new BN(Math.floor(slippage * 100).toString()),
312
+ new BN(100),
313
+ );
314
+ const toAmount = byAmountIn
315
+ ? res.estimatedAmountOut
316
+ : res.estimatedAmountIn;
317
+ const amountLimit = adjustForSlippage(
318
+ toAmount,
319
+ slippagePercentage,
320
+ !byAmountIn,
321
+ );
322
+ // TransactionBlock
323
+ this.cetusSDK.senderAddress = senderAddress;
324
+ const txb = this.cetusSDK.Swap.createSwapTransactionPayload({
325
+ pool_id: pool.poolAddress,
326
+ coinTypeA: pool.coinTypeA,
327
+ coinTypeB: pool.coinTypeB,
328
+ a2b: poolDatum.a2b,
329
+ by_amount_in: byAmountIn,
330
+ amount: res.amount.toString(),
331
+ amount_limit: amountLimit.toString(),
332
+ });
333
+
334
+ return txb;
335
+ }
336
+
337
+ async createPoolTransactionBlock(
338
+ options: CreatePoolOptions,
339
+ ): Promise<Transaction> {
340
+ const initializeSqrtPrice = TickMath.priceToSqrtPriceX64(
341
+ d(options.initializePrice),
342
+ coins[options.coinNameA].expo,
343
+ coins[options.coinNameB].expo,
344
+ ).toString();
345
+
346
+ const current_tick_index = TickMath.sqrtPriceX64ToTickIndex(
347
+ new BN(Math.floor(parseFloat(initializeSqrtPrice)).toString()),
348
+ );
349
+
350
+ // build tick range
351
+ const lowerTick = TickMath.getPrevInitializableTickIndex(
352
+ new BN(Math.floor(current_tick_index).toString()).toNumber(),
353
+ new BN(options.tickSpacing.toString()).toNumber(),
354
+ );
355
+ const upperTick = TickMath.getNextInitializableTickIndex(
356
+ new BN(Math.floor(current_tick_index).toString()).toNumber(),
357
+ new BN(options.tickSpacing.toString()).toNumber(),
358
+ );
359
+
360
+ // slippage value 0.05 means 5%
361
+ const slippage = 0.01;
362
+ // Estimate liquidity and token amount from one amounts
363
+ const liquidityInput = ClmmPoolUtil.estLiquidityAndcoinAmountFromOneAmounts(
364
+ lowerTick,
365
+ upperTick,
366
+ new BN(options.amount.toString()),
367
+ options.isAmountA,
368
+ true,
369
+ slippage,
370
+ new BN(initializeSqrtPrice.toString()),
371
+ );
372
+
373
+ // Estimate token a and token b amount
374
+ const amount_a = options.isAmountA
375
+ ? options.amount
376
+ : liquidityInput.tokenMaxA.toNumber();
377
+ const amount_b = options.isAmountA
378
+ ? liquidityInput.tokenMaxB.toNumber()
379
+ : options.amount;
380
+
381
+ // build creatPoolPayload Payload
382
+ const txb = this.cetusSDK.Pool.creatPoolTransactionPayload({
383
+ coinTypeA: coins[options.coinNameA].type,
384
+ coinTypeB: coins[options.coinNameB].type,
385
+ tick_spacing: options.tickSpacing,
386
+ initialize_sqrt_price: `${initializeSqrtPrice}`,
387
+ uri: options.imageUrl,
388
+ amount_a: amount_a,
389
+ amount_b: amount_b,
390
+ fix_amount_a: options.isAmountA,
391
+ tick_lower: lowerTick,
392
+ tick_upper: upperTick,
393
+ });
394
+
395
+ return txb;
396
+ }
397
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "esnext",
4
+ "module": "esnext",
5
+ "outDir": "./dist",
6
+ "esModuleInterop": true,
7
+ "forceConsistentCasingInFileNames": true,
8
+ "strict": true,
9
+ "skipLibCheck": true,
10
+ "declaration": true,
11
+ "declarationMap": true,
12
+ "declarationDir": "./dist",
13
+ "types": ["jest"],
14
+ "sourceMap": true,
15
+ "lib": ["dom", "esnext"],
16
+ "jsx": "react",
17
+ "moduleResolution": "node"
18
+ },
19
+ "include": ["src"],
20
+ "exclude": ["node_modules", "**/*.spec.ts"]
21
+ }
@@ -0,0 +1,59 @@
1
+ const path = require("path");
2
+ const { CleanWebpackPlugin } = require("clean-webpack-plugin");
3
+
4
+ module.exports = {
5
+ entry: "./src/index.ts",
6
+ target: "node",
7
+ mode: "production", // or 'development' depending on your needs
8
+ module: {
9
+ rules: [
10
+ {
11
+ test: /\.ts$/,
12
+ use: "ts-loader",
13
+ exclude: /node_modules/,
14
+ },
15
+ {
16
+ test: /\.js$/,
17
+ use: ["source-map-loader"],
18
+ enforce: "pre",
19
+ exclude: /node_modules/,
20
+ },
21
+ ],
22
+ },
23
+ resolve: {
24
+ extensions: [".ts", ".js"],
25
+ },
26
+ output: {
27
+ filename: "index.js",
28
+ path: path.resolve(__dirname, "dist"),
29
+ library: {
30
+ name: "AlphaFiSDK", // Replace with your library name
31
+ type: "umd",
32
+ },
33
+ globalObject: "this",
34
+ },
35
+ optimization: {
36
+ splitChunks: false, // Disable splitChunks unless necessary
37
+ },
38
+ devtool: "source-map",
39
+ performance: {
40
+ hints: "warning",
41
+ },
42
+ plugins: [
43
+ new CleanWebpackPlugin(), // Clean output directory before build
44
+ ],
45
+ externals: {
46
+ lodash: {
47
+ commonjs: "lodash",
48
+ commonjs2: "lodash",
49
+ amd: "lodash",
50
+ root: "_",
51
+ },
52
+ react: {
53
+ commonjs: "react",
54
+ commonjs2: "react",
55
+ amd: "react",
56
+ root: "React",
57
+ },
58
+ },
59
+ };