Solidity Exercise - Basic Bank

Posted by Bourne's Blog - A Full-stack & Web3 Developer on May 9, 2024

Basic Bank

This is an exercise from a bundle of practices Solidity exercise.

It’s not a full functional bank application, but it’s good enough to demonstrate some features.

Download Solidity Exercise

1
git clone https://github.com/rareSkills/solidity-exercises.git

after that, you need to install foundry toolchain.

Check the BasicBank code and test case

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  solidity-exercises git:(main)  cd BasicBank
  BasicBank git:(main)  cat src/BasicBank.sol 
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.13;

contract BasicBank {
    /// @notice deposit ether into the contract
    /// @dev it should work properly when called multiple times
    function addEther() external payable {}

    /// @notice used to withdraw ether from the contract (No restriction on withdrawals)
    function removeEther(uint256 amount) external payable {
    }
}

  BasicBank git:(main)  cat test/BasicBank.t.sol 
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import "../src/BasicBank.sol";

contract BasicBankTest is Test {
    BasicBank public basicBank;

    function setUp() public {
        basicBank = new BasicBank();
    }

    function testAddEther() external {
        vm.deal(address(this), 1 ether);
        basicBank.addEther{value: 1 ether}();
        assertEq(
            address(basicBank).balance,
            1 ether,
            "expected balance of basic bank contract to be 1 ether"
        );
    }

    function testRemoveEther() external {
        vm.deal(address(this), 1 ether);
        vm.expectRevert();
        basicBank.removeEther(1);
        basicBank.addEther{value: 1 ether}();
        basicBank.removeEther(1 ether);
        assertEq(
            address(this).balance,
            1 ether,
            "expected balance of address(this) to be 1 ether"
        );
    }

    receive() external payable {}
}

Problem Analysis

It’s obvious that, we need to implement function addEther and removeEther to pass the test.
In solidity, we DONOT need do anything to receive ether as soon as we define the addEther function as payable.
To send ethers, just call “transfer” on an address to send.

Coding

1
2
3
    function removeEther(uint256 amount) external payable {
        msg.sender.transfer(amount);
    }
CAUTION: in reality, usually you need to restrict the removeEther only be called by owner.

An error prompt by IDE:

1
"send" and "transfer" are only available for objects of type "address payable", not "address".(9862)

We need to add midofier payable to msg.sender :

1
2
3
    function removeEther(uint256 amount) external payable {
        payable(msg.sender).transfer(amount);
    }

Test

Let’s run test command:

1
2
3
4
5
6
7
8
9
10
11
12
➜  BasicBank git:(main) ✗ forge test -vvv
[⠊] Compiling...
[⠒] Compiling 19 files with Solc 0.8.25
[⠑] Solc 0.8.25 finished in 549.65ms
Compiler run successful!

Ran 2 tests for test/BasicBank.t.sol:BasicBankTest
[PASS] testAddEther() (gas: 15250)
[PASS] testRemoveEther() (gas: 30447)
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 5.63ms (1.35ms CPU time)

Ran 1 test suite in 168.19ms (5.63ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)

Great, we passed 2 test cases!