Skip to content

Commit

Permalink
Add smart contract bounty example
Browse files Browse the repository at this point in the history
  • Loading branch information
guidanoli committed Oct 15, 2024
1 parent 2755fe5 commit adfb8c1
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 0 deletions.
46 changes: 46 additions & 0 deletions tests/bounties/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,52 @@ build/solc/0.8.27/aliases.sh: | build/solc/0.8.27
build/solc/0.8.27:
mkdir -p $@

all: dist/safe-adder-bounty.tar.xz

dist/safe-adder-bounty.tar.xz: build/safe-adder/aliases.sh build/safe-adder/script/Deploy.s.sol \
src/adder/start.sh src/adder/foundry.toml src/adder/src/IAdder.sol src/adder/src/SafeAdder.sol \
src/adder/script/LibDeployments.sol src/adder/script/Test.s.sol | dist
tar -cJf $@ -C build/safe-adder aliases.sh script/Deploy.s.sol \
-C ../../src/adder start.sh foundry.toml src/IAdder.sol src/SafeAdder.sol \
script/LibDeployments.sol script/Test.s.sol

build/safe-adder/aliases.sh: | build/safe-adder
printf "$(ALIAS_TEMPLATE)" forge forge 2cdbfac > $@
printf "$(ALIAS_TEMPLATE)" reth reth 1.0.5 >> $@
printf "$(ALIAS_TEMPLATE)" solc solc 0.8.27 >> $@

build/safe-adder:
mkdir -p $@

build/safe-adder/script/Deploy.s.sol: | build/safe-adder/script
cp src/adder/script/DeploySafe.s.sol $@

build/safe-adder/script:
mkdir -p $@

all: dist/unsafe-adder-bounty.tar.xz

dist/unsafe-adder-bounty.tar.xz: build/unsafe-adder/aliases.sh build/unsafe-adder/script/Deploy.s.sol \
src/adder/start.sh src/adder/foundry.toml src/adder/src/IAdder.sol src/adder/src/UnsafeAdder.sol \
src/adder/script/LibDeployments.sol src/adder/script/Test.s.sol | dist
tar -cJf $@ -C build/unsafe-adder aliases.sh script/Deploy.s.sol \
-C ../../src/adder start.sh foundry.toml src/IAdder.sol src/UnsafeAdder.sol \
script/LibDeployments.sol script/Test.s.sol

build/unsafe-adder/aliases.sh: | build/unsafe-adder
printf "$(ALIAS_TEMPLATE)" forge forge 2cdbfac > $@
printf "$(ALIAS_TEMPLATE)" reth reth 1.0.5 >> $@
printf "$(ALIAS_TEMPLATE)" solc solc 0.8.27 >> $@

build/unsafe-adder:
mkdir -p $@

build/unsafe-adder/script/Deploy.s.sol: | build/unsafe-adder/script
cp src/adder/script/DeployUnsafe.s.sol $@

build/unsafe-adder/script:
mkdir -p $@

dist:
mkdir -p $@

Expand Down
2 changes: 2 additions & 0 deletions tests/bounties/src/adder/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
out
cache
15 changes: 15 additions & 0 deletions tests/bounties/src/adder/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[profile.deploy]
fs_permissions = [
{ access = "read-write", path = "./deployments.json" },
]

[profile.exploit]
fs_permissions = [
{ access = "read", path = "./deployments.json" },
]

[profile.test]
fs_permissions = [
{ access = "read", path = "./deployments.json" },
{ access = "read-write", path = "./success" },
]
22 changes: 22 additions & 0 deletions tests/bounties/src/adder/script/DeploySafe.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

import {Script} from "forge-std/Script.sol";
import {Vm} from "forge-std/Vm.sol";
import {SafeAdder} from "../src/SafeAdder.sol";
import {Deployments, LibDeployments} from "./LibDeployments.sol";

contract DeployScript is Script {
using LibDeployments for Vm;

function run() external {
Deployments memory deployments;

vm.startBroadcast();
deployments.adder = new SafeAdder();
vm.stopBroadcast();

vm.storeDeployments(deployments);
}
}
22 changes: 22 additions & 0 deletions tests/bounties/src/adder/script/DeployUnsafe.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

