├── .gitignore ├── README.md ├── contracts ├── ColabBank.sol ├── Lock.sol └── v2 │ ├── ColabBankV2.sol │ └── observations.md ├── hardhat.config.js ├── package-lock.json ├── package.json ├── scripts └── deploy.js └── test ├── ColabBank.test.js ├── ColabBankV2.test.js └── Lock.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | coverage 4 | coverage.json 5 | typechain 6 | typechain-types 7 | 8 | #Hardhat files 9 | cache 10 | artifacts 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Intro to Smart Contract Testing 2 | 3 | 4 | To test, run `npm run test` 5 | 6 | 7 | -------------------------------------------------------------------------------- /contracts/ColabBank.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.9; 3 | 4 | // Uncomment this line to use console.log 5 | // import "hardhat/console.sol"; 6 | 7 | contract ColabBank { 8 | // The keyword "public" makes variables 9 | // accessible from other contracts 10 | uint256 public unlockTime; 11 | mapping(address => uint256) public balances; 12 | uint256 public totalColabBalance; 13 | 14 | address payable public owner; 15 | // Events allow clients to react to specific 16 | // contract changes you declare 17 | event Deposit(uint256 amount, uint256 when, address caller); 18 | event Withdrawal(uint256 amount, uint256 when); 19 | 20 | // Constructor code is only run when the contract 21 | // is created 22 | constructor(uint256 _unlockTime) payable { 23 | require( 24 | block.timestamp < _unlockTime, 25 | "Unlock time should be in the future" 26 | ); 27 | 28 | unlockTime = _unlockTime; 29 | owner = payable(msg.sender); 30 | } 31 | 32 | 33 | // spot the error here 34 | function deposit(uint256 amount) public { 35 | // Uncomment this line, and the import of "hardhat/console.sol", to print a log in your terminal 36 | // console.log("Unlock time is %o and block timestamp is %o", unlockTime, block.timestamp); 37 | 38 | require(amount != 0, "cannot deposit 0 amount"); 39 | 40 | totalColabBalance += amount; 41 | 42 | emit Deposit(amount, block.timestamp, msg.sender); 43 | 44 | 45 | } 46 | 47 | function withdraw() public { 48 | // Uncomment this line, and the import of "hardhat/console.sol", to print a log in your terminal 49 | // console.log("Unlock time is %o and block timestamp is %o", unlockTime, block.timestamp); 50 | 51 | require(block.timestamp >= unlockTime, "You can't withdraw yet"); 52 | require(msg.sender == owner, "You aren't the owner"); 53 | 54 | emit Withdrawal(address(this).balance, block.timestamp); 55 | 56 | owner.transfer(address(this).balance); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /contracts/Lock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.9; 3 | // pragma solidity >=0.4.0 <0.9.0; 4 | 5 | // Uncomment this line to use console.log 6 | // import "hardhat/console.sol"; 7 | 8 | contract Lock { 9 | uint public unlockTime; 10 | address payable public owner; 11 | 12 | event Withdrawal(uint amount, uint when); 13 | 14 | constructor(uint _unlockTime) payable { 15 | require( 16 | block.timestamp < _unlockTime, 17 | "Unlock time should be in the future" 18 | ); 19 | 20 | unlockTime = _unlockTime; 21 | owner = payable(msg.sender); 22 | } 23 | 24 | function withdraw() public { 25 | // Uncomment this line, and the import of "hardhat/console.sol", to print a log in your terminal 26 | // console.log("Unlock time is %o and block timestamp is %o", unlockTime, block.timestamp); 27 | 28 | require(block.timestamp >= unlockTime, "You can't withdraw yet"); 29 | require(msg.sender == owner, "You aren't the owner"); 30 | 31 | emit Withdrawal(address(this).balance, block.timestamp); 32 | 33 | owner.transfer(address(this).balance); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contracts/v2/ColabBankV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.9; 4 | 5 | contract ColabBankV2 { 6 | 7 | mapping(address => uint256) public balances; 8 | address payable public owner; 9 | 10 | event Deposit(uint256 amount, uint256 when, address caller); 11 | event Withdrawal(uint256 amount, uint256 when); 12 | 13 | constructor() payable { 14 | owner = payable(msg.sender); 15 | } 16 | 17 | // spot the vulnerability 18 | function deposit() public payable { 19 | require(msg.value != 0, "cannot deposit 0 ETH"); 20 | uint256 value = msg.value; 21 | balances[msg.sender] = value; 22 | emit Deposit(value, block.timestamp, msg.sender); 23 | } 24 | 25 | // spot the vulnerability in this function 26 | function withdraw() public { 27 | require(balances[msg.sender] != 0, "you have 0 ETH deposit"); 28 | uint256 amount = balances[msg.sender]; 29 | payable(msg.sender).transfer(address(this).balance); 30 | emit Withdrawal(amount, block.timestamp); 31 | } 32 | 33 | receive() external payable {} 34 | } 35 | -------------------------------------------------------------------------------- /contracts/v2/observations.md: -------------------------------------------------------------------------------- 1 | # My Observations on the vulnerabilities present in the ColabBank V2. 2 | 3 | _I found out that in the deposit function there are some vulnerabilities which are highlighted below;_ 4 | 5 | - ### **Type of Deposit not specified** 6 | 7 | > I noticed that the type of deposit is not checked and validated to be sure that the person is depositing eth and not just anything, with this anybody can deposit trashy items and withdraw valuable eth, anything goes in this deposit function. 8 | 9 | - ### **Current Balance can be altered because of a bug present** 10 | 11 | > I also noticed that the current balance can be altered and tampered with, in line 21 `balances[msg.sender] = value;` this means that the balance is equal to the latest deposit value and its not adding the latest deposit to the previous balance to get the accrued valued, with this I believe the bug will be sorted `balances[msg.sender] += value;` and save the company from a huge lose by someone who has spotted the vulnerability. 12 | 13 | - ### **The withdraw function is buggy as it allows a person withdraw more than they deposited** 14 | > I realised that this function allows anyone to withdraw eth regardless of whatever the person deposited and also it allows the person to withdraw the total amount in the contract which is not proper, a person should only withdraw what he/she deposited and not more than the deposited amount made by the person. 15 | 16 | ## **THANK YOU** 17 | -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | require("@nomicfoundation/hardhat-toolbox"); 2 | 3 | /** @type import('hardhat/config').HardhatUserConfig */ 4 | module.exports = { 5 | solidity: "0.8.17", 6 | }; 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@ethersproject/providers": "^5.7.2", 5 | "@nomicfoundation/hardhat-chai-matchers": "^1.0.5", 6 | "@nomicfoundation/hardhat-network-helpers": "^1.0.7", 7 | "@nomicfoundation/hardhat-toolbox": "^2.0.0", 8 | "@nomiclabs/hardhat-ethers": "^2.2.1", 9 | "@nomiclabs/hardhat-etherscan": "^3.1.3", 10 | "@typechain/ethers-v5": "^10.1.1", 11 | "@typechain/hardhat": "^6.1.4", 12 | "@types/chai": "^4.3.4", 13 | "@types/mocha": "^9.1.1", 14 | "chai": "^4.3.7", 15 | "ethers": "^5.7.2", 16 | "hardhat": "^2.12.2", 17 | "hardhat-gas-reporter": "^1.0.9", 18 | "solidity-coverage": "^0.8.2", 19 | "ts-node": "^10.9.1", 20 | "typechain": "^8.1.1", 21 | "typescript": "^4.9.3" 22 | }, 23 | "scripts": { 24 | "test": "npx hardhat test" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /scripts/deploy.js: -------------------------------------------------------------------------------- 1 | // We require the Hardhat Runtime Environment explicitly here. This is optional 2 | // but useful for running the script in a standalone fashion through `node