Skip to content

Instantly share code, notes, and snippets.

@j-w-yun
Created April 3, 2019 01:19
Show Gist options
  • Save j-w-yun/5db95a5ebfb8855bdf9919784b1e01a7 to your computer and use it in GitHub Desktop.
Save j-w-yun/5db95a5ebfb8855bdf9919784b1e01a7 to your computer and use it in GitHub Desktop.
Check later
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