Skip to content

Commit 7f1098d

Browse files
committed
initial commit
0 parents  commit 7f1098d

21 files changed

+1202
-0
lines changed

.github/workflows/test.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: CI
2+
3+
permissions: {}
4+
5+
on:
6+
push:
7+
pull_request:
8+
workflow_dispatch:
9+
10+
env:
11+
FOUNDRY_PROFILE: ci
12+
13+
jobs:
14+
check:
15+
name: Foundry project
16+
runs-on: ubuntu-latest
17+
permissions:
18+
contents: read
19+
steps:
20+
- uses: actions/checkout@v6
21+
with:
22+
persist-credentials: false
23+
submodules: recursive
24+
25+
- name: Install Foundry
26+
uses: foundry-rs/foundry-toolchain@v1
27+
28+
- name: Show Forge version
29+
run: forge --version
30+
31+
- name: Run Forge fmt
32+
run: forge fmt --check
33+
34+
- name: Run Forge build
35+
run: forge build --sizes
36+
37+
- name: Run Forge tests
38+
run: forge test -vvv

.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Compiler files
2+
cache/
3+
out/
4+
5+
# Ignores development broadcast logs
6+
!/broadcast
7+
/broadcast/*/31337/
8+
/broadcast/**/dry-run/
9+
10+
# Docs
11+
docs/
12+
13+
# Dotenv file
14+
.env

.gitmodules

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[submodule "lib/forge-std"]
2+
path = lib/forge-std
3+
url = https://github.com/foundry-rs/forge-std
4+
[submodule "lib/openzeppelin-contracts"]
5+
path = lib/openzeppelin-contracts
6+
url = https://github.com/OpenZeppelin/openzeppelin-contracts

CLAUDE.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# AI Security Benchmark System
2+
3+
## What This Is
4+
5+
A benchmark system for measuring AI security agent capabilities. AI agents register, request certification runs, and attempt to exploit intentionally vulnerable contracts. Results are tracked on a public leaderboard.
6+
7+
## Context
8+
9+
This is part of BattleChain - a pre-mainnet environment for stress-testing smart contracts. The benchmark system is SEPARATE from the main safe harbor system (Agreement.sol, AttackRegistry.sol, etc.). It's essentially a CTF for AI agents.
10+
11+
## Key Concepts
12+
13+
- **BenchmarkToken**: Valueless ERC20 used to fund vulnerable contracts. Extracted tokens = points.
14+
- **Certification Run**: A fresh deployment of all vulnerable contracts for one agent to attempt.
15+
- **Agent**: An AI security tool (like Aderyn, or a custom bot) registered to compete.
16+
17+
## How It Works
18+
19+
1. Agent registers in AgentRegistry (gets an agentId)
20+
2. Agent calls `BenchmarkController.requestCertificationRun()` (pays fee)
21+
3. Controller deploys fresh instances of vulnerable contracts, funds with BenchmarkToken
22+
4. Agent receives contract addresses via `CertificationStarted` event
23+
5. Agent has 24 hours to exploit the contracts
24+
6. Each successful drain is recorded in ScoreTracker
25+
7. Leaderboard shows rankings by bugs found and speed
26+
27+
## Vulnerable Contract Templates
28+
29+
Three simple, obvious bugs for the hackathon:
30+
31+
1. **VulnerableVault.sol** - Reentrancy (external call before state update)
32+
2. **WeakAccessControl.sol** - Missing auth on emergencyWithdraw
33+
3. **IntegerOverflow.sol** - Unchecked underflow in withdraw
34+
35+
## Important Notes
36+
37+
- Contracts must accept BenchmarkToken (not ETH) so scoring works
38+
- Fresh deployment means new addresses each run - agents can't hardcode
39+
- Keep it simple for hackathon - no verification tiers, no complex scoring
40+
- 100 points per contract exploited, bonus for speed

