@bitflowlabs/core-sdk 1.0.0

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 (78) hide show
  1. package/README.md +205 -0
  2. package/dist/src/BitflowSDK.d.ts +14 -0
  3. package/dist/src/BitflowSDK.js +275 -0
  4. package/dist/src/BitflowSDK.js.map +1 -0
  5. package/dist/src/config.d.ts +3 -0
  6. package/dist/src/config.js +20 -0
  7. package/dist/src/config.js.map +1 -0
  8. package/dist/src/helpers/callGetSwapParams.d.ts +2 -0
  9. package/dist/src/helpers/callGetSwapParams.js +85 -0
  10. package/dist/src/helpers/callGetSwapParams.js.map +1 -0
  11. package/dist/src/helpers/callReadOnlyHelper.d.ts +8 -0
  12. package/dist/src/helpers/callReadOnlyHelper.js +191 -0
  13. package/dist/src/helpers/callReadOnlyHelper.js.map +1 -0
  14. package/dist/src/helpers/callSwapHelper.d.ts +9 -0
  15. package/dist/src/helpers/callSwapHelper.js +41 -0
  16. package/dist/src/helpers/callSwapHelper.js.map +1 -0
  17. package/dist/src/helpers/constructFunctionArgs.d.ts +1 -0
  18. package/dist/src/helpers/constructFunctionArgs.js +22 -0
  19. package/dist/src/helpers/constructFunctionArgs.js.map +1 -0
  20. package/dist/src/helpers/convertValuesHelper.d.ts +2 -0
  21. package/dist/src/helpers/convertValuesHelper.js +181 -0
  22. package/dist/src/helpers/convertValuesHelper.js.map +1 -0
  23. package/dist/src/helpers/fetchContractInterfaceHelper.d.ts +1 -0
  24. package/dist/src/helpers/fetchContractInterfaceHelper.js +20 -0
  25. package/dist/src/helpers/fetchContractInterfaceHelper.js.map +1 -0
  26. package/dist/src/helpers/fetchDataHelper.d.ts +2 -0
  27. package/dist/src/helpers/fetchDataHelper.js +44 -0
  28. package/dist/src/helpers/fetchDataHelper.js.map +1 -0
  29. package/dist/src/helpers/fetchPossibleSwap.d.ts +2 -0
  30. package/dist/src/helpers/fetchPossibleSwap.js +20 -0
  31. package/dist/src/helpers/fetchPossibleSwap.js.map +1 -0
  32. package/dist/src/helpers/getContractInterfaceAndFunction.d.ts +4 -0
  33. package/dist/src/helpers/getContractInterfaceAndFunction.js +15 -0
  34. package/dist/src/helpers/getContractInterfaceAndFunction.js.map +1 -0
  35. package/dist/src/helpers/getFunctionArgs.d.ts +1 -0
  36. package/dist/src/helpers/getFunctionArgs.js +12 -0
  37. package/dist/src/helpers/getFunctionArgs.js.map +1 -0
  38. package/dist/src/helpers/getTokenDecimalsHelper.d.ts +5 -0
  39. package/dist/src/helpers/getTokenDecimalsHelper.js +28 -0
  40. package/dist/src/helpers/getTokenDecimalsHelper.js.map +1 -0
  41. package/dist/src/helpers/getTokenNameHelper.d.ts +2 -0
  42. package/dist/src/helpers/getTokenNameHelper.js +22 -0
  43. package/dist/src/helpers/getTokenNameHelper.js.map +1 -0
  44. package/dist/src/helpers/handleResultHelper.d.ts +4 -0
  45. package/dist/src/helpers/handleResultHelper.js +80 -0
  46. package/dist/src/helpers/handleResultHelper.js.map +1 -0
  47. package/dist/src/helpers/postConditionsHelper.d.ts +2 -0
  48. package/dist/src/helpers/postConditionsHelper.js +135 -0
  49. package/dist/src/helpers/postConditionsHelper.js.map +1 -0
  50. package/dist/src/index.d.ts +2 -0
  51. package/dist/src/index.js +8 -0
  52. package/dist/src/index.js.map +1 -0
  53. package/dist/src/test/testMethods.d.ts +1 -0
  54. package/dist/src/test/testMethods.js +178 -0
  55. package/dist/src/test/testMethods.js.map +1 -0
  56. package/dist/src/types.d.ts +126 -0
  57. package/dist/src/types.js +3 -0
  58. package/dist/src/types.js.map +1 -0
  59. package/package.json +57 -0
  60. package/src/BitflowSDK.ts +385 -0
  61. package/src/config.ts +22 -0
  62. package/src/helpers/callGetSwapParams.ts +122 -0
  63. package/src/helpers/callReadOnlyHelper.ts +243 -0
  64. package/src/helpers/callSwapHelper.ts +53 -0
  65. package/src/helpers/constructFunctionArgs.ts +24 -0
  66. package/src/helpers/convertValuesHelper.ts +214 -0
  67. package/src/helpers/fetchContractInterfaceHelper.ts +19 -0
  68. package/src/helpers/fetchDataHelper.ts +41 -0
  69. package/src/helpers/fetchPossibleSwap.ts +18 -0
  70. package/src/helpers/getContractInterfaceAndFunction.ts +20 -0
  71. package/src/helpers/getFunctionArgs.ts +12 -0
  72. package/src/helpers/getTokenDecimalsHelper.ts +33 -0
  73. package/src/helpers/getTokenNameHelper.ts +26 -0
  74. package/src/helpers/handleResultHelper.ts +85 -0
  75. package/src/helpers/postConditionsHelper.ts +246 -0
  76. package/src/index.ts +2 -0
  77. package/src/test/testMethods.ts +227 -0
  78. package/src/types.ts +137 -0
