recon-generate 0.0.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.
Files changed (42) hide show
  1. package/README.md +84 -0
  2. package/dist/generator.d.ts +52 -0
  3. package/dist/generator.js +512 -0
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.js +169 -0
  6. package/dist/templateManager.d.ts +14 -0
  7. package/dist/templateManager.js +236 -0
  8. package/dist/templates/before-after.d.ts +1 -0
  9. package/dist/templates/before-after.js +37 -0
  10. package/dist/templates/crytic-tester.d.ts +1 -0
  11. package/dist/templates/crytic-tester.js +23 -0
  12. package/dist/templates/crytic-to-foundry.d.ts +1 -0
  13. package/dist/templates/crytic-to-foundry.js +32 -0
  14. package/dist/templates/echidna-config.d.ts +1 -0
  15. package/dist/templates/echidna-config.js +20 -0
  16. package/dist/templates/halmos-config.d.ts +1 -0
  17. package/dist/templates/halmos-config.js +14 -0
  18. package/dist/templates/handlebars-helpers.d.ts +2 -0
  19. package/dist/templates/handlebars-helpers.js +142 -0
  20. package/dist/templates/index.d.ts +14 -0
  21. package/dist/templates/index.js +29 -0
  22. package/dist/templates/medusa-config.d.ts +1 -0
  23. package/dist/templates/medusa-config.js +112 -0
  24. package/dist/templates/properties.d.ts +1 -0
  25. package/dist/templates/properties.js +18 -0
  26. package/dist/templates/setup.d.ts +1 -0
  27. package/dist/templates/setup.js +55 -0
  28. package/dist/templates/target-functions.d.ts +1 -0
  29. package/dist/templates/target-functions.js +37 -0
  30. package/dist/templates/targets/admin-targets.d.ts +1 -0
  31. package/dist/templates/targets/admin-targets.js +33 -0
  32. package/dist/templates/targets/doomsday-targets.d.ts +1 -0
  33. package/dist/templates/targets/doomsday-targets.js +33 -0
  34. package/dist/templates/targets/managers-targets.d.ts +1 -0
  35. package/dist/templates/targets/managers-targets.js +61 -0
  36. package/dist/templates/targets/targets.d.ts +1 -0
  37. package/dist/templates/targets/targets.js +35 -0
  38. package/dist/types.d.ts +45 -0
  39. package/dist/types.js +14 -0
  40. package/dist/utils.d.ts +7 -0
  41. package/dist/utils.js +106 -0
  42. package/package.json +30 -0
