E1: EthWallet.sol - Update

Modify the above contract to include events for each deposit and withdrawal action. Test the contract to ensure that events are emitted correctly.

Modifying EthWallet.sol

In this lesson the key differences to the contract are:

  • Gas optimized 'deposit' and 'withdraw' functions

  • Events added for both functions.

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/* errors */
error EthWallet__DepositMustBeAboveZero();
error EthWallet__WithdrawalMustBeAboveZero();
error EthWallet__WalletIsEmpty();
error EthWallet__WithdrawalExceedsUserBalance();
error EthWallet_InsufficientContractBalance();

// ----------------- Events added ---------------------

/* events */
event DepositSuccess(address depositer, uint amount);
event WithdrawSuccess(address withdrawer, uint amount);

// ----------------------------------------------------

contract EthWallet {
    /* structs */
    struct User {
        address ownerAddress;
        uint userBalance;
        uint withdrawnToday;
        uint lastWithdrawalTime;
    }

    /* mappings */
    mapping(address => User) private users;

    /* state variables */
    uint public constant dailyWithdrawalLimit = 10 ether;
    bool private locked;
    uint currentBalance;

    modifier withdrawalLimitCheck(uint _withdrawalAmount) {
        User storage currentUser = users[msg.sender];

        // Reset withdrawal amount if a new day has started
        if (isNewDay(currentUser.lastWithdrawalTime)) {
            currentUser.withdrawnToday = 0;
        }

        // Check if the requested withdrawal exceeds the daily limit
        require(
            currentUser.withdrawnToday + _withdrawalAmount <=
                dailyWithdrawalLimit,
            "Daily withdrawal limit exceeded"
        );

        // Update user's withdrawal data
        currentUser.withdrawnToday += _withdrawalAmount;
        currentUser.lastWithdrawalTime = block.timestamp;
        _;
    }

    modifier sufficientBalance(uint _withdrawalAmount) {
        uint withdrawalAmount = _withdrawalAmount;
        currentBalance = users[msg.sender].userBalance;
        if (currentBalance == 0) {
            revert EthWallet__WalletIsEmpty();
        } else if (_withdrawalAmount > address(this).balance) {
            revert EthWallet_InsufficientContractBalance();
        } else if (_withdrawalAmount > currentBalance) {
            revert EthWallet__WithdrawalExceedsUserBalance();
        }
        _;
    }

    modifier noReeentrant() {
        require(!locked, "No re_entrancy");
        locked = true;
        _;
        locked = false;
    }

    // Helper function to determine if a new day has started
    function isNewDay(uint lastWithdrawalTime) internal view returns (bool) {
        uint currentDay = block.timestamp / 1 days;
        uint lastWithdrawalDay = lastWithdrawalTime / 1 days;
        return currentDay > lastWithdrawalDay;
    }

    function deposit() public payable {
    
        // -Require statement replaced custom error for input validation-
        // ---------- 18.3% gas reduction for calculation cost ----------
        
        require(msg.value > 0, "Deposit must be above zero!");
        
        // --------------------------------------------------------------

        uint depositAmount = msg.value;

        if (users[msg.sender].userBalance > 0) {
            users[msg.sender].userBalance += depositAmount;
        } else {
            users[msg.sender] = User(msg.sender, depositAmount, 0, 0);
        }

        emit DepositSuccess(msg.sender, depositAmount);
    }

    function withdraw(
        uint _withdrawalAmount
    )
        external
        withdrawalLimitCheck(_withdrawalAmount)
        sufficientBalance(_withdrawalAmount)
        noReeentrant
    {
    
        // -Require statement replaced custom error for input validation-
        // ---------- 18.3% gas reduction for calculation cost ----------
        
        require(_withdrawalAmount > 0, "Withdrawal must be above zero!");
        
        // --------------------------------------------------------------

        uint withdrawalAmount = _withdrawalAmount;

        // Update user Balance
        users[msg.sender].userBalance -= withdrawalAmount;

        // Process withdrawal
        payable(msg.sender).transfer(withdrawalAmount);

        emit WithdrawSuccess(msg.sender, withdrawalAmount);
    }

    function getUserBalance() public view returns (uint) {
        if (users[msg.sender].ownerAddress != address(0)) {
            return users[msg.sender].userBalance;
        } else {
            return 0;
        }
    }
}

Last updated