DEV Community

Cover image for πŸ’Ž Day 5 of 30 Days of Solidity β€” Build a Treasure Chest Contract
Saurav Kumar
Saurav Kumar

Posted on

πŸ’Ž Day 5 of 30 Days of Solidity β€” Build a Treasure Chest Contract

In Day 5 of my Solidity journey, I built a Treasure Chest Contract β€” a fun yet powerful way to understand how access control, ownership, and fund management work in Ethereum smart contracts.

This project simulates a treasure chest where only the owner can manage treasure and control who can withdraw from it. It’s a simple yet realistic example of how permission-based systems are created in blockchain applications, such as admin-controlled games or vaults.


πŸͺ™ What I Built

A Treasure Chest Smart Contract that:

  • Allows the owner to add treasure (Ether) into the chest.
  • Lets the owner approve specific users to withdraw treasure.
  • Ensures users can withdraw only once, unless the owner resets them.
  • Enables the owner to withdraw treasure anytime.
  • Allows ownership transfer to another address securely.

πŸ’» Source Code

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

/**
 * @title TreasureChest
 * @dev A contract where only the owner controls access to treasure.
 * Users can withdraw only if approved by the owner.
 */
contract TreasureChest {
    address public owner;
    uint256 public treasureBalance;

    mapping(address => bool) public approvedUsers;
    mapping(address => bool) public hasWithdrawn;

    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
    event TreasureAdded(uint256 amount);
    event UserApproved(address indexed user);
    event Withdrawal(address indexed user, uint256 amount);
    event WithdrawalReset(address indexed user);

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not the owner!");
        _;
    }

    function addTreasure() external payable onlyOwner {
        require(msg.value > 0, "Must add some treasure!");
        treasureBalance += msg.value;
        emit TreasureAdded(msg.value);
    }

    function approveUser(address _user) external onlyOwner {
        approvedUsers[_user] = true;
        hasWithdrawn[_user] = false;
        emit UserApproved(_user);
    }

    function withdraw(uint256 _amount) external {
        require(approvedUsers[msg.sender], "Not approved!");
        require(!hasWithdrawn[msg.sender], "Already withdrawn!");
        require(_amount <= treasureBalance, "Not enough treasure!");

        hasWithdrawn[msg.sender] = true;
        treasureBalance -= _amount;

        payable(msg.sender).transfer(_amount);
        emit Withdrawal(msg.sender, _amount);
    }

    function resetWithdrawal(address _user) external onlyOwner {
        hasWithdrawn[_user] = false;
        emit WithdrawalReset(_user);
    }

    function transferOwnership(address _newOwner) external onlyOwner {
        require(_newOwner != address(0), "Invalid address!");
        address oldOwner = owner;
        owner = _newOwner;
        emit OwnershipTransferred(oldOwner, _newOwner);
    }

    function getContractBalance() public view returns (uint256) {
        return address(this).balance;
    }
}
Enter fullscreen mode Exit fullscreen mode

🧠 What I Learned

πŸ” Access Control with Modifiers

I learned how to use modifier to restrict access to certain functions.
This ensures only the owner can perform critical actions like adding treasure, approving users, or resetting withdrawals.

πŸ’° Managing Ether with Payable Functions

The contract demonstrates how to safely receive and manage Ether inside a smart contract using payable functions and transfer().

πŸ—‚οΈ Mappings for User Permissions

Mappings make it easy to store and track user approvals and withdrawal statuses.

πŸ‘‘ Ownership Management

I implemented ownership transfer logic, helping me understand how administrative roles can be safely reassigned in decentralized systems.


βš™οΈ How It Works

  1. Deploy the Contract β€” the deployer becomes the owner.
  2. Add Treasure β€” the owner deposits Ether into the contract.
  3. Approve Users β€” the owner grants permission to specific users.
  4. Withdraw β€” approved users can withdraw once.
  5. Reset β€” the owner can reset users to allow them again.
  6. Transfer Ownership β€” control can be given to another address.

This project highlights the importance of security and trust in smart contract development β€” ensuring only authorized users can access funds.


🧩 Why It’s Important

Understanding ownership and restricted access is a core concept in Solidity.
Whether you’re building a DeFi protocol, a DAO, or even a game with admin roles, this foundation is essential.


πŸ§ͺ Tools I Used

  • Remix IDE for development and testing
  • Solidity (v0.8.0) for writing the contract
  • MetaMask for deploying and interacting with the contract

πŸ”— GitHub Repository

πŸ‘‰ View Full Code Here


πŸ’¬ Final Thoughts

This day’s challenge helped me understand the concept of ownership and controlled access in smart contracts β€” something every Solidity developer must master.

Each day in this journey brings me closer to becoming proficient in building secure, transparent, and powerful decentralized applications.

Stay tuned for Day 6, where I’ll explore another exciting Solidity concept! πŸš€

Top comments (0)