Version: V.0.1.0 Solidity: 0.8.33 Framework: Foundry
A multi-user Ether bank implemented as a Solidity smart contract. The contract acts as a registry of balances per address, enforces a configurable per-user deposit cap, and exposes a hand-crafted access control system for the contract owner. No external dependencies — zero third-party libraries.
The diagram shows the two external actors (User and Owner), the four public entry points, the modifier guards each function passes through, how state variables are affected, and which events are emitted as a result.
User ──► depositEther() ── balances[user] += ──► EtherDeposited
User ──► withdrawEther() ── balances[user] -= ──► ETH sent to user ──► EtherWithdrawn
User ──► sendEth() ── balances re-routed ──► ETH sent to recv ──► EtherSent
Owner ──► modifyMaxLimit() ── depositLimit = ──► MaxBalanceEdited
-
Deposit — The caller sends ETH with the transaction. The contract checks the deposit is non-zero and that the new total does not exceed
depositLimit. If both checks pass,balances[msg.sender]is incremented bymsg.value. -
Withdrawal — The caller specifies an
amount. ThecheckTransferAmountmodifier validates the amount is positive and within the caller's balance. The balance is decremented before the Ether is sent (Checks-Effects-Interactions pattern), protecting against reentrancy. -
Peer transfer — Works like a withdrawal but instead of sending ETH out to the caller, it credits
balances[to_]and sends the ETH directly to the recipient address. The recipient's resulting balance must not exceeddepositLimit. -
Limit management — The owner can call
modifyMaxLimitat any time to adjust the cap. A zero value is explicitly rejected.
# Install Foundry
curl -L https://foundry.paradigm.xyz | bash && foundryup
# Build
forge build
# Deploy locally (default: 10 ETH limit, deployer = owner)
anvil
forge script script/CryptoBankDeployScript.s.sol --broadcast --rpc-url http://127.0.0.1:8545
# Deploy to testnet
forge script script/CryptoBankDeployScript.s.sol --broadcast --rpc-url <RPC_URL> --private-key <PRIVATE_KEY>This contract implements a hand-crafted reentrancy guard without relying on OpenZeppelin or any external library. The mechanism is a private boolean lock — _locked — combined with the nonReentrant modifier:
bool private _locked;
modifier nonReentrant() {
require(_locked == false, "Reentrant call");
_locked = true;
_;
_locked = false;
}How it works:
- Before executing,
nonReentrantasserts_locked == falsethen sets it totrue. - The function body runs, including the external
.call{value:}that sends ETH. - If a malicious
receive()orfallback()attempts to re-enter,nonReentrantfinds_locked == trueand reverts, blocking the attack. - After normal completion,
_lockedis reset tofalse.
If the guarded function reverts for any reason, Solidity rolls back all state changes in the transaction — including _locked = true. The lock releases automatically; the contract is never left permanently locked.