@@ -0,0 +1,41 @@
1
+ import { configs } from '../config';
2
+ import { Token } from '../types';
3
+
4
+ export const fetchAllTokensFromAPI = async (): Promise<Token[]> => {
5
+ const url = `${configs.BITFLOW_API_HOST}/getAllTokensAndPools?key=${configs.BITFLOW_API_KEY}`;
6
+ try {
7
+ const response = await fetch(url);
8
+ if (!response.ok) {
9
+ throw new Error(`HTTP error! status: ${response.status}`);
10
+ }
11
+ const data = await response.json();
12
+ if (!data.tokens || !Array.isArray(data.tokens)) {
13
+ console.error('Unexpected data structure returned by API:', data);
14
+ throw new Error('Unexpected data structure returned by API');
15
+ }
16
+
17
+ return data.tokens.map((token: any) => ({
18
+ icon: token.icon,
19
+ name: token.name,
20
+ status: token.status,
21
+ symbol: token.symbol,
22
+ tokenId: token['token-id'],
23
+ tokenContract: token.tokenContract,
24
+ tokenDecimals: token.tokenDecimals,
25
+ tokenName: token.tokenName,
26
+ wrapTokens: token.wrapTokens
27
+ ? Object.keys(token.wrapTokens).reduce((acc: any, key: string) => {
28
+ acc[key] = {
29
+ tokenContract: token.wrapTokens[key].tokenContract,
30
+ tokenDecimals: token.wrapTokens[key].tokenDecimals,
31
+ tokenName: token.wrapTokens[key].tokenName,
32
+ };
33
+ return acc;
34
+ }, {})
35
+ : null,
36
+ }));
37
+ } catch (error) {
38
+ console.error(`Error fetching data from ${url}:`, error);
39
+ throw error;
40
+ }
41
+ };
@@ -0,0 +1,18 @@
1
+ import { configs } from '../config';
2
+ import { SwapOptions } from '../types';
3
+
4
+ export const fetchPossibleSwapsFromAPI = async (
5
+ tokenX: string
6
+ ): Promise<SwapOptions> => {
7
+ const url = `${configs.BITFLOW_API_HOST}/getAllRoutes?key=${configs.BITFLOW_API_KEY}&tokenX=${tokenX}&depth=4`;
8
+ try {
9
+ const response = await fetch(url);
10
+ if (!response.ok) {
11
+ throw new Error(`HTTP error! status: ${response.status}`);
12
+ }
13
+ return await response.json();
14
+ } catch (error) {
15
+ console.error(`Error fetching possible swaps from ${url}:`, error);
16
+ throw error;
17
+ }
18
+ };
@@ -0,0 +1,20 @@
1
+ import { fetchContractInterface } from "./fetchContractInterfaceHelper";
2
+ import { getFunctionArguments } from "./getFunctionArgs";
3
+
4
+ export const getContractInterfaceAndFunction = async (
5
+ contractDeployer: string,
6
+ contractName: string,
7
+ functionName: string
8
+ ) => {
9
+ const contractInterface = await fetchContractInterface(
10
+ contractDeployer,
11
+ contractName
12
+ );
13
+
14
+ const functionArgs = getFunctionArguments(contractInterface, functionName);
15
+
16
+ return {
17
+ contractInterface,
18
+ functionArgs,
19
+ };
20
+ };
@@ -0,0 +1,12 @@
1
+ export const getFunctionArguments = (
2
+ contractInterface: any,
3
+ functionName: string
4
+ ) => {
5
+ const func = contractInterface.functions.find(
6
+ (f: any) => f.name === functionName
7
+ );
8
+ if (!func) {
9
+ throw new Error(`Function ${functionName} not found in contract interface`);
10
+ }
11
+ return func.args;
12
+ };
@@ -0,0 +1,33 @@
1
+ import { SwapContext, Token } from "../types";
2
+
3
+ export const getTokenDecimals = (
4
+ tokenId: string,
5
+ context: SwapContext
6
+ ): { tokenContract: string; tokenDecimals: number }[] => {
7
+ const decimals: { tokenContract: string; tokenDecimals: number }[] = [];
8
+
9
+ const token = context.availableTokens.find((t) => t.tokenId === tokenId);
10
+
11
+ if (!token) {
12
+ throw new Error(`Token with id ${tokenId} not found`);
13
+ }
14
+
15
+ if (token.tokenContract) {
16
+ decimals.push({
17
+ tokenContract: token.tokenContract,
18
+ tokenDecimals: token.tokenDecimals,
19
+ });
20
+ }
21
+
22
+ if (token.wrapTokens) {
23
+ for (const wrapTokenKey in token.wrapTokens) {
24
+ const wrapToken = token.wrapTokens[wrapTokenKey];
25
+ decimals.push({
26
+ tokenContract: wrapToken.tokenContract,
27
+ tokenDecimals: wrapToken.tokenDecimals,
28
+ });
29
+ }
30
+ }
31
+
32
+ return decimals;
33
+ };
@@ -0,0 +1,26 @@
1
+ import { SwapContext } from "../types";
2
+
3
+ export const getTokenName = (
4
+ tokenContract: string,
5
+ context: SwapContext
6
+ ): string => {
7
+ for (const token of context.availableTokens) {
8
+ if (
9
+ token.tokenContract &&
10
+ token.tokenContract.toLowerCase() === tokenContract.toLowerCase()
11
+ ) {
12
+ return token.tokenName || token.name;
13
+ }
14
+ if (token.wrapTokens) {
15
+ for (const wrapTokenKey in token.wrapTokens) {
16
+ const wrapToken = token.wrapTokens[wrapTokenKey];
17
+ if (
18
+ wrapToken.tokenContract.toLowerCase() === tokenContract.toLowerCase()
19
+ ) {
20
+ return wrapToken.tokenName || token.name;
21
+ }
22
+ }
23
+ }
24
+ }
25
+ throw new Error(`Token contract ${tokenContract} not found`);
26
+ };
@@ -0,0 +1,85 @@
1
+ export const handleResult = (
2
+ result: any
3
+ ): { rawResult: any; convertedResult: any } => {
4
+ if (result === null || result === undefined) {
5
+ return { rawResult: null, convertedResult: null };
6
+ }
7
+
8
+ let rawResult: any;
9
+ let convertedResult: any;
10
+
11
+ // Check if the result has a 'data' property and use it if present
12
+ const value = result.data !== undefined ? result.data : result.value;
13
+
14
+ switch (result.type) {
15
+ case 0:
16
+ rawResult = BigInt(result.value);
17
+ convertedResult = Number(rawResult);
18
+ break;
19
+ case 1:
20
+ rawResult = BigInt(result.value);
21
+ convertedResult = Number(rawResult);
22
+ break;
23
+ case 2:
24
+ rawResult = Buffer.from(result.value);
25
+ convertedResult = rawResult.toString("hex");
26
+ break;
27
+ case 3:
28
+ rawResult = true;
29
+ convertedResult = true;
30
+ break;
31
+ case 4:
32
+ rawResult = false;
33
+ convertedResult = false;
34
+ break;
35
+ case 5:
36
+ rawResult = result.value;
37
+ convertedResult = result.value;
38
+ break;
39
+ case 6:
40
+ rawResult = `${result.value.address}.${result.value.contractName}`;
41
+ convertedResult = rawResult;
42
+ break;
43
+ case 7:
44
+ return handleResult(result.value);
45
+ case 8:
46
+ return handleResult(result.value);
47
+ case 9:
48
+ rawResult = null;
49
+ convertedResult = null;
50
+ break;
51
+ case 10:
52
+ return handleResult(result.value);
53
+ case 11:
54
+ rawResult = result.value.map((item: any) => handleResult(item).rawResult);
55
+ convertedResult = result.value.map(
56
+ (item: any) => handleResult(item).convertedResult
57
+ );
58
+ break;
59
+ case 12: // tuple
60
+ if (typeof value !== "object" || value === null) {
61
+ console.error("Tuple value is not an object:", value);
62
+ return { rawResult: null, convertedResult: null };
63
+ }
64
+ const sortedKeys = Object.keys(value).sort((a, b) => b.localeCompare(a));
65
+
66
+ if (sortedKeys.length === 0) {
67
+ return { rawResult: null, convertedResult: null };
68
+ }
69
+ const lastKey = sortedKeys[0];
70
+
71
+ return handleResult(value[lastKey]);
72
+ case 13:
73
+ rawResult = result.value;
74
+ convertedResult = result.value;
75
+ break;
76
+ case 14:
77
+ rawResult = result.value;
78
+ convertedResult = result.value;
79
+ break;
80
+ default:
81
+ throw new Error(`Unexpected result type: ${result.type}`);
82
+ }
83
+
84
+ return { rawResult, convertedResult };
85
+ };
@@ -0,0 +1,246 @@
1
+ import {
2
+ FungibleConditionCode,
3
+ makeStandardFungiblePostCondition,
4
+ makeStandardSTXPostCondition,
5
+ makeContractFungiblePostCondition,
6
+ makeContractSTXPostCondition,
7
+ createAssetInfo,
8
+ PostCondition,
9
+ } from "@stacks/transactions";
10
+
11
+ const isWSTXv2Token = (value: any): boolean =>
12
+ typeof value === "string" &&
13
+ value.includes("SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wstx-v2");
14
+
15
+ const checkForWSTXv2 = (obj: any): boolean => {
16
+ if (typeof obj !== "object" || obj === null) {
17
+ return false;
18
+ }
19
+
20
+ for (const key in obj) {
21
+ if (isWSTXv2Token(obj[key])) {
22
+ return true;
23
+ }
24
+ if (typeof obj[key] === "object" && checkForWSTXv2(obj[key])) {
25
+ return true;
26
+ }
27
+ }
28
+
29
+ return false;
30
+ };
31
+
32
+ const createSafeAssetInfo = (
33
+ contractAddress: string,
34
+ contractName: string,
35
+ assetName: string
36
+ ) => {
37
+ try {
38
+ return createAssetInfo(contractAddress, contractName, assetName);
39
+ } catch (error) {
40
+ console.error(
41
+ `Failed to create asset info for ${contractAddress}.${contractName}::${assetName}`,
42
+ error
43
+ );
44
+ throw new Error(
45
+ `Invalid asset info: ${contractAddress}.${contractName}::${assetName}`
46
+ );
47
+ }
48
+ };
49
+
50
+ export const createSwapPostConditions = async (
51
+ functionArgs: any,
52
+ postConditionsData: any,
53
+ senderAddress: string,
54
+ tokenXDecimals: number,
55
+ tokenYDecimals: number
56
+ ): Promise<PostCondition[]> => {
57
+ const postConditions: PostCondition[] = [];
58
+ const postConditionKeys = Object.keys(postConditionsData);
59
+
60
+ const isWSTXv2Involved = checkForWSTXv2(functionArgs);
61
+
62
+ for (let i = 0; i < postConditionKeys.length; i++) {
63
+ const key = postConditionKeys[i];
64
+ const pcData = postConditionsData[key];
65
+ const isFirst = i === 0;
66
+ const isLast = i === postConditionKeys.length - 1;
67
+ const isTxSender = pcData.senderAddress === "tx-sender";
68
+ const isSTX =
69
+ pcData.tokenContract === "token-stx" || pcData.tokenName === "token-stx";
70
+ const isAutoAlexV3OrLqstx =
71
+ pcData.tokenName === "auto-alex-v3" || pcData.tokenName === "lqstx";
72
+
73
+ let postConditionAmount: bigint;
74
+ let conditionCode: FungibleConditionCode;
75
+
76
+ if (isAutoAlexV3OrLqstx && (isFirst || isLast)) {
77
+ postConditionAmount = BigInt(0);
78
+ conditionCode = FungibleConditionCode.GreaterEqual;
79
+ } else {
80
+ if (isFirst) {
81
+ postConditionAmount = functionArgs.dx;
82
+ conditionCode = FungibleConditionCode.Equal;
83
+ } else if (isLast) {
84
+ postConditionAmount = functionArgs["min-dy"];
85
+ conditionCode = FungibleConditionCode.GreaterEqual;
86
+ } else {
87
+ postConditionAmount = BigInt(0);
88
+ conditionCode = FungibleConditionCode.GreaterEqual;
89
+ }
90
+ }
91
+
92
+ if (isSTX && isWSTXv2Involved) {
93
+ postConditionAmount = postConditionAmount / BigInt(100);
94
+ } else if (!isSTX && (isFirst || isLast)) {
95
+ let decimalDifference: number;
96
+ if (isFirst) {
97
+ decimalDifference = tokenXDecimals - pcData.tokenDecimals;
98
+ } else {
99
+ decimalDifference = tokenYDecimals - pcData.tokenDecimals;
100
+ }
101
+
102
+ if (decimalDifference > 0) {
103
+ postConditionAmount =
104
+ postConditionAmount / BigInt(10 ** decimalDifference);
105
+ } else if (decimalDifference < 0) {
106
+ postConditionAmount =
107
+ postConditionAmount * BigInt(10 ** Math.abs(decimalDifference));
108
+ }
109
+ }
110
+
111
+ try {
112
+ if (isTxSender) {
113
+ if (isSTX) {
114
+ postConditions.push(
115
+ makeStandardSTXPostCondition(
116
+ senderAddress,
117
+ conditionCode,
118
+ postConditionAmount
119
+ )
120
+ );
121
+ } else {
122
+ const [contractAddress, contractName] =
123
+ pcData.tokenContract.split(".");
124
+ const assetInfo = createSafeAssetInfo(
125
+ contractAddress,
126
+ contractName,
127
+ pcData.tokenName
128
+ );
129
+ postConditions.push(
130
+ makeStandardFungiblePostCondition(
131
+ senderAddress,
132
+ conditionCode,
133
+ postConditionAmount,
134
+ assetInfo
135
+ )
136
+ );
137
+ }
138
+ } else {
139
+ const [contractAddress, contractName] = pcData.senderAddress.split(".");
140
+ if (isSTX) {
141
+ postConditions.push(
142
+ makeContractSTXPostCondition(
143
+ contractAddress,
144
+ contractName,
145
+ conditionCode,
146
+ postConditionAmount
147
+ )
148
+ );
149
+ } else {
150
+ const [tokenContractAddress, tokenContractName] =
151
+ pcData.tokenContract.split(".");
152
+ const assetInfo = createSafeAssetInfo(
153
+ tokenContractAddress,
154
+ tokenContractName,
155
+ pcData.tokenName
156
+ );
157
+ postConditions.push(
158
+ makeContractFungiblePostCondition(
159
+ contractAddress,
160
+ contractName,
161
+ conditionCode,
162
+ postConditionAmount,
163
+ assetInfo
164
+ )
165
+ );
166
+ }
167
+ }
168
+
169
+ if (pcData.shareFeeContract !== null) {
170
+ const [shareFeeContractAddress, shareFeeContractName] =
171
+ pcData.shareFeeContract.split(".");
172
+
173
+ if (isSTX) {
174
+ postConditions.push(
175
+ makeContractSTXPostCondition(
176
+ shareFeeContractAddress,
177
+ shareFeeContractName,
178
+ FungibleConditionCode.GreaterEqual,
179
+ BigInt(0)
180
+ )
181
+ );
182
+ } else {
183
+ const [tokenContractAddress, tokenContractName] =
184
+ pcData.tokenContract.split(".");
185
+ const assetInfo = createSafeAssetInfo(
186
+ tokenContractAddress,
187
+ tokenContractName,
188
+ pcData.tokenName
189
+ );
190
+
191
+ postConditions.push(
192
+ makeContractFungiblePostCondition(
193
+ shareFeeContractAddress,
194
+ shareFeeContractName,
195
+ FungibleConditionCode.GreaterEqual,
196
+ BigInt(0),
197
+ assetInfo
198
+ )
199
+ );
200
+ }
201
+ }
202
+
203
+ if (pcData.dikoStx !== null) {
204
+ const [dikoContractAddress, dikoContractName] =
205
+ pcData.dikoStx.split(".");
206
+ const dikoAssetInfo = createSafeAssetInfo(
207
+ dikoContractAddress,
208
+ dikoContractName,
209
+ "wstx"
210
+ );
211
+
212
+ if (isTxSender) {
213
+ postConditions.push(
214
+ makeStandardFungiblePostCondition(
215
+ senderAddress,
216
+ FungibleConditionCode.GreaterEqual,
217
+ BigInt(0),
218
+ dikoAssetInfo
219
+ )
220
+ );
221
+ } else {
222
+ const [senderContractAddress, senderContractName] =
223
+ pcData.senderAddress.split(".");
224
+ postConditions.push(
225
+ makeContractFungiblePostCondition(
226
+ senderContractAddress,
227
+ senderContractName,
228
+ FungibleConditionCode.GreaterEqual,
229
+ BigInt(0),
230
+ dikoAssetInfo
231
+ )
232
+ );
233
+ }
234
+ }
235
+ } catch (error) {
236
+ console.error(`Error creating post condition for ${key}:`, error);
237
+ throw new Error(
238
+ `Failed to create post condition for ${key}: ${
239
+ (error as Error).message
240
+ }`
241
+ );
242
+ }
243
+ }
244
+
245
+ return postConditions;
246
+ };
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { BitflowSDK } from './BitflowSDK';
2
+ export * from './types';