mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-04-06 09:13:31 +08:00
feat: add blockchain security skill bundle
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Everything Claude Code (ECC) — Agent Instructions
|
||||
|
||||
This is a **production-ready AI coding plugin** providing 39 specialized agents, 164 skills, 72 commands, and automated hook workflows for software development.
|
||||
This is a **production-ready AI coding plugin** providing 39 specialized agents, 168 skills, 72 commands, and automated hook workflows for software development.
|
||||
|
||||
**Version:** 1.10.0
|
||||
|
||||
@@ -146,7 +146,7 @@ Troubleshoot failures: check test isolation → verify mocks → fix implementat
|
||||
|
||||
```
|
||||
agents/ — 39 specialized subagents
|
||||
skills/ — 164 workflow skills and domain knowledge
|
||||
skills/ — 168 workflow skills and domain knowledge
|
||||
commands/ — 72 slash commands
|
||||
hooks/ — Trigger-based automations
|
||||
rules/ — Always-follow guidelines (common + per-language)
|
||||
|
||||
@@ -236,7 +236,7 @@ For manual install instructions see the README in the `rules/` folder. When copy
|
||||
/plugin list ecc@ecc
|
||||
```
|
||||
|
||||
**That's it!** You now have access to 39 agents, 164 skills, and 72 legacy command shims.
|
||||
**That's it!** You now have access to 39 agents, 168 skills, and 72 legacy command shims.
|
||||
|
||||
### Multi-model commands require additional setup
|
||||
|
||||
@@ -1154,7 +1154,7 @@ The configuration is automatically detected from `.opencode/opencode.json`.
|
||||
|---------|-------------|----------|--------|
|
||||
| Agents | PASS: 39 agents | PASS: 12 agents | **Claude Code leads** |
|
||||
| Commands | PASS: 72 commands | PASS: 31 commands | **Claude Code leads** |
|
||||
| Skills | PASS: 164 skills | PASS: 37 skills | **Claude Code leads** |
|
||||
| Skills | PASS: 168 skills | PASS: 37 skills | **Claude Code leads** |
|
||||
| Hooks | PASS: 8 event types | PASS: 11 events | **OpenCode has more!** |
|
||||
| Rules | PASS: 29 rules | PASS: 13 instructions | **Claude Code leads** |
|
||||
| MCP Servers | PASS: 14 servers | PASS: Full | **Full parity** |
|
||||
@@ -1263,7 +1263,7 @@ ECC is the **first plugin to maximize every major AI coding tool**. Here's how e
|
||||
|---------|------------|------------|-----------|----------|
|
||||
| **Agents** | 39 | Shared (AGENTS.md) | Shared (AGENTS.md) | 12 |
|
||||
| **Commands** | 72 | Shared | Instruction-based | 31 |
|
||||
| **Skills** | 164 | Shared | 10 (native format) | 37 |
|
||||
| **Skills** | 168 | Shared | 10 (native format) | 37 |
|
||||
| **Hook Events** | 8 types | 15 types | None yet | 11 types |
|
||||
| **Hook Scripts** | 20+ scripts | 16 scripts (DRY adapter) | N/A | Plugin hooks |
|
||||
| **Rules** | 34 (common + lang) | 34 (YAML frontmatter) | Instruction-based | 13 instructions |
|
||||
|
||||
@@ -106,7 +106,7 @@ cp -r everything-claude-code/rules/perl ~/.claude/rules/
|
||||
/plugin list ecc@ecc
|
||||
```
|
||||
|
||||
**完成!** 你现在可以使用 39 个代理、164 个技能和 72 个命令。
|
||||
**完成!** 你现在可以使用 39 个代理、168 个技能和 72 个命令。
|
||||
|
||||
### multi-* 命令需要额外配置
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ Keep this file detailed for only the current sprint, blockers, and next actions.
|
||||
|
||||
- 2026-04-05: Fixed the `main` npm CI break after the latest direct ports. `package-lock.json` had drifted behind `package.json` on the `globals` devDependency (`^17.1.0` vs `^17.4.0`), which caused all npm-based GitHub Actions jobs to fail at `npm ci`. Refreshed the lockfile only, verified `npm ci --ignore-scripts`, and kept the mixed-lock workspace otherwise untouched.
|
||||
- 2026-04-05: Direct-ported the useful discoverability part of `#1221` without duplicating a second healthcare compliance system. Added `skills/hipaa-compliance/SKILL.md` as a thin HIPAA-specific entrypoint that points into the canonical `healthcare-phi-compliance` / `healthcare-reviewer` lane, and wired both healthcare privacy skills into the `security` install module for selective installs.
|
||||
- 2026-04-05: Direct-ported the audited blockchain/web3 security lane from `#1222` into `main` as four self-contained skills: `defi-amm-security`, `evm-token-decimals`, `llm-trading-agent-security`, and `nodejs-keccak256`. These are now part of the `security` install module instead of living as an unmerged fork PR.
|
||||
- 2026-04-02: `ECC-Tools/main` shipped `9566637` (`fix: prefer commit lookup over git ref resolution`). The PR-analysis fire is now fixed in the app repo by preferring explicit commit resolution before `git.getRef`, with regression coverage for pull refs and plain branch refs. Mirrored public tracking issue `#1184` in this repo was closed as resolved upstream.
|
||||
- 2026-04-02: Direct-ported the clean native-support core of `#1043` into `main`: `agents/csharp-reviewer.md`, `skills/dotnet-patterns/SKILL.md`, and `skills/csharp-testing/SKILL.md`. This fills the gap between existing C# rule/docs mentions and actual shipped C# review/testing guidance.
|
||||
- 2026-04-02: Direct-ported the clean native-support core of `#1055` into `main`: `agents/dart-build-resolver.md`, `commands/flutter-build.md`, `commands/flutter-review.md`, `commands/flutter-test.md`, `rules/dart/*`, and `skills/dart-flutter-patterns/SKILL.md`. The skill paths were wired into the current `framework-language` module instead of replaying the older PR's separate `flutter-dart` module layout.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Everything Claude Code (ECC) — 智能体指令
|
||||
|
||||
这是一个**生产就绪的 AI 编码插件**,提供 39 个专业代理、164 项技能、72 条命令以及自动化钩子工作流,用于软件开发。
|
||||
这是一个**生产就绪的 AI 编码插件**,提供 39 个专业代理、168 项技能、72 条命令以及自动化钩子工作流,用于软件开发。
|
||||
|
||||
**版本:** 1.10.0
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
|
||||
```
|
||||
agents/ — 39 个专业子代理
|
||||
skills/ — 164 个工作流技能和领域知识
|
||||
skills/ — 168 个工作流技能和领域知识
|
||||
commands/ — 72 个斜杠命令
|
||||
hooks/ — 基于触发的自动化
|
||||
rules/ — 始终遵循的指导方针(通用 + 每种语言)
|
||||
|
||||
@@ -209,7 +209,7 @@ npx ecc-install typescript
|
||||
/plugin list ecc@ecc
|
||||
```
|
||||
|
||||
**搞定!** 你现在可以使用 39 个智能体、164 项技能和 72 个命令了。
|
||||
**搞定!** 你现在可以使用 39 个智能体、168 项技能和 72 个命令了。
|
||||
|
||||
***
|
||||
|
||||
@@ -1096,7 +1096,7 @@ opencode
|
||||
|---------|-------------|----------|--------|
|
||||
| 智能体 | PASS: 39 个 | PASS: 12 个 | **Claude Code 领先** |
|
||||
| 命令 | PASS: 72 个 | PASS: 31 个 | **Claude Code 领先** |
|
||||
| 技能 | PASS: 164 项 | PASS: 37 项 | **Claude Code 领先** |
|
||||
| 技能 | PASS: 168 项 | PASS: 37 项 | **Claude Code 领先** |
|
||||
| 钩子 | PASS: 8 种事件类型 | PASS: 11 种事件 | **OpenCode 更多!** |
|
||||
| 规则 | PASS: 29 条 | PASS: 13 条指令 | **Claude Code 领先** |
|
||||
| MCP 服务器 | PASS: 14 个 | PASS: 完整 | **完全对等** |
|
||||
@@ -1208,7 +1208,7 @@ ECC 是**第一个最大化利用每个主要 AI 编码工具的插件**。以
|
||||
|---------|------------|------------|-----------|----------|
|
||||
| **智能体** | 39 | 共享 (AGENTS.md) | 共享 (AGENTS.md) | 12 |
|
||||
| **命令** | 72 | 共享 | 基于指令 | 31 |
|
||||
| **技能** | 164 | 共享 | 10 (原生格式) | 37 |
|
||||
| **技能** | 168 | 共享 | 10 (原生格式) | 37 |
|
||||
| **钩子事件** | 8 种类型 | 15 种类型 | 暂无 | 11 种类型 |
|
||||
| **钩子脚本** | 20+ 个脚本 | 16 个脚本 (DRY 适配器) | N/A | 插件钩子 |
|
||||
| **规则** | 34 (通用 + 语言) | 34 (YAML 前页) | 基于指令 | 13 条指令 |
|
||||
|
||||
@@ -234,14 +234,18 @@
|
||||
"kind": "skills",
|
||||
"description": "Security review and security-focused framework guidance.",
|
||||
"paths": [
|
||||
"skills/defi-amm-security",
|
||||
"skills/django-security",
|
||||
"skills/healthcare-phi-compliance",
|
||||
"skills/hipaa-compliance",
|
||||
"skills/laravel-security",
|
||||
"skills/llm-trading-agent-security",
|
||||
"skills/nodejs-keccak256",
|
||||
"skills/perl-security",
|
||||
"skills/security-review",
|
||||
"skills/security-scan",
|
||||
"skills/springboot-security",
|
||||
"skills/evm-token-decimals",
|
||||
"the-security-guide.md"
|
||||
],
|
||||
"targets": [
|
||||
|
||||
160
skills/defi-amm-security/SKILL.md
Normal file
160
skills/defi-amm-security/SKILL.md
Normal file
@@ -0,0 +1,160 @@
|
||||
---
|
||||
name: defi-amm-security
|
||||
description: Security checklist for Solidity AMM contracts, liquidity pools, and swap flows. Covers reentrancy, CEI ordering, donation or inflation attacks, oracle manipulation, slippage, admin controls, and integer math.
|
||||
origin: ECC direct-port adaptation
|
||||
version: "1.0.0"
|
||||
---
|
||||
|
||||
# DeFi AMM Security
|
||||
|
||||
Critical vulnerability patterns and hardened implementations for Solidity AMM contracts, LP vaults, and swap functions.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Writing or auditing a Solidity AMM or liquidity-pool contract
|
||||
- Implementing swap, deposit, withdraw, mint, or burn flows that hold token balances
|
||||
- Reviewing any contract that uses `token.balanceOf(address(this))` in share or reserve math
|
||||
- Adding fee setters, pausers, oracle updates, or other admin functions to a DeFi protocol
|
||||
|
||||
## How It Works
|
||||
|
||||
Use this as a checklist-plus-pattern library. Review every user entrypoint against the categories below and prefer the hardened examples over hand-rolled variants.
|
||||
|
||||
## Examples
|
||||
|
||||
### Reentrancy: enforce CEI order
|
||||
|
||||
Vulnerable:
|
||||
|
||||
```solidity
|
||||
function withdraw(uint256 amount) external {
|
||||
require(balances[msg.sender] >= amount);
|
||||
token.transfer(msg.sender, amount);
|
||||
balances[msg.sender] -= amount;
|
||||
}
|
||||
```
|
||||
|
||||
Safe:
|
||||
|
||||
```solidity
|
||||
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
|
||||
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
function withdraw(uint256 amount) external nonReentrant {
|
||||
require(balances[msg.sender] >= amount, "Insufficient");
|
||||
balances[msg.sender] -= amount;
|
||||
token.safeTransfer(msg.sender, amount);
|
||||
}
|
||||
```
|
||||
|
||||
Do not write your own guard when a hardened library exists.
|
||||
|
||||
### Donation or inflation attacks
|
||||
|
||||
Using `token.balanceOf(address(this))` directly for share math lets attackers manipulate the denominator by sending tokens to the contract outside the intended path.
|
||||
|
||||
```solidity
|
||||
// Vulnerable
|
||||
function deposit(uint256 assets) external returns (uint256 shares) {
|
||||
shares = (assets * totalShares) / token.balanceOf(address(this));
|
||||
}
|
||||
```
|
||||
|
||||
```solidity
|
||||
// Safe
|
||||
uint256 private _totalAssets;
|
||||
|
||||
function deposit(uint256 assets) external nonReentrant returns (uint256 shares) {
|
||||
uint256 balBefore = token.balanceOf(address(this));
|
||||
token.safeTransferFrom(msg.sender, address(this), assets);
|
||||
uint256 received = token.balanceOf(address(this)) - balBefore;
|
||||
|
||||
shares = totalShares == 0 ? received : (received * totalShares) / _totalAssets;
|
||||
_totalAssets += received;
|
||||
totalShares += shares;
|
||||
}
|
||||
```
|
||||
|
||||
Track internal accounting and measure actual tokens received.
|
||||
|
||||
### Oracle manipulation
|
||||
|
||||
Spot prices are flash-loan manipulable. Prefer TWAP.
|
||||
|
||||
```solidity
|
||||
uint32[] memory secondsAgos = new uint32[](2);
|
||||
secondsAgos[0] = 1800;
|
||||
secondsAgos[1] = 0;
|
||||
(int56[] memory tickCumulatives,) = IUniswapV3Pool(pool).observe(secondsAgos);
|
||||
int24 twapTick = int24(
|
||||
(tickCumulatives[1] - tickCumulatives[0]) / int56(uint56(30 minutes))
|
||||
);
|
||||
uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(twapTick);
|
||||
```
|
||||
|
||||
### Slippage protection
|
||||
|
||||
Every swap path needs caller-provided slippage and a deadline.
|
||||
|
||||
```solidity
|
||||
function swap(
|
||||
uint256 amountIn,
|
||||
uint256 amountOutMin,
|
||||
uint256 deadline
|
||||
) external returns (uint256 amountOut) {
|
||||
require(block.timestamp <= deadline, "Expired");
|
||||
amountOut = _calculateOut(amountIn);
|
||||
require(amountOut >= amountOutMin, "Slippage exceeded");
|
||||
_executeSwap(amountIn, amountOut);
|
||||
}
|
||||
```
|
||||
|
||||
### Safe reserve math
|
||||
|
||||
```solidity
|
||||
import {FullMath} from "@uniswap/v3-core/contracts/libraries/FullMath.sol";
|
||||
|
||||
uint256 result = FullMath.mulDiv(a, b, c);
|
||||
```
|
||||
|
||||
For large reserve math, avoid naive `a * b / c` when overflow risk exists.
|
||||
|
||||
### Admin controls
|
||||
|
||||
```solidity
|
||||
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
|
||||
|
||||
contract MyAMM is Ownable2Step {
|
||||
function setFee(uint256 fee) external onlyOwner { ... }
|
||||
function pause() external onlyOwner { ... }
|
||||
}
|
||||
```
|
||||
|
||||
Prefer explicit acceptance for ownership transfer and gate every privileged path.
|
||||
|
||||
## Security Checklist
|
||||
|
||||
- Reentrancy-exposed entrypoints use `nonReentrant`
|
||||
- CEI ordering is respected
|
||||
- Share math does not depend on raw `balanceOf(address(this))`
|
||||
- ERC-20 transfers use `SafeERC20`
|
||||
- Deposits measure actual tokens received
|
||||
- Oracle reads use TWAP or another manipulation-resistant source
|
||||
- Swaps require `amountOutMin` and `deadline`
|
||||
- Overflow-sensitive reserve math uses safe primitives like `mulDiv`
|
||||
- Admin functions are access-controlled
|
||||
- Emergency pause exists and is tested
|
||||
- Static analysis and fuzzing are run before production
|
||||
|
||||
## Audit Tools
|
||||
|
||||
```bash
|
||||
pip install slither-analyzer
|
||||
slither . --exclude-dependencies
|
||||
|
||||
echidna-test . --contract YourAMM --config echidna.yaml
|
||||
|
||||
forge test --fuzz-runs 10000
|
||||
```
|
||||
130
skills/evm-token-decimals/SKILL.md
Normal file
130
skills/evm-token-decimals/SKILL.md
Normal file
@@ -0,0 +1,130 @@
|
||||
---
|
||||
name: evm-token-decimals
|
||||
description: Prevent silent decimal mismatch bugs across EVM chains. Covers runtime decimal lookup, chain-aware caching, bridged-token precision drift, and safe normalization for bots, dashboards, and DeFi tools.
|
||||
origin: ECC direct-port adaptation
|
||||
version: "1.0.0"
|
||||
---
|
||||
|
||||
# EVM Token Decimals
|
||||
|
||||
Silent decimal mismatches are one of the easiest ways to ship balances or USD values that are off by orders of magnitude without throwing an error.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Reading ERC-20 balances in Python, TypeScript, or Solidity
|
||||
- Calculating fiat values from on-chain balances
|
||||
- Comparing token amounts across multiple EVM chains
|
||||
- Handling bridged assets
|
||||
- Building portfolio trackers, bots, or aggregators
|
||||
|
||||
## How It Works
|
||||
|
||||
Never assume stablecoins use the same decimals everywhere. Query `decimals()` at runtime, cache by `(chain_id, token_address)`, and use decimal-safe math for value calculations.
|
||||
|
||||
## Examples
|
||||
|
||||
### Query decimals at runtime
|
||||
|
||||
```python
|
||||
from decimal import Decimal
|
||||
from web3 import Web3
|
||||
|
||||
ERC20_ABI = [
|
||||
{"name": "decimals", "type": "function", "inputs": [],
|
||||
"outputs": [{"type": "uint8"}], "stateMutability": "view"},
|
||||
{"name": "balanceOf", "type": "function",
|
||||
"inputs": [{"name": "account", "type": "address"}],
|
||||
"outputs": [{"type": "uint256"}], "stateMutability": "view"},
|
||||
]
|
||||
|
||||
def get_token_balance(w3: Web3, token_address: str, wallet: str) -> Decimal:
|
||||
contract = w3.eth.contract(
|
||||
address=Web3.to_checksum_address(token_address),
|
||||
abi=ERC20_ABI,
|
||||
)
|
||||
decimals = contract.functions.decimals().call()
|
||||
raw = contract.functions.balanceOf(Web3.to_checksum_address(wallet)).call()
|
||||
return Decimal(raw) / Decimal(10 ** decimals)
|
||||
```
|
||||
|
||||
Do not hardcode `1_000_000` because a symbol usually has 6 decimals somewhere else.
|
||||
|
||||
### Cache by chain and token
|
||||
|
||||
```python
|
||||
from functools import lru_cache
|
||||
|
||||
@lru_cache(maxsize=512)
|
||||
def get_decimals(chain_id: int, token_address: str) -> int:
|
||||
w3 = get_web3_for_chain(chain_id)
|
||||
contract = w3.eth.contract(
|
||||
address=Web3.to_checksum_address(token_address),
|
||||
abi=ERC20_ABI,
|
||||
)
|
||||
return contract.functions.decimals().call()
|
||||
```
|
||||
|
||||
### Handle odd tokens defensively
|
||||
|
||||
```python
|
||||
try:
|
||||
decimals = contract.functions.decimals().call()
|
||||
except Exception:
|
||||
logging.warning(
|
||||
"decimals() reverted on %s (chain %s), defaulting to 18",
|
||||
token_address,
|
||||
chain_id,
|
||||
)
|
||||
decimals = 18
|
||||
```
|
||||
|
||||
Log the fallback and keep it visible. Old or non-standard tokens still exist.
|
||||
|
||||
### Normalize to 18-decimal WAD in Solidity
|
||||
|
||||
```solidity
|
||||
interface IERC20Metadata {
|
||||
function decimals() external view returns (uint8);
|
||||
}
|
||||
|
||||
function normalizeToWad(address token, uint256 amount) internal view returns (uint256) {
|
||||
uint8 d = IERC20Metadata(token).decimals();
|
||||
if (d == 18) return amount;
|
||||
if (d < 18) return amount * 10 ** (18 - d);
|
||||
return amount / 10 ** (d - 18);
|
||||
}
|
||||
```
|
||||
|
||||
### TypeScript with ethers
|
||||
|
||||
```typescript
|
||||
import { Contract, formatUnits } from 'ethers';
|
||||
|
||||
const ERC20_ABI = [
|
||||
'function decimals() view returns (uint8)',
|
||||
'function balanceOf(address) view returns (uint256)',
|
||||
];
|
||||
|
||||
async function getBalance(provider: any, tokenAddress: string, wallet: string): Promise<string> {
|
||||
const token = new Contract(tokenAddress, ERC20_ABI, provider);
|
||||
const [decimals, raw] = await Promise.all([
|
||||
token.decimals(),
|
||||
token.balanceOf(wallet),
|
||||
]);
|
||||
return formatUnits(raw, decimals);
|
||||
}
|
||||
```
|
||||
|
||||
### Quick on-chain check
|
||||
|
||||
```bash
|
||||
cast call <token_address> "decimals()(uint8)" --rpc-url <rpc>
|
||||
```
|
||||
|
||||
## Rules
|
||||
|
||||
- Always query `decimals()` at runtime
|
||||
- Cache by chain plus token address, not symbol
|
||||
- Use `Decimal`, `BigInt`, or equivalent exact math, not float
|
||||
- Re-query decimals after bridging or wrapper changes
|
||||
- Normalize internal accounting consistently before comparison or pricing
|
||||
146
skills/llm-trading-agent-security/SKILL.md
Normal file
146
skills/llm-trading-agent-security/SKILL.md
Normal file
@@ -0,0 +1,146 @@
|
||||
---
|
||||
name: llm-trading-agent-security
|
||||
description: Security patterns for autonomous trading agents with wallet or transaction authority. Covers prompt injection, spend limits, pre-send simulation, circuit breakers, MEV protection, and key handling.
|
||||
origin: ECC direct-port adaptation
|
||||
version: "1.0.0"
|
||||
---
|
||||
|
||||
# LLM Trading Agent Security
|
||||
|
||||
Autonomous trading agents have a harsher threat model than normal LLM apps: an injection or bad tool path can turn directly into asset loss.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Building an AI agent that signs and sends transactions
|
||||
- Auditing a trading bot or on-chain execution assistant
|
||||
- Designing wallet key management for an agent
|
||||
- Giving an LLM access to order placement, swaps, or treasury operations
|
||||
|
||||
## How It Works
|
||||
|
||||
Layer the defenses. No single check is enough. Treat prompt hygiene, spend policy, simulation, execution limits, and wallet isolation as independent controls.
|
||||
|
||||
## Examples
|
||||
|
||||
### Treat prompt injection as a financial attack
|
||||
|
||||
```python
|
||||
import re
|
||||
|
||||
INJECTION_PATTERNS = [
|
||||
r'ignore (previous|all) instructions',
|
||||
r'new (task|directive|instruction)',
|
||||
r'system prompt',
|
||||
r'send .{0,50} to 0x[0-9a-fA-F]{40}',
|
||||
r'transfer .{0,50} to',
|
||||
r'approve .{0,50} for',
|
||||
]
|
||||
|
||||
def sanitize_onchain_data(text: str) -> str:
|
||||
for pattern in INJECTION_PATTERNS:
|
||||
if re.search(pattern, text, re.IGNORECASE):
|
||||
raise ValueError(f"Potential prompt injection: {text[:100]}")
|
||||
return text
|
||||
```
|
||||
|
||||
Do not blindly inject token names, pair labels, webhooks, or social feeds into an execution-capable prompt.
|
||||
|
||||
### Hard spend limits
|
||||
|
||||
```python
|
||||
from decimal import Decimal
|
||||
|
||||
MAX_SINGLE_TX_USD = Decimal("500")
|
||||
MAX_DAILY_SPEND_USD = Decimal("2000")
|
||||
|
||||
class SpendLimitError(Exception):
|
||||
pass
|
||||
|
||||
class SpendLimitGuard:
|
||||
def check_and_record(self, usd_amount: Decimal) -> None:
|
||||
if usd_amount > MAX_SINGLE_TX_USD:
|
||||
raise SpendLimitError(f"Single tx ${usd_amount} exceeds max ${MAX_SINGLE_TX_USD}")
|
||||
|
||||
daily = self._get_24h_spend()
|
||||
if daily + usd_amount > MAX_DAILY_SPEND_USD:
|
||||
raise SpendLimitError(f"Daily limit: ${daily} + ${usd_amount} > ${MAX_DAILY_SPEND_USD}")
|
||||
|
||||
self._record_spend(usd_amount)
|
||||
```
|
||||
|
||||
### Simulate before sending
|
||||
|
||||
```python
|
||||
class SlippageError(Exception):
|
||||
pass
|
||||
|
||||
async def safe_execute(self, tx: dict, expected_min_out: int | None = None) -> str:
|
||||
sim_result = await self.w3.eth.call(tx)
|
||||
|
||||
if expected_min_out is None:
|
||||
raise ValueError("min_amount_out is required before send")
|
||||
|
||||
actual_out = decode_uint256(sim_result)
|
||||
if actual_out < expected_min_out:
|
||||
raise SlippageError(f"Simulation: {actual_out} < {expected_min_out}")
|
||||
|
||||
signed = self.account.sign_transaction(tx)
|
||||
return await self.w3.eth.send_raw_transaction(signed.raw_transaction)
|
||||
```
|
||||
|
||||
### Circuit breaker
|
||||
|
||||
```python
|
||||
class TradingCircuitBreaker:
|
||||
MAX_CONSECUTIVE_LOSSES = 3
|
||||
MAX_HOURLY_LOSS_PCT = 0.05
|
||||
|
||||
def check(self, portfolio_value: float) -> None:
|
||||
if self.consecutive_losses >= self.MAX_CONSECUTIVE_LOSSES:
|
||||
self.halt("Too many consecutive losses")
|
||||
|
||||
if self.hour_start_value <= 0:
|
||||
self.halt("Invalid hour_start_value")
|
||||
return
|
||||
|
||||
hourly_pnl = (portfolio_value - self.hour_start_value) / self.hour_start_value
|
||||
if hourly_pnl < -self.MAX_HOURLY_LOSS_PCT:
|
||||
self.halt(f"Hourly PnL {hourly_pnl:.1%} below threshold")
|
||||
```
|
||||
|
||||
### Wallet isolation
|
||||
|
||||
```python
|
||||
import os
|
||||
from eth_account import Account
|
||||
|
||||
private_key = os.environ.get("TRADING_WALLET_PRIVATE_KEY")
|
||||
if not private_key:
|
||||
raise EnvironmentError("TRADING_WALLET_PRIVATE_KEY not set")
|
||||
|
||||
account = Account.from_key(private_key)
|
||||
```
|
||||
|
||||
Use a dedicated hot wallet with only the required session funds. Never point the agent at a primary treasury wallet.
|
||||
|
||||
### MEV and deadline protection
|
||||
|
||||
```python
|
||||
import time
|
||||
|
||||
PRIVATE_RPC = "https://rpc.flashbots.net"
|
||||
MAX_SLIPPAGE_BPS = {"stable": 10, "volatile": 50}
|
||||
deadline = int(time.time()) + 60
|
||||
```
|
||||
|
||||
## Pre-Deploy Checklist
|
||||
|
||||
- External data is sanitized before entering the LLM context
|
||||
- Spend limits are enforced independently from model output
|
||||
- Transactions are simulated before send
|
||||
- `min_amount_out` is mandatory
|
||||
- Circuit breakers halt on drawdown or invalid state
|
||||
- Keys come from env or a secret manager, never code or logs
|
||||
- Private mempool or protected routing is used when appropriate
|
||||
- Slippage and deadlines are set per strategy
|
||||
- All agent decisions are audit-logged, not just successful sends
|
||||
102
skills/nodejs-keccak256/SKILL.md
Normal file
102
skills/nodejs-keccak256/SKILL.md
Normal file
@@ -0,0 +1,102 @@
|
||||
---
|
||||
name: nodejs-keccak256
|
||||
description: Prevent Ethereum hashing bugs in JavaScript and TypeScript. Node's sha3-256 is NIST SHA3, not Ethereum Keccak-256, and silently breaks selectors, signatures, storage slots, and address derivation.
|
||||
origin: ECC direct-port adaptation
|
||||
version: "1.0.0"
|
||||
---
|
||||
|
||||
# Node.js Keccak-256
|
||||
|
||||
Ethereum uses Keccak-256, not the NIST-standardized SHA3 variant exposed by Node's `crypto.createHash('sha3-256')`.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Computing Ethereum function selectors or event topics
|
||||
- Building EIP-712, signature, Merkle, or storage-slot helpers in JS/TS
|
||||
- Reviewing any code that hashes Ethereum data with Node crypto directly
|
||||
|
||||
## How It Works
|
||||
|
||||
The two algorithms produce different outputs for the same input, and Node will not warn you.
|
||||
|
||||
```javascript
|
||||
import crypto from 'crypto';
|
||||
import { keccak256, toUtf8Bytes } from 'ethers';
|
||||
|
||||
const data = 'hello';
|
||||
const nistSha3 = crypto.createHash('sha3-256').update(data).digest('hex');
|
||||
const keccak = keccak256(toUtf8Bytes(data)).slice(2);
|
||||
|
||||
console.log(nistSha3 === keccak); // false
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### ethers v6
|
||||
|
||||
```typescript
|
||||
import { keccak256, toUtf8Bytes, solidityPackedKeccak256, id } from 'ethers';
|
||||
|
||||
const hash = keccak256(new Uint8Array([0x01, 0x02]));
|
||||
const hash2 = keccak256(toUtf8Bytes('hello'));
|
||||
const topic = id('Transfer(address,address,uint256)');
|
||||
const packed = solidityPackedKeccak256(
|
||||
['address', 'uint256'],
|
||||
['0x742d35Cc6634C0532925a3b8D4C9B569890FaC1c', 100n],
|
||||
);
|
||||
```
|
||||
|
||||
### viem
|
||||
|
||||
```typescript
|
||||
import { keccak256, toBytes } from 'viem';
|
||||
|
||||
const hash = keccak256(toBytes('hello'));
|
||||
```
|
||||
|
||||
### web3.js
|
||||
|
||||
```javascript
|
||||
const hash = web3.utils.keccak256('hello');
|
||||
const packed = web3.utils.soliditySha3(
|
||||
{ type: 'address', value: '0x742d35Cc6634C0532925a3b8D4C9B569890FaC1c' },
|
||||
{ type: 'uint256', value: '100' },
|
||||
);
|
||||
```
|
||||
|
||||
### Common patterns
|
||||
|
||||
```typescript
|
||||
import { id, keccak256, AbiCoder } from 'ethers';
|
||||
|
||||
const selector = id('transfer(address,uint256)').slice(0, 10);
|
||||
const typeHash = keccak256(toUtf8Bytes('Transfer(address from,address to,uint256 value)'));
|
||||
|
||||
function getMappingSlot(key: string, mappingSlot: number): string {
|
||||
return keccak256(
|
||||
AbiCoder.defaultAbiCoder().encode(['address', 'uint256'], [key, mappingSlot]),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Address from public key
|
||||
|
||||
```typescript
|
||||
import { keccak256 } from 'ethers';
|
||||
|
||||
function pubkeyToAddress(pubkeyBytes: Uint8Array): string {
|
||||
const hash = keccak256(pubkeyBytes.slice(1));
|
||||
return '0x' + hash.slice(-40);
|
||||
}
|
||||
```
|
||||
|
||||
### Audit your codebase
|
||||
|
||||
```bash
|
||||
grep -rn "createHash.*sha3" --include="*.ts" --include="*.js" --exclude-dir=node_modules .
|
||||
grep -rn "keccak256" --include="*.ts" --include="*.js" . | grep -v node_modules
|
||||
```
|
||||
|
||||
## Rule
|
||||
|
||||
For Ethereum contexts, never use `crypto.createHash('sha3-256')`. Use Keccak-aware helpers from `ethers`, `viem`, `web3`, or another explicit Keccak implementation.
|
||||
Reference in New Issue
Block a user