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;
}
}
}
PreviousA1 - Solidity error handling - notes on require, revert and assertNextE1 - EthWallet.test.js - Update
Last updated