Repository navigation
Expand file tree
/
Copy pathlib.ts
More file actions
140 lines (127 loc) · 4.54 KB
/
Copy pathlib.ts
File metadata and controls
140 lines (127 loc) · 4.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import type { Simnet } from "@stacks/clarinet-sdk";
import type { ContractInterfaceFunction } from "@stacks/clarinet-sdk-wasm";
import type { ClarityValue } from "@stacks/transactions";
import fc from "fast-check";
import { argsToCV, functionToArbitrary } from "./shared";
import type { EnrichedContractInterfaceFunction } from "./shared.types";
import {
buildTraitReferenceMap,
enrichInterfaceWithTraitData,
extractProjectTraitImplementations,
isTraitReferenceFunction,
} from "./traits";
import type { ImplementedTraitType } from "./traits.types";
export type { EnrichedContractInterfaceFunction } from "./shared.types";
/**
* Retrieves a function interface from a simnet contract by name. The returned
* interface is enriched with trait reference data when applicable, making it
* ready for use with {@link strategyFor}.
*
* @param simnet The simnet instance.
* @param contractName The contract name (e.g., "counter").
* @param functionName The function name (e.g., "increment").
* @param deployer The deployer address. Defaults to `simnet.deployer`.
* @returns The enriched function interface.
*
* @example
* ```ts
* const simnet = await initSimnet("./Clarinet.toml");
* const increment = getContractFunction(simnet, "counter", "increment");
* ```
*/
export const getContractFunction = (
simnet: Simnet,
contractName: string,
functionName: string,
deployer?: string,
): EnrichedContractInterfaceFunction => {
const targetDeployer = deployer ?? simnet.deployer;
const allContracts = simnet.getContractsInterfaces();
const contractId = `${targetDeployer}.${contractName}`;
const contractInterface = allContracts.get(contractId);
if (!contractInterface) {
throw new Error(`Contract "${contractId}" not found.`);
}
const fn = contractInterface.functions.find(
(f: ContractInterfaceFunction) => f.name === functionName,
);
if (!fn) {
throw new Error(
`Function "${functionName}" not found in contract "${contractName}".`,
);
}
// Enrich with trait data if the function uses trait references.
if (isTraitReferenceFunction(fn)) {
const traitReferenceMap = buildTraitReferenceMap([fn]);
const enriched = enrichInterfaceWithTraitData(
simnet.getContractAST(contractName),
traitReferenceMap,
[fn],
contractId,
);
return enriched.get(contractId)![0];
}
return fn as EnrichedContractInterfaceFunction;
};
/**
* Generates a fast-check arbitrary that produces `ClarityValue[]` arrays
* ready for use with `simnet.callPublicFn` or similar.
*
* By default, principal addresses and trait implementations are resolved from
* the simnet instance. Pass `allAddresses` to restrict the principal pool
* (e.g. to a user-filtered account set), and `projectTraitImplementations` to
* reuse a precomputed map.
*
* @param simnet The simnet instance.
* @param fn The enriched function interface (from {@link getContractFunction}).
* @param allAddresses Optional addresses used for principal-typed argument
* generation. Defaults to all accounts in the simnet.
* @param projectTraitImplementations Optional project/requirement contracts
* keyed by the traits they implement. Defaults to extracting them from the
* simnet.
* @returns A fast-check arbitrary producing Clarity argument arrays.
*
* @example
* ```ts
* import fc from "fast-check";
* import { initSimnet } from "@stacks/clarinet-sdk";
* import { getContractFunction, strategyFor } from "@stacks/rendezvous";
*
* const simnet = await initSimnet("./Clarinet.toml");
* const increment = getContractFunction(simnet, "counter", "increment");
* const argsArb = strategyFor(simnet, increment);
*
* fc.assert(
* fc.property(argsArb, (args) => {
* const { result } = simnet.callPublicFn(
* "counter",
* "increment",
* args,
* simnet.deployer,
* );
* return result.type !== "err";
* })
* );
* ```
*/
export const strategyFor = (
simnet: Simnet,
fn: EnrichedContractInterfaceFunction,
allAddresses?: string[],
projectTraitImplementations?: Record<string, ImplementedTraitType[]>,
): fc.Arbitrary<ClarityValue[]> => {
const resolvedAddresses = allAddresses ?? [...simnet.getAccounts().values()];
const resolvedTraitImplementations =
projectTraitImplementations ?? extractProjectTraitImplementations(simnet);
const arbitraries = functionToArbitrary(
fn,
resolvedAddresses,
resolvedTraitImplementations,
);
if (arbitraries.length === 0) {
return fc.constant([]);
}
return fc
.tuple(...arbitraries)
.map((generated: unknown[]) => argsToCV(fn, generated));
};