Created
April 3, 2019 01:19
-
-
Save j-w-yun/5db95a5ebfb8855bdf9919784b1e01a7 to your computer and use it in GitHub Desktop.
Check later
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.16; | |
contract Token { | |
// ERC-20 token standard interface | |
function totalSupply() public view returns (uint); | |
function balanceOf(address tokenOwner) public view returns (uint balance); | |
function allowance(address tokenOwner, address spender) public view returns (uint remaining); | |
function transfer(address to, uint tokens) public returns (bool success); | |
function approve(address spender, uint tokens) public returns (bool success); | |
function transferFrom(address from, address to, uint tokens) public returns (bool success); | |
event Transfer(address indexed from, address indexed to, uint tokens); | |
event Approval(address indexed tokenOwner, address indexed spender, uint tokens); | |
} | |
contract Exchange { | |
// Set in constructor but modifiable | |
address public owner; | |
address public fee_account; | |
uint256 public inactivity_release_period; | |
// Controls onlyAdmin modifier | |
mapping (address => bool) public admins; | |
// Mapping of token contract addresses to the mapping of account addresses to the token balance of that account | |
mapping (address => mapping (address => uint256)) public tokens; | |
mapping (bytes32 => uint256) public filled_orders; | |
mapping (address => uint256) public user_last_invalid_order_nonce; | |
mapping (address => uint256) public user_last_transaction_block; | |
mapping (bytes32 => bool) public traded; | |
mapping (bytes32 => bool) public withdrawn; | |
// Events | |
event Deposit(address token, address user, uint256 amount, uint256 balance); | |
event Withdraw(address token, address user, uint256 amount, uint256 balance); | |
function safeMul(uint a, uint b) returns (uint) { | |
uint c = a * b; | |
if (!(a == 0 || c / a == b)) | |
throw; | |
return c; | |
} | |
function safeSub(uint a, uint b) returns (uint) { | |
if (!(b <= a)) | |
throw; | |
return a - b; | |
} | |
function safeAdd(uint a, uint b) returns (uint) { | |
uint c = a + b; | |
if (!(c >= a && c >= b)) | |
throw; | |
return c; | |
} | |
modifier onlyOwner { | |
if (msg.sender != owner) | |
throw; | |
_; | |
} | |
modifier onlyAdmin { | |
if (msg.sender != owner && !admins[msg.sender]) | |
throw; | |
_; | |
} | |
function Exchange(address _fee_account) { | |
owner = msg.sender; | |
fee_account = _fee_account; | |
inactivity_release_period = 100000; | |
} | |
function() external { | |
throw; | |
} | |
function setOwner(address _owner) onlyOwner { | |
owner = _owner; | |
} | |
function setAdmin(address _admin, bool _is_admin) onlyOwner { | |
admins[_admin] = _is_admin; | |
} | |
function setInactivityReleasePeriod(uint256 _expiry) onlyAdmin { | |
if (_expiry > 1000000) | |
throw; | |
inactivity_release_period = _expiry; | |
} | |
function invalidateNonce(address _user, uint256 _nonce) onlyAdmin { | |
if (_nonce < user_last_invalid_order_nonce[_user]) | |
throw; | |
user_last_invalid_order_nonce[_user] = _nonce; | |
} | |
function balanceOf(address _token, address _user) constant returns (uint256) { | |
return tokens[_token][_user]; | |
} | |
function deposit() payable { | |
tokens[address(0)][msg.sender] = safeAdd(tokens[address(0)][msg.sender], msg.value); | |
user_last_transaction_block[msg.sender] = block.number; | |
Deposit(address(0), msg.sender, msg.value, tokens[address(0)][msg.sender]); | |
} | |
function depositToken(address _token, uint256 _amount) { | |
tokens[_token][msg.sender] = safeAdd(tokens[_token][msg.sender], _amount); | |
user_last_transaction_block[msg.sender] = block.number; | |
if (!Token(_token).transferFrom(msg.sender, this, _amount)) | |
throw; | |
Deposit(_token, msg.sender, _amount, tokens[_token][msg.sender]); | |
} | |
function withdraw(address _token, uint256 _amount) { | |
if (safeSub(block.number, user_last_transaction_block[msg.sender]) < inactivity_release_period) | |
throw; | |
if (tokens[_token][msg.sender] < _amount) | |
throw; | |
tokens[_token][msg.sender] = safeSub(tokens[_token][msg.sender], _amount); | |
if (_token == address(0)) { | |
if (!msg.sender.send(_amount)) | |
throw; | |
} else { | |
if (!Token(_token).transfer(msg.sender, _amount)) | |
throw; | |
} | |
Withdraw(_token, msg.sender, _amount, tokens[_token][msg.sender]); | |
} | |
function adminWithdraw(address _token, uint256 _amount, address _user, uint256 _nonce, uint8 _v, bytes32 _r, bytes32 _s, uint256 _withdraw_fee) onlyAdmin { | |
bytes32 hash = keccak256(this, _token, _amount, _user, _nonce); | |
if (withdrawn[hash]) | |
throw; | |
withdrawn[hash] = true; | |
if (ecrecover(keccak256("\x19Ethereum Signed Message:\n32", hash), _v, _r, _s) != _user) | |
throw; | |
if (_withdraw_fee > 50 finney) | |
_withdraw_fee = 50 finney; | |
if (tokens[_token][_user] < _amount) | |
throw; | |
tokens[_token][_user] = safeSub( | |
tokens[_token][_user], | |
_amount | |
); | |
tokens[_token][fee_account] = safeAdd( | |
tokens[_token][fee_account], | |
safeMul(_withdraw_fee, _amount) / 1 ether | |
); | |
_amount = safeMul((1 ether - _withdraw_fee), _amount) / 1 ether; | |
if (_token == address(0)) { | |
if (!_user.send(_amount)) | |
throw; | |
} else { | |
if (!Token(_token).transfer(_user, _amount)) | |
throw; | |
} | |
user_last_transaction_block[_user] = block.number; | |
Withdraw(_token, _user, _amount, tokens[_token][_user]); | |
} | |
function trade(uint256[8] _trade_values, address[4] _trade_addresses, uint8[2] _v, bytes32[2] _r, bytes32[2] _s) onlyAdmin { | |
// Unit of _trade_amount is in _buy_amount terms | |
uint256 _buy_amount = _trade_values[0]; | |
uint256 _sell_amount = _trade_values[1]; | |
uint256 _order_expires = _trade_values[2]; | |
uint256 _order_nonce = _trade_values[3]; | |
uint256 _trade_amount = _trade_values[4]; | |
uint256 _trade_nonce = _trade_values[5]; | |
uint256 _maker_fee = _trade_values[6]; | |
uint256 _taker_fee = _trade_values[7]; | |
address _token_to_buy = _trade_addresses[0]; | |
address _token_to_sell = _trade_addresses[1]; | |
address _maker_account = _trade_addresses[2]; | |
address _taker_account = _trade_addresses[3]; | |
if (user_last_invalid_order_nonce[_maker_account] > _order_nonce) | |
throw; | |
bytes32 order_hash = keccak256(this, _token_to_buy, _buy_amount, _token_to_sell, _sell_amount, _order_expires, _order_nonce, _maker_account); | |
if (ecrecover(keccak256("\x19Ethereum Signed Message:\n32", order_hash), _v[0], _r[0], _s[0]) != _maker_account) | |
throw; | |
bytes32 trade_hash = keccak256(order_hash, _trade_amount, _taker_account, _trade_nonce); | |
if (ecrecover(keccak256("\x19Ethereum Signed Message:\n32", trade_hash), _v[1], _r[1], _s[1]) != _taker_account) | |
throw; | |
if (traded[trade_hash]) | |
throw; | |
traded[trade_hash] = true; | |
if (_maker_fee > 100 finney) | |
_maker_fee = 100 finney; | |
if (_taker_fee > 100 finney) | |
_taker_fee = 100 finney; | |
if (safeAdd(filled_orders[order_hash], _trade_amount) > _buy_amount) | |
throw; | |
if (tokens[_token_to_buy][_taker_account] < _trade_amount) | |
throw; | |
if (tokens[_token_to_sell][_maker_account] < (safeMul(_sell_amount, _trade_amount) / _buy_amount)) | |
throw; | |
tokens[_token_to_buy][_taker_account] = safeSub( | |
tokens[_token_to_buy][_taker_account], | |
_trade_amount | |
); | |
tokens[_token_to_buy][_maker_account] = safeAdd( | |
tokens[_token_to_buy][_maker_account], | |
safeMul(_trade_amount, ((1 ether) - _maker_fee)) / (1 ether) | |
); | |
tokens[_token_to_buy][fee_account] = safeAdd( | |
tokens[_token_to_buy][fee_account], | |
safeMul(_trade_amount, _maker_fee) / (1 ether) | |
); | |
tokens[_token_to_sell][_maker_account] = safeSub( | |
tokens[_token_to_sell][_maker_account], | |
safeMul(_sell_amount, _trade_amount) / _buy_amount | |
); | |
tokens[_token_to_sell][_taker_account] = safeAdd( | |
tokens[_token_to_sell][_taker_account], | |
safeMul(safeMul(((1 ether) - _taker_fee), _sell_amount), _trade_amount) / _buy_amount / (1 ether) | |
); | |
tokens[_token_to_sell][fee_account] = safeAdd( | |
tokens[_token_to_sell][fee_account], | |
safeMul(safeMul(_taker_fee, _sell_amount), _trade_amount) / _buy_amount / (1 ether) | |
); | |
filled_orders[order_hash] = safeAdd(filled_orders[order_hash], _trade_amount); | |
user_last_transaction_block[_maker_account] = block.number; | |
user_last_transaction_block[_taker_account] = block.number; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment