Skip to content

Commit

Permalink
Merge pull request #29 from immunefi-team/mocks
Browse files Browse the repository at this point in the history
Add Boilerplate Mock contracts
  • Loading branch information
arbaz-immunefi authored Dec 15, 2023
2 parents 73b1083 + 0a73a71 commit 2361acb
Show file tree
Hide file tree
Showing 21 changed files with 1,101 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ forge test -vv --match-path test/[test_name]
| Reentrancy | [reentrancy](https://github.com/immunefi-team/forge-poc-templates/tree/reentrancy) | [Source](./src/reentrancy/Reentrancy.sol) | [Readme](./src/reentrancy/README.md) |
| Flash Loan | [flash_loan](https://github.com/immunefi-team/forge-poc-templates/tree/flash_loan) | [Source](./src/flashloan/FlashLoan.sol) | [Readme](./src/flashloan/README.md) |
| Price Manipulation | [price_manipulation](https://github.com/immunefi-team/forge-poc-templates/tree/price_manipulation) | [Source](./src/pricemanipulation/PriceManipulation.sol) | [Readme](./src/pricemanipulation/README.md) |
| Boilterplate Mocks | [mocks](https://github.com/immunefi-team/forge-poc-templates/tree/mocks) | [Source](./src/mocks/) | [Readme](./src/mocks/README.md) |
<!-- | Forking | [Template](./src/ForkingTemplate.sol) | [Source](./src/Forking.sol) | [Test](./test/Forking.t.sol) |
| NFTX Loan | [Template](./src/NFTXLoanTemplate.sol) | [Source](./src/NFTXLoan.sol) | [Test](./test/NFTXLoan.t.sol) |
| Uninitialized Proxy | [Template](./src/UninitializedProxyTemplate.sol) | [Source](./src/UninitializedProxy.sol) | [Test](./test/UninitializedProxy.t.sol) | -->
Expand Down
26 changes: 26 additions & 0 deletions src/mocks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Boilerplate Mock Contracts Repository

## Introduction
Welcome to the Boilerplate Mock Contracts repository. This collection offers a wide array of mock contracts, specifically tailored for whitehat testing and seamless integration into various blockchain projects. From unconventional ERC-20 tokens to potentially hazardous contracts, our repository provides essential tools for rigorous smart contract testing.

## Directory Structure
The repository is organized into different categories, each containing specific types of contracts:

## Usage
The following templates represent the core of the Boilerplate Mock Contracts. You can quickly integrate and test these templates in your projects.

### Templates
* [Malicious Contracts](./malicious)
* [Gas Exhaust](./malicious/gasExhaust.sol)
* [Return Bomb](./malicious/returnBomb.sol)
* [Self-Destruct](./malicious/self-destruct.sol)
* [Miscellaneous Contracts](./miscs)
* [Proxy Contract](./miscs/Proxy.sol)
* [Token Contracts](./tokens)
* [ERC20 Bool](./tokens/ERC20-bool.sol)
* [ERC20 with Fee Transfer](./tokens/ERC20-feeTransfer.sol)
* [ERC20 Rebase](./tokens/ERC20-rebase.sol)
* [ERC777 Token](./tokens/ERC777-token.sol)

## Ideas and Contributions
We are always looking for new ideas to expand our collection. If you have suggestions for new templates or improvements, feel free to create a GitHub issue or submit a pull request. Your contributions help make this repository a valuable resource for the blockchain development community.
16 changes: 16 additions & 0 deletions src/mocks/malicious/gasExhaust.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
pragma solidity ^0.8.0;

contract gasExhaust {
uint256 counter;
uint256 gasConsumeLimit;

function setGasConsumeLimit(uint256 _gasConsume) public {
gasConsumeLimit = _gasConsume;
}

fallback() external {
while (gasleft() > gasConsumeLimit) {
counter++;
}
}
}
22 changes: 22 additions & 0 deletions src/mocks/malicious/returnBomb.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
pragma solidity ^0.8.0;

/*
The returnDataSize value needs careful calibration: it should not be so high that it depletes all the gas, causing a revert, nor should it be so low that the function consumes all the gas yet still returns the data successfully.
Our goal is to determine an optimal median value for returnDataSize that will ensure the outer call reverts as intended.
*/

contract returnBomb {
uint128 public returnDataSize = 10000; // by default

function setReturnDataSize(uint128 _returnDataSize) external {
returnDataSize = _returnDataSize;
}

fallback() external {
assembly {
revert(0, returnDataSize.slot)
}
}
}
16 changes: 16 additions & 0 deletions src/mocks/malicious/self-destruct.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
pragma solidity ^0.8.0;

// Deprecation of selfdestruct
// https://soliditylang.org/blog/2023/02/01/solidity-0.8.18-release-announcement/

contract selfDestruct {
constructor() {}

function attack(address _contractAddr) public {
selfdestruct(payable(_contractAddr));
}

function destruct() external {
selfdestruct(payable(msg.sender));
}
}
43 changes: 43 additions & 0 deletions src/mocks/miscs/Proxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
pragma solidity ^0.8.0;

contract Proxy {
address public implementation;
address public owner;

event Upgraded(address implementation);

modifier onlyImplementation() {
require(msg.sender == implementation, "Proxy: only implementation allowed");
_;
}

modifier onlyOwner() {
require(msg.sender == owner, "Proxy: only owner allowed");
_;
}

constructor(address initialImplementation) {
implementation = initialImplementation;
owner = msg.sender;
}

function upgradeTo(address newImplementation) external onlyOwner {
require(newImplementation != address(0), "Proxy: Cannot upgrade to the zero address");
require(newImplementation != implementation, "Proxy: Cannot upgrade to the same implementation");

implementation = newImplementation;
emit Upgraded(newImplementation);
}

fallback() external payable {
address _impl = implementation;
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), _impl, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
}
43 changes: 43 additions & 0 deletions src/mocks/tokens/ERC20-bool.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
pragma solidity ^0.8.0;

import "forge-std/interfaces/IERC20.sol";
import {ERC20Base} from "./base/ERC20Base.sol";

contract ERC20Bool is ERC20Base {
constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _initialSupply) {
name = _name;
symbol = _symbol;
decimals = _decimals;
totalSupply = _initialSupply;
balanceOf[msg.sender] = _initialSupply;

emit Transfer(address(0), msg.sender, _initialSupply);
}

function transfer(address to, uint256 amount) public override returns (bool) {
if (balanceOf[msg.sender] >= amount && balanceOf[to] + amount >= balanceOf[to]) {
balanceOf[to] += amount;
balanceOf[msg.sender] -= amount;
emit Transfer(msg.sender, to, amount);
return true;
} else {
return false;
}
}

function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
if (
balanceOf[from] >= amount && allowance[from][msg.sender] >= amount
&& balanceOf[to] + amount >= balanceOf[to]
) {
balanceOf[to] += amount;
balanceOf[from] -= amount;
emit Transfer(from, to, amount);
allowance[from][msg.sender] -= amount;
emit Approval(from, msg.sender, allowance[from][msg.sender]);
return true;
} else {
return false;
}
}
}
53 changes: 53 additions & 0 deletions src/mocks/tokens/ERC20-feeTransfer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
pragma solidity ^0.8.0;

import "forge-std/interfaces/IERC20.sol";
import {ERC20Base} from "./base/ERC20Base.sol";

contract ERC20FeeTransfer is ERC20Base {
uint256 public fee;

constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _initialSupply, uint256 _fee) {
name = _name;
symbol = _symbol;
decimals = _decimals;
totalSupply = _initialSupply;
fee = _fee;
balanceOf[msg.sender] = _initialSupply;

emit Transfer(address(0), msg.sender, _initialSupply);
}

function setFee(uint256 _fee) public {
fee = _fee;
}

function transfer(address to, uint256 amount) public override returns (bool) {
require(balanceOf[msg.sender] >= amount, "ERC20Fee: Insufficient-balance");

balanceOf[msg.sender] -= amount;
balanceOf[to] += amount - fee;
balanceOf[address(0)] += fee;

emit Transfer(msg.sender, to, amount - fee);
emit Transfer(msg.sender, address(0), fee);

return true;
}

function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
require(balanceOf[from] >= amount, "ERC20Fee: Insufficient-balance");
if (from != msg.sender && allowance[from][msg.sender] != type(uint256).max) {
require(allowance[from][msg.sender] >= amount, "ERC20Fee: Insufficient-balance");
allowance[from][msg.sender] -= amount;
}

balanceOf[from] -= amount;
balanceOf[to] += amount - fee;
balanceOf[address(0)] += fee;

emit Transfer(from, to, amount - fee);
emit Transfer(from, address(0), fee);

return true;
}
}
60 changes: 60 additions & 0 deletions src/mocks/tokens/ERC20-rebase.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
pragma solidity ^0.8.0;

