Skip to content

Commit cba8e6f

Browse files
author
bohendo
committed
updated not-so-smart-contracts to add SpankChain
1 parent 777bc54 commit cba8e6f

File tree

4 files changed

+1061
-1
lines changed

4 files changed

+1061
-1
lines changed

reentrancy/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ that they do not have.
1616
- Update all bookkeeping state variables _before_ transferring execution to an external contract.
1717

1818
## Examples
19-
- The [DAO](http://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit/) hack
19+
20+
- The [DAO](http://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit/) hack
21+
- The [SpankChain](https://medium.com/spankchain/we-got-spanked-what-we-know-so-far-d5ed3a0f38fe) hack
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Overview
2+
3+
There are two contracts in this directory:
4+
5+
- `SpankChain.sol`, which was not vulnerable
6+
- `SpankChain_Payment.sol` which contained the [SpankChain hack](https://medium.com/spankchain/we-got-spanked-what-we-know-so-far-d5ed3a0f38fe) vulnerability
7+
8+
Both contracts are preserved here for posterity. The "tl;dr" of the vulnerability:
9+
10+
- The attacker called `createChannel` to setup a channel
11+
- they then called `LCOpenTimeout` repeatedly
12+
- Since `LCOpenTimeout` sends ETH *and then* removes the balance, an attacker can call it over and over to drain the account
13+
14+
The fix? Never update state before a `transfer`, a `send`, a `call`, and so on; always perform those actions as the last step of the process in any contract that interacts with the
15+
world
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// https://etherscan.io/address/0x42d6622dece394b54999fbd73d108123806f6a18#code
2+
3+
// Abstract contract for the full ERC 20 Token standard
4+
// https://github.com/ethereum/EIPs/issues/20
5+
pragma solidity 0.4.15;
6+
7+
contract Token {
8+
/* This is a slight change to the ERC20 base standard.
9+
function totalSupply() constant returns (uint256 supply);
10+
is replaced with:
11+
uint256 public totalSupply;
12+
This automatically creates a getter function for the totalSupply.
13+
This is moved to the base contract since public getter functions are not
14+
currently recognised as an implementation of the matching abstract
15+
function by the compiler.
16+
*/
17+
/// total amount of tokens
18+
uint256 public totalSupply;
19+
20+
/// @param _owner The address from which the balance will be retrieved
21+
/// @return The balance
22+
function balanceOf(address _owner) constant returns (uint256 balance);
23+
24+
/// @notice send `_value` token to `_to` from `msg.sender`
25+
/// @param _to The address of the recipient
26+
/// @param _value The amount of token to be transferred
27+
/// @return Whether the transfer was successful or not
28+
function transfer(address _to, uint256 _value) returns (bool success);
29+
30+
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
31+
/// @param _from The address of the sender
32+
/// @param _to The address of the recipient
33+
/// @param _value The amount of token to be transferred
34+
/// @return Whether the transfer was successful or not
35+
function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
36+
37+
/// @notice `msg.sender` approves `_spender` to spend `_value` tokens
38+
/// @param _spender The address of the account able to transfer the tokens
39+
/// @param _value The amount of tokens to be approved for transfer
40+
/// @return Whether the approval was successful or not
41+
function approve(address _spender, uint256 _value) returns (bool success);
42+
43+
/// @param _owner The address of the account owning tokens
44+
/// @param _spender The address of the account able to transfer the tokens
45+
/// @return Amount of remaining tokens allowed to spent
46+
function allowance(address _owner, address _spender) constant returns (uint256 remaining);
47+
48+
event Transfer(address indexed _from, address indexed _to, uint256 _value);
49+
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
50+
}
51+
52+
53+
/*
54+
You should inherit from StandardToken or, for a token like you would want to
55+
deploy in something like Mist, see HumanStandardToken.sol.
56+
(This implements ONLY the standard functions and NOTHING else.
57+
If you deploy this, you won't have anything useful.)
58+
59+
Implements ERC 20 Token standard: https://github.com/ethereum/EIPs/issues/20
60+
.*/
61+
contract StandardToken is Token {
62+
63+
function transfer(address _to, uint256 _value) returns (bool success) {
64+
//Default assumes totalSupply can't be over max (2^256 - 1).
65+
//If your token leaves out totalSupply and can issue more tokens as time goes on, you need to check if it doesn't wrap.
66+
//Replace the if with this one instead.
67+
//require(balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]);
68+
require(balances[msg.sender] >= _value);
69+
balances[msg.sender] -= _value;
70+
balances[_to] += _value;
71+
Transfer(msg.sender, _to, _value);
72+
return true;
73+
}
74+
75+
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
76+
//same as above. Replace this line with the following if you want to protect against wrapping uints.
77+
//require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]);
78+
require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value);
79+
balances[_to] += _value;
80+
balances[_from] -= _value;
81+
allowed[_from][msg.sender] -= _value;
82+
Transfer(_from, _to, _value);
83+
return true;
84+
}
85+
86+
function balanceOf(address _owner) constant returns (uint256 balance) {
87+
return balances[_owner];
88+
}
89+
90+
function approve(address _spender, uint256 _value) returns (bool success) {
91+
allowed[msg.sender][_spender] = _value;
92+
Approval(msg.sender, _spender, _value);
93+
return true;
94+
}
95+
96+
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
97+
return allowed[_owner][_spender];
98+
}
99+
100+
mapping (address => uint256) balances;
101+
mapping (address => mapping (address => uint256)) allowed;
102+
}
103+
104+
/*
105+
This Token Contract implements the standard token functionality (https://github.com/ethereum/EIPs/issues/20) as well as the following OPTIONAL extras intended for use by humans.
106+
107+
In other words. This is intended for deployment in something like a Token Factory or Mist wallet, and then used by humans.
108+
Imagine coins, currencies, shares, voting weight, etc.
109+
Machine-based, rapid creation of many tokens would not necessarily need these extra features or will be minted in other manners.
110+
111+
1) Initial Finite Supply (upon creation one specifies how much is minted).
112+
2) In the absence of a token registry: Optional Decimal, Symbol & Name.
113+
3) Optional approveAndCall() functionality to notify a contract if an approval() has occurred.
114+
115+
.*/
116+
contract HumanStandardToken is StandardToken {
117+
118+
/* Public variables of the token */
119+
120+
/*
121+
NOTE:
122+
The following variables are OPTIONAL vanities. One does not have to include them.
123+
They allow one to customise the token contract & in no way influences the core functionality.
124+
Some wallets/interfaces might not even bother to look at this information.
125+
*/
126+
string public name; //fancy name: eg Simon Bucks
127+
uint8 public decimals; //How many decimals to show. ie. There could 1000 base units with 3 decimals. Meaning 0.980 SBX = 980 base units. It's like comparing 1 wei to 1 ether.
128+
string public symbol; //An identifier: eg SBX
129+
string public version = 'H0.1'; //human 0.1 standard. Just an arbitrary versioning scheme.
130+
131+
function HumanStandardToken(
132+
uint256 _initialAmount,
133+
string _tokenName,
134+
uint8 _decimalUnits,
135+
string _tokenSymbol
136+
) {
137+
balances[msg.sender] = _initialAmount; // Give the creator all initial tokens
138+
totalSupply = _initialAmount; // Update total supply
139+
name = _tokenName; // Set the name for display purposes
140+
decimals = _decimalUnits; // Amount of decimals for display purposes
141+
symbol = _tokenSymbol; // Set the symbol for display purposes
142+
}
143+
144+
/* Approves and then calls the receiving contract */
145+
function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) {
146+
allowed[msg.sender][_spender] = _value;
147+
Approval(msg.sender, _spender, _value);
148+
149+
//call the receiveApproval function on the contract you want to be notified. This crafts the function signature manually so one doesn't have to include a contract in here just for this.
150+
//receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
151+
//it is assumed that when does this that the call *should* succeed, otherwise one would use vanilla approve instead.
152+
require(_spender.call(bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData));
153+
return true;
154+
}
155+
}

0 commit comments

Comments
 (0)