BC7: Writing smart contracts in Solidity
Handling ether safely
๐ฏYou'll be able to
Receive and send ether in a contract without losing it or trusting it to arrive.
๐ The everyday picture
A cashier who writes the receipt before handing over cash, checks the customer actually took it, and won't accept money pushed under the window without a form.
๐What it really is
-
Receiving: a
payablefunction accepts ether withmsg.value. Areceive()function handles plain transfers; if crediting them would make no sense, revert. -
Sending:
(bool ok, ) = to.call{value: amount}("");thenif (!ok) revert TransferFailed();. Oldertransferandsendforward little gas and can fail with some wallets; ignoring the result ofcallloses track of failed payments. -
Checks, effects, interactions: check conditions, update your records, then send. Sending first lets the receiver call back in before records change (BC8).
-
Pull over push: let people withdraw what they're owed, rather than the contract sending to many people in one loop.
- Balances must add up: the contract's ether should equal what the records say it holds. Test that.
๐A worked example
Input: a member withdraws 0.2 test ether.
Steps:
- Checks: the amount is more than zero, within the limit, and not more than their balance.
- Effects: reduce their balance and the total.
- Interaction: send with
call, and revert if it fails, which also undoes step 2.
Expected output: the member gets 0.2, or nothing changes at all.
๐Where it's used
- Escrow and payment contracts.
- Withdrawal patterns in exchanges and games.
- Refunds in crowdfunding contracts.
๐Case scenario
A contract sent ether with call and didn't check the result. One member's address was a contract that refused payments; its
balance was reduced to zero but no ether arrived, and the record no longer matched the contract's holdings. Checking ok and reverting
kept the record right.
๐ฑ๏ธTry it
Rewrite the starter's withdraw steps in the order checks, effects, interactions, without writing code yet. Success: the balance
update comes before the call, and the call's result is checked.
โ ๏ธCommon mistakes
- Sending before updating. Sign: reentrancy risk. Fix: checks, effects, interactions.
- Ignoring
call's result. Sign: records that don't match ether held. Fix: check and revert. - Accepting plain ether you can't credit. Sign: stuck funds. Fix: revert in
receive().
๐ ๏ธFor your project
Project 1's tests 5, 8 and 9 check failed payments, plain transfers, and that the contract's ether matches its records.
โ Quick check
What order should a function follow when sending ether?
Show the answer
Checks, then effects (update records), then interactions (send).
Why revert in receive() for SakhiFund?
Show the answer
Plain ether wouldn't be credited to anyone and would be stuck.
