-
Notifications
You must be signed in to change notification settings - Fork 68
File split and removing solc warnings #12
Changes from 4 commits
4e494fa
b0e9609
d92f6e4
5d136e7
41d9239
6b8f429
e6e46e9
3f2684e
08068fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,64 +1,12 @@ | ||
pragma solidity ^0.4.20; | ||
pragma solidity ^0.4.21; | ||
|
||
contract SafeMath { | ||
function safeMul(uint a, uint b) pure internal returns (uint) { | ||
uint c = a * b; | ||
assert(a == 0 || c / a == b); | ||
return c; | ||
} | ||
|
||
function safeSub(uint a, uint b) pure internal returns (uint) { | ||
assert(b <= a); | ||
return a - b; | ||
} | ||
|
||
function safeAdd(uint a, uint b) pure internal returns (uint) { | ||
uint c = a + b; | ||
assert(c>=a && c>=b); | ||
return c; | ||
} | ||
} | ||
|
||
contract Token { | ||
/// @return total amount of tokens | ||
function totalSupply() public constant returns (uint256 supply) {} | ||
|
||
/// @param _owner The address from which the balance will be retrieved | ||
/// @return The balance | ||
function balanceOf(address _owner) public constant returns (uint256 balance) {} | ||
|
||
/// @notice send `_value` token to `_to` from `msg.sender` | ||
/// @param _to The address of the recipient | ||
/// @param _value The amount of token to be transferred | ||
/// @return Whether the transfer was successful or not | ||
function transfer(address _to, uint256 _value) public returns (bool success) {} | ||
import "./Token.sol"; | ||
import "./SafeMath.sol"; | ||
|
||
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` | ||
/// @param _from The address of the sender | ||
/// @param _to The address of the recipient | ||
/// @param _value The amount of token to be transferred | ||
/// @return Whether the transfer was successful or not | ||
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {} | ||
contract ForkDelta { | ||
|
||
using SafeMath for uint; | ||
|
||
/// @notice `msg.sender` approves `_addr` to spend `_value` tokens | ||
/// @param _spender The address of the account able to transfer the tokens | ||
/// @param _value The amount of wei to be approved for transfer | ||
/// @return Whether the approval was successful or not | ||
function approve(address _spender, uint256 _value) public returns (bool success) {} | ||
|
||
/// @param _owner The address of the account owning tokens | ||
/// @param _spender The address of the account able to transfer the tokens | ||
/// @return Amount of remaining tokens allowed to spent | ||
function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {} | ||
|
||
event Transfer(address indexed _from, address indexed _to, uint256 _value); | ||
event Approval(address indexed _owner, address indexed _spender, uint256 _value); | ||
|
||
uint public decimals; | ||
string public name; | ||
} | ||
|
||
contract ForkDelta is SafeMath { | ||
address public admin; //the admin address | ||
address public feeAccount; //the account that will receive fees | ||
uint public feeMake; //percentage times (1 ether) | ||
|
@@ -115,31 +63,31 @@ contract ForkDelta is SafeMath { | |
} | ||
|
||
function deposit() public payable { | ||
tokens[0][msg.sender] = safeAdd(tokens[0][msg.sender], msg.value); | ||
Deposit(0, msg.sender, msg.value, tokens[0][msg.sender]); | ||
tokens[0][msg.sender] = tokens[0][msg.sender].add(msg.value); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So much more syntactically pleasing. Good addition. |
||
emit Deposit(0, msg.sender, msg.value, tokens[0][msg.sender]); | ||
} | ||
|
||
function withdraw(uint amount) public { | ||
require(tokens[0][msg.sender] >= amount); | ||
tokens[0][msg.sender] = safeSub(tokens[0][msg.sender], amount); | ||
require(msg.sender.call.value(amount)()); | ||
Withdraw(0, msg.sender, amount, tokens[0][msg.sender]); | ||
tokens[0][msg.sender] = tokens[0][msg.sender].sub(amount); | ||
msg.sender.transfer(amount); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did we remove the require here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Previously: require throws when function returns false, e.g. when not enough eth. You could also say that transfer is safer to use, because you don't have to check the result. Reason for the change: Safety against reentrancy as explained in: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Beautiful. |
||
emit Withdraw(0, msg.sender, amount, tokens[0][msg.sender]); | ||
} | ||
|
||
function depositToken(address token, uint amount) public { | ||
//remember to call Token(address).approve(this, amount) or this contract will not be able to do the transfer on your behalf. | ||
require(token!=0); | ||
require(Token(token).transferFrom(msg.sender, this, amount)); | ||
tokens[token][msg.sender] = safeAdd(tokens[token][msg.sender], amount); | ||
Deposit(token, msg.sender, amount, tokens[token][msg.sender]); | ||
tokens[token][msg.sender] = tokens[token][msg.sender].add(amount); | ||
emit Deposit(token, msg.sender, amount, tokens[token][msg.sender]); | ||
} | ||
|
||
function withdrawToken(address token, uint amount) public { | ||
require(token!=0); | ||
require(tokens[token][msg.sender] >= amount); | ||
tokens[token][msg.sender] = safeSub(tokens[token][msg.sender], amount); | ||
tokens[token][msg.sender] = tokens[token][msg.sender].sub(amount); | ||
require(Token(token).transfer(msg.sender, amount)); | ||
Withdraw(token, msg.sender, amount, tokens[token][msg.sender]); | ||
emit Withdraw(token, msg.sender, amount, tokens[token][msg.sender]); | ||
} | ||
|
||
//support ERC223 | ||
|
@@ -154,7 +102,7 @@ contract ForkDelta is SafeMath { | |
function order(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce) public { | ||
bytes32 hash = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce); | ||
orders[msg.sender][hash] = true; | ||
Order(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, msg.sender); | ||
emit Order(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, msg.sender); | ||
} | ||
|
||
function trade(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s, uint amount) public { | ||
|
@@ -163,11 +111,11 @@ contract ForkDelta is SafeMath { | |
require(( | ||
(orders[user][hash] || ecrecover(keccak256("\x19Ethereum Signed Message:\n32", hash),v,r,s) == user) && | ||
block.number <= expires && | ||
safeAdd(orderFills[user][hash], amount) <= amountGet | ||
orderFills[user][hash].add(amount) <= amountGet | ||
)); | ||
tradeBalances(tokenGet, amountGet, tokenGive, amountGive, user, amount); | ||
orderFills[user][hash] = safeAdd(orderFills[user][hash], amount); | ||
Trade(tokenGet, amount, tokenGive, amountGive * amount / amountGet, user, msg.sender); | ||
orderFills[user][hash] = orderFills[user][hash].add(amount); | ||
emit Trade(tokenGet, amount, tokenGive, amountGive * amount / amountGet, user, msg.sender); | ||
} | ||
|
||
function tradeBalances(address tokenGet, uint amountGet, address tokenGive, uint amountGive, address user, uint amount) private { | ||
|
@@ -176,35 +124,45 @@ contract ForkDelta is SafeMath { | |
uint feeMakeXfer = 0; | ||
uint feeTakeXfer = 0; | ||
if (now >= freeUntilDate) { | ||
feeMakeXfer = safeMul(amount, feeMake) / (1 ether); | ||
feeTakeXfer = safeMul(amount, feeTake) / (1 ether); | ||
feeMakeXfer = amount.mul(feeMake) / (1 ether); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need a SafeMath division? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No. Dividing by 1 ether will never result in an overflow. |
||
feeTakeXfer = amount.mul(feeTake) / (1 ether); | ||
} | ||
|
||
tokens[tokenGet][msg.sender] = safeSub(tokens[tokenGet][msg.sender], safeAdd(amount, feeTakeXfer)); | ||
tokens[tokenGet][user] = safeAdd(tokens[tokenGet][user], safeSub(amount, feeMakeXfer)); | ||
tokens[tokenGet][feeAccount] = safeAdd(tokens[tokenGet][feeAccount], safeAdd(feeMakeXfer, feeTakeXfer)); | ||
tokens[tokenGive][user] = safeSub(tokens[tokenGive][user], safeMul(amountGive, amount) / amountGet); | ||
tokens[tokenGive][msg.sender] = safeAdd(tokens[tokenGive][msg.sender], safeMul(amountGive, amount) / amountGet); | ||
tokens[tokenGet][msg.sender] = tokens[tokenGet][msg.sender].sub(amount.add(feeTakeXfer)); | ||
tokens[tokenGet][user] = tokens[tokenGet][user].add(amount.sub(feeMakeXfer)); | ||
tokens[tokenGet][feeAccount] = tokens[tokenGet][feeAccount].add(feeMakeXfer.sub(feeTakeXfer)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whoops, typo:
Should be
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ups.. Will fix. |
||
tokens[tokenGive][user] = tokens[tokenGive][user].sub(amountGive.mul(amount) / amountGet); | ||
tokens[tokenGive][user] = tokens[tokenGive][user].sub(amountGive.mul(amount) / amountGet); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicate line. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ups. Will fix. |
||
tokens[tokenGive][msg.sender] = tokens[tokenGive][msg.sender].add(amountGive.mul(amount) / amountGet); | ||
} | ||
|
||
function testTrade(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s, uint amount, address sender) public constant returns(bool) { | ||
if (!( | ||
tokens[tokenGet][sender] >= amount && | ||
availableVolume(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, user, v, r, s) >= amount | ||
)) return false; | ||
return true; | ||
)) { | ||
return false; | ||
} else { | ||
return true; | ||
} | ||
} | ||
|
||
function availableVolume(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s) public constant returns(uint) { | ||
bytes32 hash = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce); | ||
if (!( | ||
(orders[user][hash] || ecrecover(keccak256("\x19Ethereum Signed Message:\n32", hash),v,r,s) == user) && | ||
block.number <= expires | ||
)) return 0; | ||
uint available1 = safeSub(amountGet, orderFills[user][hash]); | ||
uint available2 = safeMul(tokens[tokenGive][user], amountGet) / amountGive; | ||
if (available1<available2) return available1; | ||
return available2; | ||
)) { | ||
return 0; | ||
} | ||
uint[2] memory available; | ||
available[0] = amountGet.sub(orderFills[user][hash]); | ||
available[1] = tokens[tokenGive][user].mul(amountGet) / amountGive; | ||
if (available[0]<available[1]) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's make this |
||
return available[0]; | ||
} else { | ||
return available[1]; | ||
} | ||
} | ||
|
||
function amountFilled(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s) public constant returns(uint) { | ||
|
@@ -216,6 +174,6 @@ contract ForkDelta is SafeMath { | |
bytes32 hash = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce); | ||
require ((orders[msg.sender][hash] || ecrecover(keccak256("\x19Ethereum Signed Message:\n32", hash),v,r,s) == msg.sender)); | ||
orderFills[msg.sender][hash] = amountGet; | ||
Cancel(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, msg.sender, v, r, s); | ||
emit Cancel(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, msg.sender, v, r, s); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
pragma solidity ^0.4.21; | ||
|
||
/** | ||
* @title SafeMath | ||
* @dev Math operations with safety checks that throw on error | ||
*/ | ||
library SafeMath { | ||
|
||
/** | ||
* @dev Multiplies two numbers, throws on overflow. | ||
*/ | ||
function mul(uint256 a, uint256 b) internal pure returns (uint256) { | ||
if (a == 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should the logic be if a == 0 OR b == 0 ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SafeMath.sol is from https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/math/SafeMath.sol They kind of know what they are doing, at least much better than I do. Regarding your comment, no, for the check that follows it's only vital that a is not 0. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, if either A or B is 0, the function will return 0. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but if a is 0 the function would in fact throw an division by zero exception. In contrast to b = 0. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess that's true. |
||
return 0; | ||
} | ||
uint256 c = a * b; | ||
assert(c / a == b); | ||
return c; | ||
} | ||
|
||
/** | ||
* @dev Integer division of two numbers, truncating the quotient. | ||
*/ | ||
function div(uint256 a, uint256 b) internal pure returns (uint256) { | ||
// assert(b > 0); // Solidity automatically throws when dividing by 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't want a throw; here do we? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, Solidity will automatically throw/revert on division by zero. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it revert or does it throw? Very different outcomes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From the solidity docs: An assert-style exception is generated in the following situations: So, the OpenZeppelin removed the assert, because it is implicitly done by solidity already. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be better to revert? Save users gas if you can? |
||
uint256 c = a / b; | ||
// assert(a == b * c + a % b); // There is no case in which this doesn't hold | ||
return c; | ||
} | ||
|
||
/** | ||
* @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). | ||
*/ | ||
function sub(uint256 a, uint256 b) internal pure returns (uint256) { | ||
assert(b <= a); | ||
return a - b; | ||
} | ||
|
||
/** | ||
* @dev Adds two numbers, throws on overflow. | ||
*/ | ||
function add(uint256 a, uint256 b) internal pure returns (uint256) { | ||
uint256 c = a + b; | ||
assert(c >= a); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think the contract should revert if you add by 0? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No. :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
"assert(false) compiles to 0xfe, which is an invalid opcode, using up all remaining gas, and reverting all changes. require(false) compiles to 0xfd which is the REVERT opcode, meaning it will refund the remaining gas. The opcode can also return a value (useful for debugging), but I don't believe that is supported in Solidity as of this moment. (2017-11-21)"
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @betterdelta Thoughts on this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Re 1.): You are in opposition to https://solidity.readthedocs.io/en/develop/control-structures.html#error-handling-assert-require-revert-and-exceptions: "The assert function should only be used to test for internal errors, and to check invariants. The require function should be used to ensure valid conditions, such as inputs, or contract state variables are met, or to validate return values from calls to external contracts. If used properly, analysis tools can evaluate your contract to identify the conditions and function calls which will reach a failing assert. Properly functioning code should never reach a failing assert statement; if this happens there is a bug in your contract which you should fix." Re 2: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
return c; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
pragma solidity ^0.4.21; | ||
|
||
contract Token { | ||
/// @return total amount of tokens | ||
function totalSupply() public constant returns (uint256 supply) {} | ||
|
||
/// @param _owner The address from which the balance will be retrieved | ||
/// @return The balance | ||
function balanceOf(address _owner) public constant returns (uint256 balance) {} | ||
|
||
/// @notice send `_value` token to `_to` from `msg.sender` | ||
/// @param _to The address of the recipient | ||
/// @param _value The amount of token to be transferred | ||
/// @return Whether the transfer was successful or not | ||
function transfer(address _to, uint256 _value) public returns (bool success) {} | ||
|
||
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` | ||
/// @param _from The address of the sender | ||
/// @param _to The address of the recipient | ||
/// @param _value The amount of token to be transferred | ||
/// @return Whether the transfer was successful or not | ||
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {} | ||
|
||
/// @notice `msg.sender` approves `_addr` to spend `_value` tokens | ||
/// @param _spender The address of the account able to transfer the tokens | ||
/// @param _value The amount of wei to be approved for transfer | ||
/// @return Whether the approval was successful or not | ||
function approve(address _spender, uint256 _value) public returns (bool success) {} | ||
|
||
/// @param _owner The address of the account owning tokens | ||
/// @param _spender The address of the account able to transfer the tokens | ||
/// @return Amount of remaining tokens allowed to spent | ||
function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {} | ||
|
||
event Transfer(address indexed _from, address indexed _to, uint256 _value); | ||
event Approval(address indexed _owner, address indexed _spender, uint256 _value); | ||
|
||
uint public decimals; | ||
string public name; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<3