@bitflowlabs/core-sdk 1.0.1 → 2.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.
- package/dist/src/BitflowSDK.d.ts +23 -2
- package/dist/src/BitflowSDK.js +536 -82
- package/dist/src/BitflowSDK.js.map +1 -1
- package/dist/src/config.d.ts +1 -1
- package/dist/src/config.js +6 -4
- package/dist/src/config.js.map +1 -1
- package/dist/src/helpers/callReadOnlyHelper.js +10 -4
- package/dist/src/helpers/callReadOnlyHelper.js.map +1 -1
- package/dist/src/helpers/callSwapHelper.d.ts +2 -2
- package/dist/src/helpers/callSwapHelper.js +48 -7
- package/dist/src/helpers/callSwapHelper.js.map +1 -1
- package/dist/src/helpers/fetchDataHelper.d.ts +1 -1
- package/dist/src/helpers/fetchDataHelper.js +50 -17
- package/dist/src/helpers/fetchDataHelper.js.map +1 -1
- package/dist/src/helpers/fetchPossibleSwap.d.ts +2 -2
- package/dist/src/helpers/fetchPossibleSwap.js +10 -2
- package/dist/src/helpers/fetchPossibleSwap.js.map +1 -1
- package/dist/src/helpers/handleResultHelper.js +15 -15
- package/dist/src/helpers/handleResultHelper.js.map +1 -1
- package/dist/src/helpers/newPostConditionsHelper.d.ts +2 -0
- package/dist/src/helpers/newPostConditionsHelper.js +145 -0
- package/dist/src/helpers/newPostConditionsHelper.js.map +1 -0
- package/dist/src/helpers/postConditionsHelper.js +38 -13
- package/dist/src/helpers/postConditionsHelper.js.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/keeper/keeperAPI.d.ts +10 -0
- package/dist/src/keeper/keeperAPI.js +332 -0
- package/dist/src/keeper/keeperAPI.js.map +1 -0
- package/dist/src/keeper/types.d.ts +253 -0
- package/dist/src/keeper/types.js +65 -0
- package/dist/src/keeper/types.js.map +1 -0
- package/dist/src/test-keeper-routes.d.ts +1 -0
- package/dist/src/test-keeper-routes.js +67 -0
- package/dist/src/test-keeper-routes.js.map +1 -0
- package/dist/src/test-raw-token-response.d.ts +1 -0
- package/dist/src/test-raw-token-response.js +79 -0
- package/dist/src/test-raw-token-response.js.map +1 -0
- package/dist/src/test-sdk.d.ts +1 -0
- package/dist/src/test-sdk.js +229 -0
- package/dist/src/test-sdk.js.map +1 -0
- package/dist/src/test-token.fetch.d.ts +1 -0
- package/dist/src/test-token.fetch.js +63 -0
- package/dist/src/test-token.fetch.js.map +1 -0
- package/dist/src/types.d.ts +27 -2
- package/package.json +6 -5
- package/src/BitflowSDK.ts +675 -97
- package/src/config.ts +9 -6
- package/src/helpers/callReadOnlyHelper.ts +12 -7
- package/src/helpers/callSwapHelper.ts +21 -7
- package/src/helpers/fetchDataHelper.ts +58 -19
- package/src/helpers/fetchPossibleSwap.ts +18 -4
- package/src/helpers/handleResultHelper.ts +17 -16
- package/src/helpers/newPostConditionsHelper.ts +172 -0
- package/src/helpers/postConditionsHelper.ts +71 -19
- package/src/index.ts +3 -2
- package/src/keeper/keeperAPI.ts +435 -0
- package/src/keeper/types.ts +293 -0
- package/src/test-keeper-routes.ts +76 -0
- package/src/test-raw-token-response.ts +124 -0
- package/src/test-sdk.ts +262 -0
- package/src/test-token.fetch.ts +72 -0
- package/src/types.ts +29 -2
package/src/config.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import { BitflowSDKConfig } from
|
|
1
|
+
import { BitflowSDKConfig } from "./types";
|
|
2
2
|
|
|
3
3
|
export const configs: BitflowSDKConfig = {
|
|
4
4
|
BITFLOW_API_HOST:
|
|
5
|
-
process.env.NEXT_PUBLIC_BITFLOW_API_HOST ??
|
|
5
|
+
(process.env.NEXT_PUBLIC_BITFLOW_API_HOST ??
|
|
6
|
+
process.env.BITFLOW_API_HOST) ||
|
|
7
|
+
"",
|
|
6
8
|
BITFLOW_API_KEY:
|
|
7
|
-
process.env.NEXT_PUBLIC_BITFLOW_API_KEY ?? process.env.BITFLOW_API_KEY
|
|
9
|
+
(process.env.NEXT_PUBLIC_BITFLOW_API_KEY ?? process.env.BITFLOW_API_KEY) ||
|
|
10
|
+
"",
|
|
8
11
|
READONLY_CALL_API_HOST:
|
|
9
|
-
process.env.NEXT_PUBLIC_READONLY_CALL_API_HOST ??
|
|
10
|
-
|
|
12
|
+
(process.env.NEXT_PUBLIC_READONLY_CALL_API_HOST ??
|
|
13
|
+
process.env.READONLY_CALL_API_HOST) ||
|
|
14
|
+
"",
|
|
11
15
|
};
|
|
12
16
|
|
|
13
17
|
export function validateConfig() {
|
|
@@ -15,7 +19,6 @@ export function validateConfig() {
|
|
|
15
19
|
|
|
16
20
|
for (const envVar of requiredEnvVars) {
|
|
17
21
|
if (!configs[envVar]) {
|
|
18
|
-
console.error(`Missing required configuration: ${envVar}`);
|
|
19
22
|
throw new Error(`Missing required configuration: ${envVar}`);
|
|
20
23
|
}
|
|
21
24
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { fetchCallReadOnlyFunction } from "@stacks/transactions";
|
|
2
2
|
import { SwapContext } from "../types";
|
|
3
3
|
import { getTokenDecimals } from "./getTokenDecimalsHelper";
|
|
4
4
|
import { constructFunctionArgs } from "./constructFunctionArgs";
|
|
5
|
-
import { StacksMainnet } from "@stacks/network";
|
|
6
5
|
import { configs } from "../config";
|
|
7
6
|
import { getContractInterfaceAndFunction } from "./getContractInterfaceAndFunction";
|
|
8
7
|
import { handleResult } from "./handleResultHelper";
|
|
@@ -29,7 +28,11 @@ export const callReadOnlyFunctionHelper = async (
|
|
|
29
28
|
tokenXDecimals: number;
|
|
30
29
|
tokenYDecimals: number;
|
|
31
30
|
}> => {
|
|
32
|
-
const network =
|
|
31
|
+
const network = "mainnet";
|
|
32
|
+
|
|
33
|
+
const client = {
|
|
34
|
+
baseUrl: configs.READONLY_CALL_API_HOST,
|
|
35
|
+
};
|
|
33
36
|
|
|
34
37
|
try {
|
|
35
38
|
const contractKey = `${contractDeployer}.${contractName}`;
|
|
@@ -64,6 +67,7 @@ export const callReadOnlyFunctionHelper = async (
|
|
|
64
67
|
| { tokenContract: string; tokenDecimals: number }
|
|
65
68
|
| undefined;
|
|
66
69
|
|
|
70
|
+
// Attempt to find matching token decimals from parameters
|
|
67
71
|
for (const key in parameters) {
|
|
68
72
|
if (typeof parameters[key] === "object") {
|
|
69
73
|
for (const subKey in parameters[key]) {
|
|
@@ -81,6 +85,7 @@ export const callReadOnlyFunctionHelper = async (
|
|
|
81
85
|
if (tokenXMatchingDecimal) break;
|
|
82
86
|
}
|
|
83
87
|
|
|
88
|
+
// If not found yet, also check swapData parameters
|
|
84
89
|
if (!tokenXMatchingDecimal && swapData && swapData.parameters) {
|
|
85
90
|
const swapParameters = swapData.parameters;
|
|
86
91
|
for (const key in swapParameters) {
|
|
@@ -101,6 +106,7 @@ export const callReadOnlyFunctionHelper = async (
|
|
|
101
106
|
}
|
|
102
107
|
}
|
|
103
108
|
|
|
109
|
+
// Scale parameters if we find a matching decimal for tokenX
|
|
104
110
|
if (tokenXMatchingDecimal) {
|
|
105
111
|
const scaleAmount = (amount: number | string) => {
|
|
106
112
|
const scaledAmount =
|
|
@@ -149,13 +155,14 @@ export const callReadOnlyFunctionHelper = async (
|
|
|
149
155
|
functionArgsDefinition
|
|
150
156
|
);
|
|
151
157
|
|
|
152
|
-
const result = await
|
|
158
|
+
const result = await fetchCallReadOnlyFunction({
|
|
153
159
|
contractAddress: contractDeployer,
|
|
154
160
|
contractName,
|
|
155
161
|
functionName,
|
|
156
162
|
functionArgs,
|
|
157
|
-
senderAddress,
|
|
158
163
|
network,
|
|
164
|
+
client,
|
|
165
|
+
senderAddress: senderAddress,
|
|
159
166
|
});
|
|
160
167
|
|
|
161
168
|
const { rawResult, convertedResult } = handleResult(result);
|
|
@@ -217,7 +224,6 @@ export const callReadOnlyFunctionHelper = async (
|
|
|
217
224
|
console.warn(
|
|
218
225
|
`No matching decimal found for tokenY: ${tokenYId} or result is not a number`
|
|
219
226
|
);
|
|
220
|
-
|
|
221
227
|
return {
|
|
222
228
|
convertedResult,
|
|
223
229
|
rawResult,
|
|
@@ -228,7 +234,6 @@ export const callReadOnlyFunctionHelper = async (
|
|
|
228
234
|
} catch (error) {
|
|
229
235
|
console.warn(`Couldn't apply decimal conversion: ${error}`);
|
|
230
236
|
console.warn("Using raw result without decimal conversion");
|
|
231
|
-
|
|
232
237
|
return {
|
|
233
238
|
convertedResult,
|
|
234
239
|
rawResult,
|
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
import { AnchorMode, PostConditionMode } from "@stacks/transactions";
|
|
2
|
-
import {
|
|
2
|
+
import type { StacksProvider } from "@stacks/connect";
|
|
3
3
|
import { SwapContext } from "../types";
|
|
4
4
|
|
|
5
|
+
const loadStacksConnect = async () => {
|
|
6
|
+
if (typeof window === "undefined") {
|
|
7
|
+
throw new Error(
|
|
8
|
+
"Stacks Connect functionality is only available in browser environments"
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const { openContractCall } = await import("@stacks/connect");
|
|
14
|
+
return { openContractCall };
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.error("Error loading Stacks Connect:", error);
|
|
17
|
+
throw new Error("Failed to load Stacks Connect dependencies");
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
5
21
|
export const executeSwapHelper = async (
|
|
6
22
|
swapParams: {
|
|
7
23
|
functionArgs: any[];
|
|
@@ -12,13 +28,15 @@ export const executeSwapHelper = async (
|
|
|
12
28
|
},
|
|
13
29
|
senderAddress: string,
|
|
14
30
|
context: SwapContext,
|
|
15
|
-
stacksProvider
|
|
31
|
+
stacksProvider: StacksProvider,
|
|
16
32
|
onFinish?: (data: any) => void,
|
|
17
33
|
onCancel?: () => void
|
|
18
34
|
): Promise<void> => {
|
|
19
35
|
const network = context.network;
|
|
20
36
|
|
|
21
37
|
try {
|
|
38
|
+
const { openContractCall } = await loadStacksConnect();
|
|
39
|
+
|
|
22
40
|
const txOptions = {
|
|
23
41
|
contractAddress: swapParams.contractAddress,
|
|
24
42
|
contractName: swapParams.contractName,
|
|
@@ -41,11 +59,7 @@ export const executeSwapHelper = async (
|
|
|
41
59
|
}),
|
|
42
60
|
};
|
|
43
61
|
|
|
44
|
-
|
|
45
|
-
await openContractCall(txOptions, stacksProvider);
|
|
46
|
-
} else {
|
|
47
|
-
await openContractCall(txOptions);
|
|
48
|
-
}
|
|
62
|
+
await openContractCall({ ...txOptions }, stacksProvider);
|
|
49
63
|
} catch (error) {
|
|
50
64
|
console.error("Error executing swap:", error);
|
|
51
65
|
throw error;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { configs } from
|
|
2
|
-
import { Token } from
|
|
1
|
+
import { configs } from "../config";
|
|
2
|
+
import { Token, LayerOneAsset, PriceData } from "../types";
|
|
3
3
|
|
|
4
4
|
export const fetchAllTokensFromAPI = async (): Promise<Token[]> => {
|
|
5
5
|
const url = `${configs.BITFLOW_API_HOST}/getAllTokensAndPools?key=${configs.BITFLOW_API_KEY}`;
|
|
@@ -10,30 +10,69 @@ export const fetchAllTokensFromAPI = async (): Promise<Token[]> => {
|
|
|
10
10
|
}
|
|
11
11
|
const data = await response.json();
|
|
12
12
|
if (!data.tokens || !Array.isArray(data.tokens)) {
|
|
13
|
-
console.error(
|
|
14
|
-
throw new Error(
|
|
13
|
+
console.error("Unexpected data structure returned by API:", data);
|
|
14
|
+
throw new Error("Unexpected data structure returned by API");
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
return data.tokens.map((token: any) =>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
return data.tokens.map((token: any) => {
|
|
18
|
+
// Basic token properties
|
|
19
|
+
const mappedToken: Token = {
|
|
20
|
+
icon: token.icon || "",
|
|
21
|
+
name: token.name || "",
|
|
22
|
+
status: token.status || "",
|
|
23
|
+
symbol: token.symbol || "",
|
|
24
|
+
"token-id": token["token-id"] || "",
|
|
25
|
+
tokenId: token["token-id"] || "", // Duplicate for compatibility
|
|
26
|
+
tokenContract: token.tokenContract || null,
|
|
27
|
+
tokenDecimals: token.tokenDecimals || 0,
|
|
28
|
+
tokenName: token.tokenName || null,
|
|
29
|
+
wrapTokens: null,
|
|
30
|
+
base: token.base || "",
|
|
31
|
+
type: token.type || "",
|
|
32
|
+
isKeeperToken: token.isKeeperToken || false,
|
|
33
|
+
bridge: token.bridge || "FALSE",
|
|
34
|
+
layerOneAsset: token.layerOneAsset || null,
|
|
35
|
+
priceData: token.priceData || {
|
|
36
|
+
"1h_change": null,
|
|
37
|
+
"1yr_change": null,
|
|
38
|
+
"24h_change": null,
|
|
39
|
+
"30d_change": null,
|
|
40
|
+
"7d_change": null,
|
|
41
|
+
last_price: null,
|
|
42
|
+
last_updated: null,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Handle wrapTokens if present
|
|
47
|
+
if (token.wrapTokens) {
|
|
48
|
+
mappedToken.wrapTokens = Object.keys(token.wrapTokens).reduce(
|
|
49
|
+
(acc: any, key: string) => {
|
|
28
50
|
acc[key] = {
|
|
29
51
|
tokenContract: token.wrapTokens[key].tokenContract,
|
|
30
52
|
tokenDecimals: token.wrapTokens[key].tokenDecimals,
|
|
31
|
-
tokenName: token.wrapTokens[key].tokenName,
|
|
53
|
+
tokenName: token.wrapTokens[key].tokenName || null,
|
|
32
54
|
};
|
|
33
55
|
return acc;
|
|
34
|
-
},
|
|
35
|
-
|
|
36
|
-
|
|
56
|
+
},
|
|
57
|
+
{}
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Handle layerOneAsset if present
|
|
62
|
+
if (token.layerOneAsset && Object.keys(token.layerOneAsset).length > 0) {
|
|
63
|
+
mappedToken.layerOneAsset = {
|
|
64
|
+
address: token.layerOneAsset.address || "",
|
|
65
|
+
divisibility: token.layerOneAsset.divisibility || 0,
|
|
66
|
+
icon: token.layerOneAsset.icon || "",
|
|
67
|
+
isBitcoin: token.layerOneAsset.isBitcoin || false,
|
|
68
|
+
runeid: token.layerOneAsset.runeid || "",
|
|
69
|
+
spacedRune: token.layerOneAsset.spacedRune || "",
|
|
70
|
+
symbol: token.layerOneAsset.symbol || null,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return mappedToken;
|
|
75
|
+
});
|
|
37
76
|
} catch (error) {
|
|
38
77
|
console.error(`Error fetching data from ${url}:`, error);
|
|
39
78
|
throw error;
|
|
@@ -1,10 +1,24 @@
|
|
|
1
|
-
import { configs } from
|
|
2
|
-
import { SwapOptions } from
|
|
1
|
+
import { configs } from "../config";
|
|
2
|
+
import { SwapOptions } from "../types";
|
|
3
3
|
|
|
4
4
|
export const fetchPossibleSwapsFromAPI = async (
|
|
5
|
-
tokenX: string
|
|
5
|
+
tokenX: string,
|
|
6
|
+
page?: "KEEPER"
|
|
6
7
|
): Promise<SwapOptions> => {
|
|
7
|
-
const
|
|
8
|
+
const queryParams = new URLSearchParams({
|
|
9
|
+
key: configs.BITFLOW_API_KEY,
|
|
10
|
+
tokenX: tokenX,
|
|
11
|
+
depth: "4",
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
if (page) {
|
|
15
|
+
queryParams.append("page", page);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const url = `${
|
|
19
|
+
configs.BITFLOW_API_HOST
|
|
20
|
+
}/getAllRoutes?${queryParams.toString()}`;
|
|
21
|
+
|
|
8
22
|
try {
|
|
9
23
|
const response = await fetch(url);
|
|
10
24
|
if (!response.ok) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ClarityType } from "@stacks/transactions";
|
|
2
|
+
|
|
1
3
|
export const handleResult = (
|
|
2
4
|
result: any
|
|
3
5
|
): { rawResult: any; convertedResult: any } => {
|
|
@@ -10,53 +12,52 @@ export const handleResult = (
|
|
|
10
12
|
|
|
11
13
|
// Check if the result has a 'data' property and use it if present
|
|
12
14
|
const value = result.data !== undefined ? result.data : result.value;
|
|
13
|
-
|
|
14
15
|
switch (result.type) {
|
|
15
|
-
case
|
|
16
|
+
case "int":
|
|
16
17
|
rawResult = BigInt(result.value);
|
|
17
18
|
convertedResult = Number(rawResult);
|
|
18
19
|
break;
|
|
19
|
-
case
|
|
20
|
+
case "uint":
|
|
20
21
|
rawResult = BigInt(result.value);
|
|
21
22
|
convertedResult = Number(rawResult);
|
|
22
23
|
break;
|
|
23
|
-
case
|
|
24
|
+
case "buffer":
|
|
24
25
|
rawResult = Buffer.from(result.value);
|
|
25
26
|
convertedResult = rawResult.toString("hex");
|
|
26
27
|
break;
|
|
27
|
-
case
|
|
28
|
+
case "true":
|
|
28
29
|
rawResult = true;
|
|
29
30
|
convertedResult = true;
|
|
30
31
|
break;
|
|
31
|
-
case
|
|
32
|
+
case "false":
|
|
32
33
|
rawResult = false;
|
|
33
34
|
convertedResult = false;
|
|
34
35
|
break;
|
|
35
|
-
case
|
|
36
|
+
case "address":
|
|
36
37
|
rawResult = result.value;
|
|
37
38
|
convertedResult = result.value;
|
|
38
39
|
break;
|
|
39
|
-
case
|
|
40
|
+
case "contract":
|
|
40
41
|
rawResult = `${result.value.address}.${result.value.contractName}`;
|
|
41
42
|
convertedResult = rawResult;
|
|
42
43
|
break;
|
|
43
|
-
case
|
|
44
|
+
case "ok":
|
|
44
45
|
return handleResult(result.value);
|
|
45
|
-
case
|
|
46
|
+
case "err":
|
|
46
47
|
return handleResult(result.value);
|
|
47
|
-
case
|
|
48
|
+
case "none":
|
|
48
49
|
rawResult = null;
|
|
49
50
|
convertedResult = null;
|
|
50
51
|
break;
|
|
51
|
-
case
|
|
52
|
+
case "some":
|
|
52
53
|
return handleResult(result.value);
|
|
53
|
-
case
|
|
54
|
+
case "list":
|
|
54
55
|
rawResult = result.value.map((item: any) => handleResult(item).rawResult);
|
|
55
56
|
convertedResult = result.value.map(
|
|
56
57
|
(item: any) => handleResult(item).convertedResult
|
|
57
58
|
);
|
|
58
59
|
break;
|
|
59
|
-
case
|
|
60
|
+
case "tuple":
|
|
60
61
|
if (typeof value !== "object" || value === null) {
|
|
61
62
|
console.error("Tuple value is not an object:", value);
|
|
62
63
|
return { rawResult: null, convertedResult: null };
|
|
@@ -69,11 +70,11 @@ export const handleResult = (
|
|
|
69
70
|
const lastKey = sortedKeys[0];
|
|
70
71
|
|
|
71
72
|
return handleResult(value[lastKey]);
|
|
72
|
-
case
|
|
73
|
+
case "ascii":
|
|
73
74
|
rawResult = result.value;
|
|
74
75
|
convertedResult = result.value;
|
|
75
76
|
break;
|
|
76
|
-
case
|
|
77
|
+
case "utf8":
|
|
77
78
|
rawResult = result.value;
|
|
78
79
|
convertedResult = result.value;
|
|
79
80
|
break;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { Pc, PostCondition } from "@stacks/transactions";
|
|
2
|
+
|
|
3
|
+
const isWSTXv2Token = (value: any): boolean =>
|
|
4
|
+
typeof value === "string" &&
|
|
5
|
+
value.includes("SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wstx-v2");
|
|
6
|
+
|
|
7
|
+
const checkForWSTXv2 = (obj: any): boolean => {
|
|
8
|
+
if (typeof obj !== "object" || obj === null) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
for (const key in obj) {
|
|
13
|
+
if (isWSTXv2Token(obj[key])) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
if (typeof obj[key] === "object" && checkForWSTXv2(obj[key])) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return false;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const createSwapPostConditions = async (
|
|
25
|
+
functionArgs: any,
|
|
26
|
+
postConditionsData: any,
|
|
27
|
+
senderAddress: string,
|
|
28
|
+
tokenXDecimals: number,
|
|
29
|
+
tokenYDecimals: number
|
|
30
|
+
): Promise<PostCondition[]> => {
|
|
31
|
+
const postConditions: PostCondition[] = [];
|
|
32
|
+
const postConditionKeys = Object.keys(postConditionsData);
|
|
33
|
+
|
|
34
|
+
const isWSTXv2Involved = checkForWSTXv2(functionArgs);
|
|
35
|
+
|
|
36
|
+
for (let i = 0; i < postConditionKeys.length; i++) {
|
|
37
|
+
const key = postConditionKeys[i];
|
|
38
|
+
const pcData = postConditionsData[key];
|
|
39
|
+
const isFirst = i === 0;
|
|
40
|
+
const isLast = i === postConditionKeys.length - 1;
|
|
41
|
+
const isTxSender = pcData.senderAddress === "tx-sender";
|
|
42
|
+
const isSTX =
|
|
43
|
+
pcData.tokenContract === "token-stx" || pcData.tokenName === "token-stx";
|
|
44
|
+
const isAutoAlexV3OrLqstx =
|
|
45
|
+
pcData.tokenName === "auto-alex-v3" || pcData.tokenName === "lqstx";
|
|
46
|
+
|
|
47
|
+
let postConditionAmount: bigint;
|
|
48
|
+
let conditionCode: string;
|
|
49
|
+
|
|
50
|
+
if (isAutoAlexV3OrLqstx && (isFirst || isLast)) {
|
|
51
|
+
postConditionAmount = BigInt(0);
|
|
52
|
+
conditionCode = "willSendGte";
|
|
53
|
+
} else {
|
|
54
|
+
if (isFirst) {
|
|
55
|
+
postConditionAmount = functionArgs.dx;
|
|
56
|
+
conditionCode = "willSendEq";
|
|
57
|
+
} else if (isLast) {
|
|
58
|
+
postConditionAmount = functionArgs["min-dy"];
|
|
59
|
+
conditionCode = "willSendGte";
|
|
60
|
+
} else {
|
|
61
|
+
postConditionAmount = BigInt(0);
|
|
62
|
+
conditionCode = "willSendGte";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (isSTX && isWSTXv2Involved) {
|
|
67
|
+
postConditionAmount = postConditionAmount / BigInt(100);
|
|
68
|
+
} else if (!isSTX && (isFirst || isLast)) {
|
|
69
|
+
let decimalDifference: number;
|
|
70
|
+
if (isFirst) {
|
|
71
|
+
decimalDifference = tokenXDecimals - pcData.tokenDecimals;
|
|
72
|
+
} else {
|
|
73
|
+
decimalDifference = tokenYDecimals - pcData.tokenDecimals;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (decimalDifference > 0) {
|
|
77
|
+
postConditionAmount =
|
|
78
|
+
postConditionAmount / BigInt(10 ** decimalDifference);
|
|
79
|
+
} else if (decimalDifference < 0) {
|
|
80
|
+
postConditionAmount =
|
|
81
|
+
postConditionAmount * BigInt(10 ** Math.abs(decimalDifference));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
if (isTxSender) {
|
|
87
|
+
if (isSTX) {
|
|
88
|
+
postConditions.push(
|
|
89
|
+
conditionCode === "willSendEq"
|
|
90
|
+
? Pc.principal(senderAddress)
|
|
91
|
+
.willSendEq(postConditionAmount)
|
|
92
|
+
.ustx()
|
|
93
|
+
: Pc.principal(senderAddress)
|
|
94
|
+
.willSendGte(postConditionAmount)
|
|
95
|
+
.ustx()
|
|
96
|
+
);
|
|
97
|
+
} else {
|
|
98
|
+
postConditions.push(
|
|
99
|
+
conditionCode === "willSendEq"
|
|
100
|
+
? Pc.principal(senderAddress)
|
|
101
|
+
.willSendEq(postConditionAmount)
|
|
102
|
+
.ft(pcData.tokenContract, pcData.tokenName)
|
|
103
|
+
: Pc.principal(senderAddress)
|
|
104
|
+
.willSendGte(postConditionAmount)
|
|
105
|
+
.ft(pcData.tokenContract, pcData.tokenName)
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
if (isSTX) {
|
|
110
|
+
postConditions.push(
|
|
111
|
+
conditionCode === "willSendEq"
|
|
112
|
+
? Pc.principal(pcData.senderAddress)
|
|
113
|
+
.willSendEq(postConditionAmount)
|
|
114
|
+
.ustx()
|
|
115
|
+
: Pc.principal(pcData.senderAddress)
|
|
116
|
+
.willSendGte(postConditionAmount)
|
|
117
|
+
.ustx()
|
|
118
|
+
);
|
|
119
|
+
} else {
|
|
120
|
+
postConditions.push(
|
|
121
|
+
conditionCode === "willSendEq"
|
|
122
|
+
? Pc.principal(pcData.senderAddress)
|
|
123
|
+
.willSendEq(postConditionAmount)
|
|
124
|
+
.ft(pcData.tokenContract, pcData.tokenName)
|
|
125
|
+
: Pc.principal(pcData.senderAddress)
|
|
126
|
+
.willSendGte(postConditionAmount)
|
|
127
|
+
.ft(pcData.tokenContract, pcData.tokenName)
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (pcData.shareFeeContract !== null) {
|
|
133
|
+
if (isSTX) {
|
|
134
|
+
postConditions.push(
|
|
135
|
+
Pc.principal(pcData.shareFeeContract).willSendGte(0).ustx()
|
|
136
|
+
);
|
|
137
|
+
} else {
|
|
138
|
+
postConditions.push(
|
|
139
|
+
Pc.principal(pcData.shareFeeContract)
|
|
140
|
+
.willSendGte(0)
|
|
141
|
+
.ft(pcData.tokenContract, pcData.tokenName)
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (pcData.dikoStx !== null) {
|
|
147
|
+
if (isTxSender) {
|
|
148
|
+
postConditions.push(
|
|
149
|
+
Pc.principal(senderAddress)
|
|
150
|
+
.willSendGte(0)
|
|
151
|
+
.ft(pcData.dikoStx, "wstx")
|
|
152
|
+
);
|
|
153
|
+
} else {
|
|
154
|
+
postConditions.push(
|
|
155
|
+
Pc.principal(pcData.senderAddress)
|
|
156
|
+
.willSendGte(0)
|
|
157
|
+
.ft(pcData.dikoStx, "wstx")
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error(`Error creating post condition for ${key}:`, error);
|
|
163
|
+
throw new Error(
|
|
164
|
+
`Failed to create post condition for ${key}: ${
|
|
165
|
+
(error as Error).message
|
|
166
|
+
}`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return postConditions;
|
|
172
|
+
};
|
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
FungibleConditionCode,
|
|
3
|
-
makeStandardFungiblePostCondition,
|
|
4
|
-
makeStandardSTXPostCondition,
|
|
5
|
-
makeContractFungiblePostCondition,
|
|
6
|
-
makeContractSTXPostCondition,
|
|
7
|
-
createAssetInfo,
|
|
8
|
-
PostCondition,
|
|
9
|
-
} from "@stacks/transactions";
|
|
1
|
+
import { FungibleConditionCode, Pc, PostCondition } from "@stacks/transactions";
|
|
10
2
|
|
|
11
3
|
const isWSTXv2Token = (value: any): boolean =>
|
|
12
4
|
typeof value === "string" &&
|
|
@@ -34,17 +26,77 @@ const createSafeAssetInfo = (
|
|
|
34
26
|
contractName: string,
|
|
35
27
|
assetName: string
|
|
36
28
|
) => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
29
|
+
return {
|
|
30
|
+
contract: `${contractAddress}.${contractName}` as `${string}.${string}`,
|
|
31
|
+
tokenName: `${assetName}`,
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const makeStandardSTXPostCondition = (
|
|
36
|
+
senderAddress: string,
|
|
37
|
+
conditionCode:
|
|
38
|
+
| FungibleConditionCode.Equal
|
|
39
|
+
| FungibleConditionCode.GreaterEqual,
|
|
40
|
+
postConditionAmount: bigint
|
|
41
|
+
) => {
|
|
42
|
+
let initialPostCondition = Pc.principal(senderAddress);
|
|
43
|
+
let postCondition;
|
|
44
|
+
if (conditionCode === FungibleConditionCode.Equal) {
|
|
45
|
+
postCondition = initialPostCondition.willSendEq(postConditionAmount);
|
|
46
|
+
} else {
|
|
47
|
+
postCondition = initialPostCondition.willSendGte(postConditionAmount);
|
|
48
|
+
}
|
|
49
|
+
return postCondition.ustx();
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const makeStandardFungiblePostCondition = (
|
|
53
|
+
senderAddress: string,
|
|
54
|
+
conditionCode:
|
|
55
|
+
| FungibleConditionCode.Equal
|
|
56
|
+
| FungibleConditionCode.GreaterEqual,
|
|
57
|
+
postConditionAmount: bigint,
|
|
58
|
+
asset: { contract: `${string}.${string}`; tokenName: string }
|
|
59
|
+
) => {
|
|
60
|
+
let initialPostCondition = Pc.principal(senderAddress);
|
|
61
|
+
let postCondition;
|
|
62
|
+
if (conditionCode === FungibleConditionCode.Equal) {
|
|
63
|
+
postCondition = initialPostCondition.willSendEq(postConditionAmount);
|
|
64
|
+
} else {
|
|
65
|
+
postCondition = initialPostCondition.willSendGte(postConditionAmount);
|
|
47
66
|
}
|
|
67
|
+
return postCondition.ft(asset.contract, asset.tokenName);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const makeContractSTXPostCondition = (
|
|
71
|
+
contractAddress: string,
|
|
72
|
+
contractName: string,
|
|
73
|
+
conditionCode:
|
|
74
|
+
| FungibleConditionCode.Equal
|
|
75
|
+
| FungibleConditionCode.GreaterEqual,
|
|
76
|
+
postConditionAmount: bigint
|
|
77
|
+
) => {
|
|
78
|
+
return makeStandardSTXPostCondition(
|
|
79
|
+
`${contractAddress}.${contractName}`,
|
|
80
|
+
conditionCode,
|
|
81
|
+
postConditionAmount
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const makeContractFungiblePostCondition = (
|
|
86
|
+
contractAddress: string,
|
|
87
|
+
contractName: string,
|
|
88
|
+
conditionCode:
|
|
89
|
+
| FungibleConditionCode.Equal
|
|
90
|
+
| FungibleConditionCode.GreaterEqual,
|
|
91
|
+
postConditionAmount: bigint,
|
|
92
|
+
asset: { contract: `${string}.${string}`; tokenName: string }
|
|
93
|
+
) => {
|
|
94
|
+
return makeStandardFungiblePostCondition(
|
|
95
|
+
`${contractAddress}.${contractName}`,
|
|
96
|
+
conditionCode,
|
|
97
|
+
postConditionAmount,
|
|
98
|
+
asset
|
|
99
|
+
);
|
|
48
100
|
};
|
|
49
101
|
|
|
50
102
|
export const createSwapPostConditions = async (
|
package/src/index.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export { BitflowSDK } from
|
|
2
|
-
export * from
|
|
1
|
+
export { BitflowSDK } from "./BitflowSDK";
|
|
2
|
+
export * from "./types";
|
|
3
|
+
export * from "./keeper/types";
|