@stacks/rendezvous 0.2.0 → 0.3.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/citizen.js CHANGED
@@ -19,17 +19,17 @@ const path_1 = require("path");
19
19
  const yaml_1 = __importDefault(require("yaml"));
20
20
  const clarinet_sdk_1 = require("@hirosystems/clarinet-sdk");
21
21
  /**
22
- * Prepares the simnet environment and assures the target contract is treated
23
- * as a first-class citizen, by combining it with its tests. This function
24
- * handles:
22
+ * Prepares the simnet instance and assures the target contract's corresponding
23
+ * test contract is treated as a first-class citizen, relying on their
24
+ * concatenation. This function handles:
25
25
  * - Contract sorting by epoch based on the deployment plan.
26
26
  * - Combining the target contract with its tests and deploying all contracts
27
27
  * to the simnet.
28
28
  *
29
- * @param manifestDir - The relative path to the manifest directory.
30
- * @param sutContractName - The target contract name.
29
+ * @param manifestDir The relative path to the manifest directory.
30
+ * @param sutContractName The target contract name.
31
31
  * @returns The initialized simnet instance with all contracts deployed, with
32
- * the target contract treated as a first-class citizen.
32
+ * the test contract treated as a first-class citizen of the target contract.
33
33
  */
34
34
  const issueFirstClassCitizenship = (manifestDir, sutContractName) => __awaiter(void 0, void 0, void 0, function* () {
35
35
  const manifestPath = (0, path_1.join)(manifestDir, "Clarinet.toml");
@@ -43,8 +43,8 @@ const issueFirstClassCitizenship = (manifestDir, sutContractName) => __awaiter(v
43
43
  const sortedContractsByEpoch = (0, exports.groupContractsByEpochFromSimnetPlan)(simnetPlan);
44
44
  yield simnet.initEmptySession();
45
45
  // Combine the target contract with its tests into a single contract. The
46
- // resulting contract will replace the target contract in the simnet. This
47
- // map stores the contract name and its corresponding source code.
46
+ // resulting contract will replace the target contract in the simnet.
47
+ /** The contract names mapped to the concatenated source code. */
48
48
  const rendezvousSources = new Map([sutContractName]
49
49
  .map((contractName) => (0, exports.buildRendezvousData)(simnetPlan, contractName, manifestDir))
50
50
  .map((rendezvousContractData) => [
@@ -58,7 +58,7 @@ const issueFirstClassCitizenship = (manifestDir, sutContractName) => __awaiter(v
58
58
  exports.issueFirstClassCitizenship = issueFirstClassCitizenship;
59
59
  /**
60
60
  * Groups contracts by epoch from the simnet plan.
61
- * @param simnetPlan - The simnet plan.
61
+ * @param simnetPlan The simnet plan.
62
62
  * @returns A record of contracts grouped by epoch. The record key is the epoch
63
63
  * string, and the value is an array of contracts. Each contract is represented
64
64
  * as a record with the contract name as the key and a record containing the
@@ -86,10 +86,10 @@ const groupContractsByEpochFromSimnetPlan = (simnetPlan) => {
86
86
  };
87
87
  exports.groupContractsByEpochFromSimnetPlan = groupContractsByEpochFromSimnetPlan;
88
88
  /**
89
- * Deploy the contracts to the simnet in the correct order.
89
+ * Deploys the contracts to the simnet in the correct order.
90
90
  * @param simnet The simnet instance.
91
- * @param contractsByEpoch - The record of contracts by epoch.
92
- * @param getContractSourceFn - The function to retrieve the contract source.
91
+ * @param contractsByEpoch The record of contracts by epoch.
92
+ * @param getContractSourceFn The function to retrieve the contract source.
93
93
  */
94
94
  const deployContracts = (simnet, contractsByEpoch, getContractSourceFn) => __awaiter(void 0, void 0, void 0, function* () {
95
95
  for (const [epoch, contracts] of Object.entries(contractsByEpoch)) {
@@ -109,18 +109,19 @@ const deployContracts = (simnet, contractsByEpoch, getContractSourceFn) => __awa
109
109
  }
110
110
  });
111
111
  /**
112
- * Conditionally retrieve the contract source based on whether the contract is
112
+ * Conditionally retrieves the contract source based on whether the contract is
113
113
  * a SUT contract or not.
114
- * @param sutContractNames - The list of SUT contract names.
115
- * @param rendezvousMap - The rendezvous map.
116
- * @param contractName - The contract name.
117
- * @param contractProps - The contract properties.
118
- * @param manifestDir - The relative path to the manifest directory.
119
- * @returns The contract source.
114
+ * @param targetContractNames The list of target contract names.
115
+ * @param rendezvousSourcesMap The contract names mapped to the concatenated
116
+ * source code.
117
+ * @param contractName The contract name.
118
+ * @param contractProps The contract deployment properties.
119
+ * @param manifestDir The relative path to the manifest directory.
120
+ * @returns The contract source code.
120
121
  */
121
- const getContractSource = (sutContractNames, rendezvousMap, contractName, contractProps, manifestDir) => {
122
- if (sutContractNames.includes(contractName)) {
123
- const contractSource = rendezvousMap.get(contractName);
122
+ const getContractSource = (targetContractNames, rendezvousSourcesMap, contractName, contractProps, manifestDir) => {
123
+ if (targetContractNames.includes(contractName)) {
124
+ const contractSource = rendezvousSourcesMap.get(contractName);
124
125
  if (!contractSource) {
125
126
  throw new Error(`Contract source not found for ${contractName}`);
126
127
  }
@@ -134,11 +135,11 @@ const getContractSource = (sutContractNames, rendezvousMap, contractName, contra
134
135
  };
135
136
  exports.getContractSource = getContractSource;
136
137
  /**
137
- * Build the Rendezvous data.
138
+ * Builds the Rendezvous data.
138
139
  * @param simnetPlan The parsed simnet plan.
139
140
  * @param contractName The contract name.
140
141
  * @param manifestDir The relative path to the manifest directory.
141
- * @returns The Rendezvous data representing an object. The returned object
142
+ * @returns The Rendezvous data representing a record. The returned record
142
143
  * contains the Rendezvous source code and the Rendezvous contract name.
143
144
  */
144
145
  const buildRendezvousData = (simnetPlan, contractName, manifestDir) => {
@@ -157,7 +158,7 @@ const buildRendezvousData = (simnetPlan, contractName, manifestDir) => {
157
158
  };
158
159
  exports.buildRendezvousData = buildRendezvousData;
159
160
  /**
160
- * Get the contract source code from the simnet plan.
161
+ * Retrieves the contract source code using the simnet plan.
161
162
  * @param simnetPlan The parsed simnet plan.
162
163
  * @param manifestDir The relative path to the manifest directory.
163
164
  * @param sutContractName The target contract name.
@@ -179,7 +180,7 @@ const getSimnetPlanContractSource = (simnetPlan, manifestDir, sutContractName) =
179
180
  }).toString();
180
181
  };
181
182
  /**
182
- * Get the test contract source code.
183
+ * Retrieves the test contract source code.
183
184
  * @param simnetPlan The parsed simnet plan.
184
185
  * @param sutContractName The target contract name.
185
186
  * @param manifestDir The relative path to the manifest directory.
@@ -209,13 +210,13 @@ const getTestContractSource = (simnetPlan, sutContractName, manifestDir) => {
209
210
  };
210
211
  exports.getTestContractSource = getTestContractSource;
211
212
  /**
212
- * Schedule a Rendezvous between the System Under Test (`SUT`) and the
213
- * invariants.
214
- * @param sutContractSource The SUT contract source code.
215
- * @param invariants The invariants contract source code.
213
+ * Schedules a Rendezvous between the System Under Test (`SUT`) and the test
214
+ * contract.
215
+ * @param targetContractSource The target contract source code.
216
+ * @param tests The corresponding test contract source code.
216
217
  * @returns The Rendezvous source code.
217
218
  */
218
- function scheduleRendezvous(sutContractSource, invariants) {
219
+ function scheduleRendezvous(targetContractSource, tests) {
219
220
  /**
220
221
  * The `context` map tracks how many times each function has been called.
221
222
  * This data can be useful for invariant tests to check behavior over time.
@@ -227,5 +228,5 @@ function scheduleRendezvous(sutContractSource, invariants) {
227
228
 
228
229
  (define-public (update-context (function-name (string-ascii 100)) (called uint))
229
230
  (ok (map-set context function-name {called: called})))`;
230
- return `${sutContractSource}\n\n${context}\n\n${invariants}`;
231
+ return `${targetContractSource}\n\n${context}\n\n${tests}`;
231
232
  }
@@ -1,38 +1,29 @@
1
1
  "use strict";
2
- /**
3
- * Heatstrokes Reporter
4
- *
5
- * This reporter integrates with `fast-check` to provide detailed and formatted
6
- * outputs for failed property-based tests. It captures key information such as
7
- * the contract, functions, arguments, outputs, and the specific invariant that
8
- * failed, enabling quick identification of issues.
9
- */
10
2
  Object.defineProperty(exports, "__esModule", { value: true });
11
3
  exports.reporter = reporter;
4
+ const ansicolor_1 = require("ansicolor");
5
+ const shared_1 = require("./shared");
12
6
  /**
13
- * Reports the details of a failed property-based test run.
14
- *
15
- * This function provides a detailed report when a fuzzing test fails including
16
- * the contract, functions, arguments, outputs, and the specific invariant that
17
- * failed.
7
+ * Heatstrokes Reporter
18
8
  *
19
- * @param runDetails - The details of the test run provided by fast-check.
20
- * @property runDetails.failed - Indicates if the property test failed.
21
- * @property runDetails.counterexample - The input that caused the failure.
22
- * @property runDetails.numRuns - The number of test cases that were run.
23
- * @property runDetails.seed - The seed used to generate the test cases.
24
- * @property runDetails.path - The path to reproduce the failing test.
25
- * @property runDetails.error - The error thrown during the test.
9
+ * Provides a detailed report when a test run test ends. In case of failure,
10
+ * includes the contract, functions, arguments, outputs, and the specific
11
+ * invariant or property test that failed.
12
+ * @param runDetails The details of the test run provided by fast-check.
13
+ * @property `runDetails.failed`: Indicates if the test run failed.
14
+ * @property `runDetails.counterexample`: The input that caused the failure.
15
+ * @property `runDetails.numRuns`: The number of test cases that were run.
16
+ * @property `runDetails.seed`: The replay seed for reproducing the failure.
17
+ * @property `runDetails.path`: The replay path for reproducing the failure.
18
+ * @property `runDetails.error`: The error thrown during the test.
19
+ * @param radio The event emitter to log messages.
20
+ * @param type The type of test that failed: invariant or property.
21
+ * @returns void
26
22
  */
27
- const ansicolor_1 = require("ansicolor");
28
- const shared_1 = require("./shared");
29
- function reporter(
30
- //@ts-ignore
31
- runDetails, radio, type) {
23
+ function reporter(runDetails, radio, type) {
32
24
  var _a, _b;
33
25
  if (runDetails.failed) {
34
26
  // Report general run data.
35
- const r = runDetails.counterexample[0];
36
27
  radio.emit("logFailure", `\nError: Property failed after ${runDetails.numRuns} tests.`);
37
28
  radio.emit("logFailure", `Seed : ${runDetails.seed}`);
38
29
  if (runDetails.path) {
@@ -40,15 +31,26 @@ runDetails, radio, type) {
40
31
  }
41
32
  switch (type) {
42
33
  case "invariant": {
34
+ const r = runDetails.counterexample[0];
43
35
  // Report specific run data for the invariant testing type.
44
36
  radio.emit("logFailure", `\nCounterexample:`);
45
37
  radio.emit("logFailure", `- Contract : ${(0, shared_1.getContractNameFromContractId)(r.rendezvousContractId)}`);
46
- radio.emit("logFailure", `- Function : ${r.selectedFunction.name} (${r.selectedFunction.access})`);
47
- radio.emit("logFailure", `- Arguments: ${JSON.stringify(r.functionArgsArb)}`);
48
- radio.emit("logFailure", `- Caller : ${r.sutCaller[0]}`);
49
- radio.emit("logFailure", `- Outputs : ${JSON.stringify(r.selectedFunction.outputs)}`);
38
+ radio.emit("logFailure", `- Functions: ${r.selectedFunctions
39
+ .map((selectedFunction) => selectedFunction.name)
40
+ .join(", ")} (${r.selectedFunctions
41
+ .map((selectedFunction) => selectedFunction.access)
42
+ .join(", ")})`);
43
+ radio.emit("logFailure", `- Arguments: ${r.selectedFunctionsArgsList
44
+ .map((selectedFunctionArgs) => JSON.stringify(selectedFunctionArgs))
45
+ .join(", ")}`);
46
+ radio.emit("logFailure", `- Callers : ${r.sutCallers
47
+ .map((sutCaller) => sutCaller[0])
48
+ .join(", ")}`);
49
+ radio.emit("logFailure", `- Outputs : ${r.selectedFunctions
50
+ .map((selectedFunction) => JSON.stringify(selectedFunction.outputs))
51
+ .join(", ")}`);
50
52
  radio.emit("logFailure", `- Invariant: ${r.selectedInvariant.name} (${r.selectedInvariant.access})`);
51
- radio.emit("logFailure", `- Arguments: ${JSON.stringify(r.invariantArgsArb)}`);
53
+ radio.emit("logFailure", `- Arguments: ${JSON.stringify(r.invariantArgs)}`);
52
54
  radio.emit("logFailure", `- Caller : ${r.invariantCaller[0]}`);
53
55
  radio.emit("logFailure", `\nWhat happened? Rendezvous went on a rampage and found a weak spot:\n`);
54
56
  const formattedError = `The invariant "${r.selectedInvariant.name}" returned:\n\n${(_a = runDetails.error) === null || _a === void 0 ? void 0 : _a.toString().split("\n").map((line) => " " + line).join("\n")}\n`;
@@ -56,11 +58,12 @@ runDetails, radio, type) {
56
58
  break;
57
59
  }
58
60
  case "test": {
61
+ const r = runDetails.counterexample[0];
59
62
  // Report specific run data for the property testing type.
60
63
  radio.emit("logFailure", `\nCounterexample:`);
61
64
  radio.emit("logFailure", `- Test Contract : ${(0, shared_1.getContractNameFromContractId)(r.testContractId)}`);
62
65
  radio.emit("logFailure", `- Test Function : ${r.selectedTestFunction.name} (${r.selectedTestFunction.access})`);
63
- radio.emit("logFailure", `- Arguments : ${JSON.stringify(r.functionArgsArb)}`);
66
+ radio.emit("logFailure", `- Arguments : ${JSON.stringify(r.functionArgs)}`);
64
67
  radio.emit("logFailure", `- Caller : ${r.testCaller[0]}`);
65
68
  radio.emit("logFailure", `- Outputs : ${JSON.stringify(r.selectedTestFunction.outputs)}`);
66
69
  radio.emit("logFailure", `\nWhat happened? Rendezvous went on a rampage and found a weak spot:\n`);
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/invariant.js CHANGED
@@ -10,7 +10,21 @@ const heatstroke_1 = require("./heatstroke");
10
10
  const fast_check_1 = __importDefault(require("fast-check"));
11
11
  const ansicolor_1 = require("ansicolor");
12
12
  const traits_1 = require("./traits");
13
- const checkInvariants = (simnet, sutContractName, rendezvousList, rendezvousAllFunctions, seed, path, runs, radio) => {
13
+ /**
14
+ * Runs invariant testing on the target contract and logs the progress. Reports
15
+ * the test results through a custom reporter.
16
+ * @param simnet The Simnet instance.
17
+ * @param targetContractName The name of the target contract.
18
+ * @param rendezvousList The list of contract IDs for each target contract.
19
+ * @param rendezvousAllFunctions The map of all function interfaces for each
20
+ * target contract.
21
+ * @param seed The seed for reproducible invariant testing.
22
+ * @param path The path for reproducible invariant testing.
23
+ * @param runs The number of test runs.
24
+ * @param radio The custom logging event emitter.
25
+ * @returns void
26
+ */
27
+ const checkInvariants = (simnet, targetContractName, rendezvousList, rendezvousAllFunctions, seed, path, runs, radio) => {
14
28
  // A map where the keys are the Rendezvous identifiers and the values are
15
29
  // arrays of their SUT (System Under Test) functions. This map will be used
16
30
  // to access the SUT functions for each Rendezvous contract afterwards.
@@ -44,27 +58,27 @@ const checkInvariants = (simnet, sutContractName, rendezvousList, rendezvousAllF
44
58
  return;
45
59
  }
46
60
  const enrichedSutFunctionsInterfaces = traitReferenceSutFunctions.length > 0
47
- ? (0, traits_1.enrichInterfaceWithTraitData)(simnet.getContractAST(sutContractName), (0, traits_1.buildTraitReferenceMap)(rendezvousSutFunctions.get(rendezvousContractId)), rendezvousSutFunctions.get(rendezvousContractId), rendezvousContractId)
61
+ ? (0, traits_1.enrichInterfaceWithTraitData)(simnet.getContractAST(targetContractName), (0, traits_1.buildTraitReferenceMap)(rendezvousSutFunctions.get(rendezvousContractId)), rendezvousSutFunctions.get(rendezvousContractId), rendezvousContractId)
48
62
  : rendezvousSutFunctions;
49
63
  const enrichedInvariantFunctionsInterfaces = traitReferenceInvariantFunctions.length > 0
50
- ? (0, traits_1.enrichInterfaceWithTraitData)(simnet.getContractAST(sutContractName), (0, traits_1.buildTraitReferenceMap)(rendezvousInvariantFunctions.get(rendezvousContractId)), rendezvousInvariantFunctions.get(rendezvousContractId), rendezvousContractId)
64
+ ? (0, traits_1.enrichInterfaceWithTraitData)(simnet.getContractAST(targetContractName), (0, traits_1.buildTraitReferenceMap)(rendezvousInvariantFunctions.get(rendezvousContractId)), rendezvousInvariantFunctions.get(rendezvousContractId), rendezvousContractId)
51
65
  : rendezvousInvariantFunctions;
52
66
  // Set up local context to track SUT function call counts.
53
67
  const localContext = (0, exports.initializeLocalContext)(enrichedSutFunctionsInterfaces);
54
68
  // Set up context in simnet by initializing state for SUT.
55
69
  (0, exports.initializeClarityContext)(simnet, enrichedSutFunctionsInterfaces);
56
- radio.emit("logMessage", `\nStarting invariant testing type for the ${sutContractName} contract...\n`);
70
+ radio.emit("logMessage", `\nStarting invariant testing type for the ${targetContractName} contract...\n`);
57
71
  const simnetAccounts = simnet.getAccounts();
58
72
  const eligibleAccounts = new Map([...simnetAccounts].filter(([key]) => key !== "faucet"));
59
73
  const simnetAddresses = Array.from(simnetAccounts.values());
60
74
  const functions = (0, shared_1.getFunctionsListForContract)(enrichedSutFunctionsInterfaces, rendezvousContractId);
61
75
  const invariants = (0, shared_1.getFunctionsListForContract)(enrichedInvariantFunctionsInterfaces, rendezvousContractId);
62
76
  if ((functions === null || functions === void 0 ? void 0 : functions.length) === 0) {
63
- radio.emit("logMessage", (0, ansicolor_1.red)(`No public functions found for the "${sutContractName}" contract. Without public functions, no state transitions can happen inside the contract, and the invariant test is not meaningful.\n`));
77
+ radio.emit("logMessage", (0, ansicolor_1.red)(`No public functions found for the "${targetContractName}" contract. Without public functions, no state transitions can happen inside the contract, and the invariant test is not meaningful.\n`));
64
78
  return;
65
79
  }
66
80
  if ((invariants === null || invariants === void 0 ? void 0 : invariants.length) === 0) {
67
- radio.emit("logMessage", (0, ansicolor_1.red)(`No invariant functions found for the "${sutContractName}" contract. Beware, for your contract may be exposed to unforeseen issues.\n`));
81
+ radio.emit("logMessage", (0, ansicolor_1.red)(`No invariant functions found for the "${targetContractName}" contract. Beware, for your contract may be exposed to unforeseen issues.\n`));
68
82
  return;
69
83
  }
70
84
  const radioReporter = (runDetails) => {
@@ -76,20 +90,25 @@ const checkInvariants = (simnet, sutContractName, rendezvousList, rendezvousAllF
76
90
  // to the first contract in the list. The arbitrary is still needed,
77
91
  // being used for reporting purposes in `heatstroke.ts`.
78
92
  rendezvousContractId: fast_check_1.default.constant(rendezvousContractId),
79
- sutCaller: fast_check_1.default.constantFrom(...eligibleAccounts.entries()),
80
93
  invariantCaller: fast_check_1.default.constantFrom(...eligibleAccounts.entries()),
81
94
  canMineBlocks: fast_check_1.default.boolean(),
82
95
  })
83
96
  .chain((r) => fast_check_1.default
84
97
  .record({
85
- selectedFunction: fast_check_1.default.constantFrom(...functions),
98
+ selectedFunctions: fast_check_1.default.array(fast_check_1.default.constantFrom(...functions), {
99
+ minLength: 1, // At least one function must be selected.
100
+ }),
86
101
  selectedInvariant: fast_check_1.default.constantFrom(...invariants),
87
102
  })
88
103
  .map((selectedFunctions) => (Object.assign(Object.assign({}, r), selectedFunctions))))
89
104
  .chain((r) => fast_check_1.default
90
105
  .record({
91
- functionArgsArb: fast_check_1.default.tuple(...(0, shared_1.functionToArbitrary)(r.selectedFunction, simnetAddresses, projectTraitImplementations)),
92
- invariantArgsArb: fast_check_1.default.tuple(...(0, shared_1.functionToArbitrary)(r.selectedInvariant, simnetAddresses, projectTraitImplementations)),
106
+ sutCallers: fast_check_1.default.array(fast_check_1.default.constantFrom(...eligibleAccounts.entries()), {
107
+ minLength: r.selectedFunctions.length,
108
+ maxLength: r.selectedFunctions.length,
109
+ }),
110
+ selectedFunctionsArgsList: fast_check_1.default.tuple(...r.selectedFunctions.map((selectedFunction) => fast_check_1.default.tuple(...(0, shared_1.functionToArbitrary)(selectedFunction, simnetAddresses, projectTraitImplementations)))),
111
+ invariantArgs: fast_check_1.default.tuple(...(0, shared_1.functionToArbitrary)(r.selectedInvariant, simnetAddresses, projectTraitImplementations)),
93
112
  })
94
113
  .map((args) => (Object.assign(Object.assign({}, r), args))))
95
114
  .chain((r) => fast_check_1.default
@@ -108,58 +127,60 @@ const checkInvariants = (simnet, sutContractName, rendezvousList, rendezvousAllF
108
127
  : fast_check_1.default.constant(0),
109
128
  })
110
129
  .map((burnBlocks) => (Object.assign(Object.assign({}, r), burnBlocks)))), (r) => {
111
- const selectedFunctionArgs = (0, shared_1.argsToCV)(r.selectedFunction, r.functionArgsArb);
112
- const selectedInvariantArgs = (0, shared_1.argsToCV)(r.selectedInvariant, r.invariantArgsArb);
113
- const printedFunctionArgs = r.functionArgsArb
114
- .map((arg) => {
130
+ const selectedFunctionsArgsCV = r.selectedFunctions.map((selectedFunction, index) => (0, shared_1.argsToCV)(selectedFunction, r.selectedFunctionsArgsList[index]));
131
+ const selectedInvariantArgsCV = (0, shared_1.argsToCV)(r.selectedInvariant, r.invariantArgs);
132
+ r.selectedFunctions.forEach((selectedFunction, index) => {
133
+ const [sutCallerWallet, sutCallerAddress] = r.sutCallers[index];
134
+ const printedFunctionArgs = r.selectedFunctionsArgsList[index]
135
+ .map((arg) => {
136
+ try {
137
+ return typeof arg === "object"
138
+ ? JSON.stringify(arg)
139
+ : arg.toString();
140
+ }
141
+ catch (_a) {
142
+ return "[Circular]";
143
+ }
144
+ })
145
+ .join(" ");
115
146
  try {
116
- return typeof arg === "object"
117
- ? JSON.stringify(arg)
118
- : arg.toString();
147
+ const { result: functionCallResult } = simnet.callPublicFn(r.rendezvousContractId, selectedFunction.name, selectedFunctionsArgsCV[index], sutCallerAddress);
148
+ const functionCallResultJson = (0, transactions_1.cvToJSON)(functionCallResult);
149
+ if (functionCallResultJson.success) {
150
+ localContext[r.rendezvousContractId][selectedFunction.name]++;
151
+ simnet.callPublicFn(r.rendezvousContractId, "update-context", [
152
+ transactions_1.Cl.stringAscii(selectedFunction.name),
153
+ transactions_1.Cl.uint(localContext[r.rendezvousContractId][selectedFunction.name]),
154
+ ], simnet.deployer);
155
+ radio.emit("logMessage", `₿ ${simnet.burnBlockHeight.toString().padStart(8)} ` +
156
+ `Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
157
+ (0, ansicolor_1.dim)(`${sutCallerWallet} `) +
158
+ `${targetContractName} ` +
159
+ `${(0, ansicolor_1.underline)(selectedFunction.name)} ` +
160
+ printedFunctionArgs);
161
+ }
162
+ else {
163
+ radio.emit("logMessage", (0, ansicolor_1.dim)(`₿ ${simnet.burnBlockHeight.toString().padStart(8)} ` +
164
+ `Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
165
+ `${sutCallerWallet} ` +
166
+ `${targetContractName} ` +
167
+ `${(0, ansicolor_1.underline)(selectedFunction.name)} ` +
168
+ printedFunctionArgs));
169
+ }
119
170
  }
120
- catch (_a) {
121
- return "[Circular]";
122
- }
123
- })
124
- .join(" ");
125
- const [sutCallerWallet, sutCallerAddress] = r.sutCaller;
126
- try {
127
- const { result: functionCallResult } = simnet.callPublicFn(r.rendezvousContractId, r.selectedFunction.name, selectedFunctionArgs, sutCallerAddress);
128
- const functionCallResultJson = (0, transactions_1.cvToJSON)(functionCallResult);
129
- if (functionCallResultJson.success) {
130
- localContext[r.rendezvousContractId][r.selectedFunction.name]++;
131
- simnet.callPublicFn(r.rendezvousContractId, "update-context", [
132
- transactions_1.Cl.stringAscii(r.selectedFunction.name),
133
- transactions_1.Cl.uint(localContext[r.rendezvousContractId][r.selectedFunction.name]),
134
- ], simnet.deployer);
135
- radio.emit("logMessage", `₿ ${simnet.burnBlockHeight.toString().padStart(8)} ` +
136
- `Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
137
- (0, ansicolor_1.dim)(`${sutCallerWallet} `) +
138
- `${sutContractName} ` +
139
- `${(0, ansicolor_1.underline)(r.selectedFunction.name)} ` +
140
- printedFunctionArgs);
141
- }
142
- else {
171
+ catch (error) {
172
+ // If the function call fails with a runtime error, log a dimmed
173
+ // message. Since the public function result is ignored, there's
174
+ // no need to throw an error.
143
175
  radio.emit("logMessage", (0, ansicolor_1.dim)(`₿ ${simnet.burnBlockHeight.toString().padStart(8)} ` +
144
176
  `Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
145
177
  `${sutCallerWallet} ` +
146
- `${sutContractName} ` +
147
- `${(0, ansicolor_1.underline)(r.selectedFunction.name)} ` +
178
+ `${targetContractName} ` +
179
+ `${(0, ansicolor_1.underline)(selectedFunction.name)} ` +
148
180
  printedFunctionArgs));
149
181
  }
150
- }
151
- catch (error) {
152
- // If the function call fails with a runtime error, log a dimmed
153
- // message. Since the public function result is ignored, there's
154
- // no need to throw an error.
155
- radio.emit("logMessage", (0, ansicolor_1.dim)(`₿ ${simnet.burnBlockHeight.toString().padStart(8)} ` +
156
- `Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
157
- `${sutCallerWallet} ` +
158
- `${sutContractName} ` +
159
- `${(0, ansicolor_1.underline)(r.selectedFunction.name)} ` +
160
- printedFunctionArgs));
161
- }
162
- const printedInvariantArgs = r.invariantArgsArb
182
+ });
183
+ const printedInvariantArgs = r.invariantArgs
163
184
  .map((arg) => {
164
185
  try {
165
186
  return typeof arg === "object"
@@ -173,19 +194,19 @@ const checkInvariants = (simnet, sutContractName, rendezvousList, rendezvousAllF
173
194
  .join(" ");
174
195
  const [invariantCallerWallet, invariantCallerAddress] = r.invariantCaller;
175
196
  try {
176
- const { result: invariantCallResult } = simnet.callReadOnlyFn(r.rendezvousContractId, r.selectedInvariant.name, selectedInvariantArgs, invariantCallerAddress);
197
+ const { result: invariantCallResult } = simnet.callReadOnlyFn(r.rendezvousContractId, r.selectedInvariant.name, selectedInvariantArgsCV, invariantCallerAddress);
177
198
  const invariantCallResultJson = (0, transactions_1.cvToJSON)(invariantCallResult);
178
199
  if (invariantCallResultJson.value === true) {
179
200
  radio.emit("logMessage", `₿ ${simnet.burnBlockHeight.toString().padStart(8)} ` +
180
201
  `Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
181
202
  `${(0, ansicolor_1.dim)(invariantCallerWallet)} ` +
182
203
  `${(0, ansicolor_1.green)("[PASS]")} ` +
183
- `${sutContractName} ` +
204
+ `${targetContractName} ` +
184
205
  `${(0, ansicolor_1.underline)(r.selectedInvariant.name)} ` +
185
206
  printedInvariantArgs);
186
207
  }
187
208
  if (!invariantCallResultJson.value) {
188
- throw new Error(`Invariant failed for ${sutContractName} contract: "${r.selectedInvariant.name}" returned ${invariantCallResultJson.value}`);
209
+ throw new Error(`Invariant failed for ${targetContractName} contract: "${r.selectedInvariant.name}" returned ${invariantCallResultJson.value}`);
189
210
  }
190
211
  }
191
212
  catch (error) {
@@ -196,7 +217,7 @@ const checkInvariants = (simnet, sutContractName, rendezvousList, rendezvousAllF
196
217
  `Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
197
218
  `${invariantCallerWallet} ` +
198
219
  `[FAIL] ` +
199
- `${sutContractName} ` +
220
+ `${targetContractName} ` +
200
221
  `${(0, ansicolor_1.underline)(r.selectedInvariant.name)} ` +
201
222
  printedInvariantArgs));
202
223
  // Re-throw the error for fast-check to catch and process.
@@ -215,7 +236,7 @@ const checkInvariants = (simnet, sutContractName, rendezvousList, rendezvousAllF
215
236
  };
216
237
  exports.checkInvariants = checkInvariants;
217
238
  /**
218
- * Initialize the local context, setting the number of times each function
239
+ * Initializes the local context, setting the number of times each function
219
240
  * has been called to zero.
220
241
  * @param rendezvousSutFunctions The Rendezvous functions.
221
242
  * @returns The initialized local context.
@@ -236,14 +257,15 @@ const initializeClarityContext = (simnet, rendezvousSutFunctions) => rendezvousS
236
257
  });
237
258
  exports.initializeClarityContext = initializeClarityContext;
238
259
  /**
239
- * Filter the System Under Test (`SUT`) functions from the map of all
240
- * contract functions.
260
+ * Filter the System Under Test (`SUT`) functions from the map of all contract
261
+ * functions.
241
262
  *
242
263
  * The SUT functions are the ones that have `public` access since they are
243
264
  * capable of changing the contract state, and they are not test functions.
244
265
  * @param allFunctionsMap The map containing all the functions for each
266
+ * Rendezvous contract.
267
+ * @returns A map containing the filtered SUT functions for each Rendezvous
245
268
  * contract.
246
- * @returns A map containing only the SUT functions for each contract.
247
269
  */
248
270
  const filterSutFunctions = (allFunctionsMap) => new Map(Array.from(allFunctionsMap, ([contractId, functions]) => [
249
271
  contractId,
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stacks/rendezvous",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Meet your contract's vulnerabilities head-on.",
5
5
  "main": "app.js",
6
6
  "bin": {
@@ -25,6 +25,10 @@
25
25
  "README.md",
26
26
  "LICENSE"
27
27
  ],
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/stacks-network/rendezvous.git"
31
+ },
28
32
  "dependencies": {
29
33
  "@hirosystems/clarinet-sdk": "2.12.0",
30
34
  "@stacks/transactions": "^6.16.1",
@@ -36,7 +40,7 @@
36
40
  "@hirosystems/clarinet-sdk-wasm": "2.12.0",
37
41
  "@types/jest": "^29.5.12",
38
42
  "jest": "^29.7.0",
39
- "ts-jest": "^29.2.3",
43
+ "ts-jest": "^29.2.5",
40
44
  "typescript": "^5.5.4"
41
45
  }
42
46
  }
package/dist/property.js CHANGED
@@ -10,7 +10,21 @@ const heatstroke_1 = require("./heatstroke");
10
10
  const shared_1 = require("./shared");
11
11
  const ansicolor_1 = require("ansicolor");
12
12
  const traits_1 = require("./traits");
13
- const checkProperties = (simnet, sutContractName, rendezvousList, rendezvousAllFunctions, seed, path, runs, radio) => {
13
+ /**
14
+ * Runs property-based tests on the target contract and logs the progress.
15
+ * Reports the test results through a custom reporter.
16
+ * @param simnet The simnet instance.
17
+ * @param targetContractName The name of the target contract.
18
+ * @param rendezvousList The list of contract IDs for each target contract.
19
+ * @param rendezvousAllFunctions A map of all target contract IDs to their
20
+ * function interfaces.
21
+ * @param seed The seed for reproducible property-based tests.
22
+ * @param path The path for reproducible property-based tests.
23
+ * @param runs The number of test runs.
24
+ * @param radio The custom logging event emitter.
25
+ * @returns void
26
+ */
27
+ const checkProperties = (simnet, targetContractName, rendezvousList, rendezvousAllFunctions, seed, path, runs, radio) => {
14
28
  const testContractId = rendezvousList[0];
15
29
  // A map where the keys are the test contract identifiers and the values are
16
30
  // arrays of their test functions. This map will be used to access the test
@@ -28,9 +42,9 @@ const checkProperties = (simnet, sutContractName, rendezvousList, rendezvousAllF
28
42
  return;
29
43
  }
30
44
  const enrichedTestFunctionsInterfaces = traitReferenceFunctions.length > 0
31
- ? (0, traits_1.enrichInterfaceWithTraitData)(simnet.getContractAST(sutContractName), (0, traits_1.buildTraitReferenceMap)(testContractsTestFunctions.get(testContractId)), testContractsTestFunctions.get(testContractId), testContractId)
45
+ ? (0, traits_1.enrichInterfaceWithTraitData)(simnet.getContractAST(targetContractName), (0, traits_1.buildTraitReferenceMap)(testContractsTestFunctions.get(testContractId)), testContractsTestFunctions.get(testContractId), testContractId)
32
46
  : testContractsTestFunctions;
33
- radio.emit("logMessage", `\nStarting property testing type for the ${sutContractName} contract...\n`);
47
+ radio.emit("logMessage", `\nStarting property testing type for the ${targetContractName} contract...\n`);
34
48
  // Search for discard functions, for each test function. This map will
35
49
  // be used to pair the test functions with their corresponding discard
36
50
  // functions.
@@ -61,7 +75,7 @@ const checkProperties = (simnet, sutContractName, rendezvousList, rendezvousAllF
61
75
  const simnetAddresses = Array.from(simnetAccounts.values());
62
76
  const testFunctions = (0, shared_1.getFunctionsListForContract)(enrichedTestFunctionsInterfaces, testContractId);
63
77
  if ((testFunctions === null || testFunctions === void 0 ? void 0 : testFunctions.length) === 0) {
64
- radio.emit("logMessage", (0, ansicolor_1.red)(`No test functions found for the "${sutContractName}" contract.\n`));
78
+ radio.emit("logMessage", (0, ansicolor_1.red)(`No test functions found for the "${targetContractName}" contract.\n`));
65
79
  return;
66
80
  }
67
81
  const radioReporter = (runDetails) => {
@@ -80,7 +94,7 @@ const checkProperties = (simnet, sutContractName, rendezvousList, rendezvousAllF
80
94
  .map((selectedTestFunction) => (Object.assign(Object.assign({}, r), selectedTestFunction))))
81
95
  .chain((r) => fast_check_1.default
82
96
  .record({
83
- functionArgsArb: fast_check_1.default.tuple(...(0, shared_1.functionToArbitrary)(r.selectedTestFunction, simnetAddresses, projectTraitImplementations)),
97
+ functionArgs: fast_check_1.default.tuple(...(0, shared_1.functionToArbitrary)(r.selectedTestFunction, simnetAddresses, projectTraitImplementations)),
84
98
  })
85
99
  .map((args) => (Object.assign(Object.assign({}, r), args))))
86
100
  .chain((r) => fast_check_1.default
@@ -99,8 +113,8 @@ const checkProperties = (simnet, sutContractName, rendezvousList, rendezvousAllF
99
113
  : fast_check_1.default.constant(0),
100
114
  })
101
115
  .map((burnBlocks) => (Object.assign(Object.assign({}, r), burnBlocks)))), (r) => {
102
- const selectedTestFunctionArgs = (0, shared_1.argsToCV)(r.selectedTestFunction, r.functionArgsArb);
103
- const printedTestFunctionArgs = r.functionArgsArb
116
+ const selectedTestFunctionArgs = (0, shared_1.argsToCV)(r.selectedTestFunction, r.functionArgs);
117
+ const printedTestFunctionArgs = r.functionArgs
104
118
  .map((arg) => {
105
119
  try {
106
120
  return typeof arg === "object"
@@ -122,7 +136,7 @@ const checkProperties = (simnet, sutContractName, rendezvousList, rendezvousAllF
122
136
  `Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
123
137
  `${(0, ansicolor_1.dim)(testCallerWallet)} ` +
124
138
  `${(0, ansicolor_1.yellow)("[WARN]")} ` +
125
- `${sutContractName} ` +
139
+ `${targetContractName} ` +
126
140
  `${(0, ansicolor_1.underline)(r.selectedTestFunction.name)} ` +
127
141
  (0, ansicolor_1.dim)(printedTestFunctionArgs));
128
142
  }
@@ -138,7 +152,7 @@ const checkProperties = (simnet, sutContractName, rendezvousList, rendezvousAllF
138
152
  `Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
139
153
  `${(0, ansicolor_1.dim)(testCallerWallet)} ` +
140
154
  `${(0, ansicolor_1.yellow)("[WARN]")} ` +
141
- `${sutContractName} ` +
155
+ `${targetContractName} ` +
142
156
  `${(0, ansicolor_1.underline)(r.selectedTestFunction.name)} ` +
143
157
  (0, ansicolor_1.dim)(printedTestFunctionArgs));
144
158
  }
@@ -149,7 +163,7 @@ const checkProperties = (simnet, sutContractName, rendezvousList, rendezvousAllF
149
163
  `Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
150
164
  `${(0, ansicolor_1.dim)(testCallerWallet)} ` +
151
165
  `${(0, ansicolor_1.green)("[PASS]")} ` +
152
- `${sutContractName} ` +
166
+ `${targetContractName} ` +
153
167
  `${(0, ansicolor_1.underline)(r.selectedTestFunction.name)} ` +
154
168
  printedTestFunctionArgs);
155
169
  if (r.canMineBlocks) {
@@ -157,7 +171,7 @@ const checkProperties = (simnet, sutContractName, rendezvousList, rendezvousAllF
157
171
  }
158
172
  }
159
173
  else {
160
- throw new Error(`Test failed for ${sutContractName} contract: "${r.selectedTestFunction.name}" returned ${testFunctionCallResultJson.value.value}`);
174
+ throw new Error(`Test failed for ${targetContractName} contract: "${r.selectedTestFunction.name}" returned ${testFunctionCallResultJson.value.value}`);
161
175
  }
162
176
  }
163
177
  catch (error) {
@@ -166,7 +180,7 @@ const checkProperties = (simnet, sutContractName, rendezvousList, rendezvousAllF
166
180
  `Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
167
181
  `${testCallerWallet} ` +
168
182
  `[FAIL] ` +
169
- `${sutContractName} ` +
183
+ `${targetContractName} ` +
170
184
  `${(0, ansicolor_1.underline)(r.selectedTestFunction.name)} ` +
171
185
  printedTestFunctionArgs));
172
186
  // Re-throw the error for fast-check to catch and process.
@@ -190,12 +204,12 @@ const isTestDiscardedInPlace = (testFunctionCallResultJson) => testFunctionCallR
190
204
  testFunctionCallResultJson.value.value === false;
191
205
  exports.isTestDiscardedInPlace = isTestDiscardedInPlace;
192
206
  /**
193
- * Check if the test function has to be discarded.
207
+ * Checks if the test function has to be discarded.
194
208
  * @param discardFunctionName The discard function name.
195
209
  * @param selectedTestFunctionArgs The generated test function arguments.
196
210
  * @param contractId The contract identifier.
197
211
  * @param simnet The simnet instance.
198
- * @param selectedCaller The selected caller.
212
+ * @param selectedCaller The selected caller address.
199
213
  * @returns A boolean indicating if the test function has to be discarded.
200
214
  */
201
215
  const isTestDiscarded = (discardFunctionName, selectedTestFunctionArgs, contractId, simnet, selectedCaller) => {
@@ -206,7 +220,7 @@ const isTestDiscarded = (discardFunctionName, selectedTestFunctionArgs, contract
206
220
  return jsonDiscardFunctionCallResult.value === false;
207
221
  };
208
222
  /**
209
- * Validate the discard function, ensuring that its parameters match the test
223
+ * Validates a discard function, ensuring that its parameters match the test
210
224
  * function's parameters and that its return type is boolean.
211
225
  * @param contractId The contract identifier.
212
226
  * @param discardFunctionName The discard function name.
@@ -235,23 +249,23 @@ const validateDiscardFunction = (contractId, discardFunctionName, testFunctionNa
235
249
  return true;
236
250
  };
237
251
  /**
238
- * Verify if the test function parameters match the discard function
252
+ * Checks if the test function parameters match the discard function
239
253
  * parameters.
240
- * @param testFunction The test function's interface.
241
- * @param discardFunction The discard function's interface.
254
+ * @param testFunctionInterface The test function's interface.
255
+ * @param discardFunctionInterface The discard function's interface.
242
256
  * @returns A boolean indicating if the parameters match.
243
257
  */
244
- const isParamsMatch = (testFunction, discardFunction) => {
245
- const sortedTestFunctionArgs = [...testFunction.args].sort((a, b) => a.name.localeCompare(b.name));
246
- const sortedDiscardFunctionArgs = [...discardFunction.args].sort((a, b) => a.name.localeCompare(b.name));
258
+ const isParamsMatch = (testFunctionInterface, discardFunctionInterface) => {
259
+ const sortedTestFunctionArgs = [...testFunctionInterface.args].sort((a, b) => a.name.localeCompare(b.name));
260
+ const sortedDiscardFunctionArgs = [...discardFunctionInterface.args].sort((a, b) => a.name.localeCompare(b.name));
247
261
  return (JSON.stringify(sortedTestFunctionArgs) ===
248
262
  JSON.stringify(sortedDiscardFunctionArgs));
249
263
  };
250
264
  exports.isParamsMatch = isParamsMatch;
251
265
  /**
252
- * Verify if the discard function's return type is boolean.
253
- * @param discardFunction The discard function's interface.
266
+ * Checks if the discard function's return type is boolean.
267
+ * @param discardFunctionInterface The discard function's interface.
254
268
  * @returns A boolean indicating if the return type is boolean.
255
269
  */
256
- const isReturnTypeBoolean = (discardFunction) => discardFunction.outputs.type === "bool";
270
+ const isReturnTypeBoolean = (discardFunctionInterface) => discardFunctionInterface.outputs.type === "bool";
257
271
  exports.isReturnTypeBoolean = isReturnTypeBoolean;
package/dist/shared.js CHANGED
@@ -8,35 +8,42 @@ const fast_check_1 = __importDefault(require("fast-check"));
8
8
  const transactions_1 = require("@stacks/transactions");
9
9
  const traits_1 = require("./traits");
10
10
  /**
11
- * Get the interfaces of contracts deployed by the specified deployer from the
12
- * simnet.
11
+ * Retrieves the contract interfaces of the contracts deployed by a specific
12
+ * deployer from the simnet instance.
13
13
  * @param simnet The simnet instance.
14
- * @param deployer The deployer address.
15
- * @returns The contracts interfaces.
14
+ * @returns The contract IDs mapped to their interfaces.
16
15
  */
17
16
  const getSimnetDeployerContractsInterfaces = (simnet) => new Map(Array.from(simnet.getContractsInterfaces()).filter(([key]) => key.split(".")[0] === simnet.deployer));
18
17
  exports.getSimnetDeployerContractsInterfaces = getSimnetDeployerContractsInterfaces;
19
18
  /**
20
- * Get the functions from the smart contract interfaces.
21
- * @param contractsInterfaces The smart contract interfaces map.
22
- * @returns A map containing the contracts functions.
19
+ * Retrieves the function interfaces from the contract interfaces. Filters out
20
+ * other contract interface data such as data maps, variables, and constants.
21
+ * @param contractInterfaces The smart contract interfaces map.
22
+ * @returns The contract IDs mapped to their function interfaces.
23
23
  */
24
- const getFunctionsFromContractInterfaces = (contractsInterfaces) => new Map(Array.from(contractsInterfaces, ([contractId, contractInterface]) => [
24
+ const getFunctionsFromContractInterfaces = (contractInterfaces) => new Map(Array.from(contractInterfaces, ([contractId, contractInterface]) => [
25
25
  contractId,
26
26
  contractInterface.functions,
27
27
  ]));
28
28
  exports.getFunctionsFromContractInterfaces = getFunctionsFromContractInterfaces;
29
29
  const getFunctionsListForContract = (functionsMap, contractId) => functionsMap.get(contractId) || [];
30
30
  exports.getFunctionsListForContract = getFunctionsListForContract;
31
- /** For a given function, dynamically generate fast-check arbitraries.
32
- * @param fn The function interface.
31
+ /** Dynamically generates fast-check arbitraries for a given function
32
+ * interface.
33
+ * @param functionInterface The "enriched" function interface.
34
+ * @param addresses The array of addresses to use for principal types.
35
+ * @param projectTraitImplementations The contract IDs mapped to the traits
36
+ * they implement.
33
37
  * @returns Array of fast-check arbitraries.
34
38
  */
35
- const functionToArbitrary = (fn, addresses, projectTraitImplementations) => fn.args.map((arg) => parameterTypeToArbitrary(arg.type, addresses, projectTraitImplementations));
39
+ const functionToArbitrary = (functionInterface, addresses, projectTraitImplementations) => functionInterface.args.map((arg) => parameterTypeToArbitrary(arg.type, addresses, projectTraitImplementations));
36
40
  exports.functionToArbitrary = functionToArbitrary;
37
41
  /**
38
- * For a given type, generate a fast-check arbitrary.
39
- * @param type The parameter type.
42
+ * Generates a fast-check arbitrary for a given parameter type.
43
+ * @param type The "enriched" parameter type.
44
+ * @param addresses The array of addresses to use for principal types.
45
+ * @param projectTraitImplementations The contract IDs mapped to the traits
46
+ * they implement.
40
47
  * @returns Fast-check arbitrary.
41
48
  */
42
49
  const parameterTypeToArbitrary = (type, addresses, projectTraitImplementations) => {
@@ -129,8 +136,8 @@ const complexTypesToArbitrary = {
129
136
  };
130
137
  /**
131
138
  * Custom hexadecimal string generator. The `hexaString` generator from
132
- * fast-check has been deprecated. This generator is implemented to precisely
133
- * match the behavior of the deprecated generator.
139
+ * fast-check has been deprecated. This generator is implemented to match the
140
+ * behavior of the deprecated generator.
134
141
  *
135
142
  * @param constraints Fast-check string constraints.
136
143
  * @returns Fast-check arbitrary for hexadecimal strings.
@@ -150,31 +157,31 @@ exports.hexaString = hexaString;
150
157
  /** The character set used for generating ASCII strings.*/
151
158
  const charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
152
159
  /**
153
- * Convert function arguments to Clarity values.
154
- * @param fn The function interface.
155
- * @param args Array of arguments.
160
+ * Converts JavaScript generated function arguments to Clarity values.
161
+ * @param functionInterface The function interface.
162
+ * @param generatedArguments Array of generated arguments.
156
163
  * @returns Array of Clarity values.
157
164
  */
158
- const argsToCV = (fn, args) => fn.args.map((arg, i) => argToCV(args[i], arg.type));
165
+ const argsToCV = (functionInterface, generatedArguments) => functionInterface.args.map((arg, i) => argToCV(generatedArguments[i], arg.type));
159
166
  exports.argsToCV = argsToCV;
160
167
  /**
161
- * Convert a function argument to a Clarity value.
162
- * @param arg Generated argument.
168
+ * Converts a JavaScript generated function argument to a Clarity value.
169
+ * @param generatedArgument Generated argument.
163
170
  * @param type Argument type (base or complex).
164
171
  * @returns Clarity value.
165
172
  */
166
- const argToCV = (arg, type) => {
173
+ const argToCV = (generatedArgument, type) => {
167
174
  if (isBaseType(type)) {
168
175
  // Base type.
169
176
  switch (type) {
170
177
  case "int128":
171
- return baseTypesToCV.int128(arg);
178
+ return baseTypesToCV.int128(generatedArgument);
172
179
  case "uint128":
173
- return baseTypesToCV.uint128(arg);
180
+ return baseTypesToCV.uint128(generatedArgument);
174
181
  case "bool":
175
- return baseTypesToCV.bool(arg);
182
+ return baseTypesToCV.bool(generatedArgument);
176
183
  case "principal":
177
- return baseTypesToCV.principal(arg);
184
+ return baseTypesToCV.principal(generatedArgument);
178
185
  default:
179
186
  throw new Error(`Unsupported base parameter type: ${type}`);
180
187
  }
@@ -182,36 +189,38 @@ const argToCV = (arg, type) => {
182
189
  else {
183
190
  // Complex type.
184
191
  if ("buffer" in type) {
185
- return complexTypesToCV.buffer(arg);
192
+ return complexTypesToCV.buffer(generatedArgument);
186
193
  }
187
194
  else if ("string-ascii" in type) {
188
- return complexTypesToCV["string-ascii"](arg);
195
+ return complexTypesToCV["string-ascii"](generatedArgument);
189
196
  }
190
197
  else if ("string-utf8" in type) {
191
- return complexTypesToCV["string-utf8"](arg);
198
+ return complexTypesToCV["string-utf8"](generatedArgument);
192
199
  }
193
200
  else if ("list" in type) {
194
- const listItems = arg.map((item) => argToCV(item, type.list.type));
201
+ const listItems = generatedArgument.map((item) => argToCV(item, type.list.type));
195
202
  return complexTypesToCV.list(listItems);
196
203
  }
197
204
  else if ("tuple" in type) {
198
205
  const tupleData = {};
199
206
  type.tuple.forEach((field) => {
200
- tupleData[field.name] = argToCV(arg[field.name], field.type);
207
+ tupleData[field.name] = argToCV(generatedArgument[field.name], field.type);
201
208
  });
202
209
  return complexTypesToCV.tuple(tupleData);
203
210
  }
204
211
  else if ("optional" in type) {
205
- return (0, transactions_1.optionalCVOf)(arg ? argToCV(arg, type.optional) : undefined);
212
+ return (0, transactions_1.optionalCVOf)(generatedArgument
213
+ ? argToCV(generatedArgument, type.optional)
214
+ : undefined);
206
215
  }
207
216
  else if ("response" in type) {
208
- const status = arg.status;
217
+ const status = generatedArgument.status;
209
218
  const branchType = type.response[status];
210
- const responseValue = argToCV(arg.value, branchType);
219
+ const responseValue = argToCV(generatedArgument.value, branchType);
211
220
  return complexTypesToCV.response(status, responseValue);
212
221
  }
213
222
  else if ("trait_reference" in type) {
214
- return complexTypesToCV.trait_reference(arg);
223
+ return complexTypesToCV.trait_reference(generatedArgument);
215
224
  }
216
225
  else {
217
226
  throw new Error(`Unsupported complex parameter type: ${JSON.stringify(type)}`);
package/dist/traits.js CHANGED
@@ -2,16 +2,16 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.extractProjectTraitImplementations = exports.isTraitReferenceFunction = exports.getContractIdsImplementingTrait = exports.buildTraitReferenceMap = exports.getTraitReferenceData = exports.enrichInterfaceWithTraitData = void 0;
4
4
  /**
5
- * Enriches contract interface with trait reference data. Before enrichment,
5
+ * Enriches a contract interface with trait reference data. Before enrichment,
6
6
  * the contract interface lacks trait reference data for parameters. This
7
7
  * function constructs a copy of the contract interface with trait reference
8
8
  * data for parameters that are trait references.
9
9
  * @param ast The contract AST.
10
- * @param traitReferenceMap The map of function names to trait reference paths.
10
+ * @param traitReferenceMap The function names mapped to their trait reference
11
+ * parameter paths.
11
12
  * @param functionInterfaceList The list of function interfaces for a contract.
12
13
  * @param targetContractId The contract ID to enrich with trait reference data.
13
- * @returns A map of contract IDs to a list of enriched contract interface
14
- * functions.
14
+ * @returns The contract IDs mapped to a list of enriched function interfaces.
15
15
  */
16
16
  const enrichInterfaceWithTraitData = (ast, traitReferenceMap, functionInterfaceList, targetContractId) => {
17
17
  const enriched = new Map();
@@ -233,9 +233,10 @@ const getTraitReferenceData = (ast, functionName, parameterPath) => {
233
233
  exports.getTraitReferenceData = getTraitReferenceData;
234
234
  /**
235
235
  * Builds a map of function names to trait reference paths. The trait reference
236
- * path is the path to the trait reference in the function parameter list.
236
+ * path is the nesting path of the trait reference in the function parameter
237
+ * list.
237
238
  * @param functionInterfaces The list of function interfaces for a contract.
238
- * @returns A map of function names to trait reference paths.
239
+ * @returns The function names mapped to their trait reference parameter paths.
239
240
  */
240
241
  const buildTraitReferenceMap = (functionInterfaces) => {
241
242
  const traitReferenceMap = new Map();
@@ -363,7 +364,7 @@ exports.isTraitReferenceFunction = isTraitReferenceFunction;
363
364
  * Iterates over all project contracts's ASTs excluding the boot ones and
364
365
  * extracts a record of contract IDs to their implemented traits.
365
366
  * @param simnet The Simnet instance.
366
- * @returns A record of contract IDs to their implemented traits.
367
+ * @returns The contract IDs mapped to their implemented traits.
367
368
  */
368
369
  const extractProjectTraitImplementations = (simnet) => {
369
370
  const allProjectContracts = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stacks/rendezvous",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Meet your contract's vulnerabilities head-on.",
5
5
  "main": "app.js",
6
6
  "bin": {
@@ -25,6 +25,10 @@
25
25
  "README.md",
26
26
  "LICENSE"
27
27
  ],
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/stacks-network/rendezvous.git"
31
+ },
28
32
  "dependencies": {
29
33
  "@hirosystems/clarinet-sdk": "2.12.0",
30
34
  "@stacks/transactions": "^6.16.1",
@@ -36,7 +40,7 @@
36
40
  "@hirosystems/clarinet-sdk-wasm": "2.12.0",
37
41
  "@types/jest": "^29.5.12",
38
42
  "jest": "^29.7.0",
39
- "ts-jest": "^29.2.3",
43
+ "ts-jest": "^29.2.5",
40
44
  "typescript": "^5.5.4"
41
45
  }
42
46
  }