import "forge-std/interfaces/IERC20.sol";
import {ERC20Base} from "./base/ERC20Base.sol";

import "forge-std/Test.sol";

contract ERC20Rebase is ERC20Base, Test {
uint256 public lastRebaseTimestamp;
uint256 public rebaseInterval = 1 minutes;
uint256 public rebaseAmt = 5;

constructor(
string memory _name,
string memory _symbol,
uint8 _decimals,
uint256 _initialSupply,
uint256 _rebaseInterval,
uint256 _rebaseAmt
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
totalSupply = _initialSupply;
balanceOf[msg.sender] = _initialSupply;

lastRebaseTimestamp = block.timestamp;
rebaseInterval = _rebaseInterval;
rebaseAmt = _rebaseAmt;

emit Transfer(address(0), msg.sender, _initialSupply);
}

function setRebaseAmount(uint256 _rebaseAmt) public {
rebaseAmt = _rebaseAmt;
}

function setRebaseInterval(uint256 _rebaseInterval) public {
rebaseInterval = _rebaseInterval;
}

modifier rebase() {
uint256 timeSinceLastRebase = block.timestamp - lastRebaseTimestamp;
if (timeSinceLastRebase >= rebaseInterval) {
uint256 rebaseMultiplier = timeSinceLastRebase / rebaseInterval;
totalSupply += rebaseAmt * rebaseMultiplier;
balanceOf[msg.sender] += rebaseAmt * rebaseMultiplier;
lastRebaseTimestamp += rebaseInterval * rebaseMultiplier;
}
_;
}

function transfer(address to, uint256 amount) public override rebase returns (bool) {
super.transfer(to, amount);
}

function transferFrom(address from, address to, uint256 amount) public override rebase returns (bool) {
super.transferFrom(from, to, amount);
}
}
Loading

0 comments on commit 2361acb

Please sign in to comment.