UNPKG

dx-mgn-pool

Version:

Smart contracts and migration scripts for the MGN-pool for trading at the dutch-Exchange

1,390 lines (1,193 loc) 54.7 kB
pragma solidity ^0.5.2; // File: /home/josojo/gnosis/dx-mgn-pool/node_modules/openzeppelin-solidity/contracts/token/ERC20/IERC20.sol /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ interface IERC20 { function transfer(address to, uint256 value) external returns (bool); function approve(address spender, uint256 value) external returns (bool); function transferFrom(address from, address to, uint256 value) external returns (bool); function totalSupply() external view returns (uint256); function balanceOf(address who) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol /** * @title Standard ERC20 token * * @dev Implementation of the basic standard token. * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md * Originally based on code by FirstBlood: * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol * * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for * all accounts just by listening to said events. Note that this isn't required by the specification, and other * compliant implementations may not do it. */ contract ERC20 is IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowed; uint256 private _totalSupply; /** * @dev Total number of tokens in existence */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev Gets the balance of the specified address. * @param owner The address to query the balance of. * @return An uint256 representing the amount owned by the passed address. */ function balanceOf(address owner) public view returns (uint256) { return _balances[owner]; } /** * @dev Function to check the amount of tokens that an owner allowed to a spender. * @param owner address The address which owns the funds. * @param spender address The address which will spend the funds. * @return A uint256 specifying the amount of tokens still available for the spender. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowed[owner][spender]; } /** * @dev Transfer token for a specified address * @param to The address to transfer to. * @param value The amount to be transferred. */ function transfer(address to, uint256 value) public returns (bool) { _transfer(msg.sender, to, value); return true; } /** * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. * Beware that changing an allowance with this method brings the risk that someone may use both the old * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. */ function approve(address spender, uint256 value) public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = value; emit Approval(msg.sender, spender, value); return true; } /** * @dev Transfer tokens from one address to another. * Note that while this function emits an Approval event, this is not required as per the specification, * and other compliant implementations may not emit the event. * @param from address The address which you want to send tokens from * @param to address The address which you want to transfer to * @param value uint256 the amount of tokens to be transferred */ function transferFrom(address from, address to, uint256 value) public returns (bool) { _allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value); _transfer(from, to, value); emit Approval(from, msg.sender, _allowed[from][msg.sender]); return true; } /** * @dev Increase the amount of tokens that an owner allowed to a spender. * approve should be called when allowed_[_spender] == 0. To increment * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * Emits an Approval event. * @param spender The address which will spend the funds. * @param addedValue The amount of tokens to increase the allowance by. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = _allowed[msg.sender][spender].add(addedValue); emit Approval(msg.sender, spender, _allowed[msg.sender][spender]); return true; } /** * @dev Decrease the amount of tokens that an owner allowed to a spender. * approve should be called when allowed_[_spender] == 0. To decrement * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * Emits an Approval event. * @param spender The address which will spend the funds. * @param subtractedValue The amount of tokens to decrease the allowance by. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { require(spender != address(0)); _allowed[msg.sender][spender] = _allowed[msg.sender][spender].sub(subtractedValue); emit Approval(msg.sender, spender, _allowed[msg.sender][spender]); return true; } /** * @dev Transfer token for a specified addresses * @param from The address to transfer from. * @param to The address to transfer to. * @param value The amount to be transferred. */ function _transfer(address from, address to, uint256 value) internal { require(to != address(0)); _balances[from] = _balances[from].sub(value); _balances[to] = _balances[to].add(value); emit Transfer(from, to, value); } /** * @dev Internal function that mints an amount of the token and assigns it to * an account. This encapsulates the modification of balances such that the * proper events are emitted. * @param account The account that will receive the created tokens. * @param value The amount that will be created. */ function _mint(address account, uint256 value) internal { require(account != address(0)); _totalSupply = _totalSupply.add(value); _balances[account] = _balances[account].add(value); emit Transfer(address(0), account, value); } /** * @dev Internal function that burns an amount of the token of a given * account. * @param account The account whose tokens will be burnt. * @param value The amount that will be burnt. */ function _burn(address account, uint256 value) internal { require(account != address(0)); _totalSupply = _totalSupply.sub(value); _balances[account] = _balances[account].sub(value); emit Transfer(account, address(0), value); } /** * @dev Internal function that burns an amount of the token of a given * account, deducting from the sender's allowance for said account. Uses the * internal burn function. * Emits an Approval event (reflecting the reduced allowance). * @param account The account whose tokens will be burnt. * @param value The amount that will be burnt. */ function _burnFrom(address account, uint256 value) internal { _allowed[account][msg.sender] = _allowed[account][msg.sender].sub(value); _burn(account, value); emit Approval(account, msg.sender, _allowed[account][msg.sender]); } } // File: openzeppelin-solidity/contracts/ownership/Ownable.sol /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". */ contract Ownable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor () internal { _owner = msg.sender; emit OwnershipTransferred(address(0), _owner); } /** * @return the address of the owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner()); _; } /** * @return true if `msg.sender` is the owner of the contract. */ function isOwner() public view returns (bool) { return msg.sender == _owner; } /** * @dev Allows the current owner to relinquish control of the contract. * @notice Renouncing to ownership will leave the contract without an owner. * It will not be possible to call the functions with the `onlyOwner` * modifier anymore. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0)); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } // File: openzeppelin-solidity/contracts/math/SafeMath.sol /** * @title SafeMath * @dev Unsigned math operations with safety checks that revert on error */ library SafeMath { /** * @dev Multiplies two unsigned integers, reverts on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b); return c; } /** * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a); uint256 c = a - b; return c; } /** * @dev Adds two unsigned integers, reverts on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a); return c; } /** * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), * reverts when dividing by zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0); return a % b; } } // File: @gnosis.pm/mock-contract/contracts/MockContract.sol interface MockInterface { /** * @dev After calling this method, the mock will return `response` when it is called * with any calldata that is not mocked more specifically below * (e.g. using givenMethodReturn). * @param response ABI encoded response that will be returned if method is invoked */ function givenAnyReturn(bytes calldata response) external; function givenAnyReturnBool(bool response) external; function givenAnyReturnUint(uint response) external; function givenAnyReturnAddress(address response) external; function givenAnyRevert() external; function givenAnyRevertWithMessage(string calldata message) external; function givenAnyRunOutOfGas() external; /** * @dev After calling this method, the mock will return `response` when the given * methodId is called regardless of arguments. If the methodId and arguments * are mocked more specifically (using `givenMethodAndArguments`) the latter * will take precedence. * @param method ABI encoded methodId. It is valid to pass full calldata (including arguments). The mock will extract the methodId from it * @param response ABI encoded response that will be returned if method is invoked */ function givenMethodReturn(bytes calldata method, bytes calldata response) external; function givenMethodReturnBool(bytes calldata method, bool response) external; function givenMethodReturnUint(bytes calldata method, uint response) external; function givenMethodReturnAddress(bytes calldata method, address response) external; function givenMethodRevert(bytes calldata method) external; function givenMethodRevertWithMessage(bytes calldata method, string calldata message) external; function givenMethodRunOutOfGas(bytes calldata method) external; /** * @dev After calling this method, the mock will return `response` when the given * methodId is called with matching arguments. These exact calldataMocks will take * precedence over all other calldataMocks. * @param call ABI encoded calldata (methodId and arguments) * @param response ABI encoded response that will be returned if contract is invoked with calldata */ function givenCalldataReturn(bytes calldata call, bytes calldata response) external; function givenCalldataReturnBool(bytes calldata call, bool response) external; function givenCalldataReturnUint(bytes calldata call, uint response) external; function givenCalldataReturnAddress(bytes calldata call, address response) external; function givenCalldataRevert(bytes calldata call) external; function givenCalldataRevertWithMessage(bytes calldata call, string calldata message) external; function givenCalldataRunOutOfGas(bytes calldata call) external; /** * @dev Returns the number of times anything has been called on this mock since last reset */ function invocationCount() external returns (uint); /** * @dev Returns the number of times the given method has been called on this mock since last reset * @param method ABI encoded methodId. It is valid to pass full calldata (including arguments). The mock will extract the methodId from it */ function invocationCountForMethod(bytes calldata method) external returns (uint); /** * @dev Returns the number of times this mock has been called with the exact calldata since last reset. * @param call ABI encoded calldata (methodId and arguments) */ function invocationCountForCalldata(bytes calldata call) external returns (uint); /** * @dev Resets all mocked methods and invocation counts. */ function reset() external; } /** * Implementation of the MockInterface. */ contract MockContract is MockInterface { enum MockType { Return, Revert, OutOfGas } bytes32 public constant MOCKS_LIST_START = hex"01"; bytes public constant MOCKS_LIST_END = "0xff"; bytes32 public constant MOCKS_LIST_END_HASH = keccak256(MOCKS_LIST_END); bytes4 public constant SENTINEL_ANY_MOCKS = hex"01"; // A linked list allows easy iteration and inclusion checks mapping(bytes32 => bytes) calldataMocks; mapping(bytes => MockType) calldataMockTypes; mapping(bytes => bytes) calldataExpectations; mapping(bytes => string) calldataRevertMessage; mapping(bytes32 => uint) calldataInvocations; mapping(bytes4 => bytes4) methodIdMocks; mapping(bytes4 => MockType) methodIdMockTypes; mapping(bytes4 => bytes) methodIdExpectations; mapping(bytes4 => string) methodIdRevertMessages; mapping(bytes32 => uint) methodIdInvocations; MockType fallbackMockType; bytes fallbackExpectation; string fallbackRevertMessage; uint invocations; uint resetCount; constructor() public { calldataMocks[MOCKS_LIST_START] = MOCKS_LIST_END; methodIdMocks[SENTINEL_ANY_MOCKS] = SENTINEL_ANY_MOCKS; } function trackCalldataMock(bytes memory call) private { bytes32 callHash = keccak256(call); if (calldataMocks[callHash].length == 0) { calldataMocks[callHash] = calldataMocks[MOCKS_LIST_START]; calldataMocks[MOCKS_LIST_START] = call; } } function trackMethodIdMock(bytes4 methodId) private { if (methodIdMocks[methodId] == 0x0) { methodIdMocks[methodId] = methodIdMocks[SENTINEL_ANY_MOCKS]; methodIdMocks[SENTINEL_ANY_MOCKS] = methodId; } } function _givenAnyReturn(bytes memory response) internal { fallbackMockType = MockType.Return; fallbackExpectation = response; } function givenAnyReturn(bytes calldata response) external { _givenAnyReturn(response); } function givenAnyReturnBool(bool response) external { uint flag = response ? 1 : 0; _givenAnyReturn(uintToBytes(flag)); } function givenAnyReturnUint(uint response) external { _givenAnyReturn(uintToBytes(response)); } function givenAnyReturnAddress(address response) external { _givenAnyReturn(uintToBytes(uint(response))); } function givenAnyRevert() external { fallbackMockType = MockType.Revert; fallbackRevertMessage = ""; } function givenAnyRevertWithMessage(string calldata message) external { fallbackMockType = MockType.Revert; fallbackRevertMessage = message; } function givenAnyRunOutOfGas() external { fallbackMockType = MockType.OutOfGas; } function _givenCalldataReturn(bytes memory call, bytes memory response) private { calldataMockTypes[call] = MockType.Return; calldataExpectations[call] = response; trackCalldataMock(call); } function givenCalldataReturn(bytes calldata call, bytes calldata response) external { _givenCalldataReturn(call, response); } function givenCalldataReturnBool(bytes calldata call, bool response) external { uint flag = response ? 1 : 0; _givenCalldataReturn(call, uintToBytes(flag)); } function givenCalldataReturnUint(bytes calldata call, uint response) external { _givenCalldataReturn(call, uintToBytes(response)); } function givenCalldataReturnAddress(bytes calldata call, address response) external { _givenCalldataReturn(call, uintToBytes(uint(response))); } function _givenMethodReturn(bytes memory call, bytes memory response) private { bytes4 method = bytesToBytes4(call); methodIdMockTypes[method] = MockType.Return; methodIdExpectations[method] = response; trackMethodIdMock(method); } function givenMethodReturn(bytes calldata call, bytes calldata response) external { _givenMethodReturn(call, response); } function givenMethodReturnBool(bytes calldata call, bool response) external { uint flag = response ? 1 : 0; _givenMethodReturn(call, uintToBytes(flag)); } function givenMethodReturnUint(bytes calldata call, uint response) external { _givenMethodReturn(call, uintToBytes(response)); } function givenMethodReturnAddress(bytes calldata call, address response) external { _givenMethodReturn(call, uintToBytes(uint(response))); } function givenCalldataRevert(bytes calldata call) external { calldataMockTypes[call] = MockType.Revert; calldataRevertMessage[call] = ""; trackCalldataMock(call); } function givenMethodRevert(bytes calldata call) external { bytes4 method = bytesToBytes4(call); methodIdMockTypes[method] = MockType.Revert; trackMethodIdMock(method); } function givenCalldataRevertWithMessage(bytes calldata call, string calldata message) external { calldataMockTypes[call] = MockType.Revert; calldataRevertMessage[call] = message; trackCalldataMock(call); } function givenMethodRevertWithMessage(bytes calldata call, string calldata message) external { bytes4 method = bytesToBytes4(call); methodIdMockTypes[method] = MockType.Revert; methodIdRevertMessages[method] = message; trackMethodIdMock(method); } function givenCalldataRunOutOfGas(bytes calldata call) external { calldataMockTypes[call] = MockType.OutOfGas; trackCalldataMock(call); } function givenMethodRunOutOfGas(bytes calldata call) external { bytes4 method = bytesToBytes4(call); methodIdMockTypes[method] = MockType.OutOfGas; trackMethodIdMock(method); } function invocationCount() external returns (uint) { return invocations; } function invocationCountForMethod(bytes calldata call) external returns (uint) { bytes4 method = bytesToBytes4(call); return methodIdInvocations[keccak256(abi.encodePacked(resetCount, method))]; } function invocationCountForCalldata(bytes calldata call) external returns (uint) { return calldataInvocations[keccak256(abi.encodePacked(resetCount, call))]; } function reset() external { // Reset all exact calldataMocks bytes memory nextMock = calldataMocks[MOCKS_LIST_START]; bytes32 mockHash = keccak256(nextMock); // We cannot compary bytes while(mockHash != MOCKS_LIST_END_HASH) { // Reset all mock maps calldataMockTypes[nextMock] = MockType.Return; calldataExpectations[nextMock] = hex""; calldataRevertMessage[nextMock] = ""; // Set next mock to remove nextMock = calldataMocks[mockHash]; // Remove from linked list calldataMocks[mockHash] = ""; // Update mock hash mockHash = keccak256(nextMock); } // Clear list calldataMocks[MOCKS_LIST_START] = MOCKS_LIST_END; // Reset all any calldataMocks bytes4 nextAnyMock = methodIdMocks[SENTINEL_ANY_MOCKS]; while(nextAnyMock != SENTINEL_ANY_MOCKS) { bytes4 currentAnyMock = nextAnyMock; methodIdMockTypes[currentAnyMock] = MockType.Return; methodIdExpectations[currentAnyMock] = hex""; methodIdRevertMessages[currentAnyMock] = ""; nextAnyMock = methodIdMocks[currentAnyMock]; // Remove from linked list methodIdMocks[currentAnyMock] = 0x0; } // Clear list methodIdMocks[SENTINEL_ANY_MOCKS] = SENTINEL_ANY_MOCKS; fallbackExpectation = ""; fallbackMockType = MockType.Return; invocations = 0; resetCount += 1; } function useAllGas() private { while(true) { bool s; assembly { //expensive call to EC multiply contract s := call(sub(gas, 2000), 6, 0, 0x0, 0xc0, 0x0, 0x60) } } } function bytesToBytes4(bytes memory b) private pure returns (bytes4) { bytes4 out; for (uint i = 0; i < 4; i++) { out |= bytes4(b[i] & 0xFF) >> (i * 8); } return out; } function uintToBytes(uint256 x) private pure returns (bytes memory b) { b = new bytes(32); assembly { mstore(add(b, 32), x) } } function updateInvocationCount(bytes4 methodId, bytes memory originalMsgData) public { require(msg.sender == address(this), "Can only be called from the contract itself"); invocations += 1; methodIdInvocations[keccak256(abi.encodePacked(resetCount, methodId))] += 1; calldataInvocations[keccak256(abi.encodePacked(resetCount, originalMsgData))] += 1; } function() payable external { bytes4 methodId; assembly { methodId := calldataload(0) } // First, check exact matching overrides if (calldataMockTypes[msg.data] == MockType.Revert) { revert(calldataRevertMessage[msg.data]); } if (calldataMockTypes[msg.data] == MockType.OutOfGas) { useAllGas(); } bytes memory result = calldataExpectations[msg.data]; // Then check method Id overrides if (result.length == 0) { if (methodIdMockTypes[methodId] == MockType.Revert) { revert(methodIdRevertMessages[methodId]); } if (methodIdMockTypes[methodId] == MockType.OutOfGas) { useAllGas(); } result = methodIdExpectations[methodId]; } // Last, use the fallback override if (result.length == 0) { if (fallbackMockType == MockType.Revert) { revert(fallbackRevertMessage); } if (fallbackMockType == MockType.OutOfGas) { useAllGas(); } result = fallbackExpectation; } // Record invocation as separate call so we don't rollback in case we are called with STATICCALL (, bytes memory r) = address(this).call.gas(100000)(abi.encodeWithSignature("updateInvocationCount(bytes4,bytes)", methodId, msg.data)); assert(r.length == 0); assembly { return(add(0x20, result), mload(result)) } } } // File: /home/josojo/gnosis/dx-mgn-pool/contracts/interfaces/IDutchExchange.sol contract IDutchExchange { mapping(address => mapping(address => mapping(uint => mapping(address => uint)))) public sellerBalances; mapping(address => mapping(address => mapping(uint => mapping(address => uint)))) public buyerBalances; mapping(address => mapping(address => mapping(uint => mapping(address => uint)))) public claimedAmounts; mapping(address => mapping(address => uint)) public balances; function withdraw(address tokenAddress, uint amount) public returns (uint); function deposit(address tokenAddress, uint amount) public returns (uint); function ethToken() public returns(address); function getAuctionIndex(address token1, address token2) public view returns(uint256); function postBuyOrder(address token1, address token2, uint256 auctionIndex, uint256 amount) public returns(uint256); function postSellOrder(address token1, address token2, uint256 auctionIndex, uint256 tokensBought) public returns(uint256, uint256); function getCurrentAuctionPrice(address token1, address token2, uint256 auctionIndex) public view returns(uint256, uint256); function claimSellerFunds(address sellToken, address buyToken, address user, uint auctionIndex) public returns (uint returned, uint frtsIssued); } // File: /home/josojo/gnosis/dx-mgn-pool/node_modules/@gnosis.pm/util-contracts/contracts/Token.sol /// Implements ERC 20 Token standard: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md pragma solidity ^0.5.2; /// @title Abstract token contract - Functions to be implemented by token contracts contract Token { /* * Events */ event Transfer(address indexed from, address indexed to, uint value); event Approval(address indexed owner, address indexed spender, uint value); /* * Public functions */ function transfer(address to, uint value) public returns (bool); function transferFrom(address from, address to, uint value) public returns (bool); function approve(address spender, uint value) public returns (bool); function balanceOf(address owner) public view returns (uint); function allowance(address owner, address spender) public view returns (uint); function totalSupply() public view returns (uint); } // File: /home/josojo/gnosis/dx-mgn-pool/node_modules/@gnosis.pm/util-contracts/contracts/Math.sol /// @title Math library - Allows calculation of logarithmic and exponential functions /// @author Alan Lu - <alan.lu@gnosis.pm> /// @author Stefan George - <stefan@gnosis.pm> library GnosisMath { /* * Constants */ // This is equal to 1 in our calculations uint public constant ONE = 0x10000000000000000; uint public constant LN2 = 0xb17217f7d1cf79ac; uint public constant LOG2_E = 0x171547652b82fe177; /* * Public functions */ /// @dev Returns natural exponential function value of given x /// @param x x /// @return e**x function exp(int x) public pure returns (uint) { // revert if x is > MAX_POWER, where // MAX_POWER = int(mp.floor(mp.log(mpf(2**256 - 1) / ONE) * ONE)) require(x <= 2454971259878909886679); // return 0 if exp(x) is tiny, using // MIN_POWER = int(mp.floor(mp.log(mpf(1) / ONE) * ONE)) if (x < -818323753292969962227) return 0; // Transform so that e^x -> 2^x x = x * int(ONE) / int(LN2); // 2^x = 2^whole(x) * 2^frac(x) // ^^^^^^^^^^ is a bit shift // so Taylor expand on z = frac(x) int shift; uint z; if (x >= 0) { shift = x / int(ONE); z = uint(x % int(ONE)); } else { shift = x / int(ONE) - 1; z = ONE - uint(-x % int(ONE)); } // 2^x = 1 + (ln 2) x + (ln 2)^2/2! x^2 + ... // // Can generate the z coefficients using mpmath and the following lines // >>> from mpmath import mp // >>> mp.dps = 100 // >>> ONE = 0x10000000000000000 // >>> print('\n'.join(hex(int(mp.log(2)**i / mp.factorial(i) * ONE)) for i in range(1, 7))) // 0xb17217f7d1cf79ab // 0x3d7f7bff058b1d50 // 0xe35846b82505fc5 // 0x276556df749cee5 // 0x5761ff9e299cc4 // 0xa184897c363c3 uint zpow = z; uint result = ONE; result += 0xb17217f7d1cf79ab * zpow / ONE; zpow = zpow * z / ONE; result += 0x3d7f7bff058b1d50 * zpow / ONE; zpow = zpow * z / ONE; result += 0xe35846b82505fc5 * zpow / ONE; zpow = zpow * z / ONE; result += 0x276556df749cee5 * zpow / ONE; zpow = zpow * z / ONE; result += 0x5761ff9e299cc4 * zpow / ONE; zpow = zpow * z / ONE; result += 0xa184897c363c3 * zpow / ONE; zpow = zpow * z / ONE; result += 0xffe5fe2c4586 * zpow / ONE; zpow = zpow * z / ONE; result += 0x162c0223a5c8 * zpow / ONE; zpow = zpow * z / ONE; result += 0x1b5253d395e * zpow / ONE; zpow = zpow * z / ONE; result += 0x1e4cf5158b * zpow / ONE; zpow = zpow * z / ONE; result += 0x1e8cac735 * zpow / ONE; zpow = zpow * z / ONE; result += 0x1c3bd650 * zpow / ONE; zpow = zpow * z / ONE; result += 0x1816193 * zpow / ONE; zpow = zpow * z / ONE; result += 0x131496 * zpow / ONE; zpow = zpow * z / ONE; result += 0xe1b7 * zpow / ONE; zpow = zpow * z / ONE; result += 0x9c7 * zpow / ONE; if (shift >= 0) { if (result >> (256 - shift) > 0) return (2 ** 256 - 1); return result << shift; } else return result >> (-shift); } /// @dev Returns natural logarithm value of given x /// @param x x /// @return ln(x) function ln(uint x) public pure returns (int) { require(x > 0); // binary search for floor(log2(x)) int ilog2 = floorLog2(x); int z; if (ilog2 < 0) z = int(x << uint(-ilog2)); else z = int(x >> uint(ilog2)); // z = x * 2^-⌊log₂x⌋ // so 1 <= z < 2 // and ln z = ln x - ⌊log₂x⌋/log₂e // so just compute ln z using artanh series // and calculate ln x from that int term = (z - int(ONE)) * int(ONE) / (z + int(ONE)); int halflnz = term; int termpow = term * term / int(ONE) * term / int(ONE); halflnz += termpow / 3; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 5; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 7; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 9; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 11; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 13; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 15; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 17; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 19; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 21; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 23; termpow = termpow * term / int(ONE) * term / int(ONE); halflnz += termpow / 25; return (ilog2 * int(ONE)) * int(ONE) / int(LOG2_E) + 2 * halflnz; } /// @dev Returns base 2 logarithm value of given x /// @param x x /// @return logarithmic value function floorLog2(uint x) public pure returns (int lo) { lo = -64; int hi = 193; // I use a shift here instead of / 2 because it floors instead of rounding towards 0 int mid = (hi + lo) >> 1; while ((lo + 1) < hi) { if (mid < 0 && x << uint(-mid) < ONE || mid >= 0 && x >> uint(mid) < ONE) hi = mid; else lo = mid; mid = (hi + lo) >> 1; } } /// @dev Returns maximum of an array /// @param nums Numbers to look through /// @return Maximum number function max(int[] memory nums) public pure returns (int maxNum) { require(nums.length > 0); maxNum = -2 ** 255; for (uint i = 0; i < nums.length; i++) if (nums[i] > maxNum) maxNum = nums[i]; } /// @dev Returns whether an add operation causes an overflow /// @param a First addend /// @param b Second addend /// @return Did no overflow occur? function safeToAdd(uint a, uint b) internal pure returns (bool) { return a + b >= a; } /// @dev Returns whether a subtraction operation causes an underflow /// @param a Minuend /// @param b Subtrahend /// @return Did no underflow occur? function safeToSub(uint a, uint b) internal pure returns (bool) { return a >= b; } /// @dev Returns whether a multiply operation causes an overflow /// @param a First factor /// @param b Second factor /// @return Did no overflow occur? function safeToMul(uint a, uint b) internal pure returns (bool) { return b == 0 || a * b / b == a; } /// @dev Returns sum if no overflow occurred /// @param a First addend /// @param b Second addend /// @return Sum function add(uint a, uint b) internal pure returns (uint) { require(safeToAdd(a, b)); return a + b; } /// @dev Returns difference if no overflow occurred /// @param a Minuend /// @param b Subtrahend /// @return Difference function sub(uint a, uint b) internal pure returns (uint) { require(safeToSub(a, b)); return a - b; } /// @dev Returns product if no overflow occurred /// @param a First factor /// @param b Second factor /// @return Product function mul(uint a, uint b) internal pure returns (uint) { require(safeToMul(a, b)); return a * b; } /// @dev Returns whether an add operation causes an overflow /// @param a First addend /// @param b Second addend /// @return Did no overflow occur? function safeToAdd(int a, int b) internal pure returns (bool) { return (b >= 0 && a + b >= a) || (b < 0 && a + b < a); } /// @dev Returns whether a subtraction operation causes an underflow /// @param a Minuend /// @param b Subtrahend /// @return Did no underflow occur? function safeToSub(int a, int b) internal pure returns (bool) { return (b >= 0 && a - b <= a) || (b < 0 && a - b > a); } /// @dev Returns whether a multiply operation causes an overflow /// @param a First factor /// @param b Second factor /// @return Did no overflow occur? function safeToMul(int a, int b) internal pure returns (bool) { return (b == 0) || (a * b / b == a); } /// @dev Returns sum if no overflow occurred /// @param a First addend /// @param b Second addend /// @return Sum function add(int a, int b) internal pure returns (int) { require(safeToAdd(a, b)); return a + b; } /// @dev Returns difference if no overflow occurred /// @param a Minuend /// @param b Subtrahend /// @return Difference function sub(int a, int b) internal pure returns (int) { require(safeToSub(a, b)); return a - b; } /// @dev Returns product if no overflow occurred /// @param a First factor /// @param b Second factor /// @return Product function mul(int a, int b) internal pure returns (int) { require(safeToMul(a, b)); return a * b; } } // File: /home/josojo/gnosis/dx-mgn-pool/node_modules/@gnosis.pm/util-contracts/contracts/Proxy.sol /// @title Proxied - indicates that a contract will be proxied. Also defines storage requirements for Proxy. /// @author Alan Lu - <alan@gnosis.pm> contract Proxied { address public masterCopy; } /// @title Proxy - Generic proxy contract allows to execute all transactions applying the code of a master contract. /// @author Stefan George - <stefan@gnosis.pm> contract Proxy is Proxied { /// @dev Constructor function sets address of master copy contract. /// @param _masterCopy Master copy address. constructor(address _masterCopy) public { require(_masterCopy != address(0), "The master copy is required"); masterCopy = _masterCopy; } /// @dev Fallback function forwards all transactions and returns all received return data. function() external payable { address _masterCopy = masterCopy; assembly { calldatacopy(0, 0, calldatasize) let success := delegatecall(not(0), _masterCopy, 0, calldatasize, 0, 0) returndatacopy(0, 0, returndatasize) switch success case 0 { revert(0, returndatasize) } default { return(0, returndatasize) } } } } // File: @gnosis.pm/util-contracts/contracts/GnosisStandardToken.sol /** * Deprecated: Use Open Zeppeling one instead */ contract StandardTokenData { /* * Storage */ mapping(address => uint) balances; mapping(address => mapping(address => uint)) allowances; uint totalTokens; } /** * Deprecated: Use Open Zeppeling one instead */ /// @title Standard token contract with overflow protection contract GnosisStandardToken is Token, StandardTokenData { using GnosisMath for *; /* * Public functions */ /// @dev Transfers sender's tokens to a given address. Returns success /// @param to Address of token receiver /// @param value Number of tokens to transfer /// @return Was transfer successful? function transfer(address to, uint value) public returns (bool) { if (!balances[msg.sender].safeToSub(value) || !balances[to].safeToAdd(value)) { return false; } balances[msg.sender] -= value; balances[to] += value; emit Transfer(msg.sender, to, value); return true; } /// @dev Allows allowed third party to transfer tokens from one address to another. Returns success /// @param from Address from where tokens are withdrawn /// @param to Address to where tokens are sent /// @param value Number of tokens to transfer /// @return Was transfer successful? function transferFrom(address from, address to, uint value) public returns (bool) { if (!balances[from].safeToSub(value) || !allowances[from][msg.sender].safeToSub( value ) || !balances[to].safeToAdd(value)) { return false; } balances[from] -= value; allowances[from][msg.sender] -= value; balances[to] += value; emit Transfer(from, to, value); return true; } /// @dev Sets approved amount of tokens for spender. Returns success /// @param spender Address of allowed account /// @param value Number of approved tokens /// @return Was approval successful? function approve(address spender, uint value) public returns (bool) { allowances[msg.sender][spender] = value; emit Approval(msg.sender, spender, value); return true; } /// @dev Returns number of allowed tokens for given address /// @param owner Address of token owner /// @param spender Address of token spender /// @return Remaining allowance for spender function allowance(address owner, address spender) public view returns (uint) { return allowances[owner][spender]; } /// @dev Returns number of tokens owned by given address /// @param owner Address of token owner /// @return Balance of owner function balanceOf(address owner) public view returns (uint) { return balances[owner]; } /// @dev Returns total supply of tokens /// @return Total supply function totalSupply() public view returns (uint) { return totalTokens; } } // File: @gnosis.pm/dx-contracts/contracts/TokenFRT.sol /// @title Standard token contract with overflow protection contract TokenFRT is Proxied, GnosisStandardToken { address public owner; string public constant symbol = "MGN"; string public constant name = "Magnolia Token"; uint8 public constant decimals = 18; struct UnlockedToken { uint amountUnlocked; uint withdrawalTime; } /* * Storage */ address public minter; // user => UnlockedToken mapping(address => UnlockedToken) public unlockedTokens; // user => amount mapping(address => uint) public lockedTokenBalances; /* * Public functions */ // @dev allows to set the minter of Magnolia tokens once. // @param _minter the minter of the Magnolia tokens, should be the DX-proxy function updateMinter(address _minter) public { require(msg.sender == owner, "Only the minter can set a new one"); require(_minter != address(0), "The new minter must be a valid address"); minter = _minter; } // @dev the intention is to set the owner as the DX-proxy, once it is deployed // Then only an update of the DX-proxy contract after a 30 days delay could change the minter again. function updateOwner(address _owner) public { require(msg.sender == owner, "Only the owner can update the owner"); require(_owner != address(0), "The new owner must be a valid address"); owner = _owner; } function mintTokens(address user, uint amount) public { require(msg.sender == minter, "Only the minter can mint tokens"); lockedTokenBalances[user] = add(lockedTokenBalances[user], amount); totalTokens = add(totalTokens, amount); } /// @dev Lock Token function lockTokens(uint amount) public returns (uint totalAmountLocked) { // Adjust amount by balance uint actualAmount = min(amount, balances[msg.sender]); // Update state variables balances[msg.sender] = sub(balances[msg.sender], actualAmount); lockedTokenBalances[msg.sender] = add(lockedTokenBalances[msg.sender], actualAmount); // Get return variable totalAmountLocked = lockedTokenBalances[msg.sender]; } function unlockTokens() public returns (uint totalAmountUnlocked, uint withdrawalTime) { // Adjust amount by locked balances uint amount = lockedTokenBalances[msg.sender]; if (amount > 0) { // Update state variables lockedTokenBalances[msg.sender] = sub(lockedTokenBalances[msg.sender], amount); unlockedTokens[msg.sender].amountUnlocked = add(unlockedTokens[msg.sender].amountUnlocked, amount); unlockedTokens[msg.sender].withdrawalTime = now + 24 hours; } // Get return variables totalAmountUnlocked = unlockedTokens[msg.sender].amountUnlocked; withdrawalTime = unlockedTokens[msg.sender].withdrawalTime; } function withdrawUnlockedTokens() public { require(unlockedTokens[msg.sender].withdrawalTime < now, "The tokens cannot be withdrawn yet"); balances[msg.sender] = add(balances[msg.sender], unlockedTokens[msg.sender].amountUnlocked); unlockedTokens[msg.sender].amountUnlocked = 0; } function min(uint a, uint b) public pure returns (uint) { if (a < b) { return a; } else { return b; } } /// @dev Returns whether an add operation causes an overflow /// @param a First addend /// @param b Second addend /// @return Did no overflow occur? function safeToAdd(uint a, uint b) public pure returns (bool) { return a + b >= a; } /// @dev Returns whether a subtraction operation causes an underflow /// @param a Minuend /// @param b Subtrahend /// @return Did no underflow occur? function safeToSub(uint a, uint b) public pure returns (bool) { return a >= b; } /// @dev Returns sum if no overflow occurred /// @param a First addend /// @param b Second addend /// @return Sum function add(uint a, uint b) public pure returns (uint) { require(safeToAdd(a, b), "It must be a safe adition"); return a + b; } /// @dev Returns difference if no overflow occurred /// @param a Minuend /// @param b Subtrahend /// @return Difference function sub(uint a, uint b) public pure returns (uint) { require(safeToSub(a, b), "It must be a safe substraction"); return a - b; } } // File: /home/josojo/gnosis/dx-mgn-pool/contracts/DxMgnPool.sol contract DxMgnPool is Ownable { using SafeMath for uint; struct Participation { uint startAuctionCount; // how many auction passed when this participation started contributing uint poolShares; // number of shares this participation accounts for (absolute) bool withdrawn; // flag indicating whether the participation has been withdrawn } enum State { Pooling, PoolingEnded, MgnUnlocked } mapping (address => Participation[]) public participationsByAddress; uint public totalPoolShares = 0; // total number of shares in this pool uint public totalPoolSharesCummulative = 0; // over all auctions, the rolling sum of all shares participated uint public totalDeposit = 0; uint public totalMgn = 0; uint public lastParticipatedAuctionIndex = 0; uint public auctionCount = 0; ERC20 public depositToken; ERC20 public secondaryToken; TokenFRT public mgnToken; IDutchExchange public dx; uint public poolingPeriodEndBlockNumber; constructor ( ERC20 _depositToken, ERC20 _secondaryToken, TokenFRT _mgnToken, IDutchExchange _dx, uint _poolingPeriodEndBlockNumber ) public Ownable() { depositToken = _depositToken; secondaryToken = _secondaryToken; mgnToken = _mgnToken; dx = _dx; poolingPeriodEndBlockNumber = _poolingPeriodEndBlockNumber; } /** * Public interface */ function deposit(uint amount) public { uint poolShares = calculatePoolShares(amount); Participation memory participation = Participation({ startAuctionCount: isDepositTokenTurn() ? auctionCount : auctionCount + 1, poolShares: poolShares, withdrawn: false }); participationsByAddress[msg.sender].push(participation); totalPoolShares += poolShares; totalDeposit += amount; require(depositToken.transferFrom(msg.sender, address(this), amount), "Failed to transfer deposit"); } function withdrawDeposit() public { require(currentState() != State.Pooling, "Pooling period is not over, yet"); uint totalDepositAmount = 0; Participation[] storage participations = participationsByAddress[msg.sender]; for (uint i = 0; i < participations.length; i++) { totalDepositAmount += calculateClaimableDeposit(participations[i]); participations[i].withdrawn = true; } require(depositToken.transfer(msg.sender, totalDepositAmount), "Failed to transfer deposit"); } function withdrawMagnolia() public { require(currentState() == State.MgnUnlocked, "MGN has not been unlocked, yet"); uint totalMgnClaimed = 0; Participation[] memory participations = participationsByAddress[msg.sender]; for (uint i = 0; i < participations.length; i++) { require(participations[i].withdrawn, "Withdraw deposits first"); totalMgnClaimed += calculateClaimableMgn(participations[i]); } delete participationsByAddress[msg.sender]; require(mgnToken.transfer(msg.sender, totalMgnClaimed), "Failed to transfer MGN"); } function participateInAuction() public onlyOwner() { require(currentState() == State.Pooling, "Pooling period is over."); uint auctionIndex = dx.getAuctionIndex(address(depositToken), address(secondaryToken)); require(auctionIndex > lastParticipatedAuctionIndex, "Has to wait for new auction to start"); (address sellToken, address buyToken) = buyAndSellToken(); uint depositAmount = depositToken.balanceOf(address(this)); if (isDepositTokenTurn() && depositAmount > 0) { //depositing new tokens depositToken.approve