web3skill 0.1.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/LICENSE +21 -0
- package/README.md +127 -0
- package/dist/archives/web3-audit-orchestrator.skill +0 -0
- package/dist/archives/web3-audit-reporting.skill +0 -0
- package/dist/archives/web3-fuzzing-and-invariants.skill +0 -0
- package/dist/archives/web3-native-operator.skill +0 -0
- package/dist/archives/web3-repo-heuristics.skill +0 -0
- package/dist/archives/web3-research-and-market-intel.skill +0 -0
- package/dist/archives/web3-risk-gate.skill +0 -0
- package/dist/archives/web3-service-orchestrator.skill +0 -0
- package/dist/archives/web3-static-analysis-runner.skill +0 -0
- package/dist/archives/web3-trace-and-state-analysis.skill +0 -0
- package/dist/archives/web3-transaction-simulator.skill +0 -0
- package/dist/archives/web3-wallet-operator.skill +0 -0
- package/dist/manifest.json +170 -0
- package/dist/skills/web3-audit-orchestrator/SKILL.md +79 -0
- package/dist/skills/web3-audit-orchestrator/references/ADAPTER_CONSUMPTION_MAP.md +15 -0
- package/dist/skills/web3-audit-orchestrator/references/OUTPUT_TEMPLATE.md +52 -0
- package/dist/skills/web3-audit-orchestrator/references/REVIEW_STATE_MACHINE.md +25 -0
- package/dist/skills/web3-audit-orchestrator/scripts/render_audit_review.py +95 -0
- package/dist/skills/web3-audit-reporting/SKILL.md +77 -0
- package/dist/skills/web3-audit-reporting/references/FINDING_TEMPLATE.md +54 -0
- package/dist/skills/web3-audit-reporting/references/REPORT_TEMPLATE.md +58 -0
- package/dist/skills/web3-audit-reporting/references/RETEST_TEMPLATE.md +35 -0
- package/dist/skills/web3-audit-reporting/references/SEVERITY_RUBRIC.md +75 -0
- package/dist/skills/web3-fuzzing-and-invariants/SKILL.md +68 -0
- package/dist/skills/web3-fuzzing-and-invariants/references/ADAPTER_CONSUMPTION_MAP.md +14 -0
- package/dist/skills/web3-fuzzing-and-invariants/references/OUTPUT_TEMPLATE.md +40 -0
- package/dist/skills/web3-fuzzing-and-invariants/references/READINESS_AND_FAILURES.md +25 -0
- package/dist/skills/web3-fuzzing-and-invariants/scripts/render_fuzz_summary.py +64 -0
- package/dist/skills/web3-native-operator/SKILL.md +218 -0
- package/dist/skills/web3-native-operator/references/EXECUTION_BUNDLE_TEMPLATE.md +47 -0
- package/dist/skills/web3-native-operator/references/OPERATOR_BUNDLE_TEMPLATE.md +39 -0
- package/dist/skills/web3-native-operator/references/POSTTRADE_FOLLOWUP_BUNDLE_TEMPLATE.md +35 -0
- package/dist/skills/web3-native-operator/references/POSTTRADE_WATCH_TEMPLATE.md +34 -0
- package/dist/skills/web3-native-operator/references/PRETRADE_PACKET_TEMPLATE.md +34 -0
- package/dist/skills/web3-native-operator/references/ROUTE_RECIPES.md +140 -0
- package/dist/skills/web3-native-operator/references/ROUTING_STATE_MACHINE.md +73 -0
- package/dist/skills/web3-native-operator/references/WATCH_CRON_REQUEST_TEMPLATE.md +26 -0
- package/dist/skills/web3-native-operator/references/WATCH_FOLLOWUP_BUNDLE_TEMPLATE.md +35 -0
- package/dist/skills/web3-native-operator/references/WATCH_HEARTBEAT_TEMPLATE.md +31 -0
- package/dist/skills/web3-native-operator/scripts/apply_followup_bundle_to_heartbeat.py +118 -0
- package/dist/skills/web3-native-operator/scripts/render_execution_bundle.py +259 -0
- package/dist/skills/web3-native-operator/scripts/render_operator_bundle.py +800 -0
- package/dist/skills/web3-native-operator/scripts/render_posttrade_followup_bundle.py +118 -0
- package/dist/skills/web3-native-operator/scripts/render_posttrade_watch_status.py +125 -0
- package/dist/skills/web3-native-operator/scripts/render_pretrade_packet.py +205 -0
- package/dist/skills/web3-native-operator/scripts/render_watch_cron_request.py +88 -0
- package/dist/skills/web3-native-operator/scripts/render_watch_followup_bundle.py +118 -0
- package/dist/skills/web3-native-operator/scripts/render_watch_heartbeat.py +52 -0
- package/dist/skills/web3-repo-heuristics/SKILL.md +37 -0
- package/dist/skills/web3-repo-heuristics/references/FOUNDRY.md +49 -0
- package/dist/skills/web3-repo-heuristics/references/HARDHAT.md +47 -0
- package/dist/skills/web3-repo-heuristics/references/VYPER.md +26 -0
- package/dist/skills/web3-research-and-market-intel/SKILL.md +138 -0
- package/dist/skills/web3-research-and-market-intel/references/ADAPTER_CONSUMPTION_MAP.md +66 -0
- package/dist/skills/web3-research-and-market-intel/references/EVIDENCE_QUALITY.md +27 -0
- package/dist/skills/web3-research-and-market-intel/references/OUTPUT_TEMPLATE.md +37 -0
- package/dist/skills/web3-research-and-market-intel/references/PORTFOLIO_STATUS_TEMPLATE.md +51 -0
- package/dist/skills/web3-research-and-market-intel/references/WATCH_STATUS_TEMPLATE.md +39 -0
- package/dist/skills/web3-research-and-market-intel/scripts/render_portfolio_status.py +85 -0
- package/dist/skills/web3-research-and-market-intel/scripts/render_research_brief.py +58 -0
- package/dist/skills/web3-research-and-market-intel/scripts/render_watch_status.py +70 -0
- package/dist/skills/web3-risk-gate/SKILL.md +100 -0
- package/dist/skills/web3-risk-gate/references/OUTPUT_TEMPLATE.md +72 -0
- package/dist/skills/web3-risk-gate/references/SIGNAL_TAXONOMY.md +34 -0
- package/dist/skills/web3-risk-gate/scripts/merge_risk_gate_blocks.py +189 -0
- package/dist/skills/web3-service-orchestrator/SKILL.md +34 -0
- package/dist/skills/web3-static-analysis-runner/SKILL.md +76 -0
- package/dist/skills/web3-static-analysis-runner/references/ADAPTER_CONSUMPTION_MAP.md +13 -0
- package/dist/skills/web3-static-analysis-runner/references/OUTPUT_TEMPLATE.md +45 -0
- package/dist/skills/web3-static-analysis-runner/references/TRIAGE_BUCKETS.md +16 -0
- package/dist/skills/web3-static-analysis-runner/scripts/render_static_analysis_summary.py +64 -0
- package/dist/skills/web3-trace-and-state-analysis/SKILL.md +74 -0
- package/dist/skills/web3-trace-and-state-analysis/references/ADAPTER_CONSUMPTION_MAP.md +27 -0
- package/dist/skills/web3-trace-and-state-analysis/references/OUTPUT_TEMPLATE.md +63 -0
- package/dist/skills/web3-trace-and-state-analysis/references/TRACE_BACKEND_PREFLIGHT.md +47 -0
- package/dist/skills/web3-trace-and-state-analysis/scripts/render_trace_summary.py +99 -0
- package/dist/skills/web3-transaction-simulator/SKILL.md +83 -0
- package/dist/skills/web3-transaction-simulator/references/OUTPUT_TEMPLATE.md +86 -0
- package/dist/skills/web3-transaction-simulator/references/STATUS_AND_FAILURES.md +49 -0
- package/dist/skills/web3-transaction-simulator/scripts/merge_simulation_blocks.py +198 -0
- package/dist/skills/web3-wallet-operator/SKILL.md +52 -0
- package/dist/skills/web3-wallet-operator/references/ACTION_RECIPES.md +56 -0
- package/dist/skills/web3-wallet-operator/references/OUTPUT_TEMPLATE.md +43 -0
- package/dist/skills/web3-wallet-operator/scripts/render_wallet_operation_plan.py +101 -0
- package/index.js +50 -0
- package/package.json +36 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Render a stable Web3 research brief block."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import json
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
12
|
+
parser = argparse.ArgumentParser(description="Render a Web3 research brief block.")
|
|
13
|
+
parser.add_argument("--question", required=True)
|
|
14
|
+
parser.add_argument("--freshness", choices=("fresh", "mixed", "stale"), default="mixed")
|
|
15
|
+
parser.add_argument("--source", action="append", default=[])
|
|
16
|
+
parser.add_argument("--evidence", action="append", default=[])
|
|
17
|
+
parser.add_argument("--cross-check", action="append", default=[])
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
"--conclusion",
|
|
20
|
+
choices=("watch", "investigate-more", "ready-for-risk-gate", "avoid-for-now"),
|
|
21
|
+
required=True,
|
|
22
|
+
)
|
|
23
|
+
parser.add_argument("--next-step", action="append", default=[])
|
|
24
|
+
return parser
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def parse_evidence(entries: list[str]) -> list[dict[str, str]]:
|
|
28
|
+
parsed = []
|
|
29
|
+
for entry in entries:
|
|
30
|
+
adapter, sep, detail = entry.partition(":")
|
|
31
|
+
if sep:
|
|
32
|
+
parsed.append({"adapter": adapter.strip(), "detail": detail.strip()})
|
|
33
|
+
else:
|
|
34
|
+
parsed.append({"adapter": "unknown", "detail": entry})
|
|
35
|
+
return parsed
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def main() -> int:
|
|
39
|
+
args = build_parser().parse_args()
|
|
40
|
+
payload = {
|
|
41
|
+
"research_brief": {
|
|
42
|
+
"version": 1,
|
|
43
|
+
"question": args.question,
|
|
44
|
+
"freshness": args.freshness,
|
|
45
|
+
"sources_used": args.source,
|
|
46
|
+
"evidence": parse_evidence(args.evidence),
|
|
47
|
+
"cross_checks": args.cross_check,
|
|
48
|
+
"conclusion": args.conclusion,
|
|
49
|
+
"next_steps": args.next_step,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
json.dump(payload, sys.stdout, ensure_ascii=False, indent=2)
|
|
53
|
+
sys.stdout.write("\n")
|
|
54
|
+
return 0
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
if __name__ == "__main__":
|
|
58
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Render a stable Web3 watch status block."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import json
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
12
|
+
parser = argparse.ArgumentParser(description="Render a Web3 watch status block.")
|
|
13
|
+
parser.add_argument(
|
|
14
|
+
"--status",
|
|
15
|
+
choices=("ACTIVE", "TRIGGERED", "CLEARED", "UNAVAILABLE"),
|
|
16
|
+
required=True,
|
|
17
|
+
)
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
"--watch-kind",
|
|
20
|
+
choices=("research", "portfolio", "posttrade", "trace", "venue", "execution"),
|
|
21
|
+
required=True,
|
|
22
|
+
)
|
|
23
|
+
parser.add_argument("--subject", required=True)
|
|
24
|
+
parser.add_argument("--trigger-source", default="")
|
|
25
|
+
parser.add_argument(
|
|
26
|
+
"--severity",
|
|
27
|
+
choices=("low", "medium", "high", "critical"),
|
|
28
|
+
default="medium",
|
|
29
|
+
)
|
|
30
|
+
parser.add_argument("--next-check-hint", default="")
|
|
31
|
+
parser.add_argument("--schedule-hint", default="")
|
|
32
|
+
parser.add_argument("--recommended-adapter", default="")
|
|
33
|
+
parser.add_argument("--evidence", action="append", default=[])
|
|
34
|
+
return parser
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def parse_evidence(entries: list[str]) -> list[dict[str, str]]:
|
|
38
|
+
parsed: list[dict[str, str]] = []
|
|
39
|
+
for entry in entries:
|
|
40
|
+
adapter, sep, detail = entry.partition(":")
|
|
41
|
+
if sep:
|
|
42
|
+
parsed.append({"adapter": adapter.strip(), "detail": detail.strip()})
|
|
43
|
+
else:
|
|
44
|
+
parsed.append({"adapter": "unknown", "detail": entry})
|
|
45
|
+
return parsed
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def main() -> int:
|
|
49
|
+
args = build_parser().parse_args()
|
|
50
|
+
payload = {
|
|
51
|
+
"watch_status": {
|
|
52
|
+
"version": 1,
|
|
53
|
+
"status": args.status,
|
|
54
|
+
"watch_kind": args.watch_kind,
|
|
55
|
+
"subject": args.subject,
|
|
56
|
+
"trigger_source": args.trigger_source,
|
|
57
|
+
"severity": args.severity,
|
|
58
|
+
"next_check_hint": args.next_check_hint,
|
|
59
|
+
"schedule_hint": args.schedule_hint,
|
|
60
|
+
"recommended_adapter": args.recommended_adapter,
|
|
61
|
+
"evidence": parse_evidence(args.evidence),
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
json.dump(payload, sys.stdout, ensure_ascii=False, indent=2)
|
|
65
|
+
sys.stdout.write("\n")
|
|
66
|
+
return 0
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if __name__ == "__main__":
|
|
70
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: web3-risk-gate
|
|
3
|
+
description: Pre-execution Web3 risk gate for transfers, approvals, swaps, and protocol interactions. Use before any value-moving or approval-changing action. It normalizes adapter output into ALLOW, WARN, or BLOCK.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Web3 Risk Gate
|
|
7
|
+
|
|
8
|
+
Use this skill before any transfer, approval, swap, liquidity action, or contract interaction that can move funds or grant permissions.
|
|
9
|
+
|
|
10
|
+
## Required Adapters
|
|
11
|
+
|
|
12
|
+
Load the matching Web3 profile adapters instead of improvising:
|
|
13
|
+
|
|
14
|
+
- `security-check`
|
|
15
|
+
- `binance-token-audit`
|
|
16
|
+
- `query-token-audit`
|
|
17
|
+
- `query-address-info`
|
|
18
|
+
- `token-integration-analyzer`
|
|
19
|
+
- `proxy-upgrade-safety`
|
|
20
|
+
|
|
21
|
+
When consuming adapter output, prefer each adapter's `references/RISK_GATE_NORMALIZATION.md`
|
|
22
|
+
to keep signal names and evidence fields stable.
|
|
23
|
+
|
|
24
|
+
## Workflow
|
|
25
|
+
|
|
26
|
+
1. Identify the action type: transfer, approve, swap, LP, or protocol interaction.
|
|
27
|
+
2. Identify the subject: token, spender, receiver, router, proxy, or external protocol.
|
|
28
|
+
3. Run the relevant adapter checks.
|
|
29
|
+
4. Normalize the result into one gate decision.
|
|
30
|
+
|
|
31
|
+
## Reusable Output Contract
|
|
32
|
+
|
|
33
|
+
Always emit both:
|
|
34
|
+
|
|
35
|
+
1. A short human-readable gate summary
|
|
36
|
+
2. A normalized block that other Web3 skills can reuse
|
|
37
|
+
|
|
38
|
+
Use [references/OUTPUT_TEMPLATE.md](references/OUTPUT_TEMPLATE.md) for the exact scaffold.
|
|
39
|
+
If you need to map adapter findings into stable blocker/warning labels, use
|
|
40
|
+
[references/SIGNAL_TAXONOMY.md](references/SIGNAL_TAXONOMY.md).
|
|
41
|
+
When deterministic merge behavior is needed, use
|
|
42
|
+
[scripts/merge_risk_gate_blocks.py](scripts/merge_risk_gate_blocks.py)
|
|
43
|
+
to combine multiple adapter-produced `risk_gate` blocks into one conservative result.
|
|
44
|
+
|
|
45
|
+
The minimum decision fields are:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
Decision: ALLOW | WARN | BLOCK
|
|
49
|
+
Action:
|
|
50
|
+
- transfer | approve | swap | liquidity | protocol-interaction
|
|
51
|
+
Coverage:
|
|
52
|
+
- complete | partial | missing
|
|
53
|
+
Reasons:
|
|
54
|
+
- concrete signal
|
|
55
|
+
Warnings:
|
|
56
|
+
- optional risk signal
|
|
57
|
+
Must-Do Next:
|
|
58
|
+
- required follow-up
|
|
59
|
+
Evidence:
|
|
60
|
+
- adapter name + exact hit
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The normalized block must preserve:
|
|
64
|
+
|
|
65
|
+
- decision
|
|
66
|
+
- action type
|
|
67
|
+
- chain and subject
|
|
68
|
+
- coverage quality
|
|
69
|
+
- blockers and warnings as separate lists
|
|
70
|
+
- next steps
|
|
71
|
+
- exact evidence source per signal
|
|
72
|
+
|
|
73
|
+
## Hard Block Conditions
|
|
74
|
+
|
|
75
|
+
Block by default if any checked source confirms one of:
|
|
76
|
+
|
|
77
|
+
- honeypot / unsellable token
|
|
78
|
+
- risk level `5` from Binance token audit
|
|
79
|
+
- selfdestruct risk on live token or target contract
|
|
80
|
+
- hidden owner combined with mint / reclaim ownership path
|
|
81
|
+
- storage collision or uninitialized implementation in an upgrade path
|
|
82
|
+
- clear proxy takeover or arbitrary upgrade control
|
|
83
|
+
|
|
84
|
+
## Warning Conditions
|
|
85
|
+
|
|
86
|
+
Warn and require explicit confirmation if any checked source shows:
|
|
87
|
+
|
|
88
|
+
- buy or sell tax above 10%
|
|
89
|
+
- proxy / upgradeable token or contract
|
|
90
|
+
- mintable supply or concentrated owner control
|
|
91
|
+
- missing verification / opaque code
|
|
92
|
+
- abnormal holder concentration or thin distribution
|
|
93
|
+
|
|
94
|
+
## Guardrails
|
|
95
|
+
|
|
96
|
+
- Do not average away critical signals just because another adapter returned a lower risk score.
|
|
97
|
+
- If the action is a swap, require `web3-transaction-simulator` after this gate.
|
|
98
|
+
- If adapter coverage is missing for the target chain or token, say `coverage incomplete` instead of implying safety.
|
|
99
|
+
- If evidence is weak or adapter coverage is partial, downgrade certainty, not the signal itself.
|
|
100
|
+
- If the output will be consumed by another skill, keep the normalized block stable and do not rename fields ad hoc.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Web3 Risk Gate Output Template
|
|
2
|
+
|
|
3
|
+
Always emit two sections in this order.
|
|
4
|
+
|
|
5
|
+
## 1. Human Summary
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
Decision: BLOCK
|
|
9
|
+
Action:
|
|
10
|
+
- swap
|
|
11
|
+
Coverage:
|
|
12
|
+
- partial
|
|
13
|
+
Reasons:
|
|
14
|
+
- Honeypot risk confirmed by query-token-audit
|
|
15
|
+
- Proxy upgrade path is externally controlled
|
|
16
|
+
Warnings:
|
|
17
|
+
- Holder concentration is elevated
|
|
18
|
+
Must-Do Next:
|
|
19
|
+
- Do not execute this swap
|
|
20
|
+
- If still investigating, fetch verified source and owner privileges
|
|
21
|
+
Evidence:
|
|
22
|
+
- query-token-audit: honeypot / unsellable token flag
|
|
23
|
+
- proxy-upgrade-safety: arbitrary upgrade control
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 2. Normalized Block
|
|
27
|
+
|
|
28
|
+
Use this exact field layout. Omit empty optional arrays, but do not rename fields.
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
risk_gate:
|
|
32
|
+
version: 1
|
|
33
|
+
decision: BLOCK
|
|
34
|
+
action: swap
|
|
35
|
+
chain: bsc
|
|
36
|
+
coverage: partial
|
|
37
|
+
subject:
|
|
38
|
+
token: "0x..."
|
|
39
|
+
router: "0x..."
|
|
40
|
+
spender: "0x..."
|
|
41
|
+
blockers:
|
|
42
|
+
- type: honeypot
|
|
43
|
+
severity: critical
|
|
44
|
+
source: query-token-audit
|
|
45
|
+
detail: unsellable token
|
|
46
|
+
- type: unsafe-upgrade-control
|
|
47
|
+
severity: critical
|
|
48
|
+
source: proxy-upgrade-safety
|
|
49
|
+
detail: privileged arbitrary implementation change
|
|
50
|
+
warnings:
|
|
51
|
+
- type: holder-concentration
|
|
52
|
+
severity: medium
|
|
53
|
+
source: binance-token-audit
|
|
54
|
+
detail: top holders dominate supply
|
|
55
|
+
next_steps:
|
|
56
|
+
- stop
|
|
57
|
+
- gather verified source and owner privilege evidence
|
|
58
|
+
evidence:
|
|
59
|
+
- adapter: query-token-audit
|
|
60
|
+
signal: honeypot
|
|
61
|
+
exact_hit: unsellable token flag
|
|
62
|
+
- adapter: proxy-upgrade-safety
|
|
63
|
+
signal: arbitrary upgrade control
|
|
64
|
+
exact_hit: implementation can be changed by privileged actor
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Notes
|
|
68
|
+
|
|
69
|
+
- `decision` is mandatory and must be one of `ALLOW`, `WARN`, `BLOCK`.
|
|
70
|
+
- `coverage` is mandatory and must be one of `complete`, `partial`, `missing`.
|
|
71
|
+
- `blockers` and `warnings` are separate. Do not merge them.
|
|
72
|
+
- `evidence` should retain adapter-level provenance so later skills can cite it.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Web3 Risk Gate Signal Taxonomy
|
|
2
|
+
|
|
3
|
+
Use these stable labels when normalizing adapter output.
|
|
4
|
+
|
|
5
|
+
## Blocker Types
|
|
6
|
+
|
|
7
|
+
- `honeypot`
|
|
8
|
+
- `unsellable-token`
|
|
9
|
+
- `malicious-upgrade-path`
|
|
10
|
+
- `unsafe-upgrade-control`
|
|
11
|
+
- `hidden-owner-with-mint`
|
|
12
|
+
- `storage-collision-risk`
|
|
13
|
+
- `uninitialized-implementation`
|
|
14
|
+
- `selfdestruct-risk`
|
|
15
|
+
- `known-blacklist-hit`
|
|
16
|
+
- `unsafe-token-callback`
|
|
17
|
+
|
|
18
|
+
## Warning Types
|
|
19
|
+
|
|
20
|
+
- `high-tax`
|
|
21
|
+
- `mintable-supply`
|
|
22
|
+
- `upgradeable-contract`
|
|
23
|
+
- `opaque-code`
|
|
24
|
+
- `holder-concentration`
|
|
25
|
+
- `unverified-contract`
|
|
26
|
+
- `allowance-exposure`
|
|
27
|
+
- `admin-centralization`
|
|
28
|
+
|
|
29
|
+
## Mapping Rules
|
|
30
|
+
|
|
31
|
+
- If any blocker type is confirmed, the decision is `BLOCK`.
|
|
32
|
+
- If only warning types are present, the decision is `WARN` unless the action is strictly read-only.
|
|
33
|
+
- If coverage is missing for the primary subject, keep the decision conservative and mark `coverage: missing` or `partial`.
|
|
34
|
+
- Do not invent new labels when an existing label is close enough. Stable labels are more useful than expressive prose.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Merge multiple normalized risk_gate blocks into one conservative decision."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import json
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
COVERAGE_ORDER = {
|
|
13
|
+
"complete": 0,
|
|
14
|
+
"partial": 1,
|
|
15
|
+
"missing": 2,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
20
|
+
parser = argparse.ArgumentParser(description="Merge multiple risk_gate payloads into one block.")
|
|
21
|
+
parser.add_argument(
|
|
22
|
+
"--input-file",
|
|
23
|
+
action="append",
|
|
24
|
+
required=True,
|
|
25
|
+
help="Path to a JSON file containing a risk_gate payload or '-' for stdin",
|
|
26
|
+
)
|
|
27
|
+
return parser
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def load_payload(path: str) -> dict[str, object]:
|
|
31
|
+
if path == "-":
|
|
32
|
+
return json.load(sys.stdin)
|
|
33
|
+
return json.loads(Path(path).read_text(encoding="utf-8"))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def extract_gate(payload: dict[str, object]) -> dict[str, object]:
|
|
37
|
+
gate = payload.get("risk_gate")
|
|
38
|
+
if isinstance(gate, dict):
|
|
39
|
+
return gate
|
|
40
|
+
if {"decision", "action", "chain", "coverage"}.issubset(payload):
|
|
41
|
+
return payload
|
|
42
|
+
raise ValueError("input payload does not contain risk_gate")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def merge_scalar(current: str, new_value: str, field_name: str) -> str:
|
|
46
|
+
if not new_value:
|
|
47
|
+
return current
|
|
48
|
+
if not current:
|
|
49
|
+
return new_value
|
|
50
|
+
if current != new_value:
|
|
51
|
+
raise ValueError(f"conflicting {field_name}: {current} vs {new_value}")
|
|
52
|
+
return current
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def merge_subject(subject: dict[str, object], new_subject: dict[str, object]) -> dict[str, object]:
|
|
56
|
+
merged = dict(subject)
|
|
57
|
+
for key, value in new_subject.items():
|
|
58
|
+
if key in merged and merged[key] != value:
|
|
59
|
+
raise ValueError(f"conflicting subject field {key}: {merged[key]} vs {value}")
|
|
60
|
+
merged[key] = value
|
|
61
|
+
return merged
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def dedupe_items(items: list[dict[str, object]]) -> list[dict[str, object]]:
|
|
65
|
+
seen: set[str] = set()
|
|
66
|
+
deduped: list[dict[str, object]] = []
|
|
67
|
+
for item in items:
|
|
68
|
+
key = json.dumps(item, sort_keys=True, ensure_ascii=False)
|
|
69
|
+
if key in seen:
|
|
70
|
+
continue
|
|
71
|
+
seen.add(key)
|
|
72
|
+
deduped.append(item)
|
|
73
|
+
return deduped
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def dedupe_strings(items: list[str]) -> list[str]:
|
|
77
|
+
seen: set[str] = set()
|
|
78
|
+
deduped: list[str] = []
|
|
79
|
+
for item in items:
|
|
80
|
+
if item in seen:
|
|
81
|
+
continue
|
|
82
|
+
seen.add(item)
|
|
83
|
+
deduped.append(item)
|
|
84
|
+
return deduped
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def default_next_steps(decision: str, action: str, coverage: str) -> list[str]:
|
|
88
|
+
if decision == "BLOCK":
|
|
89
|
+
return ["stop", "collect additional evidence before retrying"]
|
|
90
|
+
|
|
91
|
+
steps: list[str] = []
|
|
92
|
+
if coverage != "complete":
|
|
93
|
+
steps.append("gather missing adapter coverage")
|
|
94
|
+
if decision == "WARN":
|
|
95
|
+
steps.append("require explicit confirmation")
|
|
96
|
+
if action in {"transfer", "approve", "swap", "liquidity", "protocol-interaction"}:
|
|
97
|
+
steps.append("run web3-transaction-simulator")
|
|
98
|
+
if not steps:
|
|
99
|
+
steps.append("continue with standard confirmation")
|
|
100
|
+
return steps
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def merge_payloads(payloads: list[dict[str, object]]) -> dict[str, object]:
|
|
104
|
+
action = ""
|
|
105
|
+
chain = ""
|
|
106
|
+
subject: dict[str, object] = {}
|
|
107
|
+
coverages: list[str] = []
|
|
108
|
+
blockers: list[dict[str, object]] = []
|
|
109
|
+
warnings: list[dict[str, object]] = []
|
|
110
|
+
evidence: list[dict[str, object]] = []
|
|
111
|
+
next_steps: list[str] = []
|
|
112
|
+
seen_warn = False
|
|
113
|
+
seen_block = False
|
|
114
|
+
|
|
115
|
+
for payload in payloads:
|
|
116
|
+
gate = extract_gate(payload)
|
|
117
|
+
gate_action = str(gate.get("action", ""))
|
|
118
|
+
gate_chain = str(gate.get("chain", ""))
|
|
119
|
+
gate_coverage = str(gate.get("coverage", "partial"))
|
|
120
|
+
if gate_coverage not in COVERAGE_ORDER:
|
|
121
|
+
raise ValueError(f"unsupported coverage value: {gate_coverage}")
|
|
122
|
+
|
|
123
|
+
action = merge_scalar(action, gate_action, "action")
|
|
124
|
+
chain = merge_scalar(chain, gate_chain, "chain")
|
|
125
|
+
coverages.append(gate_coverage)
|
|
126
|
+
seen_warn = seen_warn or str(gate.get("decision", "")) == "WARN"
|
|
127
|
+
seen_block = seen_block or str(gate.get("decision", "")) == "BLOCK"
|
|
128
|
+
|
|
129
|
+
gate_subject = gate.get("subject", {})
|
|
130
|
+
if isinstance(gate_subject, dict):
|
|
131
|
+
subject = merge_subject(subject, gate_subject)
|
|
132
|
+
|
|
133
|
+
gate_blockers = gate.get("blockers", [])
|
|
134
|
+
if isinstance(gate_blockers, list):
|
|
135
|
+
blockers.extend(item for item in gate_blockers if isinstance(item, dict))
|
|
136
|
+
gate_warnings = gate.get("warnings", [])
|
|
137
|
+
if isinstance(gate_warnings, list):
|
|
138
|
+
warnings.extend(item for item in gate_warnings if isinstance(item, dict))
|
|
139
|
+
gate_evidence = gate.get("evidence", [])
|
|
140
|
+
if isinstance(gate_evidence, list):
|
|
141
|
+
evidence.extend(item for item in gate_evidence if isinstance(item, dict))
|
|
142
|
+
gate_next_steps = gate.get("next_steps", [])
|
|
143
|
+
if isinstance(gate_next_steps, list):
|
|
144
|
+
next_steps.extend(str(item) for item in gate_next_steps if isinstance(item, str))
|
|
145
|
+
|
|
146
|
+
coverage = max(coverages, key=lambda item: COVERAGE_ORDER[item]) if coverages else "missing"
|
|
147
|
+
blockers = dedupe_items(blockers)
|
|
148
|
+
warnings = dedupe_items(warnings)
|
|
149
|
+
evidence = dedupe_items(evidence)
|
|
150
|
+
|
|
151
|
+
if blockers or seen_block:
|
|
152
|
+
decision = "BLOCK"
|
|
153
|
+
elif warnings or seen_warn or coverage != "complete":
|
|
154
|
+
decision = "WARN"
|
|
155
|
+
else:
|
|
156
|
+
decision = "ALLOW"
|
|
157
|
+
|
|
158
|
+
next_steps = dedupe_strings(next_steps) or default_next_steps(decision, action, coverage)
|
|
159
|
+
|
|
160
|
+
payload: dict[str, object] = {
|
|
161
|
+
"risk_gate": {
|
|
162
|
+
"version": 1,
|
|
163
|
+
"decision": decision,
|
|
164
|
+
"action": action,
|
|
165
|
+
"chain": chain,
|
|
166
|
+
"coverage": coverage,
|
|
167
|
+
"subject": subject,
|
|
168
|
+
"next_steps": next_steps,
|
|
169
|
+
"evidence": evidence,
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if blockers:
|
|
173
|
+
payload["risk_gate"]["blockers"] = blockers
|
|
174
|
+
if warnings:
|
|
175
|
+
payload["risk_gate"]["warnings"] = warnings
|
|
176
|
+
return payload
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def main() -> int:
|
|
180
|
+
args = build_parser().parse_args()
|
|
181
|
+
payloads = [load_payload(path) for path in args.input_file]
|
|
182
|
+
merged = merge_payloads(payloads)
|
|
183
|
+
json.dump(merged, sys.stdout, ensure_ascii=False, indent=2)
|
|
184
|
+
sys.stdout.write("\n")
|
|
185
|
+
return 0
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
if __name__ == "__main__":
|
|
189
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: web3-service-orchestrator
|
|
3
|
+
description: Service-level orchestrator for complex Web3 tasks decomposed into a local DAG. Use when a service plan is already present in prompt context and the task should be completed by combining multiple base Web3 skills step by step instead of improvising a monolithic answer.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Web3 Service Orchestrator
|
|
7
|
+
|
|
8
|
+
Use this skill only when the runtime has injected an active Web3 service DAG.
|
|
9
|
+
|
|
10
|
+
## Operating Contract
|
|
11
|
+
|
|
12
|
+
- Treat the injected `Active Web3 Service DAG` section as the local source of truth.
|
|
13
|
+
- Work only on the current frontier nodes.
|
|
14
|
+
- Do not skip ahead to downstream nodes whose dependencies are not yet satisfied.
|
|
15
|
+
- Prefer base Web3 skills and stable output blocks over free-form reasoning.
|
|
16
|
+
|
|
17
|
+
## Node Execution Rules
|
|
18
|
+
|
|
19
|
+
1. Read the current frontier node goals and candidate skills.
|
|
20
|
+
2. Use the smallest set of skills needed for that node.
|
|
21
|
+
3. Try to produce the node's declared output schema.
|
|
22
|
+
4. If a node is blocked by `risk_gate = BLOCK` or `simulation.readiness = blocked`, stop and explain the blocker.
|
|
23
|
+
5. If the DAG is awaiting confirmation, ask for confirmation instead of executing.
|
|
24
|
+
|
|
25
|
+
## Output Discipline
|
|
26
|
+
|
|
27
|
+
- Prefer normalized artifacts like `wallet_operation_plan`, `research_brief`, `risk_gate`, `simulation`, `execution_receipt`, `portfolio_status`, and `watch_status`.
|
|
28
|
+
- If multiple artifacts are available, summarize progress in plain language but keep the normalized blocks available in the turn for runtime consumption.
|
|
29
|
+
|
|
30
|
+
## Scope Boundaries
|
|
31
|
+
|
|
32
|
+
- This skill orchestrates.
|
|
33
|
+
- Downstream wallet, research, risk, simulation, and execution skills do the actual work.
|
|
34
|
+
- Do not treat MetaMask SDK documentation as an execution path unless the task explicitly becomes app-side development.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: web3-static-analysis-runner
|
|
3
|
+
description: Static analysis routing layer for smart contract and adjacent codebases. Use when running or coordinating Semgrep, CodeQL, SARIF parsing, or vulnerability pattern scans, especially during audits and pre-deployment reviews.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Web3 Static Analysis Runner
|
|
7
|
+
|
|
8
|
+
Use this skill to coordinate static analysis instead of improvising one-off scan commands.
|
|
9
|
+
|
|
10
|
+
## Required Components
|
|
11
|
+
|
|
12
|
+
- `web3-repo-heuristics`
|
|
13
|
+
- `web3-audit-reporting`
|
|
14
|
+
|
|
15
|
+
## Required Profile Adapters
|
|
16
|
+
|
|
17
|
+
- `codeql`
|
|
18
|
+
- `semgrep`
|
|
19
|
+
- `sarif-parsing`
|
|
20
|
+
- `scv-scan`
|
|
21
|
+
|
|
22
|
+
Use [references/ADAPTER_CONSUMPTION_MAP.md](references/ADAPTER_CONSUMPTION_MAP.md)
|
|
23
|
+
to normalize scanner output into stable triage buckets.
|
|
24
|
+
Use [references/TRIAGE_BUCKETS.md](references/TRIAGE_BUCKETS.md) and
|
|
25
|
+
[references/OUTPUT_TEMPLATE.md](references/OUTPUT_TEMPLATE.md) to keep scanner
|
|
26
|
+
triage and escalation semantics stable.
|
|
27
|
+
Use [scripts/render_static_analysis_summary.py](scripts/render_static_analysis_summary.py)
|
|
28
|
+
when downstream skills need a normalized static-analysis block.
|
|
29
|
+
|
|
30
|
+
## Workflow
|
|
31
|
+
|
|
32
|
+
1. Detect the repo shape with `web3-repo-heuristics`.
|
|
33
|
+
2. Decide which scanners apply:
|
|
34
|
+
- `semgrep` for fast broad pattern coverage
|
|
35
|
+
- `codeql` for deeper interprocedural analysis when language/tooling fits
|
|
36
|
+
- `sarif-parsing` when results already exist or need normalization
|
|
37
|
+
- `scv-scan` for smart contract vulnerability pattern review and checklist support
|
|
38
|
+
3. Run the chosen scanners through their own upstream workflows.
|
|
39
|
+
4. Deduplicate by root cause before surfacing anything as a finding.
|
|
40
|
+
5. Pass only evidence-backed issues to `web3-audit-reporting`.
|
|
41
|
+
|
|
42
|
+
## Output Contract
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
Scanners Run:
|
|
46
|
+
- name + scope
|
|
47
|
+
Results:
|
|
48
|
+
- raw hits
|
|
49
|
+
Triage:
|
|
50
|
+
- deduped root causes
|
|
51
|
+
Escalate:
|
|
52
|
+
- confirmed finding | review needed | false positive
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Reusable Output Contract
|
|
56
|
+
|
|
57
|
+
Always emit both:
|
|
58
|
+
|
|
59
|
+
1. A short scanner/triage summary
|
|
60
|
+
2. A normalized `static_analysis_summary` block
|
|
61
|
+
|
|
62
|
+
The normalized block must preserve:
|
|
63
|
+
|
|
64
|
+
- scanners actually run
|
|
65
|
+
- raw hit count
|
|
66
|
+
- deduped root causes
|
|
67
|
+
- escalation counts
|
|
68
|
+
- blockers and next steps
|
|
69
|
+
- exact evidence source per normalized issue
|
|
70
|
+
|
|
71
|
+
## Guardrails
|
|
72
|
+
|
|
73
|
+
- Zero findings is not proof of safety.
|
|
74
|
+
- Do not mix scanner hits with confirmed findings.
|
|
75
|
+
- If a tool cannot run because of environment or build constraints, say that explicitly.
|
|
76
|
+
- Prefer existing SARIF over rerunning scans if the user asked for interpretation rather than execution.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Static Analysis Adapter Consumption Map
|
|
2
|
+
|
|
3
|
+
- `codeql` -> deep query results
|
|
4
|
+
- `semgrep` -> fast pattern hits
|
|
5
|
+
- `sarif-parsing` -> normalized imported results
|
|
6
|
+
- `scv-scan` -> checklist-aligned smart contract patterns
|
|
7
|
+
|
|
8
|
+
Normalize into:
|
|
9
|
+
|
|
10
|
+
- scanners run
|
|
11
|
+
- raw hits
|
|
12
|
+
- deduped root causes
|
|
13
|
+
- escalate: confirmed finding | review needed | false positive
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Web3 Static Analysis Output Template
|
|
2
|
+
|
|
3
|
+
Always emit:
|
|
4
|
+
|
|
5
|
+
1. A short human-readable scanner triage summary
|
|
6
|
+
2. A normalized block
|
|
7
|
+
|
|
8
|
+
```yaml
|
|
9
|
+
static_analysis_summary:
|
|
10
|
+
version: 1
|
|
11
|
+
status: partial
|
|
12
|
+
scope: src/core
|
|
13
|
+
scanners_run:
|
|
14
|
+
- semgrep
|
|
15
|
+
- codeql
|
|
16
|
+
raw_hit_count: 17
|
|
17
|
+
deduped_root_causes:
|
|
18
|
+
- unchecked low-level call in withdraw path
|
|
19
|
+
- missing access control on emergency setter
|
|
20
|
+
escalation_counts:
|
|
21
|
+
confirmed_finding: 1
|
|
22
|
+
review_needed: 2
|
|
23
|
+
false_positive: 4
|
|
24
|
+
blockers:
|
|
25
|
+
- smart-contract-specific CodeQL pack unavailable
|
|
26
|
+
next_steps:
|
|
27
|
+
- manually validate emergency setter authorization
|
|
28
|
+
evidence:
|
|
29
|
+
- adapter: semgrep
|
|
30
|
+
detail: unsafe low-level call pattern in Vault.sol
|
|
31
|
+
- adapter: codeql
|
|
32
|
+
detail: path-sensitive result on setter authorization path
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Required Fields
|
|
36
|
+
|
|
37
|
+
- `status`: `complete | partial | blocked`
|
|
38
|
+
- `scope`
|
|
39
|
+
- `scanners_run`
|
|
40
|
+
- `raw_hit_count`
|
|
41
|
+
- `deduped_root_causes`
|
|
42
|
+
- `escalation_counts`
|
|
43
|
+
- `blockers`
|
|
44
|
+
- `next_steps`
|
|
45
|
+
- `evidence`
|