From def580de7da58d1374e08eddcc36f450ac867050 Mon Sep 17 00:00:00 2001 From: Bernhard Mueller Date: Sun, 22 Jul 2018 21:23:04 +0200 Subject: [PATCH] Add real-world examples from https://blog.sigmaprime.io/solidity-security.html --- solidity_examples/BECToken.sol | 299 +++++++++++++ solidity_examples/WalletLibrary.sol | 396 ++++++++++++++++++ solidity_examples/ether_send.sol | 31 -- solidity_examples/etherstore.sol | 21 + solidity_examples/hashforether.sol | 12 + solidity_examples/timelock.sol | 21 + .../{underflow.sol => token.sol} | 6 +- 7 files changed, 753 insertions(+), 33 deletions(-) create mode 100644 solidity_examples/BECToken.sol create mode 100644 solidity_examples/WalletLibrary.sol delete mode 100644 solidity_examples/ether_send.sol create mode 100644 solidity_examples/etherstore.sol create mode 100644 solidity_examples/hashforether.sol create mode 100644 solidity_examples/timelock.sol rename solidity_examples/{underflow.sol => token.sol} (78%) diff --git a/solidity_examples/BECToken.sol b/solidity_examples/BECToken.sol new file mode 100644 index 00000000..b03a20e5 --- /dev/null +++ b/solidity_examples/BECToken.sol @@ -0,0 +1,299 @@ +pragma solidity ^0.4.16; + +/** + * @title SafeMath + * @dev Math operations with safety checks that throw on error + */ +library SafeMath { + function mul(uint256 a, uint256 b) internal constant returns (uint256) { + uint256 c = a * b; + assert(a == 0 || c / a == b); + return c; + } + + function div(uint256 a, uint256 b) internal constant returns (uint256) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint256 a, uint256 b) internal constant returns (uint256) { + assert(b <= a); + return a - b; + } + + function add(uint256 a, uint256 b) internal constant returns (uint256) { + uint256 c = a + b; + assert(c >= a); + return c; + } +} + +/** + * @title ERC20Basic + * @dev Simpler version of ERC20 interface + * @dev see https://github.com/ethereum/EIPs/issues/179 + */ +contract ERC20Basic { + uint256 public totalSupply; + function balanceOf(address who) public constant returns (uint256); + function transfer(address to, uint256 value) public returns (bool); + event Transfer(address indexed from, address indexed to, uint256 value); +} + +/** + * @title Basic token + * @dev Basic version of StandardToken, with no allowances. + */ +contract BasicToken is ERC20Basic { + using SafeMath for uint256; + + mapping(address => uint256) balances; + + /** + * @dev transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value > 0 && _value <= balances[msg.sender]); + + // SafeMath.sub will throw if there is not enough balance. + balances[msg.sender] = balances[msg.sender].sub(_value); + balances[_to] = balances[_to].add(_value); + Transfer(msg.sender, _to, _value); + return true; + } + + /** + * @dev Gets the balance of the specified address. + * @param _owner The address to query the the balance of. + * @return An uint256 representing the amount owned by the passed address. + */ + function balanceOf(address _owner) public constant returns (uint256 balance) { + return balances[_owner]; + } +} + +/** + * @title ERC20 interface + * @dev see https://github.com/ethereum/EIPs/issues/20 + */ +contract ERC20 is ERC20Basic { + function allowance(address owner, address spender) public constant returns (uint256); + function transferFrom(address from, address to, uint256 value) public returns (bool); + function approve(address spender, uint256 value) public returns (bool); + event Approval(address indexed owner, address indexed spender, uint256 value); +} + + +/** + * @title Standard ERC20 token + * + * @dev Implementation of the basic standard token. + * @dev https://github.com/ethereum/EIPs/issues/20 + * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol + */ +contract StandardToken is ERC20, BasicToken { + + mapping (address => mapping (address => uint256)) internal allowed; + + + /** + * @dev Transfer tokens from one address to another + * @param _from address The address which you want to send tokens from + * @param _to address The address which you want to transfer to + * @param _value uint256 the amount of tokens to be transferred + */ + function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value > 0 && _value <= balances[_from]); + require(_value <= allowed[_from][msg.sender]); + + balances[_from] = balances[_from].sub(_value); + balances[_to] = balances[_to].add(_value); + allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); + Transfer(_from, _to, _value); + return true; + } + + /** + * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. + * + * Beware that changing an allowance with this method brings the risk that someone may use both the old + * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this + * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * @param _spender The address which will spend the funds. + * @param _value The amount of tokens to be spent. + */ + function approve(address _spender, uint256 _value) public returns (bool) { + allowed[msg.sender][_spender] = _value; + Approval(msg.sender, _spender, _value); + return true; + } + + /** + * @dev Function to check the amount of tokens that an owner allowed to a spender. + * @param _owner address The address which owns the funds. + * @param _spender address The address which will spend the funds. + * @return A uint256 specifying the amount of tokens still available for the spender. + */ + function allowance(address _owner, address _spender) public constant returns (uint256 remaining) { + return allowed[_owner][_spender]; + } +} + +/** + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ +contract Ownable { + address public owner; + + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + + /** + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + function Ownable() { + owner = msg.sender; + } + + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function transferOwnership(address newOwner) onlyOwner public { + require(newOwner != address(0)); + OwnershipTransferred(owner, newOwner); + owner = newOwner; + } + +} + +/** + * @title Pausable + * @dev Base contract which allows children to implement an emergency stop mechanism. + */ +contract Pausable is Ownable { + event Pause(); + event Unpause(); + + bool public paused = false; + + + /** + * @dev Modifier to make a function callable only when the contract is not paused. + */ + modifier whenNotPaused() { + require(!paused); + _; + } + + /** + * @dev Modifier to make a function callable only when the contract is paused. + */ + modifier whenPaused() { + require(paused); + _; + } + + /** + * @dev called by the owner to pause, triggers stopped state + */ + function pause() onlyOwner whenNotPaused public { + paused = true; + Pause(); + } + + /** + * @dev called by the owner to unpause, returns to normal state + */ + function unpause() onlyOwner whenPaused public { + paused = false; + Unpause(); + } +} + +/** + * @title Pausable token + * + * @dev StandardToken modified with pausable transfers. + **/ + +contract PausableToken is StandardToken, Pausable { + + function transfer(address _to, uint256 _value) public whenNotPaused returns (bool) { + return super.transfer(_to, _value); + } + + function transferFrom(address _from, address _to, uint256 _value) public whenNotPaused returns (bool) { + return super.transferFrom(_from, _to, _value); + } + + function approve(address _spender, uint256 _value) public whenNotPaused returns (bool) { + return super.approve(_spender, _value); + } + + function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) { + uint cnt = _receivers.length; + uint256 amount = uint256(cnt) * _value; + require(cnt > 0 && cnt <= 20); + require(_value > 0 && balances[msg.sender] >= amount); + + balances[msg.sender] = balances[msg.sender].sub(amount); + for (uint i = 0; i < cnt; i++) { + balances[_receivers[i]] = balances[_receivers[i]].add(_value); + Transfer(msg.sender, _receivers[i], _value); + } + return true; + } +} + +/** + * @title Bec Token + * + * @dev Implementation of Bec Token based on the basic standard token. + */ +contract BecToken is PausableToken { + /** + * Public variables of the token + * The following variables are OPTIONAL vanities. One does not have to include them. + * They allow one to customise the token contract & in no way influences the core functionality. + * Some wallets/interfaces might not even bother to look at this information. + */ + string public name = "BeautyChain"; + string public symbol = "BEC"; + string public version = '1.0.0'; + uint8 public decimals = 18; + + /** + * @dev Function to check the amount of tokens that an owner allowed to a spender. + */ + function BecToken() { + totalSupply = 7000000000 * (10**(uint256(decimals))); + balances[msg.sender] = totalSupply; // Give the creator all initial tokens + } + + function () { + //if ether is sent to this address, send it back. + revert(); + } +} \ No newline at end of file diff --git a/solidity_examples/WalletLibrary.sol b/solidity_examples/WalletLibrary.sol new file mode 100644 index 00000000..90294219 --- /dev/null +++ b/solidity_examples/WalletLibrary.sol @@ -0,0 +1,396 @@ +//sol Wallet +// Multi-sig, daily-limited account proxy/wallet. +// @authors: +// Gav Wood +// inheritable "property" contract that enables methods to be protected by requiring the acquiescence of either a +// single, or, crucially, each of a number of, designated owners. +// usage: +// use modifiers onlyowner (just own owned) or onlymanyowners(hash), whereby the same hash must be provided by +// some number (specified in constructor) of the set of owners (specified in the constructor, modifiable) before the +// interior is executed. + +pragma solidity ^0.4.9; + +contract WalletEvents { + // EVENTS + + // this contract only has six types of events: it can accept a confirmation, in which case + // we record owner and operation (hash) alongside it. + event Confirmation(address owner, bytes32 operation); + event Revoke(address owner, bytes32 operation); + + // some others are in the case of an owner changing. + event OwnerChanged(address oldOwner, address newOwner); + event OwnerAdded(address newOwner); + event OwnerRemoved(address oldOwner); + + // the last one is emitted if the required signatures change + event RequirementChanged(uint newRequirement); + + // Funds has arrived into the wallet (record how much). + event Deposit(address _from, uint value); + // Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going). + event SingleTransact(address owner, uint value, address to, bytes data, address created); + // Multi-sig transaction going out of the wallet (record who signed for it last, the operation hash, how much, and to whom it's going). + event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data, address created); + // Confirmation still needed for a transaction. + event ConfirmationNeeded(bytes32 operation, address initiator, uint value, address to, bytes data); +} + +contract WalletAbi { + // Revokes a prior confirmation of the given operation + function revoke(bytes32 _operation) external; + + // Replaces an owner `_from` with another `_to`. + function changeOwner(address _from, address _to) external; + + function addOwner(address _owner) external; + + function removeOwner(address _owner) external; + + function changeRequirement(uint _newRequired) external; + + function isOwner(address _addr) constant returns (bool); + + function hasConfirmed(bytes32 _operation, address _owner) external constant returns (bool); + + // (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today. + function setDailyLimit(uint _newLimit) external; + + function execute(address _to, uint _value, bytes _data) external returns (bytes32 o_hash); + function confirm(bytes32 _h) returns (bool o_success); +} + +contract WalletLibrary is WalletEvents { + // TYPES + + // struct for the status of a pending operation. + struct PendingState { + uint yetNeeded; + uint ownersDone; + uint index; + } + + // Transaction structure to remember details of transaction lest it need be saved for a later call. + struct Transaction { + address to; + uint value; + bytes data; + } + + // MODIFIERS + + // simple single-sig function modifier. + modifier onlyowner { + if (isOwner(msg.sender)) + _; + } + // multi-sig function modifier: the operation must have an intrinsic hash in order + // that later attempts can be realised as the same underlying operation and + // thus count as confirmations. + modifier onlymanyowners(bytes32 _operation) { + if (confirmAndCheck(_operation)) + _; + } + + // METHODS + + // gets called when no other function matches + function() payable { + // just being sent some cash? + if (msg.value > 0) + Deposit(msg.sender, msg.value); + } + + // constructor is given number of sigs required to do protected "onlymanyowners" transactions + // as well as the selection of addresses capable of confirming them. + function initMultiowned(address[] _owners, uint _required) only_uninitialized { + m_numOwners = _owners.length + 1; + m_owners[1] = uint(msg.sender); + m_ownerIndex[uint(msg.sender)] = 1; + for (uint i = 0; i < _owners.length; ++i) + { + m_owners[2 + i] = uint(_owners[i]); + m_ownerIndex[uint(_owners[i])] = 2 + i; + } + m_required = _required; + } + + // Revokes a prior confirmation of the given operation + function revoke(bytes32 _operation) external { + uint ownerIndex = m_ownerIndex[uint(msg.sender)]; + // make sure they're an owner + if (ownerIndex == 0) return; + uint ownerIndexBit = 2**ownerIndex; + var pending = m_pending[_operation]; + if (pending.ownersDone & ownerIndexBit > 0) { + pending.yetNeeded++; + pending.ownersDone -= ownerIndexBit; + Revoke(msg.sender, _operation); + } + } + + // Replaces an owner `_from` with another `_to`. + function changeOwner(address _from, address _to) onlymanyowners(sha3(msg.data)) external { + if (isOwner(_to)) return; + uint ownerIndex = m_ownerIndex[uint(_from)]; + if (ownerIndex == 0) return; + + clearPending(); + m_owners[ownerIndex] = uint(_to); + m_ownerIndex[uint(_from)] = 0; + m_ownerIndex[uint(_to)] = ownerIndex; + OwnerChanged(_from, _to); + } + + function addOwner(address _owner) onlymanyowners(sha3(msg.data)) external { + if (isOwner(_owner)) return; + + clearPending(); + if (m_numOwners >= c_maxOwners) + reorganizeOwners(); + if (m_numOwners >= c_maxOwners) + return; + m_numOwners++; + m_owners[m_numOwners] = uint(_owner); + m_ownerIndex[uint(_owner)] = m_numOwners; + OwnerAdded(_owner); + } + + function removeOwner(address _owner) onlymanyowners(sha3(msg.data)) external { + uint ownerIndex = m_ownerIndex[uint(_owner)]; + if (ownerIndex == 0) return; + if (m_required > m_numOwners - 1) return; + + m_owners[ownerIndex] = 0; + m_ownerIndex[uint(_owner)] = 0; + clearPending(); + reorganizeOwners(); //make sure m_numOwner is equal to the number of owners and always points to the optimal free slot + OwnerRemoved(_owner); + } + + function changeRequirement(uint _newRequired) onlymanyowners(sha3(msg.data)) external { + if (_newRequired > m_numOwners) return; + m_required = _newRequired; + clearPending(); + RequirementChanged(_newRequired); + } + + // Gets an owner by 0-indexed position (using numOwners as the count) + function getOwner(uint ownerIndex) external constant returns (address) { + return address(m_owners[ownerIndex + 1]); + } + + function isOwner(address _addr) constant returns (bool) { + return m_ownerIndex[uint(_addr)] > 0; + } + + function hasConfirmed(bytes32 _operation, address _owner) external constant returns (bool) { + var pending = m_pending[_operation]; + uint ownerIndex = m_ownerIndex[uint(_owner)]; + + // make sure they're an owner + if (ownerIndex == 0) return false; + + // determine the bit to set for this owner. + uint ownerIndexBit = 2**ownerIndex; + return !(pending.ownersDone & ownerIndexBit == 0); + } + + // constructor - stores initial daily limit and records the present day's index. + function initDaylimit(uint _limit) only_uninitialized { + m_dailyLimit = _limit; + m_lastDay = today(); + } + // (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today. + function setDailyLimit(uint _newLimit) onlymanyowners(sha3(msg.data)) external { + m_dailyLimit = _newLimit; + } + // resets the amount already spent today. needs many of the owners to confirm. + function resetSpentToday() onlymanyowners(sha3(msg.data)) external { + m_spentToday = 0; + } + + // throw unless the contract is not yet initialized. + modifier only_uninitialized { if (m_numOwners > 0) throw; _; } + + // constructor - just pass on the owner array to the multiowned and + // the limit to daylimit + function initWallet(address[] _owners, uint _required, uint _daylimit) only_uninitialized { + initDaylimit(_daylimit); + initMultiowned(_owners, _required); + } + + // kills the contract sending everything to `_to`. + function kill(address _to) onlymanyowners(sha3(msg.data)) external { + suicide(_to); + } + + // Outside-visible transact entry point. Executes transaction immediately if below daily spend limit. + // If not, goes into multisig process. We provide a hash on return to allow the sender to provide + // shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value + // and _data arguments). They still get the option of using them if they want, anyways. + function execute(address _to, uint _value, bytes _data) external onlyowner returns (bytes32 o_hash) { + // first, take the opportunity to check that we're under the daily limit. + if ((_data.length == 0 && underLimit(_value)) || m_required == 1) { + // yes - just execute the call. + address created; + if (_to == 0) { + created = create(_value, _data); + } else { + if (!_to.call.value(_value)(_data)) + throw; + } + SingleTransact(msg.sender, _value, _to, _data, created); + } else { + // determine our operation hash. + o_hash = sha3(msg.data, block.number); + // store if it's new + if (m_txs[o_hash].to == 0 && m_txs[o_hash].value == 0 && m_txs[o_hash].data.length == 0) { + m_txs[o_hash].to = _to; + m_txs[o_hash].value = _value; + m_txs[o_hash].data = _data; + } + if (!confirm(o_hash)) { + ConfirmationNeeded(o_hash, msg.sender, _value, _to, _data); + } + } + } + + function create(uint _value, bytes _code) internal returns (address o_addr) { + assembly { + o_addr := create(_value, add(_code, 0x20), mload(_code)) + jumpi(0xdeadbeef, iszero(extcodesize(o_addr))) + } + } + + // confirm a transaction through just the hash. we use the previous transactions map, m_txs, in order + // to determine the body of the transaction from the hash provided. + function confirm(bytes32 _h) onlymanyowners(_h) returns (bool o_success) { + if (m_txs[_h].to != 0 || m_txs[_h].value != 0 || m_txs[_h].data.length != 0) { + address created; + if (m_txs[_h].to == 0) { + created = create(m_txs[_h].value, m_txs[_h].data); + } else { + if (!m_txs[_h].to.call.value(m_txs[_h].value)(m_txs[_h].data)) + throw; + } + + MultiTransact(msg.sender, _h, m_txs[_h].value, m_txs[_h].to, m_txs[_h].data, created); + delete m_txs[_h]; + return true; + } + } + + // INTERNAL METHODS + + function confirmAndCheck(bytes32 _operation) internal returns (bool) { + // determine what index the present sender is: + uint ownerIndex = m_ownerIndex[uint(msg.sender)]; + // make sure they're an owner + if (ownerIndex == 0) return; + + var pending = m_pending[_operation]; + // if we're not yet working on this operation, switch over and reset the confirmation status. + if (pending.yetNeeded == 0) { + // reset count of confirmations needed. + pending.yetNeeded = m_required; + // reset which owners have confirmed (none) - set our bitmap to 0. + pending.ownersDone = 0; + pending.index = m_pendingIndex.length++; + m_pendingIndex[pending.index] = _operation; + } + // determine the bit to set for this owner. + uint ownerIndexBit = 2**ownerIndex; + // make sure we (the message sender) haven't confirmed this operation previously. + if (pending.ownersDone & ownerIndexBit == 0) { + Confirmation(msg.sender, _operation); + // ok - check if count is enough to go ahead. + if (pending.yetNeeded <= 1) { + // enough confirmations: reset and run interior. + delete m_pendingIndex[m_pending[_operation].index]; + delete m_pending[_operation]; + return true; + } + else + { + // not enough: record that this owner in particular confirmed. + pending.yetNeeded--; + pending.ownersDone |= ownerIndexBit; + } + } + } + + function reorganizeOwners() private { + uint free = 1; + while (free < m_numOwners) + { + while (free < m_numOwners && m_owners[free] != 0) free++; + while (m_numOwners > 1 && m_owners[m_numOwners] == 0) m_numOwners--; + if (free < m_numOwners && m_owners[m_numOwners] != 0 && m_owners[free] == 0) + { + m_owners[free] = m_owners[m_numOwners]; + m_ownerIndex[m_owners[free]] = free; + m_owners[m_numOwners] = 0; + } + } + } + + // checks to see if there is at least `_value` left from the daily limit today. if there is, subtracts it and + // returns true. otherwise just returns false. + function underLimit(uint _value) internal onlyowner returns (bool) { + // reset the spend limit if we're on a different day to last time. + if (today() > m_lastDay) { + m_spentToday = 0; + m_lastDay = today(); + } + // check to see if there's enough left - if so, subtract and return true. + // overflow protection // dailyLimit check + if (m_spentToday + _value >= m_spentToday && m_spentToday + _value <= m_dailyLimit) { + m_spentToday += _value; + return true; + } + return false; + } + + // determines today's index. + function today() private constant returns (uint) { return now / 1 days; } + + function clearPending() internal { + uint length = m_pendingIndex.length; + + for (uint i = 0; i < length; ++i) { + delete m_txs[m_pendingIndex[i]]; + + if (m_pendingIndex[i] != 0) + delete m_pending[m_pendingIndex[i]]; + } + + delete m_pendingIndex; + } + + // FIELDS + address constant _walletLibrary = 0xcafecafecafecafecafecafecafecafecafecafe; + + // the number of owners that must confirm the same operation before it is run. + uint public m_required; + // pointer used to find a free slot in m_owners + uint public m_numOwners; + + uint public m_dailyLimit; + uint public m_spentToday; + uint public m_lastDay; + + // list of owners + uint[256] m_owners; + + uint constant c_maxOwners = 250; + // index on the list of owners to allow reverse lookup + mapping(uint => uint) m_ownerIndex; + // the ongoing operations. + mapping(bytes32 => PendingState) m_pending; + bytes32[] m_pendingIndex; + + // pending transactions we have at present. + mapping (bytes32 => Transaction) m_txs; +} diff --git a/solidity_examples/ether_send.sol b/solidity_examples/ether_send.sol deleted file mode 100644 index a814332b..00000000 --- a/solidity_examples/ether_send.sol +++ /dev/null @@ -1,31 +0,0 @@ -contract Crowdfunding { - - mapping(address => uint) public balances; - address public owner; - uint256 INVEST_MIN = 1 ether; - uint256 INVEST_MAX = 10 ether; - - modifier onlyOwner() { - require(msg.sender == owner); - _; - } - - function crowdfunding() { - owner = msg.sender; - } - - function withdrawfunds() onlyOwner { - msg.sender.transfer(this.balance); - } - - function invest() public payable { - require(msg.value > INVEST_MIN && msg.value < INVEST_MAX); - - balances[msg.sender] += msg.value; - } - - function getBalance() public constant returns (uint) { - return balances[msg.sender]; - } - -} diff --git a/solidity_examples/etherstore.sol b/solidity_examples/etherstore.sol new file mode 100644 index 00000000..38a9177c --- /dev/null +++ b/solidity_examples/etherstore.sol @@ -0,0 +1,21 @@ +contract EtherStore { + + uint256 public withdrawalLimit = 1 ether; + mapping(address => uint256) public lastWithdrawTime; + mapping(address => uint256) public balances; + + function depositFunds() public payable { + balances[msg.sender] += msg.value; + } + + function withdrawFunds (uint256 _weiToWithdraw) public { + require(balances[msg.sender] >= _weiToWithdraw); + // limit the withdrawal + require(_weiToWithdraw <= withdrawalLimit); + // limit the time allowed to withdraw + require(now >= lastWithdrawTime[msg.sender] + 1 weeks); + require(msg.sender.call.value(_weiToWithdraw)()); + balances[msg.sender] -= _weiToWithdraw; + lastWithdrawTime[msg.sender] = now; + } + } \ No newline at end of file diff --git a/solidity_examples/hashforether.sol b/solidity_examples/hashforether.sol new file mode 100644 index 00000000..a90538ea --- /dev/null +++ b/solidity_examples/hashforether.sol @@ -0,0 +1,12 @@ +contract HashForEther { + + function withdrawWinnings() { + // Winner if the last 8 hex characters of the address are 0. + require(uint32(msg.sender) == 0); + _sendWinnings(); + } + + function _sendWinnings() { + msg.sender.transfer(this.balance); + } +} \ No newline at end of file diff --git a/solidity_examples/timelock.sol b/solidity_examples/timelock.sol new file mode 100644 index 00000000..33ddb4fe --- /dev/null +++ b/solidity_examples/timelock.sol @@ -0,0 +1,21 @@ +contract TimeLock { + + mapping(address => uint) public balances; + mapping(address => uint) public lockTime; + + function deposit() public payable { + balances[msg.sender] += msg.value; + lockTime[msg.sender] = now + 1 weeks; + } + + function increaseLockTime(uint _secondsToIncrease) public { + lockTime[msg.sender] += _secondsToIncrease; + } + + function withdraw() public { + require(balances[msg.sender] > 0); + require(now > lockTime[msg.sender]); + balances[msg.sender] = 0; + msg.sender.transfer(balances[msg.sender]); + } +} \ No newline at end of file diff --git a/solidity_examples/underflow.sol b/solidity_examples/token.sol similarity index 78% rename from solidity_examples/underflow.sol rename to solidity_examples/token.sol index 6ecef5df..19239427 100644 --- a/solidity_examples/underflow.sol +++ b/solidity_examples/token.sol @@ -1,4 +1,6 @@ -contract Under { +pragma solidity ^0.4.18; + +contract Token { mapping(address => uint) balances; uint public totalSupply; @@ -7,7 +9,7 @@ contract Under { balances[msg.sender] = totalSupply = _initialSupply; } - function sendeth(address _to, uint _value) public returns (bool) { + function transfer(address _to, uint _value) public returns (bool) { require(balances[msg.sender] - _value >= 0); balances[msg.sender] -= _value; balances[_to] += _value;