@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.
- package/README.md +205 -0
- package/dist/src/BitflowSDK.d.ts +14 -0
- package/dist/src/BitflowSDK.js +275 -0
- package/dist/src/BitflowSDK.js.map +1 -0
- package/dist/src/config.d.ts +3 -0
- package/dist/src/config.js +20 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/helpers/callGetSwapParams.d.ts +2 -0
- package/dist/src/helpers/callGetSwapParams.js +85 -0
- package/dist/src/helpers/callGetSwapParams.js.map +1 -0
- package/dist/src/helpers/callReadOnlyHelper.d.ts +8 -0
- package/dist/src/helpers/callReadOnlyHelper.js +191 -0
- package/dist/src/helpers/callReadOnlyHelper.js.map +1 -0
- package/dist/src/helpers/callSwapHelper.d.ts +9 -0
- package/dist/src/helpers/callSwapHelper.js +41 -0
- package/dist/src/helpers/callSwapHelper.js.map +1 -0
- package/dist/src/helpers/constructFunctionArgs.d.ts +1 -0
- package/dist/src/helpers/constructFunctionArgs.js +22 -0
- package/dist/src/helpers/constructFunctionArgs.js.map +1 -0
- package/dist/src/helpers/convertValuesHelper.d.ts +2 -0
- package/dist/src/helpers/convertValuesHelper.js +181 -0
- package/dist/src/helpers/convertValuesHelper.js.map +1 -0
- package/dist/src/helpers/fetchContractInterfaceHelper.d.ts +1 -0
- package/dist/src/helpers/fetchContractInterfaceHelper.js +20 -0
- package/dist/src/helpers/fetchContractInterfaceHelper.js.map +1 -0
- package/dist/src/helpers/fetchDataHelper.d.ts +2 -0
- package/dist/src/helpers/fetchDataHelper.js +44 -0
- package/dist/src/helpers/fetchDataHelper.js.map +1 -0
- package/dist/src/helpers/fetchPossibleSwap.d.ts +2 -0
- package/dist/src/helpers/fetchPossibleSwap.js +20 -0
- package/dist/src/helpers/fetchPossibleSwap.js.map +1 -0
- package/dist/src/helpers/getContractInterfaceAndFunction.d.ts +4 -0
- package/dist/src/helpers/getContractInterfaceAndFunction.js +15 -0
- package/dist/src/helpers/getContractInterfaceAndFunction.js.map +1 -0
- package/dist/src/helpers/getFunctionArgs.d.ts +1 -0
- package/dist/src/helpers/getFunctionArgs.js +12 -0
- package/dist/src/helpers/getFunctionArgs.js.map +1 -0
- package/dist/src/helpers/getTokenDecimalsHelper.d.ts +5 -0
- package/dist/src/helpers/getTokenDecimalsHelper.js +28 -0
- package/dist/src/helpers/getTokenDecimalsHelper.js.map +1 -0
- package/dist/src/helpers/getTokenNameHelper.d.ts +2 -0
- package/dist/src/helpers/getTokenNameHelper.js +22 -0
- package/dist/src/helpers/getTokenNameHelper.js.map +1 -0
- package/dist/src/helpers/handleResultHelper.d.ts +4 -0
- package/dist/src/helpers/handleResultHelper.js +80 -0
- package/dist/src/helpers/handleResultHelper.js.map +1 -0
- package/dist/src/helpers/postConditionsHelper.d.ts +2 -0
- package/dist/src/helpers/postConditionsHelper.js +135 -0
- package/dist/src/helpers/postConditionsHelper.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +8 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/test/testMethods.d.ts +1 -0
- package/dist/src/test/testMethods.js +178 -0
- package/dist/src/test/testMethods.js.map +1 -0
- package/dist/src/types.d.ts +126 -0
- package/dist/src/types.js +3 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +57 -0
- package/src/BitflowSDK.ts +385 -0
- package/src/config.ts +22 -0
- package/src/helpers/callGetSwapParams.ts +122 -0
- package/src/helpers/callReadOnlyHelper.ts +243 -0
- package/src/helpers/callSwapHelper.ts +53 -0
- package/src/helpers/constructFunctionArgs.ts +24 -0
- package/src/helpers/convertValuesHelper.ts +214 -0
- package/src/helpers/fetchContractInterfaceHelper.ts +19 -0
- package/src/helpers/fetchDataHelper.ts +41 -0
- package/src/helpers/fetchPossibleSwap.ts +18 -0
- package/src/helpers/getContractInterfaceAndFunction.ts +20 -0
- package/src/helpers/getFunctionArgs.ts +12 -0
- package/src/helpers/getTokenDecimalsHelper.ts +33 -0
- package/src/helpers/getTokenNameHelper.ts +26 -0
- package/src/helpers/handleResultHelper.ts +85 -0
- package/src/helpers/postConditionsHelper.ts +246 -0
- package/src/index.ts +2 -0
- package/src/test/testMethods.ts +227 -0
- package/src/types.ts +137 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { createSwapPostConditions } from "./postConditionsHelper";
|
|
2
|
+
import {
|
|
3
|
+
SwapContext,
|
|
4
|
+
SwapDataParamsAndPostConditions,
|
|
5
|
+
SwapExecutionData,
|
|
6
|
+
} from "../types";
|
|
7
|
+
import { constructFunctionArgs } from "./constructFunctionArgs";
|
|
8
|
+
import { getContractInterfaceAndFunction } from "./getContractInterfaceAndFunction";
|
|
9
|
+
import { stringifyWithBigInt } from "./callReadOnlyHelper";
|
|
10
|
+
|
|
11
|
+
const applySlippage = (
|
|
12
|
+
value: string | number | bigint,
|
|
13
|
+
slippageTolerance: number
|
|
14
|
+
): bigint => {
|
|
15
|
+
const bigIntValue = BigInt(value);
|
|
16
|
+
const slippageFactor = BigInt(Math.floor((1 - slippageTolerance) * 10000));
|
|
17
|
+
return (bigIntValue * slippageFactor) / BigInt(10000);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const executeGetParams = async (
|
|
21
|
+
swapExecutionData: SwapExecutionData,
|
|
22
|
+
senderAddress: string,
|
|
23
|
+
slippageTolerance: number,
|
|
24
|
+
context: SwapContext
|
|
25
|
+
): Promise<SwapDataParamsAndPostConditions> => {
|
|
26
|
+
const network = context.network;
|
|
27
|
+
const { route, amount, tokenXDecimals, tokenYDecimals } = swapExecutionData;
|
|
28
|
+
const [contractAddress, contractName] = route.swapData.contract.split(".");
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const contractKey = `${contractAddress}.${contractName}`;
|
|
32
|
+
let contractInterface = context.contractInterfaces[contractKey];
|
|
33
|
+
let functionArgsDefinition =
|
|
34
|
+
context.functionArgs[contractKey]?.[route.swapData.function];
|
|
35
|
+
|
|
36
|
+
if (!contractInterface || !functionArgsDefinition) {
|
|
37
|
+
const result = await getContractInterfaceAndFunction(
|
|
38
|
+
contractAddress,
|
|
39
|
+
contractName,
|
|
40
|
+
route.swapData.function
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (!contractInterface) {
|
|
44
|
+
contractInterface = result.contractInterface;
|
|
45
|
+
context.contractInterfaces[contractKey] = contractInterface;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!functionArgsDefinition) {
|
|
49
|
+
functionArgsDefinition = result.functionArgs;
|
|
50
|
+
if (!context.functionArgs[contractKey]) {
|
|
51
|
+
context.functionArgs[contractKey] = {};
|
|
52
|
+
}
|
|
53
|
+
context.functionArgs[contractKey][route.swapData.function] =
|
|
54
|
+
functionArgsDefinition;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const swapParameters = { ...route.swapData.parameters };
|
|
59
|
+
|
|
60
|
+
// Apply slippage to various parameters
|
|
61
|
+
const slippageParams = [
|
|
62
|
+
"min-received",
|
|
63
|
+
"min-dy",
|
|
64
|
+
"min-dx",
|
|
65
|
+
"min-dz",
|
|
66
|
+
"min-dw",
|
|
67
|
+
"amt-out",
|
|
68
|
+
"amt-out-min",
|
|
69
|
+
"min-x-amount",
|
|
70
|
+
"min-dv",
|
|
71
|
+
"min-y-amount",
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
slippageParams.forEach((param) => {
|
|
75
|
+
if (swapParameters[param]) {
|
|
76
|
+
swapParameters[param] = applySlippage(
|
|
77
|
+
swapParameters[param],
|
|
78
|
+
slippageTolerance
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Convert input amounts to BigInt
|
|
84
|
+
const inputParams = [
|
|
85
|
+
"amount",
|
|
86
|
+
"dx",
|
|
87
|
+
"amt-in",
|
|
88
|
+
"amt-in-max",
|
|
89
|
+
"y-amount",
|
|
90
|
+
"dy",
|
|
91
|
+
];
|
|
92
|
+
inputParams.forEach((param) => {
|
|
93
|
+
if (param in swapParameters) {
|
|
94
|
+
swapParameters[param] = BigInt(swapParameters[param]);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const functionArgs = constructFunctionArgs(
|
|
99
|
+
swapParameters,
|
|
100
|
+
functionArgsDefinition
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const postConditions = await createSwapPostConditions(
|
|
104
|
+
swapParameters,
|
|
105
|
+
route.postConditions,
|
|
106
|
+
senderAddress,
|
|
107
|
+
tokenXDecimals,
|
|
108
|
+
tokenYDecimals
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
functionArgs,
|
|
113
|
+
postConditions,
|
|
114
|
+
contractAddress,
|
|
115
|
+
contractName,
|
|
116
|
+
functionName: route.swapData.function,
|
|
117
|
+
};
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.error("Error getting swap parameters:", error);
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { callReadOnlyFunction } from "@stacks/transactions";
|
|
2
|
+
import { SwapContext } from "../types";
|
|
3
|
+
import { getTokenDecimals } from "./getTokenDecimalsHelper";
|
|
4
|
+
import { constructFunctionArgs } from "./constructFunctionArgs";
|
|
5
|
+
import { StacksMainnet } from "@stacks/network";
|
|
6
|
+
import { configs } from "../config";
|
|
7
|
+
import { getContractInterfaceAndFunction } from "./getContractInterfaceAndFunction";
|
|
8
|
+
import { handleResult } from "./handleResultHelper";
|
|
9
|
+
|
|
10
|
+
export const stringifyWithBigInt = (obj: any): string => {
|
|
11
|
+
return JSON.stringify(obj, (_, v) =>
|
|
12
|
+
typeof v === "bigint" ? v.toString() : v
|
|
13
|
+
);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const callReadOnlyFunctionHelper = async (
|
|
17
|
+
contractDeployer: string,
|
|
18
|
+
contractName: string,
|
|
19
|
+
functionName: string,
|
|
20
|
+
parameters: any,
|
|
21
|
+
senderAddress: string,
|
|
22
|
+
tokenXId: string,
|
|
23
|
+
tokenYId: string,
|
|
24
|
+
swapData: any,
|
|
25
|
+
context: SwapContext
|
|
26
|
+
): Promise<{
|
|
27
|
+
convertedResult: number;
|
|
28
|
+
rawResult: number;
|
|
29
|
+
tokenXDecimals: number;
|
|
30
|
+
tokenYDecimals: number;
|
|
31
|
+
}> => {
|
|
32
|
+
const network = new StacksMainnet({ url: configs.READONLY_CALL_API_HOST });
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const contractKey = `${contractDeployer}.${contractName}`;
|
|
36
|
+
let contractInterface = context.contractInterfaces[contractKey];
|
|
37
|
+
let functionArgsDefinition =
|
|
38
|
+
context.functionArgs[contractKey]?.[functionName];
|
|
39
|
+
|
|
40
|
+
if (!contractInterface || !functionArgsDefinition) {
|
|
41
|
+
const result = await getContractInterfaceAndFunction(
|
|
42
|
+
contractDeployer,
|
|
43
|
+
contractName,
|
|
44
|
+
functionName
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
if (!contractInterface) {
|
|
48
|
+
contractInterface = result.contractInterface;
|
|
49
|
+
context.contractInterfaces[contractKey] = contractInterface;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!functionArgsDefinition) {
|
|
53
|
+
functionArgsDefinition = result.functionArgs;
|
|
54
|
+
if (!context.functionArgs[contractKey]) {
|
|
55
|
+
context.functionArgs[contractKey] = {};
|
|
56
|
+
}
|
|
57
|
+
context.functionArgs[contractKey][functionName] =
|
|
58
|
+
functionArgsDefinition;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const tokenXDecimals = getTokenDecimals(tokenXId, context);
|
|
63
|
+
let tokenXMatchingDecimal:
|
|
64
|
+
| { tokenContract: string; tokenDecimals: number }
|
|
65
|
+
| undefined;
|
|
66
|
+
|
|
67
|
+
for (const key in parameters) {
|
|
68
|
+
if (typeof parameters[key] === "object") {
|
|
69
|
+
for (const subKey in parameters[key]) {
|
|
70
|
+
const contractValue = parameters[key][subKey];
|
|
71
|
+
tokenXMatchingDecimal = tokenXDecimals.find(
|
|
72
|
+
(d) => d.tokenContract === contractValue
|
|
73
|
+
);
|
|
74
|
+
if (tokenXMatchingDecimal) break;
|
|
75
|
+
}
|
|
76
|
+
} else if (typeof parameters[key] === "string") {
|
|
77
|
+
tokenXMatchingDecimal = tokenXDecimals.find(
|
|
78
|
+
(d) => d.tokenContract === parameters[key]
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (tokenXMatchingDecimal) break;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (!tokenXMatchingDecimal && swapData && swapData.parameters) {
|
|
85
|
+
const swapParameters = swapData.parameters;
|
|
86
|
+
for (const key in swapParameters) {
|
|
87
|
+
if (typeof swapParameters[key] === "object") {
|
|
88
|
+
for (const subKey in swapParameters[key]) {
|
|
89
|
+
const contractValue = swapParameters[key][subKey];
|
|
90
|
+
tokenXMatchingDecimal = tokenXDecimals.find(
|
|
91
|
+
(d) => d.tokenContract === contractValue
|
|
92
|
+
);
|
|
93
|
+
if (tokenXMatchingDecimal) break;
|
|
94
|
+
}
|
|
95
|
+
} else if (typeof swapParameters[key] === "string") {
|
|
96
|
+
tokenXMatchingDecimal = tokenXDecimals.find(
|
|
97
|
+
(d) => d.tokenContract === swapParameters[key]
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
if (tokenXMatchingDecimal) break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (tokenXMatchingDecimal) {
|
|
105
|
+
const scaleAmount = (amount: number | string) => {
|
|
106
|
+
const scaledAmount =
|
|
107
|
+
parseFloat(amount.toString()) *
|
|
108
|
+
10 ** tokenXMatchingDecimal!.tokenDecimals;
|
|
109
|
+
return BigInt(Math.floor(scaledAmount));
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
if (parameters.dx !== undefined && parameters.dx !== null) {
|
|
113
|
+
parameters.dx = scaleAmount(parameters.dx);
|
|
114
|
+
} else if (
|
|
115
|
+
parameters.amount !== undefined &&
|
|
116
|
+
parameters.amount !== null
|
|
117
|
+
) {
|
|
118
|
+
parameters.amount = scaleAmount(parameters.amount);
|
|
119
|
+
} else if (
|
|
120
|
+
parameters["amt-in"] !== undefined &&
|
|
121
|
+
parameters["amt-in"] !== null
|
|
122
|
+
) {
|
|
123
|
+
parameters["amt-in"] = scaleAmount(parameters["amt-in"]);
|
|
124
|
+
} else if (
|
|
125
|
+
parameters["amt-in-max"] !== undefined &&
|
|
126
|
+
parameters["amt-in-max"] !== null
|
|
127
|
+
) {
|
|
128
|
+
parameters["amt-in-max"] = scaleAmount(parameters["amt-in-max"]);
|
|
129
|
+
} else if (
|
|
130
|
+
parameters["y-amount"] !== undefined &&
|
|
131
|
+
parameters["y-amount"] !== null
|
|
132
|
+
) {
|
|
133
|
+
parameters["y-amount"] = scaleAmount(parameters["y-amount"]);
|
|
134
|
+
parameters["x-amount"] = scaleAmount(parameters["x-amount"]);
|
|
135
|
+
} else if (
|
|
136
|
+
parameters["x-amount"] !== undefined &&
|
|
137
|
+
parameters["x-amount"] !== null
|
|
138
|
+
) {
|
|
139
|
+
parameters["x-amount"] = scaleAmount(parameters["x-amount"]);
|
|
140
|
+
} else if (parameters.dy !== undefined && parameters.dy !== null) {
|
|
141
|
+
parameters.dy = scaleAmount(parameters.dy);
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
console.warn(`No matching decimal found for tokenX: ${tokenXId}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const functionArgs = constructFunctionArgs(
|
|
148
|
+
parameters,
|
|
149
|
+
functionArgsDefinition
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const result = await callReadOnlyFunction({
|
|
153
|
+
contractAddress: contractDeployer,
|
|
154
|
+
contractName,
|
|
155
|
+
functionName,
|
|
156
|
+
functionArgs,
|
|
157
|
+
senderAddress,
|
|
158
|
+
network,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const { rawResult, convertedResult } = handleResult(result);
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
const tokenYDecimals = getTokenDecimals(tokenYId, context);
|
|
165
|
+
|
|
166
|
+
let tokenYMatchingDecimal:
|
|
167
|
+
| { tokenContract: string; tokenDecimals: number }
|
|
168
|
+
| undefined;
|
|
169
|
+
|
|
170
|
+
for (const key in parameters) {
|
|
171
|
+
if (typeof parameters[key] === "object") {
|
|
172
|
+
for (const subKey in parameters[key]) {
|
|
173
|
+
const contractValue = parameters[key][subKey];
|
|
174
|
+
tokenYMatchingDecimal = tokenYDecimals.find(
|
|
175
|
+
(d) => d.tokenContract === contractValue
|
|
176
|
+
);
|
|
177
|
+
if (tokenYMatchingDecimal) break;
|
|
178
|
+
}
|
|
179
|
+
} else if (typeof parameters[key] === "string") {
|
|
180
|
+
tokenYMatchingDecimal = tokenYDecimals.find(
|
|
181
|
+
(d) => d.tokenContract === parameters[key]
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
if (tokenYMatchingDecimal) break;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (!tokenYMatchingDecimal && swapData && swapData.parameters) {
|
|
188
|
+
const swapParameters = swapData.parameters;
|
|
189
|
+
for (const key in swapParameters) {
|
|
190
|
+
if (typeof swapParameters[key] === "object") {
|
|
191
|
+
for (const subKey in swapParameters[key]) {
|
|
192
|
+
const contractValue = swapParameters[key][subKey];
|
|
193
|
+
tokenYMatchingDecimal = tokenYDecimals.find(
|
|
194
|
+
(d) => d.tokenContract === contractValue
|
|
195
|
+
);
|
|
196
|
+
if (tokenYMatchingDecimal) break;
|
|
197
|
+
}
|
|
198
|
+
} else if (typeof swapParameters[key] === "string") {
|
|
199
|
+
tokenYMatchingDecimal = tokenYDecimals.find(
|
|
200
|
+
(d) => d.tokenContract === swapParameters[key]
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
if (tokenYMatchingDecimal) break;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (tokenYMatchingDecimal && typeof convertedResult === "number") {
|
|
208
|
+
const adjustedResult =
|
|
209
|
+
convertedResult / 10 ** tokenYMatchingDecimal.tokenDecimals;
|
|
210
|
+
return {
|
|
211
|
+
convertedResult: adjustedResult,
|
|
212
|
+
rawResult,
|
|
213
|
+
tokenXDecimals: tokenXMatchingDecimal?.tokenDecimals || 0,
|
|
214
|
+
tokenYDecimals: tokenYMatchingDecimal.tokenDecimals,
|
|
215
|
+
};
|
|
216
|
+
} else {
|
|
217
|
+
console.warn(
|
|
218
|
+
`No matching decimal found for tokenY: ${tokenYId} or result is not a number`
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
convertedResult,
|
|
223
|
+
rawResult,
|
|
224
|
+
tokenXDecimals: tokenXMatchingDecimal?.tokenDecimals || 0,
|
|
225
|
+
tokenYDecimals: 0,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
} catch (error) {
|
|
229
|
+
console.warn(`Couldn't apply decimal conversion: ${error}`);
|
|
230
|
+
console.warn("Using raw result without decimal conversion");
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
convertedResult,
|
|
234
|
+
rawResult,
|
|
235
|
+
tokenXDecimals: tokenXMatchingDecimal?.tokenDecimals || 0,
|
|
236
|
+
tokenYDecimals: 0,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error(`Error calling read-only function ${functionName}:`, error);
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
243
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { AnchorMode, PostConditionMode } from "@stacks/transactions";
|
|
2
|
+
import { openContractCall, StacksProvider } from "@stacks/connect";
|
|
3
|
+
import { SwapContext } from "../types";
|
|
4
|
+
|
|
5
|
+
export const executeSwapHelper = async (
|
|
6
|
+
swapParams: {
|
|
7
|
+
functionArgs: any[];
|
|
8
|
+
postConditions: any[];
|
|
9
|
+
contractAddress: string;
|
|
10
|
+
contractName: string;
|
|
11
|
+
functionName: string;
|
|
12
|
+
},
|
|
13
|
+
senderAddress: string,
|
|
14
|
+
context: SwapContext,
|
|
15
|
+
stacksProvider?: StacksProvider,
|
|
16
|
+
onFinish?: (data: any) => void,
|
|
17
|
+
onCancel?: () => void
|
|
18
|
+
): Promise<void> => {
|
|
19
|
+
const network = context.network;
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const txOptions = {
|
|
23
|
+
contractAddress: swapParams.contractAddress,
|
|
24
|
+
contractName: swapParams.contractName,
|
|
25
|
+
functionName: swapParams.functionName,
|
|
26
|
+
functionArgs: swapParams.functionArgs,
|
|
27
|
+
senderAddress,
|
|
28
|
+
network,
|
|
29
|
+
anchorMode: AnchorMode.Any,
|
|
30
|
+
postConditionMode: PostConditionMode.Deny,
|
|
31
|
+
postConditions: swapParams.postConditions,
|
|
32
|
+
onFinish:
|
|
33
|
+
onFinish ||
|
|
34
|
+
((data: any) => {
|
|
35
|
+
console.log("Transaction submitted:", data);
|
|
36
|
+
}),
|
|
37
|
+
onCancel:
|
|
38
|
+
onCancel ||
|
|
39
|
+
(() => {
|
|
40
|
+
console.log("Transaction canceled");
|
|
41
|
+
}),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
if (stacksProvider) {
|
|
45
|
+
await openContractCall(txOptions, stacksProvider);
|
|
46
|
+
} else {
|
|
47
|
+
await openContractCall(txOptions);
|
|
48
|
+
}
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error("Error executing swap:", error);
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { stringifyWithBigInt } from "./callReadOnlyHelper";
|
|
2
|
+
import { convertValue } from "./convertValuesHelper";
|
|
3
|
+
|
|
4
|
+
export const constructFunctionArgs = (
|
|
5
|
+
parameters: any,
|
|
6
|
+
functionArgsDefinition: any[]
|
|
7
|
+
) => {
|
|
8
|
+
return functionArgsDefinition.map((arg) => {
|
|
9
|
+
const value = parameters[arg.name];
|
|
10
|
+
|
|
11
|
+
if (value === undefined || value === null) {
|
|
12
|
+
console.warn(`Value for ${arg.name} is ${value}`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const convertedValue = convertValue(value, arg.type);
|
|
17
|
+
|
|
18
|
+
return convertedValue;
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error(`Error converting value for ${arg.name}:`, error);
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import {
|
|
2
|
+
boolCV,
|
|
3
|
+
bufferCV,
|
|
4
|
+
ClarityValue,
|
|
5
|
+
contractPrincipalCV,
|
|
6
|
+
intCV,
|
|
7
|
+
listCV,
|
|
8
|
+
noneCV,
|
|
9
|
+
responseErrorCV,
|
|
10
|
+
responseOkCV,
|
|
11
|
+
someCV,
|
|
12
|
+
standardPrincipalCV,
|
|
13
|
+
stringAsciiCV,
|
|
14
|
+
stringUtf8CV,
|
|
15
|
+
tupleCV,
|
|
16
|
+
uintCV,
|
|
17
|
+
} from "@stacks/transactions";
|
|
18
|
+
|
|
19
|
+
export const convertValue = (value: any, type: any): ClarityValue => {
|
|
20
|
+
if (value === null || value === undefined) {
|
|
21
|
+
console.warn(
|
|
22
|
+
`Received null or undefined value for type ${JSON.stringify(
|
|
23
|
+
type
|
|
24
|
+
)}. Using default value.`
|
|
25
|
+
);
|
|
26
|
+
return getDefaultValue(type);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (typeof type === "object") {
|
|
30
|
+
return handleObjectType(value, type);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
switch (type) {
|
|
34
|
+
case "uint128":
|
|
35
|
+
case "uint":
|
|
36
|
+
return handleUintType(value);
|
|
37
|
+
case "int128":
|
|
38
|
+
case "int":
|
|
39
|
+
return handleIntType(value);
|
|
40
|
+
case "bool":
|
|
41
|
+
return handleBoolType(value);
|
|
42
|
+
case "principal":
|
|
43
|
+
return handlePrincipalType(value);
|
|
44
|
+
case "trait_reference":
|
|
45
|
+
return handleTraitReferenceType(value);
|
|
46
|
+
case "optional":
|
|
47
|
+
return handleOptionalType(value);
|
|
48
|
+
case "response":
|
|
49
|
+
return handleResponseType(value);
|
|
50
|
+
case "string-ascii":
|
|
51
|
+
return stringAsciiCV(value);
|
|
52
|
+
case "string-utf8":
|
|
53
|
+
return stringUtf8CV(value);
|
|
54
|
+
case "list":
|
|
55
|
+
return handleListType(value);
|
|
56
|
+
case "buffer":
|
|
57
|
+
return bufferCV(Buffer.from(value));
|
|
58
|
+
default:
|
|
59
|
+
if (typeof value === "object") {
|
|
60
|
+
return handleTupleType(value);
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`Unsupported argument type: ${type}`);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const getDefaultValue = (type: any): ClarityValue => {
|
|
67
|
+
if (typeof type === "object") {
|
|
68
|
+
if (
|
|
69
|
+
type.type === "uint128" ||
|
|
70
|
+
(type.optional && type.optional === "uint128")
|
|
71
|
+
) {
|
|
72
|
+
return noneCV();
|
|
73
|
+
}
|
|
74
|
+
if (type.tuple) {
|
|
75
|
+
return tupleCV({});
|
|
76
|
+
}
|
|
77
|
+
if (type.list) {
|
|
78
|
+
return listCV([]);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
switch (type) {
|
|
82
|
+
case "uint128":
|
|
83
|
+
case "uint":
|
|
84
|
+
return uintCV(0);
|
|
85
|
+
case "int128":
|
|
86
|
+
case "int":
|
|
87
|
+
return intCV(0);
|
|
88
|
+
case "bool":
|
|
89
|
+
return boolCV(false);
|
|
90
|
+
case "optional":
|
|
91
|
+
case "optional(uint128)":
|
|
92
|
+
return noneCV();
|
|
93
|
+
case "string-ascii":
|
|
94
|
+
case "string-utf8":
|
|
95
|
+
return stringAsciiCV("");
|
|
96
|
+
case "buffer":
|
|
97
|
+
return bufferCV(Buffer.alloc(0));
|
|
98
|
+
case "list":
|
|
99
|
+
return listCV([]);
|
|
100
|
+
default:
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Cannot provide default value for type: ${JSON.stringify(type)}`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const handleObjectType = (value: any, type: any): ClarityValue => {
|
|
108
|
+
if (type.type === "uint128") {
|
|
109
|
+
return uintCV(value);
|
|
110
|
+
}
|
|
111
|
+
if (type.optional === "uint128") {
|
|
112
|
+
return someCV(uintCV(value));
|
|
113
|
+
}
|
|
114
|
+
if (type.tuple) {
|
|
115
|
+
return handleTupleType(value, type.tuple);
|
|
116
|
+
}
|
|
117
|
+
if (type.list) {
|
|
118
|
+
return handleListType(value, type.list.type);
|
|
119
|
+
}
|
|
120
|
+
throw new Error(`Unsupported object-based type: ${JSON.stringify(type)}`);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const handleUintType = (value: any): ClarityValue => {
|
|
124
|
+
if (typeof value === "number" || typeof value === "bigint") {
|
|
125
|
+
return uintCV(value);
|
|
126
|
+
} else if (typeof value === "string") {
|
|
127
|
+
if (/^\d+$/.test(value)) {
|
|
128
|
+
return uintCV(value);
|
|
129
|
+
} else if (/^0x[0-9A-Fa-f]+$/.test(value)) {
|
|
130
|
+
return uintCV(BigInt(value));
|
|
131
|
+
}
|
|
132
|
+
} else if (value instanceof Uint8Array) {
|
|
133
|
+
return uintCV(value);
|
|
134
|
+
}
|
|
135
|
+
throw new Error(`Invalid uint128 value: ${value} (type: ${typeof value})`);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const handleIntType = (value: any): ClarityValue => {
|
|
139
|
+
if (
|
|
140
|
+
typeof value === "number" ||
|
|
141
|
+
typeof value === "bigint" ||
|
|
142
|
+
(typeof value === "string" && /^-?\d+$/.test(value))
|
|
143
|
+
) {
|
|
144
|
+
return intCV(value);
|
|
145
|
+
}
|
|
146
|
+
throw new Error(`Invalid int128 value: ${value} (type: ${typeof value})`);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const handleBoolType = (value: any): ClarityValue => {
|
|
150
|
+
if (typeof value === "boolean") {
|
|
151
|
+
return boolCV(value);
|
|
152
|
+
}
|
|
153
|
+
throw new Error(`Invalid boolean value: ${value} (type: ${typeof value})`);
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const handlePrincipalType = (value: string): ClarityValue => {
|
|
157
|
+
if (value.includes(".")) {
|
|
158
|
+
const [addr, name] = value.split(".");
|
|
159
|
+
return contractPrincipalCV(addr, name);
|
|
160
|
+
} else {
|
|
161
|
+
return standardPrincipalCV(value);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const handleTraitReferenceType = (value: string): ClarityValue => {
|
|
166
|
+
const [addr, name] = value.split(".");
|
|
167
|
+
return contractPrincipalCV(addr, name);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const handleOptionalType = (value: any): ClarityValue => {
|
|
171
|
+
return value !== null && value !== undefined
|
|
172
|
+
? someCV(convertValue(value, "uint128"))
|
|
173
|
+
: noneCV();
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const handleResponseType = (value: any): ClarityValue => {
|
|
177
|
+
if (
|
|
178
|
+
value &&
|
|
179
|
+
typeof value === "object" &&
|
|
180
|
+
("ok" in value || "error" in value)
|
|
181
|
+
) {
|
|
182
|
+
return "ok" in value
|
|
183
|
+
? responseOkCV(convertValue(value.ok, typeof value.ok))
|
|
184
|
+
: responseErrorCV(convertValue(value.error, typeof value.error));
|
|
185
|
+
}
|
|
186
|
+
throw new Error(`Invalid response value: ${JSON.stringify(value)}`);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const handleListType = (value: any[], itemType?: any): ClarityValue => {
|
|
190
|
+
if (Array.isArray(value)) {
|
|
191
|
+
return listCV(
|
|
192
|
+
value.map((item) => convertValue(item, itemType || typeof item))
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
throw new Error(`Invalid list value: ${JSON.stringify(value)}`);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const handleTupleType = (value: any, tupleTypes?: any[]): ClarityValue => {
|
|
199
|
+
const tupleValues: { [key: string]: ClarityValue } = {};
|
|
200
|
+
if (tupleTypes) {
|
|
201
|
+
tupleTypes.forEach((item: { name: string; type: any }) => {
|
|
202
|
+
if (value && value[item.name] !== undefined) {
|
|
203
|
+
tupleValues[item.name] = convertValue(value[item.name], item.type);
|
|
204
|
+
} else {
|
|
205
|
+
tupleValues[item.name] = getDefaultValue(item.type);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
} else {
|
|
209
|
+
for (const [key, val] of Object.entries(value)) {
|
|
210
|
+
tupleValues[key] = convertValue(val, typeof val);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return tupleCV(tupleValues);
|
|
214
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { configs } from "../config";
|
|
2
|
+
|
|
3
|
+
export const fetchContractInterface = async (
|
|
4
|
+
contractDeployer: string,
|
|
5
|
+
contractName: string
|
|
6
|
+
): Promise<any> => {
|
|
7
|
+
const url = `${configs.READONLY_CALL_API_HOST}/v2/contracts/interface/${contractDeployer}/${contractName}`;
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
const response = await fetch(url);
|
|
11
|
+
if (!response.ok) {
|
|
12
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
13
|
+
}
|
|
14
|
+
return await response.json();
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.error(`Error fetching contract interface from ${url}:`, error);
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
};
|