Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 26 additions & 39 deletions src/PiggyBank.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ contract PiggyBank {
address public owner;
uint256 public unlockTime;
bool public paused;
address public emergencyGuardian;
bool public emergencyMode;
uint256 public emergencyUnlockTime;

// Multi-user deposit tracking
uint256 public constant MAX_DEPOSIT_AMOUNT = 1000 ether; // Maximum deposit per user
Expand All @@ -24,10 +27,6 @@ contract PiggyBank {
mapping(address => uint256) public depositTimestamps;
mapping(address => uint256) public userDepositCount;

// Deposit limits
uint256 public constant MAX_DEPOSIT_AMOUNT = type(uint256).max;
uint256 public constant MIN_DEPOSIT_AMOUNT = 0.001 ether;

// Custom errors for gas efficiency
error PiggyBank__DepositTooHigh();
error PiggyBank__DepositTooLow();
Expand All @@ -38,32 +37,32 @@ contract PiggyBank {
error PiggyBank__ZeroAmount();
error PiggyBank__InsufficientBalance();
error PiggyBank__NoDeposit();
// Statistics for monitoring
uint256 public totalDeposits;
uint256 public totalWithdrawals;
uint256 public numberOfDepositors;

event Deposited(address indexed depositor, uint256 amount);
event Withdrawn(address indexed withdrawer, uint256 amount);
event Paused(address account);
event Unpaused(address account);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

// ============ CUSTOM ERRORS ============
error PiggyBank__ZeroValue();
error PiggyBank__DepositTooLow();
error PiggyBank__DepositTooHigh();
error PiggyBank__StillLocked();
error PiggyBank__NoDeposits();
error PiggyBank__Unauthorized();
error PiggyBank__Paused();
error PiggyBank__InvalidUnlockTime();
error PiggyBank__EmergencyModeActive();
error PiggyBank__Blacklisted();
error PiggyBank__ReentrancyAttack();
error PiggyBank__TransferFailed();
error PiggyBank__MaxUsersReached();
error PiggyBank__InvalidLockTime();
// Statistics for monitoring
uint256 public totalDeposits;
uint256 public totalWithdrawals;
uint256 public numberOfDepositors;

event Deposited(address indexed depositor, uint256 amount);
event Withdrawn(address indexed withdrawer, uint256 amount);
event Paused(address account);
event Unpaused(address account);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
event EmergencyGuardianChanged(address indexed oldGuardian, address indexed newGuardian);
event EmergencyModeActivated(address indexed activator, uint256 unlockTime);
event EmergencyWithdrawal(address indexed user, uint256 amount);
event DepositLimitUpdated(uint256 oldLimit, uint256 newLimit);

// ============ MODIFIERS ============
modifier whenNotPaused() {
Expand Down Expand Up @@ -165,25 +164,19 @@ contract PiggyBank {
* @notice Owner withdraws entire contract balance after unlock
*/
function withdraw() external whenNotPaused {
require(msg.sender == owner, "PiggyBank: Not owner");
require(block.timestamp >= unlockTime, "PiggyBank: Still locked");
if (msg.sender != owner) revert PiggyBank__NotOwner();
if (block.timestamp < unlockTime) revert PiggyBank__StillLocked();

uint256 contractBalance = address(this).balance;
require(contractBalance > 0, "No balance");
if (contractBalance == 0) revert PiggyBank__ZeroAmount();

// Effects
totalWithdrawals += contractBalance;

// Interactions
emit Withdrawn(msg.sender, contractBalance);
(bool success,) = payable(msg.sender).call{value: contractBalance}("");
require(success, "Transfer failed");
// External call at the END to prevent reentrancy
(bool success, ) = payable(msg.sender).call{value: amount}("");
(bool success, ) = payable(msg.sender).call{value: contractBalance}("");
if (!success) revert PiggyBank__TransferFailed();

// Emit event after successful transfer (checks-effects-interactions pattern)
emit Withdrawn(msg.sender, amount, block.timestamp);
}

/**
Expand All @@ -203,14 +196,14 @@ contract PiggyBank {
totalWithdrawals += userDeposit;

// Interactions - Emit event first, then external call
emit Withdrawn(msg.sender, userDeposit, block.timestamp);
emit Withdrawn(msg.sender, userDeposit);

// External call at the END to prevent reentrancy
(bool success, ) = payable(msg.sender).call{value: userDeposit}("");
if (!success) revert PiggyBank__TransferFailed();

// Emit event after successful transfer (checks-effects-interactions pattern)
emit EmergencyWithdrawal(user, amount);
emit EmergencyWithdrawal(msg.sender, userDeposit);
}

// ============ ADMIN FUNCTIONS ============
Expand Down Expand Up @@ -380,12 +373,6 @@ contract PiggyBank {
}

// ============ UTILITY FUNCTIONS ============
/**
* @dev Checks if user can deposit (gas optimized)
*/
function getContractStats() external view returns (uint256, uint256, uint256) {
return (totalDeposits, totalWithdrawals, address(this).balance);
}

/**
* @dev Checks if user can withdraw (gas optimized)
Expand Down
Loading