🎓 A1Learner
🔍
0 of 50 lessons completed

Solidity Project: Piggy Bank

The Piggy Bank project is a complete contract that holds ether savings separately for each saver and lets each saver take only their own savings back. It brings payable functions, mappings, events, and sending ether together in one small program.

deposit credits the sender in a mapping

The deposit function is payable, so callers send ether with the call. The function adds msg.value to the balance recorded under msg.sender.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

contract SavingsJar {
    mapping(address => uint256) public savings;

    function deposit() public payable {
        savings[msg.sender] = savings[msg.sender] + msg.value;
    }
}

Every deposit emits a deposit event

The Deposited event records who saved and how much. The indexed who value lets outside tools find one saver's deposits quickly.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

contract LoudJar {
    mapping(address => uint256) public savings;

    event Deposited(address indexed who, uint256 amount);

    function deposit() public payable {
        savings[msg.sender] = savings[msg.sender] + msg.value;
        emit Deposited(msg.sender, msg.value);
    }
}

withdraw sends a saver's own savings back

The withdraw function reads the caller's recorded balance and clears it to 0. It then transfers that exact amount back to the caller.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

contract WithdrawJar {
    mapping(address => uint256) public savings;

    function deposit() public payable {
        savings[msg.sender] = savings[msg.sender] + msg.value;
    }

    function withdraw() public {
        uint256 amount = savings[msg.sender];
        require(amount > 0, "No savings to withdraw");
        savings[msg.sender] = 0;
        payable(msg.sender).transfer(amount);
    }
}

Example

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

contract PiggyBank {
    mapping(address => uint256) public savings;

    event Deposited(address indexed who, uint256 amount);
    event Withdrawn(address indexed who, uint256 amount);

    function deposit() public payable {
        savings[msg.sender] = savings[msg.sender] + msg.value;
        emit Deposited(msg.sender, msg.value);
    }

    function withdraw() public {
        uint256 amount = savings[msg.sender];
        require(amount > 0, "No savings to withdraw");
        savings[msg.sender] = 0;
        payable(msg.sender).transfer(amount);
        emit Withdrawn(msg.sender, amount);
    }
}

Key points

  • Ether: the money of the Ethereum network, sent and held in wei amounts inside contracts.
  • Deposit: a payable function that adds the ether sent with the call to the sender's own balance in a mapping.
  • Book balance: the amount the mapping records for one saver.
  • Real balance: the ether the contract actually holds, read with address(this).balance.
  • Withdraw: a function that sends a saver's own recorded savings back to that saver with transfer.
  • Deposit event: every deposit emits an event that names the saver and the amount.

In this example, the savings mapping records one balance for each saver. The deposit function is payable and adds msg.value to the caller's recorded balance, then emits Deposited with the saver and the amount. The withdraw function reads the caller's balance, checks it is above 0, clears it to 0, and transfers that amount back to the caller. Because every deposit adds real ether and every withdrawal removes exactly the recorded amount, the ether the contract holds always matches the total in the mapping.

Note

the contract's real ether balance should always equal the total of all book balances.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Remix IDE

Exercise

Ana saved 2 ether in Piggy Bank and Bob saved 1 ether. Ana then withdraws. How much ether does the contract hold after her withdrawal?