@stacks/rendezvous 0.1.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.
- package/LICENSE +674 -0
- package/README.md +127 -0
- package/dist/app.js +116 -0
- package/dist/citizen.js +231 -0
- package/dist/citizen.types.js +2 -0
- package/dist/heatstroke.js +76 -0
- package/dist/invariant.js +239 -0
- package/dist/invariant.types.js +2 -0
- package/dist/package.json +42 -0
- package/dist/property.js +247 -0
- package/dist/property.types.js +3 -0
- package/dist/shared.js +285 -0
- package/dist/shared.types.js +2 -0
- package/package.json +42 -0
package/dist/shared.js
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getContractNameFromContractId = exports.isTraitReferenceFunction = exports.argsToCV = exports.hexaString = exports.functionToArbitrary = exports.getFunctionsListForContract = exports.getFunctionsFromContractInterfaces = exports.getSimnetDeployerContractsInterfaces = void 0;
|
|
7
|
+
const fast_check_1 = __importDefault(require("fast-check"));
|
|
8
|
+
const transactions_1 = require("@stacks/transactions");
|
|
9
|
+
/**
|
|
10
|
+
* Get the interfaces of contracts deployed by the specified deployer from the
|
|
11
|
+
* simnet.
|
|
12
|
+
* @param simnet The simnet instance.
|
|
13
|
+
* @param deployer The deployer address.
|
|
14
|
+
* @returns The contracts interfaces.
|
|
15
|
+
*/
|
|
16
|
+
const getSimnetDeployerContractsInterfaces = (simnet) => new Map(Array.from(simnet.getContractsInterfaces()).filter(([key]) => key.split(".")[0] === simnet.deployer));
|
|
17
|
+
exports.getSimnetDeployerContractsInterfaces = getSimnetDeployerContractsInterfaces;
|
|
18
|
+
/**
|
|
19
|
+
* Get the functions from the smart contract interfaces.
|
|
20
|
+
* @param contractsInterfaces The smart contract interfaces map.
|
|
21
|
+
* @returns A map containing the contracts functions.
|
|
22
|
+
*/
|
|
23
|
+
const getFunctionsFromContractInterfaces = (contractsInterfaces) => new Map(Array.from(contractsInterfaces, ([contractId, contractInterface]) => [
|
|
24
|
+
contractId,
|
|
25
|
+
contractInterface.functions,
|
|
26
|
+
]));
|
|
27
|
+
exports.getFunctionsFromContractInterfaces = getFunctionsFromContractInterfaces;
|
|
28
|
+
const getFunctionsListForContract = (functionsMap, contractId) => functionsMap.get(contractId) || [];
|
|
29
|
+
exports.getFunctionsListForContract = getFunctionsListForContract;
|
|
30
|
+
/** For a given function, dynamically generate fast-check arbitraries.
|
|
31
|
+
* @param fn The function interface.
|
|
32
|
+
* @returns Array of fast-check arbitraries.
|
|
33
|
+
*/
|
|
34
|
+
const functionToArbitrary = (fn, addresses) => fn.args.map((arg) => parameterTypeToArbitrary(arg.type, addresses));
|
|
35
|
+
exports.functionToArbitrary = functionToArbitrary;
|
|
36
|
+
/**
|
|
37
|
+
* For a given type, generate a fast-check arbitrary.
|
|
38
|
+
* @param type The parameter type.
|
|
39
|
+
* @returns Fast-check arbitrary.
|
|
40
|
+
*/
|
|
41
|
+
const parameterTypeToArbitrary = (type, addresses) => {
|
|
42
|
+
if (typeof type === "string") {
|
|
43
|
+
// The type is a base type.
|
|
44
|
+
if (type === "principal") {
|
|
45
|
+
if (addresses.length === 0)
|
|
46
|
+
throw new Error("No addresses could be retrieved from the simnet instance!");
|
|
47
|
+
return baseTypesToArbitrary.principal(addresses);
|
|
48
|
+
}
|
|
49
|
+
else if (type === "trait_reference") {
|
|
50
|
+
throw new Error("Unsupported parameter type: trait_reference");
|
|
51
|
+
}
|
|
52
|
+
else
|
|
53
|
+
return baseTypesToArbitrary[type];
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// The type is a complex type.
|
|
57
|
+
if ("buffer" in type) {
|
|
58
|
+
return complexTypesToArbitrary["buffer"](type.buffer.length);
|
|
59
|
+
}
|
|
60
|
+
else if ("string-ascii" in type) {
|
|
61
|
+
return complexTypesToArbitrary["string-ascii"](type["string-ascii"].length);
|
|
62
|
+
}
|
|
63
|
+
else if ("string-utf8" in type) {
|
|
64
|
+
return complexTypesToArbitrary["string-utf8"](type["string-utf8"].length);
|
|
65
|
+
}
|
|
66
|
+
else if ("list" in type) {
|
|
67
|
+
return complexTypesToArbitrary["list"](type.list.type, type.list.length, addresses);
|
|
68
|
+
}
|
|
69
|
+
else if ("tuple" in type) {
|
|
70
|
+
return complexTypesToArbitrary["tuple"](type.tuple, addresses);
|
|
71
|
+
}
|
|
72
|
+
else if ("optional" in type) {
|
|
73
|
+
return complexTypesToArbitrary["optional"](type.optional, addresses);
|
|
74
|
+
}
|
|
75
|
+
else if ("response" in type) {
|
|
76
|
+
return complexTypesToArbitrary.response(type.response.ok, type.response.error, addresses);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
throw new Error(`Unsupported complex type: ${JSON.stringify(type)}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Base types to fast-check arbitraries mapping.
|
|
85
|
+
*/
|
|
86
|
+
const baseTypesToArbitrary = {
|
|
87
|
+
int128: fast_check_1.default.integer(),
|
|
88
|
+
uint128: fast_check_1.default.nat(),
|
|
89
|
+
bool: fast_check_1.default.boolean(),
|
|
90
|
+
principal: (addresses) => fast_check_1.default.constantFrom(...addresses),
|
|
91
|
+
trait_reference: undefined,
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Custom hexadecimal string generator. The `hexaString` generator from
|
|
95
|
+
* fast-check has been deprecated. This generator is implemented to precisely
|
|
96
|
+
* match the behavior of the deprecated generator.
|
|
97
|
+
*
|
|
98
|
+
* @param constraints Fast-check string constraints.
|
|
99
|
+
* @returns Fast-check arbitrary for hexadecimal strings.
|
|
100
|
+
*
|
|
101
|
+
* Reference for the proposed replacement of the deprecated `hexaString`
|
|
102
|
+
* generator:
|
|
103
|
+
* https://github.com/dubzzz/fast-check/commit/3f4f1203a8863c07d22b45591bf0de1fac02b948
|
|
104
|
+
*/
|
|
105
|
+
const hexaString = (constraints = {}) => {
|
|
106
|
+
const hexa = () => {
|
|
107
|
+
const hexCharSet = "0123456789abcdef";
|
|
108
|
+
return fast_check_1.default.integer({ min: 0, max: 15 }).map((n) => hexCharSet[n]);
|
|
109
|
+
};
|
|
110
|
+
return fast_check_1.default.string(Object.assign(Object.assign({}, constraints), { unit: hexa() }));
|
|
111
|
+
};
|
|
112
|
+
exports.hexaString = hexaString;
|
|
113
|
+
/**
|
|
114
|
+
* Complex types to fast-check arbitraries mapping.
|
|
115
|
+
*/
|
|
116
|
+
const complexTypesToArbitrary = {
|
|
117
|
+
// For buffer types, the length must be doubled because they are represented
|
|
118
|
+
// in hex. The `argToCV` function expects this format for `buff` ClarityValue
|
|
119
|
+
// conversion. The UInt8Array will have half the length of the corresponding
|
|
120
|
+
// hex string. Stacks.js reference:
|
|
121
|
+
// https://github.com/hirosystems/stacks.js/blob/fd0bf26b5f29fc3c1bf79581d0ad9b89f0d7f15a/packages/common/src/utils.ts#L522
|
|
122
|
+
buffer: (length) => (0, exports.hexaString)({ maxLength: 2 * length }),
|
|
123
|
+
"string-ascii": (length) => fast_check_1.default.string({
|
|
124
|
+
unit: fast_check_1.default.constantFrom(...charSet),
|
|
125
|
+
maxLength: length,
|
|
126
|
+
}),
|
|
127
|
+
"string-utf8": (length) => fast_check_1.default.string({ maxLength: length }),
|
|
128
|
+
list: (type, length, addresses) => fast_check_1.default.array(parameterTypeToArbitrary(type, addresses), { maxLength: length }),
|
|
129
|
+
tuple: (items, addresses) => {
|
|
130
|
+
const tupleArbitraries = {};
|
|
131
|
+
items.forEach((item) => {
|
|
132
|
+
tupleArbitraries[item.name] = parameterTypeToArbitrary(item.type, addresses);
|
|
133
|
+
});
|
|
134
|
+
return fast_check_1.default.record(tupleArbitraries);
|
|
135
|
+
},
|
|
136
|
+
optional: (type, addresses) => fast_check_1.default.option(parameterTypeToArbitrary(type, addresses)),
|
|
137
|
+
response: (okType, errType, addresses) => fast_check_1.default.oneof(fast_check_1.default.record({
|
|
138
|
+
status: fast_check_1.default.constant("ok"),
|
|
139
|
+
value: parameterTypeToArbitrary(okType, addresses),
|
|
140
|
+
}), fast_check_1.default.record({
|
|
141
|
+
status: fast_check_1.default.constant("error"),
|
|
142
|
+
value: parameterTypeToArbitrary(errType, addresses),
|
|
143
|
+
})),
|
|
144
|
+
};
|
|
145
|
+
/** The character set used for generating ASCII strings.*/
|
|
146
|
+
const charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
|
|
147
|
+
/**
|
|
148
|
+
* Convert function arguments to Clarity values.
|
|
149
|
+
* @param fn The function interface.
|
|
150
|
+
* @param args Array of arguments.
|
|
151
|
+
* @returns Array of Clarity values.
|
|
152
|
+
*/
|
|
153
|
+
const argsToCV = (fn, args) => fn.args.map((arg, i) => argToCV(args[i], arg.type));
|
|
154
|
+
exports.argsToCV = argsToCV;
|
|
155
|
+
/**
|
|
156
|
+
* Convert a function argument to a Clarity value.
|
|
157
|
+
* @param arg Generated argument.
|
|
158
|
+
* @param type Argument type (base or complex).
|
|
159
|
+
* @returns Clarity value.
|
|
160
|
+
*/
|
|
161
|
+
const argToCV = (arg, type) => {
|
|
162
|
+
if (isBaseType(type)) {
|
|
163
|
+
// Base type.
|
|
164
|
+
switch (type) {
|
|
165
|
+
case "int128":
|
|
166
|
+
return baseTypesToCV.int128(arg);
|
|
167
|
+
case "uint128":
|
|
168
|
+
return baseTypesToCV.uint128(arg);
|
|
169
|
+
case "bool":
|
|
170
|
+
return baseTypesToCV.bool(arg);
|
|
171
|
+
case "principal":
|
|
172
|
+
return baseTypesToCV.principal(arg);
|
|
173
|
+
default:
|
|
174
|
+
throw new Error(`Unsupported base parameter type: ${type}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
// Complex type.
|
|
179
|
+
if ("buffer" in type) {
|
|
180
|
+
return complexTypesToCV.buffer(arg);
|
|
181
|
+
}
|
|
182
|
+
else if ("string-ascii" in type) {
|
|
183
|
+
return complexTypesToCV["string-ascii"](arg);
|
|
184
|
+
}
|
|
185
|
+
else if ("string-utf8" in type) {
|
|
186
|
+
return complexTypesToCV["string-utf8"](arg);
|
|
187
|
+
}
|
|
188
|
+
else if ("list" in type) {
|
|
189
|
+
const listItems = arg.map((item) => argToCV(item, type.list.type));
|
|
190
|
+
return complexTypesToCV.list(listItems);
|
|
191
|
+
}
|
|
192
|
+
else if ("tuple" in type) {
|
|
193
|
+
const tupleData = {};
|
|
194
|
+
type.tuple.forEach((field) => {
|
|
195
|
+
tupleData[field.name] = argToCV(arg[field.name], field.type);
|
|
196
|
+
});
|
|
197
|
+
return complexTypesToCV.tuple(tupleData);
|
|
198
|
+
}
|
|
199
|
+
else if ("optional" in type) {
|
|
200
|
+
return (0, transactions_1.optionalCVOf)(arg ? argToCV(arg, type.optional) : undefined);
|
|
201
|
+
}
|
|
202
|
+
else if ("response" in type) {
|
|
203
|
+
const status = arg.status;
|
|
204
|
+
const branchType = type.response[status];
|
|
205
|
+
const responseValue = argToCV(arg.value, branchType);
|
|
206
|
+
return complexTypesToCV.response(status, responseValue);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
throw new Error(`Unsupported complex parameter type: ${JSON.stringify(type)}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
/**
|
|
214
|
+
* Base types to Clarity values mapping.
|
|
215
|
+
*/
|
|
216
|
+
const baseTypesToCV = {
|
|
217
|
+
int128: (arg) => transactions_1.Cl.int(arg),
|
|
218
|
+
uint128: (arg) => transactions_1.Cl.uint(arg),
|
|
219
|
+
bool: (arg) => transactions_1.Cl.bool(arg),
|
|
220
|
+
principal: (arg) => transactions_1.Cl.principal(arg),
|
|
221
|
+
};
|
|
222
|
+
/**
|
|
223
|
+
* Complex types to Clarity values mapping.
|
|
224
|
+
*/
|
|
225
|
+
const complexTypesToCV = {
|
|
226
|
+
buffer: (arg) => transactions_1.Cl.bufferFromHex(arg),
|
|
227
|
+
"string-ascii": (arg) => transactions_1.Cl.stringAscii(arg),
|
|
228
|
+
"string-utf8": (arg) => transactions_1.Cl.stringUtf8(arg),
|
|
229
|
+
list: (items) => {
|
|
230
|
+
return transactions_1.Cl.list(items);
|
|
231
|
+
},
|
|
232
|
+
tuple: (tupleData) => {
|
|
233
|
+
return transactions_1.Cl.tuple(tupleData);
|
|
234
|
+
},
|
|
235
|
+
optional: (arg) => arg ? (0, transactions_1.optionalCVOf)(arg) : (0, transactions_1.optionalCVOf)(undefined),
|
|
236
|
+
response: (status, value) => {
|
|
237
|
+
if (status === "ok")
|
|
238
|
+
return (0, transactions_1.responseOkCV)(value);
|
|
239
|
+
else if (status === "error")
|
|
240
|
+
return (0, transactions_1.responseErrorCV)(value);
|
|
241
|
+
else
|
|
242
|
+
throw new Error(`Unsupported response status: ${status}`);
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
const isBaseType = (type) => {
|
|
246
|
+
return ["int128", "uint128", "bool", "principal"].includes(type);
|
|
247
|
+
};
|
|
248
|
+
/**
|
|
249
|
+
* Checks if any parameter of the function contains a `trait_reference` type.
|
|
250
|
+
* @param fn The function interface.
|
|
251
|
+
* @returns Boolean - true if the function contains a trait reference, false
|
|
252
|
+
* otherwise.
|
|
253
|
+
*/
|
|
254
|
+
const isTraitReferenceFunction = (fn) => {
|
|
255
|
+
const hasTraitReference = (type) => {
|
|
256
|
+
if (typeof type === "string") {
|
|
257
|
+
// The type is a base type.
|
|
258
|
+
return type === "trait_reference";
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
// The type is a complex type.
|
|
262
|
+
if ("buffer" in type)
|
|
263
|
+
return false;
|
|
264
|
+
if ("string-ascii" in type)
|
|
265
|
+
return false;
|
|
266
|
+
if ("string-utf8" in type)
|
|
267
|
+
return false;
|
|
268
|
+
if ("list" in type)
|
|
269
|
+
return hasTraitReference(type.list.type);
|
|
270
|
+
if ("tuple" in type)
|
|
271
|
+
return type.tuple.some((item) => hasTraitReference(item.type));
|
|
272
|
+
if ("optional" in type)
|
|
273
|
+
return hasTraitReference(type.optional);
|
|
274
|
+
if ("response" in type)
|
|
275
|
+
return (hasTraitReference(type.response.ok) ||
|
|
276
|
+
hasTraitReference(type.response.error));
|
|
277
|
+
// Default to false for unexpected types.
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
return fn.args.some((arg) => hasTraitReference(arg.type));
|
|
282
|
+
};
|
|
283
|
+
exports.isTraitReferenceFunction = isTraitReferenceFunction;
|
|
284
|
+
const getContractNameFromContractId = (contractId) => contractId.split(".")[1];
|
|
285
|
+
exports.getContractNameFromContractId = getContractNameFromContractId;
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stacks/rendezvous",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Meet your contract's vulnerabilities head-on.",
|
|
5
|
+
"main": "app.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"rv": "./dist/app.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"postinstall": "npx -p typescript tsc --project tsconfig.json && node -e \"if (process.platform !== 'win32') require('fs').chmodSync('./dist/app.js', 0o755);\"",
|
|
11
|
+
"test": "npx tsc --project tsconfig.json && npx jest",
|
|
12
|
+
"test:coverage": "npx tsc --project tsconfig.json && npx jest --coverage"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"stacks",
|
|
16
|
+
"clarity",
|
|
17
|
+
"fuzz",
|
|
18
|
+
"testing"
|
|
19
|
+
],
|
|
20
|
+
"author": "Radu Bahmata, Nikos Baxevanis",
|
|
21
|
+
"license": "GPL-3.0-only",
|
|
22
|
+
"files": [
|
|
23
|
+
"dist/",
|
|
24
|
+
"package.json",
|
|
25
|
+
"README.md",
|
|
26
|
+
"LICENSE"
|
|
27
|
+
],
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@hirosystems/clarinet-sdk": "2.12.0",
|
|
30
|
+
"@stacks/transactions": "^6.16.1",
|
|
31
|
+
"ansicolor": "^2.0.3",
|
|
32
|
+
"fast-check": "^3.20.0",
|
|
33
|
+
"yaml": "^2.6.1"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@hirosystems/clarinet-sdk-wasm": "2.12.0",
|
|
37
|
+
"@types/jest": "^29.5.12",
|
|
38
|
+
"jest": "^29.7.0",
|
|
39
|
+
"ts-jest": "^29.2.3",
|
|
40
|
+
"typescript": "^5.5.4"
|
|
41
|
+
}
|
|
42
|
+
}
|