package/dist/index.js ADDED
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const commander_1 = require("commander");
38
+ const path = __importStar(require("path"));
39
+ const case_1 = require("case");
40
+ const generator_1 = require("./generator");
41
+ const utils_1 = require("./utils");
42
+ function parseFilter(input) {
43
+ if (!input)
44
+ return undefined;
45
+ const contractOnly = new Set();
46
+ const functions = new Map();
47
+ const splitTopLevel = (s) => {
48
+ const out = [];
49
+ let buf = '';
50
+ let depth = 0;
51
+ for (let i = 0; i < s.length; i++) {
52
+ const ch = s[i];
53
+ if (ch === '(')
54
+ depth++;
55
+ else if (ch === ')')
56
+ depth = Math.max(0, depth - 1);
57
+ if ((ch === ',' || ch === '|') && depth === 0) {
58
+ out.push(buf.trim());
59
+ buf = '';
60
+ continue;
61
+ }
62
+ buf += ch;
63
+ }
64
+ if (buf.trim())
65
+ out.push(buf.trim());
66
+ return out;
67
+ };
68
+ const addFn = (contract, fn) => {
69
+ const normalized = fn.replace(/^\{/, '').replace(/\}$/, '').trim();
70
+ if (!normalized)
71
+ return;
72
+ if (!functions.has(contract))
73
+ functions.set(contract, new Set());
74
+ functions.get(contract).add(normalized);
75
+ };
76
+ let currentContract;
77
+ for (const raw of splitTopLevel(String(input))) {
78
+ const token = raw.trim();
79
+ if (!token)
80
+ continue;
81
+ if (token.includes(':')) {
82
+ const [contractPart, fnPart] = token.split(':', 2);
83
+ const contract = contractPart.trim();
84
+ if (!contract)
85
+ continue;
86
+ currentContract = contract;
87
+ if (fnPart && fnPart.trim()) {
88
+ const pieces = splitTopLevel(fnPart);
89
+ for (const p of pieces)
90
+ addFn(contract, p);
91
+ }
92
+ continue;
93
+ }
94
+ // Function token attached to last contract
95
+ if ((token.startsWith('{') || token.includes('(')) && currentContract) {
96
+ addFn(currentContract, token);
97
+ continue;
98
+ }
99
+ // Standalone contract
100
+ currentContract = token;
101
+ contractOnly.add(token);
102
+ }
103
+ return { contractOnly, functions };
104
+ }
105
+ async function main() {
106
+ const program = new commander_1.Command();
107
+ program
108
+ .name('recon-generate')
109
+ .description('Scaffold Recon fuzzing suite inside a Foundry project')
110
+ .option('-o, --output <path>', 'Custom output folder for tests (recon will be appended if missing)')
111
+ .option('-r, --recon <path>', 'Path to recon.json configuration')
112
+ .option('--include <spec>', 'Include filter: e.g. "A,B:{foo(uint256)|bar(address)},C"')
113
+ .option('--exclude <spec>', 'Exclude filter: e.g. "A:{foo(uint256)},D" or just "B"')
114
+ .option('--admin <spec>', 'Mark functions as admin: e.g. "A:{foo(uint256),bar()},B:{baz(address)}"')
115
+ .option('--name <suite>', 'Suite name; affects folder (recon-name) and Crytic artifacts')
116
+ .option('--mock <names>', 'Comma-separated contract names to generate mocks for')
117
+ .option('--debug', 'Print debug info about filters and selection')
118
+ .option('--list', 'List available contracts/functions (after filters) and exit')
119
+ .option('--force', 'Replace existing generated suite output (under --output). Does not rebuild .recon/out.')
120
+ .option('--force-build', 'Delete .recon/out to force a fresh forge build before generating')
121
+ .option('--foundry-config <path>', 'Path to foundry.toml (defaults to ./foundry.toml)')
122
+ .parse(process.argv);
123
+ const opts = program.opts();
124
+ const workspaceRoot = process.cwd();
125
+ const foundryConfig = (0, utils_1.getFoundryConfigPath)(workspaceRoot, opts.foundryConfig);
126
+ const foundryRoot = path.dirname(foundryConfig);
127
+ const includeFilter = parseFilter(opts.include);
128
+ const excludeFilter = parseFilter(opts.exclude);
129
+ const adminFilter = parseFilter(opts.admin);
130
+ const mockSet = opts.mock
131
+ ? new Set(String(opts.mock).split(',').map((s) => s.trim()).filter(Boolean))
132
+ : undefined;
133
+ const suiteRaw = opts.name ? String(opts.name).trim() : '';
134
+ const suiteSnake = suiteRaw ? (0, case_1.snake)(suiteRaw) : '';
135
+ const suitePascal = suiteRaw ? (0, case_1.pascal)(suiteRaw) : '';
136
+ const suiteFolderName = suiteSnake ? `recon-${suiteSnake}` : 'recon';
137
+ const baseOut = opts.output ? String(opts.output) : await (0, utils_1.getTestFolder)(foundryRoot);
138
+ const baseOutPath = path.isAbsolute(baseOut) ? baseOut : path.join(foundryRoot, baseOut);
139
+ const suiteDir = path.join(baseOutPath, suiteFolderName);
140
+ const reconDefaultName = suiteSnake ? `recon-${suiteSnake}.json` : 'recon.json';
141
+ const reconPath = opts.recon
142
+ ? (path.isAbsolute(opts.recon) ? opts.recon : path.join(workspaceRoot, opts.recon))
143
+ : (await (0, utils_1.fileExists)(path.join(foundryRoot, reconDefaultName))
144
+ ? path.join(foundryRoot, reconDefaultName)
145
+ : path.join(foundryRoot, '.recon', reconDefaultName));
146
+ const generator = new generator_1.ReconGenerator(foundryRoot, {
147
+ suiteDir,
148
+ reconConfigPath: reconPath,
149
+ foundryConfigPath: foundryConfig,
150
+ include: includeFilter,
151
+ exclude: excludeFilter,
152
+ admin: adminFilter ? adminFilter.functions : undefined,
153
+ debug: !!opts.debug,
154
+ force: !!opts.force,
155
+ forceBuild: !!opts.forceBuild,
156
+ mocks: mockSet,
157
+ suiteNameSnake: suiteSnake,
158
+ suiteNamePascal: suitePascal,
159
+ });
160
+ if (opts.list) {
161
+ await generator.listAvailable();
162
+ return;
163
+ }
164
+ await generator.run();
165
+ }
166
+ main().catch(err => {
167
+ console.error('recon-generate failed:', err.message || err);
168
+ process.exit(1);
169
+ });
@@ -0,0 +1,14 @@
1
+ import { ContractMetadata } from './types';
2
+ export declare class TemplateManager {
3
+ private foundryRoot;
4
+ private suiteDir;
5
+ private suiteNameSnake;
6
+ private suiteNamePascal;
7
+ constructor(foundryRoot: string, suiteDir: string, suiteNameSnake: string, suiteNamePascal: string);
8
+ private skipList;
9
+ private shouldGenerateFile;
10
+ private updateTargetFile;
11
+ private collectFunctions;
12
+ private defaultFunctionsFromAbi;
13
+ generateTemplates(contracts: ContractMetadata[], reconConfig: Record<string, any>): Promise<void>;
14
+ }
@@ -0,0 +1,236 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.TemplateManager = void 0;
37
+ const path = __importStar(require("path"));
38
+ const fs = __importStar(require("fs/promises"));
39
+ const templates = __importStar(require("./templates"));
40
+ const types_1 = require("./types");
41
+ class TemplateManager {
42
+ constructor(foundryRoot, suiteDir, suiteNameSnake, suiteNamePascal) {
43
+ this.foundryRoot = foundryRoot;
44
+ this.suiteDir = suiteDir;
45
+ this.suiteNameSnake = suiteNameSnake;
46
+ this.suiteNamePascal = suiteNamePascal;
47
+ }
48
+ skipList() {
49
+ const suiteRel = path.relative(this.foundryRoot, this.suiteDir);
50
+ const suffix = this.suiteNameSnake ? `-${this.suiteNameSnake}` : '';
51
+ const cryticTesterName = `CryticTester${this.suiteNamePascal}`;
52
+ const cryticToFoundryName = `CryticToFoundry${this.suiteNamePascal}`;
53
+ return [
54
+ `echidna${suffix}.yaml`,
55
+ `medusa${suffix}.json`,
56
+ `halmos${suffix}.toml`,
57
+ path.join(suiteRel, 'BeforeAfter.sol'),
58
+ path.join(suiteRel, `${cryticTesterName}.sol`),
59
+ path.join(suiteRel, `${cryticToFoundryName}.sol`),
60
+ path.join(suiteRel, 'Properties.sol'),
61
+ path.join(suiteRel, 'helpers/Utils.sol'),
62
+ path.join(suiteRel, 'helpers/Panic.sol'),
63
+ path.join(suiteRel, 'managers/ActorManager.sol'),
64
+ path.join(suiteRel, 'managers/AssetManager.sol'),
65
+ path.join(suiteRel, 'managers/utils/EnumerableSet.sol'),
66
+ path.join(suiteRel, 'mocks/MockERC20.sol'),
67
+ path.join(suiteRel, 'targets/DoomsdayTargets.sol'),
68
+ path.join(suiteRel, 'targets/ManagersTargets.sol'),
69
+ ];
70
+ }
71
+ async shouldGenerateFile(filePath) {
72
+ if (!this.skipList().includes(filePath)) {
73
+ return true;
74
+ }
75
+ try {
76
+ const targetPath = path.isAbsolute(filePath) ? filePath : path.join(this.foundryRoot, filePath);
77
+ await fs.access(targetPath);
78
+ return false;
79
+ }
80
+ catch {
81
+ return true;
82
+ }
83
+ }
84
+ async updateTargetFile(filepath, newContent) {
85
+ try {
86
+ const existingContent = await fs.readFile(filepath, 'utf8');
87
+ if (existingContent.includes('/// AUTO GENERATED TARGET FUNCTIONS - WARNING: DO NOT DELETE OR MODIFY THIS LINE ///')) {
88
+ const [beforeMarker, afterMarker] = existingContent.split('/// AUTO GENERATED TARGET FUNCTIONS - WARNING: DO NOT DELETE OR MODIFY THIS LINE ///');
89
+ const [, newAutoGenerated] = newContent.split('/// AUTO GENERATED TARGET FUNCTIONS - WARNING: DO NOT DELETE OR MODIFY THIS LINE ///');
90
+ return beforeMarker + '/// AUTO GENERATED TARGET FUNCTIONS - WARNING: DO NOT DELETE OR MODIFY THIS LINE ///' + newAutoGenerated;
91
+ }
92
+ return newContent;
93
+ }
94
+ catch {
95
+ return newContent;
96
+ }
97
+ }
98
+ collectFunctions(contracts, reconConfig) {
99
+ const enabledContracts = [];
100
+ const adminFunctions = [];
101
+ const otherFunctions = [];
102
+ const nonSeparatedFunctions = [];
103
+ const separatedByContract = {};
104
+ for (const contract of contracts) {
105
+ const cfg = reconConfig[contract.jsonPath] || { enabled: true, functions: [], separated: true };
106
+ if (cfg.enabled === false) {
107
+ continue;
108
+ }
109
+ enabledContracts.push(contract);
110
+ const separated = cfg.separated !== false;
111
+ const functionsConfig = Array.isArray(cfg.functions) ? cfg.functions : [];
112
+ const functionList = functionsConfig.length > 0 ? functionsConfig : this.defaultFunctionsFromAbi(contract);
113
+ for (const fnCfg of functionList) {
114
+ const fnName = fnCfg.signature.split('(')[0];
115
+ const fnAbi = contract.abi.find((item) => {
116
+ if (item.type !== 'function' || item.name !== fnName) {
117
+ return false;
118
+ }
119
+ const sig = `${item.name}(${item.inputs.map((i) => i.internalType && i.internalType.startsWith('struct ')
120
+ ? i.internalType.replace(/^struct\s+/, '')
121
+ : i.type).join(',')})`;
122
+ return sig === fnCfg.signature;
123
+ });
124
+ if (!fnAbi) {
125
+ continue;
126
+ }
127
+ const fnInfo = {
128
+ contractName: contract.name,
129
+ contractPath: contract.path,
130
+ functionName: fnAbi.name,
131
+ abi: fnAbi,
132
+ actor: fnCfg.actor || types_1.Actor.ACTOR,
133
+ mode: fnCfg.mode || types_1.Mode.NORMAL,
134
+ separated,
135
+ };
136
+ if (fnCfg.actor === types_1.Actor.ADMIN) {
137
+ adminFunctions.push(fnInfo);
138
+ }
139
+ else {
140
+ otherFunctions.push(fnInfo);
141
+ if (separated) {
142
+ if (!separatedByContract[contract.name]) {
143
+ separatedByContract[contract.name] = [];
144
+ }
145
+ separatedByContract[contract.name].push(fnInfo);
146
+ }
147
+ else {
148
+ nonSeparatedFunctions.push(fnInfo);
149
+ }
150
+ }
151
+ }
152
+ }
153
+ const allContractNames = [
154
+ 'Admin',
155
+ 'Doomsday',
156
+ 'Managers',
157
+ ...Object.keys(separatedByContract)
158
+ ].sort();
159
+ return {
160
+ enabledContracts,
161
+ adminFunctions,
162
+ otherFunctions,
163
+ nonSeparatedFunctions,
164
+ separatedByContract,
165
+ allContractNames,
166
+ };
167
+ }
168
+ defaultFunctionsFromAbi(contract) {
169
+ var _a;
170
+ const functions = [];
171
+ for (const item of contract.abi) {
172
+ if (item.type === 'function' && !((_a = item.stateMutability) === null || _a === void 0 ? void 0 : _a.match(/^(view|pure)$/))) {
173
+ const sig = `${item.name}(${item.inputs.map((i) => i.internalType && i.internalType.startsWith('struct ')
174
+ ? i.internalType.replace(/^struct\s+/, '')
175
+ : i.type).join(',')})`;
176
+ functions.push({ signature: sig, actor: types_1.Actor.ACTOR, mode: types_1.Mode.NORMAL });
177
+ }
178
+ }
179
+ return functions;
180
+ }
181
+ async generateTemplates(contracts, reconConfig) {
182
+ const { enabledContracts, adminFunctions, nonSeparatedFunctions, separatedByContract, allContractNames, } = this.collectFunctions(contracts, reconConfig);
183
+ const suiteRel = path.relative(this.foundryRoot, this.suiteDir);
184
+ const suffix = this.suiteNameSnake ? `-${this.suiteNameSnake}` : '';
185
+ const cryticTesterName = `CryticTester${this.suiteNamePascal}`;
186
+ const cryticToFoundryName = `CryticToFoundry${this.suiteNamePascal}`;
187
+ const suiteTargetsDir = path.join(suiteRel, 'targets');
188
+ const files = {
189
+ [`echidna${suffix}.yaml`]: templates.echidnaConfigTemplate({ corpusDir: `echidna${suffix}` }),
190
+ [`medusa${suffix}.json`]: templates.medusaConfigTemplate({ cryticTesterName }),
191
+ [`halmos${suffix}.toml`]: templates.halmosConfigTemplate({ cryticToFoundryName }),
192
+ [path.join(suiteRel, 'BeforeAfter.sol')]: templates.beforeAfterTemplate({}),
193
+ [path.join(suiteRel, `${cryticTesterName}.sol`)]: templates.cryticTesterTemplate({ cryticTesterName, suiteNameSuffix: suffix }),
194
+ [path.join(suiteRel, `${cryticToFoundryName}.sol`)]: templates.cryticToFoundryTemplate({ cryticToFoundryName }),
195
+ [path.join(suiteRel, 'Properties.sol')]: templates.propertiesTemplate({}),
196
+ [path.join(suiteRel, 'Setup.sol')]: templates.setupTemplate({ contracts: enabledContracts }),
197
+ [path.join(suiteRel, 'TargetFunctions.sol')]: templates.targetFunctionsTemplate({
198
+ functions: nonSeparatedFunctions,
199
+ contracts: allContractNames,
200
+ }),
201
+ [path.join(suiteTargetsDir, 'AdminTargets.sol')]: templates.adminTargetsTemplate({ functions: adminFunctions }),
202
+ [path.join(suiteTargetsDir, 'DoomsdayTargets.sol')]: templates.doomsdayTargetsTemplate({}),
203
+ [path.join(suiteTargetsDir, 'ManagersTargets.sol')]: templates.managersTargetsTemplate({}),
204
+ };
205
+ for (const [contractName, functions] of Object.entries(separatedByContract)) {
206
+ const targetPath = path.join(suiteTargetsDir, `${contractName}Targets.sol`);
207
+ files[targetPath] = templates.targetsTemplate({
208
+ contractName,
209
+ path: functions.length > 0 ? functions[0].contractPath : '',
210
+ functions,
211
+ });
212
+ }
213
+ for (const [name, content] of Object.entries(files)) {
214
+ const outputPath = path.isAbsolute(name) ? name : path.join(this.foundryRoot, name);
215
+ if (!(await this.shouldGenerateFile(name))) {
216
+ continue;
217
+ }
218
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
219
+ if (name.endsWith('Setup.sol')) {
220
+ try {
221
+ await fs.access(outputPath);
222
+ continue; // do not overwrite user setup
223
+ }
224
+ catch { }
225
+ }
226
+ if (name.includes('targets/') && name.endsWith('Targets.sol')) {
227
+ const finalContent = await this.updateTargetFile(outputPath, content);
228
+ await fs.writeFile(outputPath, finalContent);
229
+ }
230
+ else {
231
+ await fs.writeFile(outputPath, content);
232
+ }
233
+ }
234
+ }
235
+ }
236
+ exports.TemplateManager = TemplateManager;
@@ -0,0 +1 @@
1
+ export declare const beforeAfterTemplate: HandlebarsTemplateDelegate<any>;
@@ -0,0 +1,37 @@
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.beforeAfterTemplate = void 0;
7
+ const handlebars_1 = __importDefault(require("handlebars"));
8
+ const handlebars_helpers_1 = require("./handlebars-helpers");
9
+ (0, handlebars_helpers_1.registerHelpers)(handlebars_1.default);
10
+ exports.beforeAfterTemplate = handlebars_1.default.compile(`// SPDX-License-Identifier: GPL-2.0
11
+ pragma solidity ^0.8.0;
12
+
13
+ import {Setup} from "./Setup.sol";
14
+
15
+ // ghost variables for tracking state variable values before and after function calls
16
+ abstract contract BeforeAfter is Setup {
17
+ struct Vars {
18
+ uint256 __ignore__;
19
+ }
20
+
21
+ Vars internal _before;
22
+ Vars internal _after;
23
+
24
+ modifier updateGhosts {
25
+ __before();
26
+ _;
27
+ __after();
28
+ }
29
+
30
+ function __before() internal {
31
+
32
+ }
33
+
34
+ function __after() internal {
35
+
36
+ }
37
+ }`, { noEscape: true });
@@ -0,0 +1 @@
1
+ export declare const cryticTesterTemplate: HandlebarsTemplateDelegate<any>;
@@ -0,0 +1,23 @@
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.cryticTesterTemplate = void 0;
7
+ const handlebars_1 = __importDefault(require("handlebars"));
8
+ const handlebars_helpers_1 = require("./handlebars-helpers");
9
+ (0, handlebars_helpers_1.registerHelpers)(handlebars_1.default);
10
+ exports.cryticTesterTemplate = handlebars_1.default.compile(`// SPDX-License-Identifier: GPL-2.0
11
+ pragma solidity ^0.8.0;
12
+
13
+ import {CryticAsserts} from "@chimera/CryticAsserts.sol";
14
+
15
+ import {TargetFunctions} from "./TargetFunctions.sol";
16
+
17
+ // echidna . --contract {{cryticTesterName}} --config echidna{{#if suiteNameSuffix}}{{suiteNameSuffix}}{{/if}}.yaml --format text --workers 16 --test-limit 1000000
18
+ // medusa fuzz
19
+ contract {{cryticTesterName}} is TargetFunctions, CryticAsserts {
20
+ constructor() payable {
21
+ setup();
22
+ }
23
+ }`, { noEscape: true });
@@ -0,0 +1 @@
1
+ export declare const cryticToFoundryTemplate: HandlebarsTemplateDelegate<any>;
@@ -0,0 +1,32 @@
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.cryticToFoundryTemplate = void 0;
7
+ const handlebars_1 = __importDefault(require("handlebars"));
8
+ const handlebars_helpers_1 = require("./handlebars-helpers");
9
+ (0, handlebars_helpers_1.registerHelpers)(handlebars_1.default);
10
+ exports.cryticToFoundryTemplate = handlebars_1.default.compile(`// SPDX-License-Identifier: GPL-2.0
11
+ pragma solidity ^0.8.0;
12
+
13
+ import {FoundryAsserts} from "@chimera/FoundryAsserts.sol";
14
+
15
+ import "forge-std/console2.sol";
16
+
17
+ import {Test} from "forge-std/Test.sol";
18
+ import {TargetFunctions} from "./TargetFunctions.sol";
19
+
20
+ // forge test --match-contract CryticToFoundry -vv
21
+ contract {{cryticToFoundryName}} is Test, TargetFunctions, FoundryAsserts {
22
+ function setUp() public {
23
+ setup();
24
+
25
+ targetContract(address(this));
26
+ }
27
+
28
+ // forge test --match-test test_crytic -vvv
29
+ function test_crytic() public {
30
+ // TODO: add failing property tests here for debugging
31
+ }
32
+ }`, { noEscape: true });
@@ -0,0 +1 @@
1
+ export declare const echidnaConfigTemplate: HandlebarsTemplateDelegate<any>;
@@ -0,0 +1,20 @@
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.echidnaConfigTemplate = void 0;
7
+ const handlebars_1 = __importDefault(require("handlebars"));
8
+ const handlebars_helpers_1 = require("./handlebars-helpers");
9
+ (0, handlebars_helpers_1.registerHelpers)(handlebars_1.default);
10
+ exports.echidnaConfigTemplate = handlebars_1.default.compile(`testMode: "assertion"
11
+ prefix: "echidna_"
12
+ coverage: true
13
+ corpusDir: "{{corpusDir}}"
14
+ balanceAddr: 0x1043561a8829300000
15
+ balanceContract: 0x1043561a8829300000
16
+ filterFunctions: []
17
+ cryticArgs: ["--foundry-compile-all"]
18
+ deployer: "0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38"
19
+ contractAddr: "0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496"
20
+ shrinkLimit: 100000`, { noEscape: true });
@@ -0,0 +1 @@
1
+ export declare const halmosConfigTemplate: HandlebarsTemplateDelegate<any>;
@@ -0,0 +1,14 @@
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.halmosConfigTemplate = void 0;
7
+ const handlebars_1 = __importDefault(require("handlebars"));
8
+ const handlebars_helpers_1 = require("./handlebars-helpers");
9
+ (0, handlebars_helpers_1.registerHelpers)(handlebars_1.default);
10
+ exports.halmosConfigTemplate = handlebars_1.default.compile(`[global]
11
+ # match tests with the invariant_ prefix
12
+ function = "(check|invariant)_"
13
+
14
+ contract = "{{cryticToFoundryName}}"`, { noEscape: true });
@@ -0,0 +1,2 @@
1
+ import Handlebars from "handlebars";
2
+ export declare function registerHelpers(handlebars: typeof Handlebars): void;