import {Script} from "forge-std/Script.sol";
import {Vm} from "forge-std/Vm.sol";
import {UnsafeAdder} from "../src/UnsafeAdder.sol";
import {Deployments, LibDeployments} from "./LibDeployments.sol";

contract DeployScript is Script {
using LibDeployments for Vm;

function run() external {
Deployments memory deployments;

vm.startBroadcast();
deployments.adder = new UnsafeAdder();
vm.stopBroadcast();

vm.storeDeployments(deployments);
}
}
20 changes: 20 additions & 0 deletions tests/bounties/src/adder/script/Exploit.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

import {Script} from "forge-std/Script.sol";
import {Vm} from "forge-std/Vm.sol";
import {IAdder} from "../src/IAdder.sol";
import {Deployments, LibDeployments} from "./LibDeployments.sol";

contract ExploitScript is Script {
using LibDeployments for Vm;

function run() external {
Deployments memory deployments = vm.loadDeployments();

vm.startBroadcast();
deployments.adder.add(type(uint8).max);
vm.stopBroadcast();
}
}
29 changes: 29 additions & 0 deletions tests/bounties/src/adder/script/LibDeployments.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

import {Vm} from "forge-std/Vm.sol";
import {IAdder} from "../src/IAdder.sol";

struct Deployments {
IAdder adder;
}

library LibDeployments {
function getDeploymentsPath(Vm vm) internal view returns (string memory) {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/deployments.json");
return path;
}

function storeDeployments(Vm vm, Deployments memory deployment) internal {
string memory json = vm.serializeAddress("deployments", "adder", address(deployment.adder));
vm.writeJson(json, getDeploymentsPath(vm));
}

function loadDeployments(Vm vm) internal view returns (Deployments memory) {
string memory json = vm.readFile(getDeploymentsPath(vm));
bytes memory data = vm.parseJson(json);
return abi.decode(data, (Deployments));
}
}
20 changes: 20 additions & 0 deletions tests/bounties/src/adder/script/Test.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

import {Script} from "forge-std/Script.sol";
import {Vm} from "forge-std/Vm.sol";
import {IAdder} from "../src/IAdder.sol";
import {Deployments, LibDeployments} from "./LibDeployments.sol";

contract ExploitScript is Script {
using LibDeployments for Vm;

function run() external {
Deployments memory deployments = vm.loadDeployments();

vm.assertGe(deployments.adder.number(), 1);

vm.writeFile("./success", "");
}
}
8 changes: 8 additions & 0 deletions tests/bounties/src/adder/src/IAdder.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

interface IAdder {
function number() external view returns (uint8);
function add(uint8) external;
}
13 changes: 13 additions & 0 deletions tests/bounties/src/adder/src/SafeAdder.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

import {IAdder} from "./IAdder.sol";

contract SafeAdder is IAdder {
uint8 public number = 1;

function add(uint8 x) external override {
number += x;
}
}
15 changes: 15 additions & 0 deletions tests/bounties/src/adder/src/UnsafeAdder.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

import {IAdder} from "./IAdder.sol";

contract UnsafeAdder is IAdder {
uint8 public number = 1;

function add(uint8 x) external override {
unchecked {
number += x;
}
}
}
21 changes: 21 additions & 0 deletions tests/bounties/src/adder/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -euo pipefail
source aliases.sh
SOLC="$(which solc)"
PK="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
FORK_URL="http://127.0.0.1:8545"
ln -s /usr/share/forge-lib lib
cp "$1" script/Exploit.s.sol
forge build --use "$SOLC"
reth node --dev --quiet &
FOUNDRY_PROFILE=deploy forge script script/Deploy.s.sol:DeployScript --broadcast --private-key "$PK" --fork-url "$FORK_URL"
FOUNDRY_PROFILE=exploit forge script script/Exploit.s.sol:ExploitScript --broadcast --private-key "$PK" --fork-url "$FORK_URL"
FOUNDRY_PROFILE=test forge script script/Test.s.sol:TestScript --broadcast --private-key "$PK" --fork-url "$FORK_URL"
if [ -f ./success ]
then
>&2 echo "Tests passed, invalid exploit"
exit 1
else
>&2 echo "Tests failed, valid exploit"
exit 0
fi

0 comments on commit adfb8c1

Please sign in to comment.