solidity-argus 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/AGENTS.md +3 -3
- package/README.md +93 -37
- package/package.json +33 -7
- package/skills/INVENTORY.md +88 -57
- package/skills/README.md +26 -23
- package/skills/case-studies/beanstalk-governance/SKILL.md +52 -0
- package/skills/case-studies/bzx-flash-loan/SKILL.md +53 -0
- package/skills/case-studies/cream-finance/SKILL.md +52 -0
- package/skills/case-studies/curve-reentrancy/SKILL.md +52 -0
- package/skills/case-studies/dao-hack/SKILL.md +51 -0
- package/skills/case-studies/euler-finance/SKILL.md +52 -0
- package/skills/case-studies/harvest-finance/SKILL.md +52 -0
- package/skills/case-studies/level-finance/SKILL.md +51 -0
- package/skills/case-studies/mango-markets/SKILL.md +53 -0
- package/skills/case-studies/nomad-bridge/SKILL.md +51 -0
- package/skills/case-studies/parity-multisig/SKILL.md +55 -0
- package/skills/case-studies/poly-network/SKILL.md +51 -0
- package/skills/case-studies/rari-fuse/SKILL.md +51 -0
- package/skills/case-studies/ronin-bridge/SKILL.md +52 -0
- package/skills/case-studies/wormhole-bridge/SKILL.md +51 -0
- package/skills/manifests/smartbugs.json +1 -3
- package/skills/manifests/sunweb3sec.json +1 -3
- package/skills/vulnerability-patterns/access-control/SKILL.md +14 -0
- package/skills/vulnerability-patterns/arbitrary-storage-location/SKILL.md +13 -1
- package/skills/vulnerability-patterns/assert-violation/SKILL.md +8 -1
- package/skills/vulnerability-patterns/asserting-contract-from-code-size/SKILL.md +12 -1
- package/skills/vulnerability-patterns/authorization-txorigin/SKILL.md +2 -1
- package/skills/vulnerability-patterns/cross-chain-bridge-vulnerabilities/SKILL.md +217 -0
- package/skills/vulnerability-patterns/default-visibility/SKILL.md +13 -1
- package/skills/vulnerability-patterns/delegatecall-untrusted-callee/SKILL.md +2 -1
- package/skills/vulnerability-patterns/dos-gas-limit/SKILL.md +8 -1
- package/skills/vulnerability-patterns/dos-revert/SKILL.md +1 -0
- package/skills/vulnerability-patterns/erc4626-exchange-rate-manipulation/SKILL.md +64 -0
- package/skills/vulnerability-patterns/fee-on-transfer-tokens/SKILL.md +93 -0
- package/skills/vulnerability-patterns/flash-loan-attacks/SKILL.md +1 -0
- package/skills/vulnerability-patterns/floating-pragma/SKILL.md +8 -1
- package/skills/vulnerability-patterns/front-running-attacks/SKILL.md +209 -0
- package/skills/vulnerability-patterns/gas-optimization-patterns/SKILL.md +203 -0
- package/skills/vulnerability-patterns/governance-attacks/SKILL.md +208 -0
- package/skills/vulnerability-patterns/hash-collision/SKILL.md +8 -1
- package/skills/vulnerability-patterns/inadherence-to-standards/SKILL.md +12 -1
- package/skills/vulnerability-patterns/incorrect-constructor/SKILL.md +8 -1
- package/skills/vulnerability-patterns/incorrect-inheritance-order/SKILL.md +8 -1
- package/skills/vulnerability-patterns/insufficient-gas-griefing/SKILL.md +12 -1
- package/skills/vulnerability-patterns/lack-of-precision/SKILL.md +7 -1
- package/skills/vulnerability-patterns/logic-errors/SKILL.md +10 -0
- package/skills/vulnerability-patterns/missing-parameter-bounds/SKILL.md +44 -0
- package/skills/vulnerability-patterns/missing-protection-signature-replay/SKILL.md +17 -1
- package/skills/vulnerability-patterns/msgvalue-loop/SKILL.md +12 -1
- package/skills/vulnerability-patterns/off-by-one/SKILL.md +7 -1
- package/skills/vulnerability-patterns/oracle-manipulation/SKILL.md +9 -0
- package/skills/vulnerability-patterns/outdated-compiler-version/SKILL.md +8 -1
- package/skills/vulnerability-patterns/overflow-underflow/SKILL.md +1 -0
- package/skills/vulnerability-patterns/proxy-vulnerabilities/SKILL.md +209 -0
- package/skills/vulnerability-patterns/reentrancy/SKILL.md +9 -0
- package/skills/vulnerability-patterns/shadowing-state-variables/SKILL.md +8 -1
- package/skills/vulnerability-patterns/share-accounting-desynchronization/SKILL.md +44 -0
- package/skills/vulnerability-patterns/signature-malleability/SKILL.md +2 -1
- package/skills/vulnerability-patterns/stateful-parameter-update-drift/SKILL.md +44 -0
- package/skills/vulnerability-patterns/unbounded-return-data/SKILL.md +12 -1
- package/skills/vulnerability-patterns/unchecked-return-values/SKILL.md +2 -1
- package/skills/vulnerability-patterns/unencrypted-private-data-on-chain/SKILL.md +8 -1
- package/skills/vulnerability-patterns/unexpected-ecrecover-null-address/SKILL.md +8 -1
- package/skills/vulnerability-patterns/uninitialized-storage-pointer/SKILL.md +8 -1
- package/skills/vulnerability-patterns/unsafe-erc20-transfers/SKILL.md +132 -0
- package/skills/vulnerability-patterns/unsafe-low-level-call/SKILL.md +12 -1
- package/skills/vulnerability-patterns/unsecure-signatures/SKILL.md +12 -1
- package/skills/vulnerability-patterns/unsupported-opcodes/SKILL.md +11 -1
- package/skills/vulnerability-patterns/unused-variables/SKILL.md +8 -1
- package/skills/vulnerability-patterns/use-of-deprecated-functions/SKILL.md +8 -1
- package/skills/vulnerability-patterns/weak-sources-randomness/SKILL.md +8 -1
- package/skills/vulnerability-patterns/weird-tokens/SKILL.md +10 -0
- package/skills/vulnerability-patterns/zero-address-misconfiguration/SKILL.md +48 -0
- package/src/agents/argus-prompt.ts +24 -7
- package/src/agents/pythia-prompt.ts +3 -4
- package/src/agents/scribe-prompt.ts +7 -2
- package/src/agents/sentinel-prompt.ts +32 -3
- package/src/cli/cli-program.ts +29 -26
- package/src/cli/commands/check-skills.ts +135 -0
- package/src/cli/commands/doctor.ts +48 -26
- package/src/cli/commands/init.ts +5 -3
- package/src/cli/commands/install.ts +7 -5
- package/src/cli/commands/lint-skills.ts +16 -12
- package/src/cli/index.ts +5 -5
- package/src/cli/types.ts +3 -3
- package/src/config/index.ts +1 -1
- package/src/config/loader.ts +4 -6
- package/src/config/schema.ts +4 -5
- package/src/config/types.ts +2 -2
- package/src/constants/defaults.ts +2 -0
- package/src/create-hooks.ts +145 -34
- package/src/create-managers.ts +10 -8
- package/src/create-tools.ts +13 -9
- package/src/features/background-agent/background-manager.ts +93 -87
- package/src/features/background-agent/index.ts +1 -1
- package/src/features/context-monitor/context-monitor.ts +3 -3
- package/src/features/context-monitor/index.ts +2 -2
- package/src/features/error-recovery/session-recovery.ts +2 -4
- package/src/features/error-recovery/tool-error-recovery.ts +12 -7
- package/src/features/index.ts +5 -5
- package/src/features/persistent-state/audit-state-manager.ts +143 -60
- package/src/features/persistent-state/global-run-index.ts +38 -0
- package/src/features/persistent-state/index.ts +1 -1
- package/src/features/persistent-state/run-journal.ts +86 -0
- package/src/hooks/config-handler.ts +28 -11
- package/src/hooks/context-budget.ts +2 -5
- package/src/hooks/event-hook.ts +47 -23
- package/src/hooks/hook-system.ts +4 -4
- package/src/hooks/index.ts +5 -5
- package/src/hooks/knowledge-sync-hook.ts +18 -21
- package/src/hooks/recon-context-builder.ts +2 -2
- package/src/hooks/safe-create-hook.ts +6 -7
- package/src/hooks/tool-tracking-hook.ts +104 -50
- package/src/hooks/types.ts +2 -1
- package/src/index.ts +23 -36
- package/src/knowledge/retry.ts +22 -22
- package/src/knowledge/scvd-client.ts +88 -95
- package/src/knowledge/scvd-errors.ts +35 -35
- package/src/knowledge/scvd-index.ts +78 -80
- package/src/knowledge/scvd-sync.ts +106 -101
- package/src/managers/index.ts +1 -1
- package/src/managers/types.ts +19 -14
- package/src/plugin-interface.ts +7 -9
- package/src/shared/binary-utils.ts +44 -35
- package/src/shared/deep-merge.ts +55 -36
- package/src/shared/file-utils.ts +21 -19
- package/src/shared/index.ts +11 -5
- package/src/shared/jsonc-parser.ts +123 -28
- package/src/shared/logger.ts +16 -3
- package/src/shared/project-utils.ts +30 -0
- package/src/skills/analysis/cluster.ts +414 -0
- package/src/skills/analysis/gates.ts +227 -0
- package/src/skills/analysis/index.ts +33 -0
- package/src/skills/analysis/normalize.ts +217 -0
- package/src/skills/analysis/similarity.ts +224 -0
- package/src/skills/argus-skill-resolver.ts +17 -6
- package/src/skills/skill-schema.ts +11 -10
- package/src/solodit-lifecycle.ts +202 -0
- package/src/state/audit-state.ts +8 -8
- package/src/state/finding-store.ts +68 -55
- package/src/state/types.ts +88 -67
- package/src/tools/argus-skill-load-tool.ts +12 -7
- package/src/tools/contract-analyzer-tool.ts +60 -77
- package/src/tools/forge-coverage-tool.ts +226 -0
- package/src/tools/forge-fuzz-tool.ts +127 -127
- package/src/tools/forge-test-tool.ts +153 -157
- package/src/tools/gas-analysis-tool.ts +264 -0
- package/src/tools/pattern-checker-tool.ts +185 -190
- package/src/tools/pattern-loader.ts +5 -111
- package/src/tools/proxy-detection-tool.ts +224 -0
- package/src/tools/report-generator-tool.ts +268 -200
- package/src/tools/slither-tool.ts +266 -218
- package/src/tools/solodit-search-tool.ts +216 -119
- package/src/tools/sync-knowledge-tool.ts +7 -11
- package/src/utils/audit-artifact-detector.ts +28 -29
- package/src/utils/dependency-scanner.ts +37 -37
- package/src/utils/project-detector.ts +111 -124
- package/src/utils/solidity-parser.ts +103 -74
- package/skills/patterns/access-control.yaml +0 -31
- package/skills/patterns/erc4626.yaml +0 -29
- package/skills/patterns/flash-loan.yaml +0 -20
- package/skills/patterns/oracle.yaml +0 -30
- package/skills/patterns/proxy.yaml +0 -30
- package/skills/patterns/reentrancy.yaml +0 -30
- package/skills/patterns/signature.yaml +0 -31
- package/src/hooks/event-hook-v2.ts +0 -99
- package/src/state/plugin-state.ts +0 -14
|
@@ -1,45 +1,46 @@
|
|
|
1
1
|
export interface DependencyRisk {
|
|
2
|
-
package: string
|
|
3
|
-
version: string
|
|
4
|
-
risk: "high" | "medium" | "low"
|
|
5
|
-
category: string
|
|
6
|
-
recommendation: string
|
|
2
|
+
package: string
|
|
3
|
+
version: string
|
|
4
|
+
risk: "high" | "medium" | "low"
|
|
5
|
+
category: string
|
|
6
|
+
recommendation: string
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
interface DependencyInput {
|
|
10
|
-
dependencies?: Record<string, string
|
|
11
|
-
devDependencies?: Record<string, string
|
|
10
|
+
dependencies?: Record<string, string>
|
|
11
|
+
devDependencies?: Record<string, string>
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function parseVersion(raw: string): [number, number, number] {
|
|
15
|
-
const cleaned = raw.replace(/^[^0-9]*/, "")
|
|
16
|
-
|
|
15
|
+
const cleaned = raw.replace(/^[^0-9]*/, "")
|
|
16
|
+
if (!cleaned) {
|
|
17
|
+
return [0, 0, 0]
|
|
18
|
+
}
|
|
19
|
+
const parts = cleaned.split(".")
|
|
20
|
+
const major = parseInt(parts[0] ?? "0", 10)
|
|
21
|
+
const minor = parseInt(parts[1] ?? "0", 10)
|
|
22
|
+
const patch = parseInt(parts[2] ?? "0", 10)
|
|
17
23
|
return [
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
]
|
|
24
|
+
Number.isNaN(major) ? 0 : major,
|
|
25
|
+
Number.isNaN(minor) ? 0 : minor,
|
|
26
|
+
Number.isNaN(patch) ? 0 : patch,
|
|
27
|
+
]
|
|
22
28
|
}
|
|
23
29
|
|
|
24
|
-
function versionLt(
|
|
25
|
-
|
|
26
|
-
major
|
|
27
|
-
minor
|
|
28
|
-
|
|
29
|
-
): boolean {
|
|
30
|
-
const [a, b, c] = parseVersion(raw);
|
|
31
|
-
if (a !== major) return a < major;
|
|
32
|
-
if (b !== minor) return b < minor;
|
|
33
|
-
return c < patch;
|
|
30
|
+
function versionLt(raw: string, major: number, minor: number, patch = 0): boolean {
|
|
31
|
+
const [a, b, c] = parseVersion(raw)
|
|
32
|
+
if (a !== major) return a < major
|
|
33
|
+
if (b !== minor) return b < minor
|
|
34
|
+
return c < patch
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
export function scanDependencyRisks(input: DependencyInput): DependencyRisk[] {
|
|
37
|
-
const risks: DependencyRisk[] = []
|
|
38
|
-
const deps = input.dependencies ?? {}
|
|
39
|
-
const devDeps = input.devDependencies ?? {}
|
|
40
|
-
const allDeps = { ...deps, ...devDeps }
|
|
38
|
+
const risks: DependencyRisk[] = []
|
|
39
|
+
const deps = input.dependencies ?? {}
|
|
40
|
+
const devDeps = input.devDependencies ?? {}
|
|
41
|
+
const allDeps = { ...deps, ...devDeps }
|
|
41
42
|
|
|
42
|
-
const ozVersion = deps["@openzeppelin/contracts"]
|
|
43
|
+
const ozVersion = deps["@openzeppelin/contracts"]
|
|
43
44
|
if (ozVersion) {
|
|
44
45
|
if (versionLt(ozVersion, 4, 9)) {
|
|
45
46
|
risks.push({
|
|
@@ -49,7 +50,7 @@ export function scanDependencyRisks(input: DependencyInput): DependencyRisk[] {
|
|
|
49
50
|
category: "known-vulnerability",
|
|
50
51
|
recommendation:
|
|
51
52
|
"Upgrade to @openzeppelin/contracts >= 4.9.0 — known vulnerabilities in OZ < 4.9",
|
|
52
|
-
})
|
|
53
|
+
})
|
|
53
54
|
} else if (versionLt(ozVersion, 5, 0)) {
|
|
54
55
|
risks.push({
|
|
55
56
|
package: "@openzeppelin/contracts",
|
|
@@ -58,14 +59,13 @@ export function scanDependencyRisks(input: DependencyInput): DependencyRisk[] {
|
|
|
58
59
|
category: "upgrade-available",
|
|
59
60
|
recommendation:
|
|
60
61
|
"Consider upgrading to OZ v5 for latest patterns and Solidity 0.8.20+ support",
|
|
61
|
-
})
|
|
62
|
+
})
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
const ozUpgradeableVersion = deps["@openzeppelin/contracts-upgradeable"]
|
|
66
|
+
const ozUpgradeableVersion = deps["@openzeppelin/contracts-upgradeable"]
|
|
66
67
|
if (ozUpgradeableVersion) {
|
|
67
|
-
const hasUpgradeTooling =
|
|
68
|
-
"@openzeppelin/hardhat-upgrades" in allDeps;
|
|
68
|
+
const hasUpgradeTooling = "@openzeppelin/hardhat-upgrades" in allDeps
|
|
69
69
|
if (!hasUpgradeTooling) {
|
|
70
70
|
risks.push({
|
|
71
71
|
package: "@openzeppelin/contracts-upgradeable",
|
|
@@ -74,11 +74,11 @@ export function scanDependencyRisks(input: DependencyInput): DependencyRisk[] {
|
|
|
74
74
|
category: "missing-tooling",
|
|
75
75
|
recommendation:
|
|
76
76
|
"Add @openzeppelin/hardhat-upgrades to devDependencies for safe upgrade workflows",
|
|
77
|
-
})
|
|
77
|
+
})
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
const solmateVersion = deps
|
|
81
|
+
const solmateVersion = deps.solmate
|
|
82
82
|
if (solmateVersion && versionLt(solmateVersion, 6, 0)) {
|
|
83
83
|
risks.push({
|
|
84
84
|
package: "solmate",
|
|
@@ -86,8 +86,8 @@ export function scanDependencyRisks(input: DependencyInput): DependencyRisk[] {
|
|
|
86
86
|
risk: "medium",
|
|
87
87
|
category: "outdated",
|
|
88
88
|
recommendation: "Upgrade solmate to >= 6.0.0 for latest fixes",
|
|
89
|
-
})
|
|
89
|
+
})
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
return risks
|
|
92
|
+
return risks
|
|
93
93
|
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { existsSync } from "fs"
|
|
2
|
-
import { join, resolve } from "path"
|
|
3
|
-
import {
|
|
1
|
+
import { existsSync } from "node:fs"
|
|
2
|
+
import { join, resolve } from "node:path"
|
|
3
|
+
import { type DependencyRisk, scanDependencyRisks } from "./dependency-scanner"
|
|
4
4
|
|
|
5
5
|
export interface ProjectConfig {
|
|
6
|
-
type: "foundry" | "hardhat" | "mixed" | "unknown"
|
|
7
|
-
srcDir: string
|
|
8
|
-
testDir: string
|
|
9
|
-
solcVersion?: string
|
|
10
|
-
remappings: string[]
|
|
11
|
-
viaIr: boolean
|
|
12
|
-
rootDir: string
|
|
13
|
-
optimizer?: { enabled: boolean; runs?: number }
|
|
14
|
-
evmVersion?: string
|
|
15
|
-
profiles?: string[]
|
|
16
|
-
hasHardhat: boolean
|
|
17
|
-
hasFoundry: boolean
|
|
18
|
-
dependencies?: Record<string, string
|
|
19
|
-
devDependencies?: Record<string, string
|
|
20
|
-
isUpgradeable: boolean
|
|
21
|
-
outDir?: string
|
|
22
|
-
dependencyRisks: DependencyRisk[]
|
|
6
|
+
type: "foundry" | "hardhat" | "mixed" | "unknown"
|
|
7
|
+
srcDir: string
|
|
8
|
+
testDir: string
|
|
9
|
+
solcVersion?: string
|
|
10
|
+
remappings: string[]
|
|
11
|
+
viaIr: boolean
|
|
12
|
+
rootDir: string
|
|
13
|
+
optimizer?: { enabled: boolean; runs?: number }
|
|
14
|
+
evmVersion?: string
|
|
15
|
+
profiles?: string[]
|
|
16
|
+
hasHardhat: boolean
|
|
17
|
+
hasFoundry: boolean
|
|
18
|
+
dependencies?: Record<string, string>
|
|
19
|
+
devDependencies?: Record<string, string>
|
|
20
|
+
isUpgradeable: boolean
|
|
21
|
+
outDir?: string
|
|
22
|
+
dependencyRisks: DependencyRisk[]
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/**
|
|
@@ -28,63 +28,63 @@ export interface ProjectConfig {
|
|
|
28
28
|
* @returns ProjectConfig with detected framework type and settings
|
|
29
29
|
*/
|
|
30
30
|
export async function detectProject(dir: string): Promise<ProjectConfig> {
|
|
31
|
-
const rootDir = resolve(dir)
|
|
32
|
-
const foundryTomlPath = join(rootDir, "foundry.toml")
|
|
33
|
-
const hardhatConfigTsPath = join(rootDir, "hardhat.config.ts")
|
|
34
|
-
const hardhatConfigJsPath = join(rootDir, "hardhat.config.js")
|
|
31
|
+
const rootDir = resolve(dir)
|
|
32
|
+
const foundryTomlPath = join(rootDir, "foundry.toml")
|
|
33
|
+
const hardhatConfigTsPath = join(rootDir, "hardhat.config.ts")
|
|
34
|
+
const hardhatConfigJsPath = join(rootDir, "hardhat.config.js")
|
|
35
35
|
|
|
36
|
-
const hasFoundry = existsSync(foundryTomlPath)
|
|
37
|
-
const hasHardhatTs = existsSync(hardhatConfigTsPath)
|
|
38
|
-
const hasHardhatJs = existsSync(hardhatConfigJsPath)
|
|
39
|
-
const hasHardhat = hasHardhatTs || hasHardhatJs
|
|
36
|
+
const hasFoundry = existsSync(foundryTomlPath)
|
|
37
|
+
const hasHardhatTs = existsSync(hardhatConfigTsPath)
|
|
38
|
+
const hasHardhatJs = existsSync(hardhatConfigJsPath)
|
|
39
|
+
const hasHardhat = hasHardhatTs || hasHardhatJs
|
|
40
40
|
|
|
41
41
|
// Determine project type
|
|
42
|
-
let type: "foundry" | "hardhat" | "mixed" | "unknown"
|
|
42
|
+
let type: "foundry" | "hardhat" | "mixed" | "unknown"
|
|
43
43
|
if (hasFoundry && hasHardhat) {
|
|
44
|
-
type = "mixed"
|
|
44
|
+
type = "mixed"
|
|
45
45
|
} else if (hasFoundry) {
|
|
46
|
-
type = "foundry"
|
|
46
|
+
type = "foundry"
|
|
47
47
|
} else if (hasHardhat) {
|
|
48
|
-
type = "hardhat"
|
|
48
|
+
type = "hardhat"
|
|
49
49
|
} else {
|
|
50
|
-
type = "unknown"
|
|
50
|
+
type = "unknown"
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
let srcDir = "src"
|
|
54
|
-
let testDir = "test"
|
|
55
|
-
let solcVersion: string | undefined
|
|
56
|
-
let remappings: string[] = []
|
|
57
|
-
let viaIr = false
|
|
58
|
-
let optimizer: { enabled: boolean; runs?: number } | undefined
|
|
59
|
-
let evmVersion: string | undefined
|
|
60
|
-
let profiles: string[] | undefined
|
|
61
|
-
let outDir: string | undefined
|
|
53
|
+
let srcDir = "src"
|
|
54
|
+
let testDir = "test"
|
|
55
|
+
let solcVersion: string | undefined
|
|
56
|
+
let remappings: string[] = []
|
|
57
|
+
let viaIr = false
|
|
58
|
+
let optimizer: { enabled: boolean; runs?: number } | undefined
|
|
59
|
+
let evmVersion: string | undefined
|
|
60
|
+
let profiles: string[] | undefined
|
|
61
|
+
let outDir: string | undefined
|
|
62
62
|
|
|
63
63
|
if (hasFoundry) {
|
|
64
|
-
const foundryConfig = await parseFoundryToml(foundryTomlPath)
|
|
65
|
-
srcDir = foundryConfig.srcDir || srcDir
|
|
66
|
-
testDir = foundryConfig.testDir || testDir
|
|
67
|
-
solcVersion = foundryConfig.solcVersion
|
|
68
|
-
remappings = foundryConfig.remappings
|
|
69
|
-
viaIr = foundryConfig.viaIr
|
|
70
|
-
optimizer = foundryConfig.optimizer
|
|
71
|
-
evmVersion = foundryConfig.evmVersion
|
|
72
|
-
profiles = foundryConfig.profiles
|
|
73
|
-
outDir = foundryConfig.outDir
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const remappingsFromTxt = parseRemappingsTxt(rootDir)
|
|
64
|
+
const foundryConfig = await parseFoundryToml(foundryTomlPath)
|
|
65
|
+
srcDir = foundryConfig.srcDir || srcDir
|
|
66
|
+
testDir = foundryConfig.testDir || testDir
|
|
67
|
+
solcVersion = foundryConfig.solcVersion
|
|
68
|
+
remappings = foundryConfig.remappings
|
|
69
|
+
viaIr = foundryConfig.viaIr
|
|
70
|
+
optimizer = foundryConfig.optimizer
|
|
71
|
+
evmVersion = foundryConfig.evmVersion
|
|
72
|
+
profiles = foundryConfig.profiles
|
|
73
|
+
outDir = foundryConfig.outDir
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const remappingsFromTxt = parseRemappingsTxt(rootDir)
|
|
77
77
|
if (remappingsFromTxt.length > 0 && remappings.length === 0) {
|
|
78
|
-
remappings = remappingsFromTxt
|
|
78
|
+
remappings = remappingsFromTxt
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
if (hasHardhat && !hasFoundry) {
|
|
82
|
-
srcDir = "contracts"
|
|
82
|
+
srcDir = "contracts"
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
const isUpgradeable = existsSync(join(rootDir, ".openzeppelin"))
|
|
85
|
+
const isUpgradeable = existsSync(join(rootDir, ".openzeppelin"))
|
|
86
86
|
|
|
87
|
-
const { dependencies, devDependencies } = await parsePackageJson(rootDir)
|
|
87
|
+
const { dependencies, devDependencies } = await parsePackageJson(rootDir)
|
|
88
88
|
|
|
89
89
|
return {
|
|
90
90
|
type,
|
|
@@ -104,26 +104,26 @@ export async function detectProject(dir: string): Promise<ProjectConfig> {
|
|
|
104
104
|
isUpgradeable,
|
|
105
105
|
outDir,
|
|
106
106
|
dependencyRisks: scanDependencyRisks({ dependencies, devDependencies }),
|
|
107
|
-
}
|
|
107
|
+
}
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
/**
|
|
111
111
|
* Parses foundry.toml file using regex-based parsing
|
|
112
112
|
*/
|
|
113
113
|
interface FoundryTomlResult {
|
|
114
|
-
srcDir?: string
|
|
115
|
-
testDir?: string
|
|
116
|
-
solcVersion?: string
|
|
117
|
-
remappings: string[]
|
|
118
|
-
viaIr: boolean
|
|
119
|
-
optimizer?: { enabled: boolean; runs?: number }
|
|
120
|
-
evmVersion?: string
|
|
121
|
-
profiles?: string[]
|
|
122
|
-
outDir?: string
|
|
114
|
+
srcDir?: string
|
|
115
|
+
testDir?: string
|
|
116
|
+
solcVersion?: string
|
|
117
|
+
remappings: string[]
|
|
118
|
+
viaIr: boolean
|
|
119
|
+
optimizer?: { enabled: boolean; runs?: number }
|
|
120
|
+
evmVersion?: string
|
|
121
|
+
profiles?: string[]
|
|
122
|
+
outDir?: string
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
async function parseFoundryToml(filePath: string): Promise<FoundryTomlResult> {
|
|
126
|
-
const content = await Bun.file(filePath).text()
|
|
126
|
+
const content = await Bun.file(filePath).text()
|
|
127
127
|
|
|
128
128
|
const result: FoundryTomlResult = {
|
|
129
129
|
srcDir: undefined,
|
|
@@ -131,117 +131,104 @@ async function parseFoundryToml(filePath: string): Promise<FoundryTomlResult> {
|
|
|
131
131
|
solcVersion: undefined,
|
|
132
132
|
remappings: [],
|
|
133
133
|
viaIr: false,
|
|
134
|
-
}
|
|
134
|
+
}
|
|
135
135
|
|
|
136
|
-
const profileNames = Array.from(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
);
|
|
136
|
+
const profileNames = Array.from(content.matchAll(/\[profile\.(\w+)\]/g), (m) => m[1]).filter(
|
|
137
|
+
(name): name is string => Boolean(name),
|
|
138
|
+
)
|
|
140
139
|
if (profileNames.length > 0) {
|
|
141
|
-
result.profiles = profileNames
|
|
140
|
+
result.profiles = profileNames
|
|
142
141
|
}
|
|
143
142
|
|
|
144
|
-
const profileDefaultMatch = content.match(
|
|
145
|
-
/\[profile\.default\]([\s\S]*?)(?:\n\[|$)/
|
|
146
|
-
);
|
|
143
|
+
const profileDefaultMatch = content.match(/\[profile\.default\]([\s\S]*?)(?:\n\[|$)/)
|
|
147
144
|
if (!profileDefaultMatch || !profileDefaultMatch[1]) {
|
|
148
|
-
return result
|
|
145
|
+
return result
|
|
149
146
|
}
|
|
150
147
|
|
|
151
|
-
const profileSection = profileDefaultMatch[1]
|
|
148
|
+
const profileSection = profileDefaultMatch[1]
|
|
152
149
|
|
|
153
|
-
const srcMatch = profileSection.match(/^\s*src\s*=\s*["']([^"']+)["']/m)
|
|
150
|
+
const srcMatch = profileSection.match(/^\s*src\s*=\s*["']([^"']+)["']/m)
|
|
154
151
|
if (srcMatch?.[1]) {
|
|
155
|
-
result.srcDir = srcMatch[1]
|
|
152
|
+
result.srcDir = srcMatch[1]
|
|
156
153
|
}
|
|
157
154
|
|
|
158
|
-
const testMatch = profileSection.match(/^\s*test\s*=\s*["']([^"']+)["']/m)
|
|
155
|
+
const testMatch = profileSection.match(/^\s*test\s*=\s*["']([^"']+)["']/m)
|
|
159
156
|
if (testMatch?.[1]) {
|
|
160
|
-
result.testDir = testMatch[1]
|
|
157
|
+
result.testDir = testMatch[1]
|
|
161
158
|
}
|
|
162
159
|
|
|
163
|
-
const solcMatch = profileSection.match(/^\s*solc\s*=\s*["']([^"']+)["']/m)
|
|
160
|
+
const solcMatch = profileSection.match(/^\s*solc\s*=\s*["']([^"']+)["']/m)
|
|
164
161
|
if (solcMatch?.[1]) {
|
|
165
|
-
result.solcVersion = solcMatch[1]
|
|
162
|
+
result.solcVersion = solcMatch[1]
|
|
166
163
|
}
|
|
167
164
|
|
|
168
|
-
const viaIrMatch = profileSection.match(/^\s*via[_-]ir\s*=\s*(true|false)/m)
|
|
165
|
+
const viaIrMatch = profileSection.match(/^\s*via[_-]ir\s*=\s*(true|false)/m)
|
|
169
166
|
if (viaIrMatch?.[1] === "true") {
|
|
170
|
-
result.viaIr = true
|
|
167
|
+
result.viaIr = true
|
|
171
168
|
}
|
|
172
169
|
|
|
173
|
-
const optimizerMatch = profileSection.match(
|
|
174
|
-
/^\s*optimizer\s*=\s*(true|false)/m
|
|
175
|
-
);
|
|
170
|
+
const optimizerMatch = profileSection.match(/^\s*optimizer\s*=\s*(true|false)/m)
|
|
176
171
|
if (optimizerMatch?.[1]) {
|
|
177
|
-
const enabled = optimizerMatch[1] === "true"
|
|
178
|
-
const runsMatch = profileSection.match(
|
|
179
|
-
/^\s*optimizer_runs\s*=\s*(\d+)/m
|
|
180
|
-
);
|
|
172
|
+
const enabled = optimizerMatch[1] === "true"
|
|
173
|
+
const runsMatch = profileSection.match(/^\s*optimizer_runs\s*=\s*(\d+)/m)
|
|
181
174
|
result.optimizer = {
|
|
182
175
|
enabled,
|
|
183
176
|
runs: runsMatch?.[1] ? parseInt(runsMatch[1], 10) : undefined,
|
|
184
|
-
}
|
|
177
|
+
}
|
|
185
178
|
}
|
|
186
179
|
|
|
187
|
-
const evmMatch = profileSection.match(
|
|
188
|
-
/^\s*evm_version\s*=\s*["']([^"']+)["']/m
|
|
189
|
-
);
|
|
180
|
+
const evmMatch = profileSection.match(/^\s*evm_version\s*=\s*["']([^"']+)["']/m)
|
|
190
181
|
if (evmMatch?.[1]) {
|
|
191
|
-
result.evmVersion = evmMatch[1]
|
|
182
|
+
result.evmVersion = evmMatch[1]
|
|
192
183
|
}
|
|
193
184
|
|
|
194
|
-
const outMatch = profileSection.match(/^\s*out\s*=\s*["']([^"']+)["']/m)
|
|
185
|
+
const outMatch = profileSection.match(/^\s*out\s*=\s*["']([^"']+)["']/m)
|
|
195
186
|
if (outMatch?.[1]) {
|
|
196
|
-
result.outDir = outMatch[1]
|
|
187
|
+
result.outDir = outMatch[1]
|
|
197
188
|
}
|
|
198
189
|
|
|
199
|
-
const remappingsMatch = profileSection.match(
|
|
200
|
-
/remappings\s*=\s*\[([\s\S]*?)\]/
|
|
201
|
-
);
|
|
190
|
+
const remappingsMatch = profileSection.match(/remappings\s*=\s*\[([\s\S]*?)\]/)
|
|
202
191
|
if (remappingsMatch?.[1]) {
|
|
203
|
-
const remappingMatches = remappingsMatch[1].match(/["']([^"']+)["']/g)
|
|
192
|
+
const remappingMatches = remappingsMatch[1].match(/["']([^"']+)["']/g)
|
|
204
193
|
if (remappingMatches) {
|
|
205
|
-
result.remappings = remappingMatches.map((m) => m.slice(1, -1))
|
|
194
|
+
result.remappings = remappingMatches.map((m) => m.slice(1, -1))
|
|
206
195
|
}
|
|
207
196
|
}
|
|
208
197
|
|
|
209
|
-
return result
|
|
198
|
+
return result
|
|
210
199
|
}
|
|
211
200
|
|
|
212
|
-
async function parsePackageJson(
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
dependencies?: Record<string, string>;
|
|
216
|
-
devDependencies?: Record<string, string>;
|
|
201
|
+
async function parsePackageJson(rootDir: string): Promise<{
|
|
202
|
+
dependencies?: Record<string, string>
|
|
203
|
+
devDependencies?: Record<string, string>
|
|
217
204
|
}> {
|
|
218
|
-
const pkgPath = join(rootDir, "package.json")
|
|
205
|
+
const pkgPath = join(rootDir, "package.json")
|
|
219
206
|
if (!existsSync(pkgPath)) {
|
|
220
|
-
return {}
|
|
207
|
+
return {}
|
|
221
208
|
}
|
|
222
209
|
try {
|
|
223
|
-
const content = JSON.parse(await Bun.file(pkgPath).text())
|
|
210
|
+
const content = JSON.parse(await Bun.file(pkgPath).text())
|
|
224
211
|
return {
|
|
225
212
|
dependencies: content.dependencies,
|
|
226
213
|
devDependencies: content.devDependencies,
|
|
227
|
-
}
|
|
214
|
+
}
|
|
228
215
|
} catch {
|
|
229
|
-
return {}
|
|
216
|
+
return {}
|
|
230
217
|
}
|
|
231
218
|
}
|
|
232
219
|
|
|
233
220
|
function parseRemappingsTxt(rootDir: string): string[] {
|
|
234
|
-
const remappingsPath = join(rootDir, "remappings.txt")
|
|
221
|
+
const remappingsPath = join(rootDir, "remappings.txt")
|
|
235
222
|
if (!existsSync(remappingsPath)) {
|
|
236
|
-
return []
|
|
223
|
+
return []
|
|
237
224
|
}
|
|
238
225
|
try {
|
|
239
|
-
const content = require("fs").readFileSync(remappingsPath, "utf-8")
|
|
226
|
+
const content = require("node:fs").readFileSync(remappingsPath, "utf-8")
|
|
240
227
|
return content
|
|
241
228
|
.split("\n")
|
|
242
229
|
.map((line: string) => line.trim())
|
|
243
|
-
.filter((line: string) => line.length > 0)
|
|
230
|
+
.filter((line: string) => line.length > 0)
|
|
244
231
|
} catch {
|
|
245
|
-
return []
|
|
232
|
+
return []
|
|
246
233
|
}
|
|
247
234
|
}
|