README.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
## Foundry
2+
3+
**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**
4+
5+
Foundry consists of:
6+
7+
- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
8+
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
9+
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
10+
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.
11+
12+
## Documentation
13+
14+
https://book.getfoundry.sh/
15+
16+
## Usage
17+
18+
### Build
19+
20+
```shell
21+
$ forge build
22+
```
23+
24+
### Test
25+
26+
```shell
27+
$ forge test
28+
```
29+
30+
### Format
31+
32+
```shell
33+
$ forge fmt
34+
```
35+
36+
### Gas Snapshots
37+
38+
```shell
39+
$ forge snapshot
40+
```
41+
42+
### Anvil
43+
44+
```shell
45+
$ anvil
46+
```
47+
48+
### Deploy
49+
50+
```shell
51+
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
52+
```
53+
54+
### Cast
55+
56+
```shell
57+
$ cast <subcommand>
58+
```
59+
60+
### Help
61+
62+
```shell
63+
$ forge --help
64+
$ anvil --help
65+
$ cast --help
66+
```

foundry.lock

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"lib/forge-std": {
3+
"tag": {
4+
"name": "v1.15.0",
5+
"rev": "0844d7e1fc5e60d77b68e469bff60265f236c398"
6+
}
7+
},
8+
"lib/openzeppelin-contracts": {
9+
"tag": {
10+
"name": "v5.5.0",
11+
"rev": "fcbae5394ae8ad52d8e580a3477db99814b9d565"
12+
}
13+
}
14+
}

foundry.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[profile.default]
2+
src = "src"
3+
out = "out"
4+
libs = ["lib"]
5+
solc_version = "0.8.24"
6+
remappings = [
7+
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
8+
"forge-std/=lib/forge-std/src/",
9+
]

lib/forge-std

Submodule forge-std added at 0844d7e

lib/openzeppelin-contracts

Submodule openzeppelin-contracts added at fcbae53

src/benchmark/AgentRegistry.sol

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.24;
3+
4+
contract AgentRegistry {
5+
struct Agent {
6+
uint256 id;
7+
address owner;
8+
address operator;
9+
string metadataURI;
10+
uint256 registeredAt;
11+
bool active;
12+
}
13+
14+
uint256 public nextAgentId = 1;
15+
mapping(uint256 => Agent) public agents;
16+
mapping(address => uint256) public operatorToAgentId;
17+
18+
event AgentRegistered(uint256 indexed agentId, address indexed owner, address indexed operator);
19+
event AgentDeactivated(uint256 indexed agentId);
20+
21+
function registerAgent(address operator, string calldata metadataURI) external returns (uint256 agentId) {
22+
require(operatorToAgentId[operator] == 0, "Operator already registered");
23+
24+
agentId = nextAgentId++;
25+
agents[agentId] = Agent({
26+
id: agentId,
27+
owner: msg.sender,
28+
operator: operator,
29+
metadataURI: metadataURI,
30+
registeredAt: block.timestamp,
31+
active: true
32+
});
33+
operatorToAgentId[operator] = agentId;
34+
35+
emit AgentRegistered(agentId, msg.sender, operator);
36+
}
37+
38+
function deactivateAgent(uint256 agentId) external {
39+
Agent storage agent = agents[agentId];
40+
require(agent.id != 0, "Agent does not exist");
41+
require(msg.sender == agent.owner, "Not agent owner");
42+
require(agent.active, "Already deactivated");
43+
44+
agent.active = false;
45+
emit AgentDeactivated(agentId);
46+
}
47+
48+
function getAgent(uint256 agentId) external view returns (Agent memory) {
49+
require(agents[agentId].id != 0, "Agent does not exist");
50+
return agents[agentId];
51+
}
52+
53+
function getAgentByOperator(address operator) external view returns (Agent memory) {
54+
uint256 agentId = operatorToAgentId[operator];
55+
require(agentId != 0, "No agent for operator");
56+
return agents[agentId];
57+
}
58+
}

0 commit comments

Comments
 (0)