Skip to content
This repository has been archived by the owner on Dec 16, 2022. It is now read-only.

File split and removing solc warnings #12

Merged
merged 9 commits into from
Mar 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
##
# Project-specific
new_tokens.csv

##
# Pythonic

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# dotenv
.env

# virtualenv
.venv
venv/
ENV/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/

#misc
.pydevproject
.project
136 changes: 45 additions & 91 deletions smart_contract.sol → contracts/ForkDelta.sol
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) {}

/// @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) {}
import "./Token.sol";
import "./SafeMath.sol";

/// @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 {

using SafeMath for uint;

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)
Expand All @@ -75,7 +23,6 @@ contract ForkDelta is SafeMath {
event Deposit(address token, address user, uint amount, uint balance);
event Withdraw(address token, address user, uint amount, uint balance);


modifier isAdmin() {
require(msg.sender == admin);
_;
Expand Down Expand Up @@ -117,15 +64,15 @@ 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);
Copy link
Contributor

Choose a reason for hiding this comment

The 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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we remove the require here?
Why did we change call.value to .transfer throughout?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.
New version: transfer will not return a result, but throw on fail itself, so no require needed

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:

https://consensys.github.io/smart-contract-best-practices/recommendations/#be-aware-of-the-tradeoffs-between-send-transfer-and-callvalue

Copy link
Contributor

Choose a reason for hiding this comment

The 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 {
Expand All @@ -134,9 +81,9 @@ contract ForkDelta is SafeMath {
depositingTokenFlag = true;
require(Token(token).transferFrom(msg.sender, this, amount));
depositingTokenFlag = false;
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]);
}

// Support ERC223 Token.transfer()
function tokenFallback( address sender, uint amount, bytes data) public returns (bool ok) {
Expand All @@ -149,14 +96,13 @@ contract ForkDelta is SafeMath {
revert();
}
}


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]);
}

function balanceOf(address token, address user) public constant returns (uint) {
Expand All @@ -166,7 +112,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 {
Expand All @@ -175,48 +121,56 @@ 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.mul(amount).div(amountGet), user, msg.sender);
}

function tradeBalances(address tokenGet, uint amountGet, address tokenGive, uint amountGive, address user, uint amount) private {

//trades are free until this date in UNIX timestamp
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).div(1 ether);
feeTakeXfer = amount.mul(feeTake).div(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.add(feeTakeXfer));
tokens[tokenGive][user] = tokens[tokenGive][user].sub(amountGive.mul(amount).div(amountGet);
tokens[tokenGive][msg.sender] = tokens[tokenGive][msg.sender].add(amountGive.mul(amount).div(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).div(amountGive);
if (available[0] < available[1]) {
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) {
Expand All @@ -228,6 +182,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);
}
}
}
47 changes: 47 additions & 0 deletions contracts/SafeMath.sol
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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the logic be if a == 0 OR b == 0 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that's true.

return 0;
}
uint256 c = a * b;
require(c / a == b);
return c;
}

/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(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;
}

/**
* @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) {
require(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;
require(c >= a);
return c;
}
}
Loading