Skip to content

Instantly share code, notes, and snippets.

@travs
Created January 8, 2020 10:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save travs/3c0356fb506ef90093c8333936f72b72 to your computer and use it in GitHub Desktop.
Save travs/3c0356fb506ef90093c8333936f72b72 to your computer and use it in GitHub Desktop.
diff --git a/src/contracts/dependencies/Owned.sol b/src/contracts/dependencies/Owned.sol
deleted file mode 100644
index 444b852a..00000000
--- a/src/contracts/dependencies/Owned.sol
+++ /dev/null
@@ -1,24 +0,0 @@
-pragma solidity ^0.4.25;
-
-
-contract Owned {
-
- address public owner;
-
- modifier onlyOwner {
- require(isOwner(msg.sender));
- _;
- }
-
- function Owned() {
- owner = msg.sender;
- }
-
- function changeOwner(address _newOwner) public onlyOwner {
- owner = _newOwner;
- }
-
- function isOwner(address _address) public view returns (bool) {
- return _address == owner;
- }
-}
diff --git a/src/contracts/dependencies/exec.sol b/src/contracts/dependencies/exec.sol
deleted file mode 100644
index 8435aecc..00000000
--- a/src/contracts/dependencies/exec.sol
+++ /dev/null
@@ -1,58 +0,0 @@
-// exec.sol - base contract used by anything that wants to do "untyped" calls
-
-// Copyright (C) 2017 DappHub, LLC
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-pragma solidity ^0.4.25;
-
-contract DSExec {
- function tryExec( address target, bytes calldata, uint value)
- internal
- returns (bool call_ret)
- {
- return target.call.value(value)(calldata);
- }
- function exec( address target, bytes calldata, uint value)
- internal
- {
- if(!tryExec(target, calldata, value)) {
- revert();
- }
- }
-
- // Convenience aliases
- function exec( address t, bytes c )
- internal
- {
- exec(t, c, 0);
- }
- function exec( address t, uint256 v )
- internal
- {
- bytes memory c; exec(t, c, v);
- }
- function tryExec( address t, bytes c )
- internal
- returns (bool)
- {
- return tryExec(t, c, 0);
- }
- function tryExec( address t, uint256 v )
- internal
- returns (bool)
- {
- bytes memory c; return tryExec(t, c, v);
- }
-}
diff --git a/src/contracts/dependencies/group.sol b/src/contracts/dependencies/group.sol
deleted file mode 100644
index 44700be2..00000000
--- a/src/contracts/dependencies/group.sol
+++ /dev/null
@@ -1,176 +0,0 @@
-/// group.sol -- simple m-of-n multisig implementation
-
-// Copyright (C) 2015, 2016 Ryan Casey <ryepdx@gmail.com>
-// Copyright (C) 2016, 2017 Daniel Brockman <daniel@brockman.se>
-
-// Licensed under the Apache License, Version 2.0 (the "License").
-// You may not use this file except in compliance with the License.
-
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND (express or implied).
-
-pragma solidity ^0.4.25;
-
-import "exec.sol";
-import "note.sol";
-
-contract DSGroup is DSExec, DSNote {
- address[] public members;
- uint public quorum;
- uint public window;
- uint public actionCount;
-
- mapping (uint => Action) public actions;
- mapping (uint => mapping (address => bool)) public confirmedBy;
- mapping (address => bool) public isMember;
-
- // Legacy events
- event Proposed (uint id, bytes calldata);
- event Confirmed (uint id, address member);
- event Triggered (uint id);
-
- struct Action {
- address target;
- bytes calldata;
- uint value;
-
- uint confirmations;
- uint deadline;
- bool triggered;
- }
-
- function DSGroup(
- address[] members_,
- uint quorum_,
- uint window_
- ) {
- members = members_;
- quorum = quorum_;
- window = window_;
-
- for (uint i = 0; i < members.length; i++) {
- isMember[members[i]] = true;
- }
- }
-
- function memberCount() constant returns (uint) {
- return members.length;
- }
-
- function target(uint id) constant returns (address) {
- return actions[id].target;
- }
- function calldata(uint id) constant returns (bytes) {
- return actions[id].calldata;
- }
- function value(uint id) constant returns (uint) {
- return actions[id].value;
- }
-
- function confirmations(uint id) constant returns (uint) {
- return actions[id].confirmations;
- }
- function deadline(uint id) constant returns (uint) {
- return actions[id].deadline;
- }
- function triggered(uint id) constant returns (bool) {
- return actions[id].triggered;
- }
-
- function confirmed(uint id) constant returns (bool) {
- return confirmations(id) >= quorum;
- }
- function expired(uint id) constant returns (bool) {
- return now > deadline(id);
- }
-
- function deposit() note payable {
- }
-
- function propose(
- address target,
- bytes calldata,
- uint value
- ) onlyMembers note returns (uint id) {
- id = ++actionCount;
-
- actions[id].target = target;
- actions[id].calldata = calldata;
- actions[id].value = value;
- actions[id].deadline = now + window;
-
- Proposed(id, calldata);
- }
-
- function confirm(uint id) onlyMembers onlyActive(id) note {
- assert(!confirmedBy[id][msg.sender]);
-
- confirmedBy[id][msg.sender] = true;
- actions[id].confirmations++;
-
- Confirmed(id, msg.sender);
- }
-
- function trigger(uint id) onlyMembers onlyActive(id) note {
- assert(confirmed(id));
-
- actions[id].triggered = true;
- exec(actions[id].target, actions[id].calldata, actions[id].value);
-
- Triggered(id);
- }
-
- modifier onlyMembers {
- assert(isMember[msg.sender]);
- _;
- }
-
- modifier onlyActive(uint id) {
- assert(!expired(id));
- assert(!triggered(id));
- _;
- }
-
- //------------------------------------------------------------------
- // Legacy functions
- //------------------------------------------------------------------
-
- function getInfo() constant returns (
- uint quorum_,
- uint memberCount,
- uint window_,
- uint actionCount_
- ) {
- return (quorum, members.length, window, actionCount);
- }
-
- function getActionStatus(uint id) constant returns (
- uint confirmations,
- uint deadline,
- bool triggered,
- address target,
- uint value
- ) {
- return (
- actions[id].confirmations,
- actions[id].deadline,
- actions[id].triggered,
- actions[id].target,
- actions[id].value
- );
- }
-}
-
-contract DSGroupFactory is DSNote {
- mapping (address => bool) public isGroup;
-
- function newGroup(
- address[] members,
- uint quorum,
- uint window
- ) note returns (DSGroup group) {
- group = new DSGroup(members, quorum, window);
- isGroup[group] = true;
- }
-}
diff --git a/src/contracts/dependencies/note.sol b/src/contracts/dependencies/note.sol
deleted file mode 100644
index 74865f8a..00000000
--- a/src/contracts/dependencies/note.sol
+++ /dev/null
@@ -1,41 +0,0 @@
-/// note.sol -- the `note' modifier, for logging calls as events
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-pragma solidity ^0.4.25;
-
-contract DSNote {
- event LogNote(
- bytes4 indexed sig,
- address indexed guy,
- bytes32 indexed foo,
- bytes32 indexed bar,
- uint wad,
- bytes fax
- ) anonymous;
-
- modifier note {
- bytes32 foo;
- bytes32 bar;
-
- assembly {
- foo := calldataload(4)
- bar := calldataload(36)
- }
-
- LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
-
- _;
- }
-}
diff --git a/src/contracts/dependencies/thing.sol b/src/contracts/dependencies/thing.sol
deleted file mode 100644
index 7aa97e01..00000000
--- a/src/contracts/dependencies/thing.sol
+++ /dev/null
@@ -1,30 +0,0 @@
-// thing.sol - `auth` with handy mixins. your things should be DSThings
-
-// Copyright (C) 2017 DappHub, LLC
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-pragma solidity ^0.4.25;
-
-import "auth.sol";
-import "note.sol";
-import "math.sol";
-
-contract DSThing is DSAuth, DSNote, DSMath {
-
- function S(string s) internal pure returns (bytes4) {
- return bytes4(keccak256(s));
- }
-
-}
diff --git a/src/contracts/exchanges/third-party/0x/Exchange.sol b/src/contracts/exchanges/third-party/0x/Exchange.sol
deleted file mode 100644
index 77d7e750..00000000
--- a/src/contracts/exchanges/third-party/0x/Exchange.sol
+++ /dev/null
@@ -1,3931 +0,0 @@
-/*
-
- Copyright 2018 ZeroEx Intl.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-*/
-
-pragma solidity ^0.4.21;
-pragma experimental ABIEncoderV2;
-
-import "StandardToken.sol";
-import "LibOrder.sol";
-import "Ownable.sol";
-
-library LibBytes {
-
- using LibBytes for bytes;
-
- /// @dev Gets the memory address for a byte array.
- /// @param input Byte array to lookup.
- /// @return memoryAddress Memory address of byte array. This
- /// points to the header of the byte array which contains
- /// the length.
- function rawAddress(bytes memory input)
- internal
- pure
- returns (uint256 memoryAddress)
- {
- assembly {
- memoryAddress := input
- }
- return memoryAddress;
- }
-
- /// @dev Gets the memory address for the contents of a byte array.
- /// @param input Byte array to lookup.
- /// @return memoryAddress Memory address of the contents of the byte array.
- function contentAddress(bytes memory input)
- internal
- pure
- returns (uint256 memoryAddress)
- {
- assembly {
- memoryAddress := add(input, 32)
- }
- return memoryAddress;
- }
-
- /// @dev Copies `length` bytes from memory location `source` to `dest`.
- /// @param dest memory address to copy bytes to.
- /// @param source memory address to copy bytes from.
- /// @param length number of bytes to copy.
- function memCopy(
- uint256 dest,
- uint256 source,
- uint256 length
- )
- internal
- pure
- {
- if (length < 32) {
- // Handle a partial word by reading destination and masking
- // off the bits we are interested in.
- // This correctly handles overlap, zero lengths and source == dest
- assembly {
- let mask := sub(exp(256, sub(32, length)), 1)
- let s := and(mload(source), not(mask))
- let d := and(mload(dest), mask)
- mstore(dest, or(s, d))
- }
- } else {
- // Skip the O(length) loop when source == dest.
- if (source == dest) {
- return;
- }
-
- // For large copies we copy whole words at a time. The final
- // word is aligned to the end of the range (instead of after the
- // previous) to handle partial words. So a copy will look like this:
- //
- // ####
- // ####
- // ####
- // ####
- //
- // We handle overlap in the source and destination range by
- // changing the copying direction. This prevents us from
- // overwriting parts of source that we still need to copy.
- //
- // This correctly handles source == dest
- //
- if (source > dest) {
- assembly {
- // We subtract 32 from `sEnd` and `dEnd` because it
- // is easier to compare with in the loop, and these
- // are also the addresses we need for copying the
- // last bytes.
- length := sub(length, 32)
- let sEnd := add(source, length)
- let dEnd := add(dest, length)
-
- // Remember the last 32 bytes of source
- // This needs to be done here and not after the loop
- // because we may have overwritten the last bytes in
- // source already due to overlap.
- let last := mload(sEnd)
-
- // Copy whole words front to back
- // Note: the first check is always true,
- // this could have been a do-while loop.
- // solhint-disable-next-line no-empty-blocks
- for {} lt(source, sEnd) {} {
- mstore(dest, mload(source))
- source := add(source, 32)
- dest := add(dest, 32)
- }
-
- // Write the last 32 bytes
- mstore(dEnd, last)
- }
- } else {
- assembly {
- // We subtract 32 from `sEnd` and `dEnd` because those
- // are the starting points when copying a word at the end.
- length := sub(length, 32)
- let sEnd := add(source, length)
- let dEnd := add(dest, length)
-
- // Remember the first 32 bytes of source
- // This needs to be done here and not after the loop
- // because we may have overwritten the first bytes in
- // source already due to overlap.
- let first := mload(source)
-
- // Copy whole words back to front
- // We use a signed comparisson here to allow dEnd to become
- // negative (happens when source and dest < 32). Valid
- // addresses in local memory will never be larger than
- // 2**255, so they can be safely re-interpreted as signed.
- // Note: the first check is always true,
- // this could have been a do-while loop.
- // solhint-disable-next-line no-empty-blocks
- for {} slt(dest, dEnd) {} {
- mstore(dEnd, mload(sEnd))
- sEnd := sub(sEnd, 32)
- dEnd := sub(dEnd, 32)
- }
-
- // Write the first 32 bytes
- mstore(dest, first)
- }
- }
- }
- }
-
- /// @dev Returns a slices from a byte array.
- /// @param b The byte array to take a slice from.
- /// @param from The starting index for the slice (inclusive).
- /// @param to The final index for the slice (exclusive).
- /// @return result The slice containing bytes at indices [from, to)
- function slice(
- bytes memory b,
- uint256 from,
- uint256 to
- )
- internal
- pure
- returns (bytes memory result)
- {
- require(
- from <= to,
- "FROM_LESS_THAN_TO_REQUIRED"
- );
- require(
- to < b.length,
- "TO_LESS_THAN_LENGTH_REQUIRED"
- );
-
- // Create a new bytes structure and copy contents
- result = new bytes(to - from);
- memCopy(
- result.contentAddress(),
- b.contentAddress() + from,
- result.length
- );
- return result;
- }
-
- /// @dev Returns a slice from a byte array without preserving the input.
- /// @param b The byte array to take a slice from. Will be destroyed in the process.
- /// @param from The starting index for the slice (inclusive).
- /// @param to The final index for the slice (exclusive).
- /// @return result The slice containing bytes at indices [from, to)
- /// @dev When `from == 0`, the original array will match the slice. In other cases its state will be corrupted.
- function sliceDestructive(
- bytes memory b,
- uint256 from,
- uint256 to
- )
- internal
- pure
- returns (bytes memory result)
- {
- require(
- from <= to,
- "FROM_LESS_THAN_TO_REQUIRED"
- );
- require(
- to < b.length,
- "TO_LESS_THAN_LENGTH_REQUIRED"
- );
-
- // Create a new bytes structure around [from, to) in-place.
- assembly {
- result := add(b, from)
- mstore(result, sub(to, from))
- }
- return result;
- }
-
- /// @dev Pops the last byte off of a byte array by modifying its length.
- /// @param b Byte array that will be modified.
- /// @return The byte that was popped off.
- function popLastByte(bytes memory b)
- internal
- pure
- returns (bytes1 result)
- {
- require(
- b.length > 0,
- "GREATER_THAN_ZERO_LENGTH_REQUIRED"
- );
-
- // Store last byte.
- result = b[b.length - 1];
-
- assembly {
- // Decrement length of byte array.
- let newLen := sub(mload(b), 1)
- mstore(b, newLen)
- }
- return result;
- }
-
- /// @dev Pops the last 20 bytes off of a byte array by modifying its length.
- /// @param b Byte array that will be modified.
- /// @return The 20 byte address that was popped off.
- function popLast20Bytes(bytes memory b)
- internal
- pure
- returns (address result)
- {
- require(
- b.length >= 20,
- "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED"
- );
-
- // Store last 20 bytes.
- result = readAddress(b, b.length - 20);
-
- assembly {
- // Subtract 20 from byte array length.
- let newLen := sub(mload(b), 20)
- mstore(b, newLen)
- }
- return result;
- }
-
- /// @dev Tests equality of two byte arrays.
- /// @param lhs First byte array to compare.
- /// @param rhs Second byte array to compare.
- /// @return True if arrays are the same. False otherwise.
- function equals(
- bytes memory lhs,
- bytes memory rhs
- )
- internal
- pure
- returns (bool equal)
- {
- // Keccak gas cost is 30 + numWords * 6. This is a cheap way to compare.
- // We early exit on unequal lengths, but keccak would also correctly
- // handle this.
- return lhs.length == rhs.length && keccak256(lhs) == keccak256(rhs);
- }
-
- /// @dev Reads an address from a position in a byte array.
- /// @param b Byte array containing an address.
- /// @param index Index in byte array of address.
- /// @return address from byte array.
- function readAddress(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (address result)
- {
- require(
- b.length >= index + 20, // 20 is length of address
- "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED"
- );
-
- // Add offset to index:
- // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
- // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)
- index += 20;
-
- // Read address from array memory
- assembly {
- // 1. Add index to address of bytes array
- // 2. Load 32-byte word from memory
- // 3. Apply 20-byte mask to obtain address
- result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff)
- }
- return result;
- }
-
- /// @dev Writes an address into a specific position in a byte array.
- /// @param b Byte array to insert address into.
- /// @param index Index in byte array of address.
- /// @param input Address to put into byte array.
- function writeAddress(
- bytes memory b,
- uint256 index,
- address input
- )
- internal
- pure
- {
- require(
- b.length >= index + 20, // 20 is length of address
- "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED"
- );
-
- // Add offset to index:
- // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
- // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)
- index += 20;
-
- // Store address into array memory
- assembly {
- // The address occupies 20 bytes and mstore stores 32 bytes.
- // First fetch the 32-byte word where we'll be storing the address, then
- // apply a mask so we have only the bytes in the word that the address will not occupy.
- // Then combine these bytes with the address and store the 32 bytes back to memory with mstore.
-
- // 1. Add index to address of bytes array
- // 2. Load 32-byte word from memory
- // 3. Apply 12-byte mask to obtain extra bytes occupying word of memory where we'll store the address
- let neighbors := and(
- mload(add(b, index)),
- 0xffffffffffffffffffffffff0000000000000000000000000000000000000000
- )
-
- // Make sure input address is clean.
- // (Solidity does not guarantee this)
- input := and(input, 0xffffffffffffffffffffffffffffffffffffffff)
-
- // Store the neighbors and address into memory
- mstore(add(b, index), xor(input, neighbors))
- }
- }
-
- /// @dev Reads a bytes32 value from a position in a byte array.
- /// @param b Byte array containing a bytes32 value.
- /// @param index Index in byte array of bytes32 value.
- /// @return bytes32 value from byte array.
- function readBytes32(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (bytes32 result)
- {
- require(
- b.length >= index + 32,
- "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED"
- );
-
- // Arrays are prefixed by a 256 bit length parameter
- index += 32;
-
- // Read the bytes32 from array memory
- assembly {
- result := mload(add(b, index))
- }
- return result;
- }
-
- /// @dev Writes a bytes32 into a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input bytes32 to put into byte array.
- function writeBytes32(
- bytes memory b,
- uint256 index,
- bytes32 input
- )
- internal
- pure
- {
- require(
- b.length >= index + 32,
- "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED"
- );
-
- // Arrays are prefixed by a 256 bit length parameter
- index += 32;
-
- // Read the bytes32 from array memory
- assembly {
- mstore(add(b, index), input)
- }
- }
-
- /// @dev Reads a uint256 value from a position in a byte array.
- /// @param b Byte array containing a uint256 value.
- /// @param index Index in byte array of uint256 value.
- /// @return uint256 value from byte array.
- function readUint256(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (uint256 result)
- {
- result = uint256(readBytes32(b, index));
- return result;
- }
-
- /// @dev Writes a uint256 into a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input uint256 to put into byte array.
- function writeUint256(
- bytes memory b,
- uint256 index,
- uint256 input
- )
- internal
- pure
- {
- writeBytes32(b, index, bytes32(input));
- }
-
- /// @dev Reads an unpadded bytes4 value from a position in a byte array.
- /// @param b Byte array containing a bytes4 value.
- /// @param index Index in byte array of bytes4 value.
- /// @return bytes4 value from byte array.
- function readBytes4(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (bytes4 result)
- {
- require(
- b.length >= index + 4,
- "GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED"
- );
-
- // Arrays are prefixed by a 32 byte length field
- index += 32;
-
- // Read the bytes4 from array memory
- assembly {
- result := mload(add(b, index))
- // Solidity does not require us to clean the trailing bytes.
- // We do it anyway
- result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)
- }
- return result;
- }
-
- /// @dev Reads nested bytes from a specific position.
- /// @dev NOTE: the returned value overlaps with the input value.
- /// Both should be treated as immutable.
- /// @param b Byte array containing nested bytes.
- /// @param index Index of nested bytes.
- /// @return result Nested bytes.
- function readBytesWithLength(
- bytes memory b,
- uint256 index
- )
- internal
- pure
- returns (bytes memory result)
- {
- // Read length of nested bytes
- uint256 nestedBytesLength = readUint256(b, index);
- index += 32;
-
- // Assert length of <b> is valid, given
- // length of nested bytes
- require(
- b.length >= index + nestedBytesLength,
- "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED"
- );
-
- // Return a pointer to the byte array as it exists inside `b`
- assembly {
- result := add(b, index)
- }
- return result;
- }
-
- /// @dev Inserts bytes at a specific position in a byte array.
- /// @param b Byte array to insert <input> into.
- /// @param index Index in byte array of <input>.
- /// @param input bytes to insert.
- function writeBytesWithLength(
- bytes memory b,
- uint256 index,
- bytes memory input
- )
- internal
- pure
- {
- // Assert length of <b> is valid, given
- // length of input
- require(
- b.length >= index + 32 + input.length, // 32 bytes to store length
- "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED"
- );
-
- // Copy <input> into <b>
- memCopy(
- b.contentAddress() + index,
- input.rawAddress(), // includes length of <input>
- input.length + 32 // +32 bytes to store <input> length
- );
- }
-
- /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length.
- /// @param dest Byte array that will be overwritten with source bytes.
- /// @param source Byte array to copy onto dest bytes.
- function deepCopyBytes(
- bytes memory dest,
- bytes memory source
- )
- internal
- pure
- {
- uint256 sourceLen = source.length;
- // Dest length must be >= source length, or some bytes would not be copied.
- require(
- dest.length >= sourceLen,
- "GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED"
- );
- memCopy(
- dest.contentAddress(),
- source.contentAddress(),
- sourceLen
- );
- }
-}
-
-contract ReentrancyGuard {
-
- // Locked state of mutex
- bool private locked = false;
-
- /// @dev Functions with this modifer cannot be reentered. The mutex will be locked
- /// before function execution and unlocked after.
- modifier nonReentrant() {
- // Ensure mutex is unlocked
- require(
- !locked,
- "REENTRANCY_ILLEGAL"
- );
-
- // Lock mutex before function call
- locked = true;
-
- // Perform function call
- _;
-
- // Unlock mutex after function call
- locked = false;
- }
-}
-
-contract SafeMathClone {
-
- function safeMul(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- if (a == 0) {
- return 0;
- }
- uint256 c = a * b;
- require(
- c / a == b,
- "UINT256_OVERFLOW"
- );
- return c;
- }
-
- function safeDiv(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- uint256 c = a / b;
- return c;
- }
-
- function safeSub(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- require(
- b <= a,
- "UINT256_UNDERFLOW"
- );
- return a - b;
- }
-
- function safeAdd(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- uint256 c = a + b;
- require(
- c >= a,
- "UINT256_OVERFLOW"
- );
- return c;
- }
-
- function max64(uint64 a, uint64 b)
- internal
- pure
- returns (uint256)
- {
- return a >= b ? a : b;
- }
-
- function min64(uint64 a, uint64 b)
- internal
- pure
- returns (uint256)
- {
- return a < b ? a : b;
- }
-
- function max256(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- return a >= b ? a : b;
- }
-
- function min256(uint256 a, uint256 b)
- internal
- pure
- returns (uint256)
- {
- return a < b ? a : b;
- }
-}
-
-// solhint-disable max-line-length
-contract LibConstants {
-
- // Asset data for ZRX token. Used for fee transfers.
-
- // The proxyId for ZRX_ASSET_DATA is bytes4(keccak256("ERC20Token(address)")) = 0xf47261b0
-
- // Kovan ZRX address is 0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570.
- // The ABI encoded proxyId and address is 0xf47261b00000000000000000000000006ff6c0ff1d68b964901f986d4c9fa3ac68346570
- // bytes constant public ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6f\xf6\xc0\xff\x1d\x68\xb9\x64\x90\x1f\x98\x6d\x4c\x9f\xa3\xac\x68\x34\x65\x70";
-
- // Mainnet ZRX address is 0xe41d2489571d322189246dafa5ebde1f4699f498.
- // The ABI encoded proxyId and address is 0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498
- bytes public ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98";
-
- // For easier testing
- function changeZRXAssetData(bytes newData) public {
- ZRX_ASSET_DATA = newData;
- }
-}
-// solhint-enable max-line-length
-
-contract LibFillResults is
- SafeMathClone
-{
- struct FillResults {
- uint256 makerAssetFilledAmount; // Total amount of makerAsset(s) filled.
- uint256 takerAssetFilledAmount; // Total amount of takerAsset(s) filled.
- uint256 makerFeePaid; // Total amount of ZRX paid by maker(s) to feeRecipient(s).
- uint256 takerFeePaid; // Total amount of ZRX paid by taker to feeRecipients(s).
- }
-
- struct MatchedFillResults {
- FillResults left; // Amounts filled and fees paid of left order.
- FillResults right; // Amounts filled and fees paid of right order.
- uint256 leftMakerAssetSpreadAmount; // Spread between price of left and right order, denominated in the left order's makerAsset, paid to taker.
- }
-
- /// @dev Adds properties of both FillResults instances.
- /// Modifies the first FillResults instance specified.
- /// @param totalFillResults Fill results instance that will be added onto.
- /// @param singleFillResults Fill results instance that will be added to totalFillResults.
- function addFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults)
- internal
- pure
- {
- totalFillResults.makerAssetFilledAmount = safeAdd(totalFillResults.makerAssetFilledAmount, singleFillResults.makerAssetFilledAmount);
- totalFillResults.takerAssetFilledAmount = safeAdd(totalFillResults.takerAssetFilledAmount, singleFillResults.takerAssetFilledAmount);
- totalFillResults.makerFeePaid = safeAdd(totalFillResults.makerFeePaid, singleFillResults.makerFeePaid);
- totalFillResults.takerFeePaid = safeAdd(totalFillResults.takerFeePaid, singleFillResults.takerFeePaid);
- }
-}
-
-contract LibMath is
- SafeMathClone
-{
- /// @dev Calculates partial value given a numerator and denominator rounded down.
- /// Reverts if rounding error is >= 0.1%
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target rounded down.
- function safeGetPartialAmountFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (uint256 partialAmount)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- require(
- !isRoundingErrorFloor(
- numerator,
- denominator,
- target
- ),
- "ROUNDING_ERROR"
- );
-
- partialAmount = safeDiv(
- safeMul(numerator, target),
- denominator
- );
- return partialAmount;
- }
-
- /// @dev Calculates partial value given a numerator and denominator rounded down.
- /// Reverts if rounding error is >= 0.1%
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target rounded up.
- function safeGetPartialAmountCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (uint256 partialAmount)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- require(
- !isRoundingErrorCeil(
- numerator,
- denominator,
- target
- ),
- "ROUNDING_ERROR"
- );
-
- // safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
- // ceil(a / b) = floor((a + b - 1) / b)
- // To implement `ceil(a / b)` using safeDiv.
- partialAmount = safeDiv(
- safeAdd(
- safeMul(numerator, target),
- safeSub(denominator, 1)
- ),
- denominator
- );
- return partialAmount;
- }
-
- /// @dev Calculates partial value given a numerator and denominator rounded down.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target rounded down.
- function getPartialAmountFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (uint256 partialAmount)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- partialAmount = safeDiv(
- safeMul(numerator, target),
- denominator
- );
- return partialAmount;
- }
-
- /// @dev Calculates partial value given a numerator and denominator rounded down.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to calculate partial of.
- /// @return Partial value of target rounded up.
- function getPartialAmountCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (uint256 partialAmount)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- // safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
- // ceil(a / b) = floor((a + b - 1) / b)
- // To implement `ceil(a / b)` using safeDiv.
- partialAmount = safeDiv(
- safeAdd(
- safeMul(numerator, target),
- safeSub(denominator, 1)
- ),
- denominator
- );
- return partialAmount;
- }
-
- /// @dev Checks if rounding error >= 0.1% when rounding down.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to multiply with numerator/denominator.
- /// @return Rounding error is present.
- function isRoundingErrorFloor(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (bool isError)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- // The absolute rounding error is the difference between the rounded
- // value and the ideal value. The relative rounding error is the
- // absolute rounding error divided by the absolute value of the
- // ideal value. This is undefined when the ideal value is zero.
- //
- // The ideal value is `numerator * target / denominator`.
- // Let's call `numerator * target % denominator` the remainder.
- // The absolute error is `remainder / denominator`.
- //
- // When the ideal value is zero, we require the absolute error to
- // be zero. Fortunately, this is always the case. The ideal value is
- // zero iff `numerator == 0` and/or `target == 0`. In this case the
- // remainder and absolute error are also zero.
- if (target == 0 || numerator == 0) {
- return false;
- }
-
- // Otherwise, we want the relative rounding error to be strictly
- // less than 0.1%.
- // The relative error is `remainder / (numerator * target)`.
- // We want the relative error less than 1 / 1000:
- // remainder / (numerator * denominator) < 1 / 1000
- // or equivalently:
- // 1000 * remainder < numerator * target
- // so we have a rounding error iff:
- // 1000 * remainder >= numerator * target
- uint256 remainder = mulmod(
- target,
- numerator,
- denominator
- );
- isError = safeMul(1000, remainder) >= safeMul(numerator, target);
- return isError;
- }
-
- /// @dev Checks if rounding error >= 0.1% when rounding up.
- /// @param numerator Numerator.
- /// @param denominator Denominator.
- /// @param target Value to multiply with numerator/denominator.
- /// @return Rounding error is present.
- function isRoundingErrorCeil(
- uint256 numerator,
- uint256 denominator,
- uint256 target
- )
- internal
- pure
- returns (bool isError)
- {
- require(
- denominator > 0,
- "DIVISION_BY_ZERO"
- );
-
- // See the comments in `isRoundingError`.
- if (target == 0 || numerator == 0) {
- // When either is zero, the ideal value and rounded value are zero
- // and there is no rounding error. (Although the relative error
- // is undefined.)
- return false;
- }
- // Compute remainder as before
- uint256 remainder = mulmod(
- target,
- numerator,
- denominator
- );
- remainder = safeSub(denominator, remainder) % denominator;
- isError = safeMul(1000, remainder) >= safeMul(numerator, target);
- return isError;
- }
-}
-
-contract LibAbiEncoder {
-
- /// @dev ABI encodes calldata for `fillOrder`.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return ABI encoded calldata for `fillOrder`.
- function abiEncodeFillOrder(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- pure
- returns (bytes memory fillOrderCalldata)
- {
- // We need to call MExchangeCore.fillOrder using a delegatecall in
- // assembly so that we can intercept a call that throws. For this, we
- // need the input encoded in memory in the Ethereum ABIv2 format [1].
-
- // | Area | Offset | Length | Contents |
- // | -------- |--------|---------|-------------------------------------------- |
- // | Header | 0x00 | 4 | function selector |
- // | Params | | 3 * 32 | function parameters: |
- // | | 0x00 | | 1. offset to order (*) |
- // | | 0x20 | | 2. takerAssetFillAmount |
- // | | 0x40 | | 3. offset to signature (*) |
- // | Data | | 12 * 32 | order: |
- // | | 0x000 | | 1. senderAddress |
- // | | 0x020 | | 2. makerAddress |
- // | | 0x040 | | 3. takerAddress |
- // | | 0x060 | | 4. feeRecipientAddress |
- // | | 0x080 | | 5. makerAssetAmount |
- // | | 0x0A0 | | 6. takerAssetAmount |
- // | | 0x0C0 | | 7. makerFeeAmount |
- // | | 0x0E0 | | 8. takerFeeAmount |
- // | | 0x100 | | 9. expirationTimeSeconds |
- // | | 0x120 | | 10. salt |
- // | | 0x140 | | 11. Offset to makerAssetData (*) |
- // | | 0x160 | | 12. Offset to takerAssetData (*) |
- // | | 0x180 | 32 | makerAssetData Length |
- // | | 0x1A0 | ** | makerAssetData Contents |
- // | | 0x1C0 | 32 | takerAssetData Length |
- // | | 0x1E0 | ** | takerAssetData Contents |
- // | | 0x200 | 32 | signature Length |
- // | | 0x220 | ** | signature Contents |
-
- // * Offsets are calculated from the beginning of the current area: Header, Params, Data:
- // An offset stored in the Params area is calculated from the beginning of the Params section.
- // An offset stored in the Data area is calculated from the beginning of the Data section.
-
- // ** The length of dynamic array contents are stored in the field immediately preceeding the contents.
-
- // [1]: https://solidity.readthedocs.io/en/develop/abi-spec.html
-
- assembly {
-
- // Areas below may use the following variables:
- // 1. <area>Start -- Start of this area in memory
- // 2. <area>End -- End of this area in memory. This value may
- // be precomputed (before writing contents),
- // or it may be computed as contents are written.
- // 3. <area>Offset -- Current offset into area. If an area's End
- // is precomputed, this variable tracks the
- // offsets of contents as they are written.
-
- /////// Setup Header Area ///////
- // Load free memory pointer
- fillOrderCalldata := mload(0x40)
- // bytes4(keccak256("fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)"))
- // = 0xb4be83d5
- // Leave 0x20 bytes to store the length
- mstore(add(fillOrderCalldata, 0x20), 0xb4be83d500000000000000000000000000000000000000000000000000000000)
- let headerAreaEnd := add(fillOrderCalldata, 0x24)
-
- /////// Setup Params Area ///////
- // This area is preallocated and written to later.
- // This is because we need to fill in offsets that have not yet been calculated.
- let paramsAreaStart := headerAreaEnd
- let paramsAreaEnd := add(paramsAreaStart, 0x60)
- let paramsAreaOffset := paramsAreaStart
-
- /////// Setup Data Area ///////
- let dataAreaStart := paramsAreaEnd
- let dataAreaEnd := dataAreaStart
-
- // Offset from the source data we're reading from
- let sourceOffset := order
- // arrayLenBytes and arrayLenWords track the length of a dynamically-allocated bytes array.
- let arrayLenBytes := 0
- let arrayLenWords := 0
-
- /////// Write order Struct ///////
- // Write memory location of Order, relative to the start of the
- // parameter list, then increment the paramsAreaOffset respectively.
- mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
- paramsAreaOffset := add(paramsAreaOffset, 0x20)
-
- // Write values for each field in the order
- // It would be nice to use a loop, but we save on gas by writing
- // the stores sequentially.
- mstore(dataAreaEnd, mload(sourceOffset)) // makerAddress
- mstore(add(dataAreaEnd, 0x20), mload(add(sourceOffset, 0x20))) // takerAddress
- mstore(add(dataAreaEnd, 0x40), mload(add(sourceOffset, 0x40))) // feeRecipientAddress
- mstore(add(dataAreaEnd, 0x60), mload(add(sourceOffset, 0x60))) // senderAddress
- mstore(add(dataAreaEnd, 0x80), mload(add(sourceOffset, 0x80))) // makerAssetAmount
- mstore(add(dataAreaEnd, 0xA0), mload(add(sourceOffset, 0xA0))) // takerAssetAmount
- mstore(add(dataAreaEnd, 0xC0), mload(add(sourceOffset, 0xC0))) // makerFeeAmount
- mstore(add(dataAreaEnd, 0xE0), mload(add(sourceOffset, 0xE0))) // takerFeeAmount
- mstore(add(dataAreaEnd, 0x100), mload(add(sourceOffset, 0x100))) // expirationTimeSeconds
- mstore(add(dataAreaEnd, 0x120), mload(add(sourceOffset, 0x120))) // salt
- mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetData
- mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetData
- dataAreaEnd := add(dataAreaEnd, 0x180)
- sourceOffset := add(sourceOffset, 0x180)
-
- // Write offset to <order.makerAssetData>
- mstore(add(dataAreaStart, mul(10, 0x20)), sub(dataAreaEnd, dataAreaStart))
-
- // Calculate length of <order.makerAssetData>
- sourceOffset := mload(add(order, 0x140)) // makerAssetData
- arrayLenBytes := mload(sourceOffset)
- sourceOffset := add(sourceOffset, 0x20)
- arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
-
- // Write length of <order.makerAssetData>
- mstore(dataAreaEnd, arrayLenBytes)
- dataAreaEnd := add(dataAreaEnd, 0x20)
-
- // Write contents of <order.makerAssetData>
- for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
- mstore(dataAreaEnd, mload(sourceOffset))
- dataAreaEnd := add(dataAreaEnd, 0x20)
- sourceOffset := add(sourceOffset, 0x20)
- }
-
- // Write offset to <order.takerAssetData>
- mstore(add(dataAreaStart, mul(11, 0x20)), sub(dataAreaEnd, dataAreaStart))
-
- // Calculate length of <order.takerAssetData>
- sourceOffset := mload(add(order, 0x160)) // takerAssetData
- arrayLenBytes := mload(sourceOffset)
- sourceOffset := add(sourceOffset, 0x20)
- arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
-
- // Write length of <order.takerAssetData>
- mstore(dataAreaEnd, arrayLenBytes)
- dataAreaEnd := add(dataAreaEnd, 0x20)
-
- // Write contents of <order.takerAssetData>
- for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
- mstore(dataAreaEnd, mload(sourceOffset))
- dataAreaEnd := add(dataAreaEnd, 0x20)
- sourceOffset := add(sourceOffset, 0x20)
- }
-
- /////// Write takerAssetFillAmount ///////
- mstore(paramsAreaOffset, takerAssetFillAmount)
- paramsAreaOffset := add(paramsAreaOffset, 0x20)
-
- /////// Write signature ///////
- // Write offset to paramsArea
- mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
-
- // Calculate length of signature
- sourceOffset := signature
- arrayLenBytes := mload(sourceOffset)
- sourceOffset := add(sourceOffset, 0x20)
- arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
-
- // Write length of signature
- mstore(dataAreaEnd, arrayLenBytes)
- dataAreaEnd := add(dataAreaEnd, 0x20)
-
- // Write contents of signature
- for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
- mstore(dataAreaEnd, mload(sourceOffset))
- dataAreaEnd := add(dataAreaEnd, 0x20)
- sourceOffset := add(sourceOffset, 0x20)
- }
-
- // Set length of calldata
- mstore(fillOrderCalldata, sub(dataAreaEnd, add(fillOrderCalldata, 0x20)))
-
- // Increment free memory pointer
- mstore(0x40, dataAreaEnd)
- }
-
- return fillOrderCalldata;
- }
-}
-
-contract IAuthorizable is
- IOwnable
-{
- /// @dev Authorizes an address.
- /// @param target Address to authorize.
- function addAuthorizedAddress(address target)
- external;
-
- /// @dev Removes authorizion of an address.
- /// @param target Address to remove authorization from.
- function removeAuthorizedAddress(address target)
- external;
-
- /// @dev Removes authorizion of an address.
- /// @param target Address to remove authorization from.
- /// @param index Index of target in authorities array.
- function removeAuthorizedAddressAtIndex(
- address target,
- uint256 index
- )
- external;
-
- /// @dev Gets all authorized addresses.
- /// @return Array of authorized addresses.
- function getAuthorizedAddresses()
- external
- view
- returns (address[] memory);
-}
-
-contract IAssetProxy is
- IAuthorizable
-{
- /// @dev Transfers assets. Either succeeds or throws.
- /// @param assetData Byte array encoded for the respective asset proxy.
- /// @param from Address to transfer asset from.
- /// @param to Address to transfer asset to.
- /// @param amount Amount of asset to transfer.
- function transferFrom(
- bytes assetData,
- address from,
- address to,
- uint256 amount
- )
- external;
-
- /// @dev Gets the proxy id associated with the proxy address.
- /// @return Proxy id.
- function getProxyId()
- external
- pure
- returns (bytes4);
-}
-
-contract IValidator {
-
- /// @dev Verifies that a signature is valid.
- /// @param hash Message hash that is signed.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external
- view
- returns (bool isValid);
-}
-
-contract IWallet {
-
- /// @dev Verifies that a signature is valid.
- /// @param hash Message hash that is signed.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- function isValidSignature(
- bytes32 hash,
- bytes signature
- )
- external
- view
- returns (bool isValid);
-}
-
-contract IExchangeCore {
-
- /// @dev Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch
- /// and senderAddress equal to msg.sender (or null address if msg.sender == makerAddress).
- /// @param targetOrderEpoch Orders created with a salt less or equal to this value will be cancelled.
- function cancelOrdersUpTo(uint256 targetOrderEpoch)
- external;
-
- /// @dev Fills the input order.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrder(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- returns (LibFillResults.FillResults memory fillResults);
-
- /// @dev After calling, the order can not be filled anymore.
- /// @param order Order struct containing order specifications.
- function cancelOrder(LibOrder.Order memory order)
- public;
-
- /// @dev Gets information about an order: status, hash, and amount filled.
- /// @param order Order to gather information on.
- /// @return OrderInfo Information about the order and its state.
- /// See LibOrder.OrderInfo for a complete description.
- function getOrderInfo(LibOrder.Order memory order)
- public
- view
- returns (LibOrder.OrderInfo memory orderInfo);
-}
-
-contract IAssetProxyDispatcher {
-
- /// @dev Registers an asset proxy to its asset proxy id.
- /// Once an asset proxy is registered, it cannot be unregistered.
- /// @param assetProxy Address of new asset proxy to register.
- function registerAssetProxy(address assetProxy)
- external;
-
- /// @dev Gets an asset proxy.
- /// @param assetProxyId Id of the asset proxy.
- /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
- function getAssetProxy(bytes4 assetProxyId)
- external
- view
- returns (address);
-}
-
-contract IMatchOrders {
-
- /// @dev Match two complementary orders that have a profitable spread.
- /// Each order is filled at their respective price point. However, the calculations are
- /// carried out as though the orders are both being filled at the right order's price point.
- /// The profit made by the left order goes to the taker (who matched the two orders).
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- /// @param leftSignature Proof that order was created by the left maker.
- /// @param rightSignature Proof that order was created by the right maker.
- /// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders.
- function matchOrders(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- bytes memory leftSignature,
- bytes memory rightSignature
- )
- public
- returns (LibFillResults.MatchedFillResults memory matchedFillResults);
-}
-
-contract ISignatureValidator {
-
- /// @dev Approves a hash on-chain using any valid signature type.
- /// After presigning a hash, the preSign signature type will become valid for that hash and signer.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- function preSign(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external;
-
- /// @dev Approves/unnapproves a Validator contract to verify signatures on signer's behalf.
- /// @param validatorAddress Address of Validator contract.
- /// @param approval Approval or disapproval of Validator contract.
- function setSignatureValidatorApproval(
- address validatorAddress,
- bool approval
- )
- external;
-
- /// @dev Verifies that a signature is valid.
- /// @param hash Message hash that is signed.
- /// @param signerAddress Address of signer.
- /// @param signature Proof of signing.
- /// @return Validity of order signature.
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes memory signature
- )
- public
- view
- returns (bool isValid);
-}
-
-contract ITransactions {
-
- /// @dev Executes an exchange method call in the context of signer.
- /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
- /// @param signerAddress Address of transaction signer.
- /// @param data AbiV2 encoded calldata.
- /// @param signature Proof of signer transaction by signer.
- function executeTransaction(
- uint256 salt,
- address signerAddress,
- bytes data,
- bytes signature
- )
- external;
-}
-
-contract IWrapperFunctions {
-
- /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
- /// @param order LibOrder.Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- function fillOrKillOrder(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- returns (LibFillResults.FillResults memory fillResults);
-
- /// @dev Fills an order with specified parameters and ECDSA signature.
- /// Returns false if the transaction would otherwise revert.
- /// @param order LibOrder.Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrderNoThrow(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- returns (LibFillResults.FillResults memory fillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrder.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function batchFillOrders(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrKill.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function batchFillOrKillOrders(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Fills an order with specified parameters and ECDSA signature.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function batchFillOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellOrders(
- LibOrder.Order[] memory orders,
- uint256 takerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256 takerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of makerAsset is bought by taker.
- /// @param orders Array of order specifications.
- /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketBuyOrders(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketBuyOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (LibFillResults.FillResults memory totalFillResults);
-
- /// @dev Synchronously cancels multiple orders in a single transaction.
- /// @param orders Array of order specifications.
- function batchCancelOrders(LibOrder.Order[] memory orders)
- public;
-
- /// @dev Fetches information for all passed in orders
- /// @param orders Array of order specifications.
- /// @return Array of OrderInfo instances that correspond to each order.
- function getOrdersInfo(LibOrder.Order[] memory orders)
- public
- view
- returns (LibOrder.OrderInfo[] memory);
-}
-
-// solhint-disable no-empty-blocks
-contract IExchange is
- IExchangeCore,
- IMatchOrders,
- ISignatureValidator,
- ITransactions,
- IAssetProxyDispatcher,
- IWrapperFunctions
-{}
-
-contract MExchangeCore is
- IExchangeCore
-{
- // Fill event is emitted whenever an order is filled.
- event Fill(
- address indexed makerAddress, // Address that created the order.
- address indexed feeRecipientAddress, // Address that received fees.
- address takerAddress, // Address that filled the order.
- address senderAddress, // Address that called the Exchange contract (msg.sender).
- uint256 makerAssetFilledAmount, // Amount of makerAsset sold by maker and bought by taker.
- uint256 takerAssetFilledAmount, // Amount of takerAsset sold by taker and bought by maker.
- uint256 makerFeePaid, // Amount of ZRX paid to feeRecipient by maker.
- uint256 takerFeePaid, // Amount of ZRX paid to feeRecipient by taker.
- bytes32 indexed orderHash, // EIP712 hash of order (see LibOrder.getOrderHash).
- bytes makerAssetData, // Encoded data specific to makerAsset.
- bytes takerAssetData // Encoded data specific to takerAsset.
- );
-
- // Cancel event is emitted whenever an individual order is cancelled.
- event Cancel(
- address indexed makerAddress, // Address that created the order.
- address indexed feeRecipientAddress, // Address that would have recieved fees if order was filled.
- address senderAddress, // Address that called the Exchange contract (msg.sender).
- bytes32 indexed orderHash, // EIP712 hash of order (see LibOrder.getOrderHash).
- bytes makerAssetData, // Encoded data specific to makerAsset.
- bytes takerAssetData // Encoded data specific to takerAsset.
- );
-
- // CancelUpTo event is emitted whenever `cancelOrdersUpTo` is executed succesfully.
- event CancelUpTo(
- address indexed makerAddress, // Orders cancelled must have been created by this address.
- address indexed senderAddress, // Orders cancelled must have a `senderAddress` equal to this address.
- uint256 orderEpoch // Orders with specified makerAddress and senderAddress with a salt less than this value are considered cancelled.
- );
-
- /// @dev Fills the input order.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrderInternal(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (LibFillResults.FillResults memory fillResults);
-
- /// @dev After calling, the order can not be filled anymore.
- /// @param order Order struct containing order specifications.
- function cancelOrderInternal(LibOrder.Order memory order)
- internal;
-
- /// @dev Updates state with results of a fill order.
- /// @param order that was filled.
- /// @param takerAddress Address of taker who filled the order.
- /// @param orderTakerAssetFilledAmount Amount of order already filled.
- /// @return fillResults Amounts filled and fees paid by maker and taker.
- function updateFilledState(
- LibOrder.Order memory order,
- address takerAddress,
- bytes32 orderHash,
- uint256 orderTakerAssetFilledAmount,
- LibFillResults.FillResults memory fillResults
- )
- internal;
-
- /// @dev Updates state with results of cancelling an order.
- /// State is only updated if the order is currently fillable.
- /// Otherwise, updating state would have no effect.
- /// @param order that was cancelled.
- /// @param orderHash Hash of order that was cancelled.
- function updateCancelledState(
- LibOrder.Order memory order,
- bytes32 orderHash
- )
- internal;
-
- /// @dev Validates context for fillOrder. Succeeds or throws.
- /// @param order to be filled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- /// @param takerAddress Address of order taker.
- /// @param signature Proof that the orders was created by its maker.
- function assertFillableOrder(
- LibOrder.Order memory order,
- LibOrder.OrderInfo memory orderInfo,
- address takerAddress,
- bytes memory signature
- )
- internal
- view;
-
- /// @dev Validates context for fillOrder. Succeeds or throws.
- /// @param order to be filled.
- /// @param orderInfo Status, orderHash, and amount already filled of order.
- /// @param takerAssetFillAmount Desired amount of order to fill by taker.
- /// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
- /// @param makerAssetFilledAmount Amount of makerAsset that will be transfered.
- function assertValidFill(
- LibOrder.Order memory order,
- LibOrder.OrderInfo memory orderInfo,
- uint256 takerAssetFillAmount,
- uint256 takerAssetFilledAmount,
- uint256 makerAssetFilledAmount
- )
- internal
- view;
-
- /// @dev Validates context for cancelOrder. Succeeds or throws.
- /// @param order to be cancelled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- function assertValidCancel(
- LibOrder.Order memory order,
- LibOrder.OrderInfo memory orderInfo
- )
- internal
- view;
-
- /// @dev Calculates amounts filled and fees paid by maker and taker.
- /// @param order to be filled.
- /// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
- /// @return fillResults Amounts filled and fees paid by maker and taker.
- function calculateFillResults(
- LibOrder.Order memory order,
- uint256 takerAssetFilledAmount
- )
- internal
- pure
- returns (LibFillResults.FillResults memory fillResults);
-
-}
-
-contract MAssetProxyDispatcher is
- IAssetProxyDispatcher
-{
- // Logs registration of new asset proxy
- event AssetProxyRegistered(
- bytes4 id, // Id of new registered AssetProxy.
- address assetProxy // Address of new registered AssetProxy.
- );
-
- /// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
- /// @param assetData Byte array encoded for the asset.
- /// @param from Address to transfer token from.
- /// @param to Address to transfer token to.
- /// @param amount Amount of token to transfer.
- function dispatchTransferFrom(
- bytes memory assetData,
- address from,
- address to,
- uint256 amount
- )
- internal;
-}
-
-contract MMatchOrders is
- IMatchOrders
-{
- /// @dev Validates context for matchOrders. Succeeds or throws.
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- function assertValidMatch(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder
- )
- internal
- pure;
-
- /// @dev Calculates fill amounts for the matched orders.
- /// Each order is filled at their respective price point. However, the calculations are
- /// carried out as though the orders are both being filled at the right order's price point.
- /// The profit made by the leftOrder order goes to the taker (who matched the two orders).
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- /// @param leftOrderTakerAssetFilledAmount Amount of left order already filled.
- /// @param rightOrderTakerAssetFilledAmount Amount of right order already filled.
- /// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
- function calculateMatchedFillResults(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- uint256 leftOrderTakerAssetFilledAmount,
- uint256 rightOrderTakerAssetFilledAmount
- )
- internal
- pure
- returns (LibFillResults.MatchedFillResults memory matchedFillResults);
-
-}
-
-contract MSignatureValidator is
- ISignatureValidator
-{
- event SignatureValidatorApproval(
- address indexed signerAddress, // Address that approves or disapproves a contract to verify signatures.
- address indexed validatorAddress, // Address of signature validator contract.
- bool approved // Approval or disapproval of validator contract.
- );
-
- // Allowed signature types.
- enum SignatureType {
- Illegal, // 0x00, default value
- Invalid, // 0x01
- EIP712, // 0x02
- EthSign, // 0x03
- Wallet, // 0x04
- Validator, // 0x05
- PreSigned, // 0x06
- NSignatureTypes // 0x07, number of signature types. Always leave at end.
- }
-
- /// @dev Verifies signature using logic defined by Wallet contract.
- /// @param hash Any 32 byte hash.
- /// @param walletAddress Address that should have signed the given hash
- /// and defines its own signature verification method.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if the address recovered from the provided signature matches the input signer address.
- function isValidWalletSignature(
- bytes32 hash,
- address walletAddress,
- bytes signature
- )
- internal
- view
- returns (bool isValid);
-
- /// @dev Verifies signature using logic defined by Validator contract.
- /// @param validatorAddress Address of validator contract.
- /// @param hash Any 32 byte hash.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if the address recovered from the provided signature matches the input signer address.
- function isValidValidatorSignature(
- address validatorAddress,
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- internal
- view
- returns (bool isValid);
-}
-
-contract MTransactions is
- ITransactions
-{
- // Hash for the EIP712 ZeroEx Transaction Schema
- bytes32 constant internal EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH = keccak256(abi.encodePacked(
- "ZeroExTransaction(",
- "uint256 salt,",
- "address signerAddress,",
- "bytes data",
- ")"
- ));
-
- /// @dev Calculates EIP712 hash of the Transaction.
- /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
- /// @param signerAddress Address of transaction signer.
- /// @param data AbiV2 encoded calldata.
- /// @return EIP712 hash of the Transaction.
- function hashZeroExTransaction(
- uint256 salt,
- address signerAddress,
- bytes memory data
- )
- internal
- pure
- returns (bytes32 result);
-
- /// @dev The current function will be called in the context of this address (either 0x transaction signer or `msg.sender`).
- /// If calling a fill function, this address will represent the taker.
- /// If calling a cancel function, this address will represent the maker.
- /// @return Signer of 0x transaction if entry point is `executeTransaction`.
- /// `msg.sender` if entry point is any other function.
- function getCurrentContextAddress()
- internal
- view
- returns (address);
-}
-
-contract MWrapperFunctions is
- IWrapperFunctions
-{
- /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
- /// @param order LibOrder.Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- function fillOrKillOrderInternal(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (LibFillResults.FillResults memory fillResults);
-}
-
-contract MixinExchangeCore is
- ReentrancyGuard,
- LibConstants,
- LibMath,
- LibOrder,
- LibFillResults,
- MAssetProxyDispatcher,
- MExchangeCore,
- MSignatureValidator,
- MTransactions
-{
- // Mapping of orderHash => amount of takerAsset already bought by maker
- mapping (bytes32 => uint256) public filled;
-
- // Mapping of orderHash => cancelled
- mapping (bytes32 => bool) public cancelled;
-
- // Mapping of makerAddress => senderAddress => lowest salt an order can have in order to be fillable
- // Orders with specified senderAddress and with a salt less than their epoch are considered cancelled
- mapping (address => mapping (address => uint256)) public orderEpoch;
-
- /// @dev Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch
- /// and senderAddress equal to msg.sender (or null address if msg.sender == makerAddress).
- /// @param targetOrderEpoch Orders created with a salt less or equal to this value will be cancelled.
- function cancelOrdersUpTo(uint256 targetOrderEpoch)
- external
- nonReentrant
- {
- address makerAddress = getCurrentContextAddress();
- // If this function is called via `executeTransaction`, we only update the orderEpoch for the makerAddress/msg.sender combination.
- // This allows external filter contracts to add rules to how orders are cancelled via this function.
- address senderAddress = makerAddress == msg.sender ? address(0) : msg.sender;
-
- // orderEpoch is initialized to 0, so to cancelUpTo we need salt + 1
- uint256 newOrderEpoch = targetOrderEpoch + 1;
- uint256 oldOrderEpoch = orderEpoch[makerAddress][senderAddress];
-
- // Ensure orderEpoch is monotonically increasing
- require(
- newOrderEpoch > oldOrderEpoch,
- "INVALID_NEW_ORDER_EPOCH"
- );
-
- // Update orderEpoch
- orderEpoch[makerAddress][senderAddress] = newOrderEpoch;
- emit CancelUpTo(
- makerAddress,
- senderAddress,
- newOrderEpoch
- );
- }
-
- /// @dev Fills the input order.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrder(
- Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- nonReentrant
- returns (FillResults memory fillResults)
- {
- fillResults = fillOrderInternal(
- order,
- takerAssetFillAmount,
- signature
- );
- return fillResults;
- }
-
- /// @dev After calling, the order can not be filled anymore.
- /// Throws if order is invalid or sender does not have permission to cancel.
- /// @param order Order to cancel. Order must be OrderStatus.FILLABLE.
- function cancelOrder(Order memory order)
- public
- nonReentrant
- {
- cancelOrderInternal(order);
- }
-
- /// @dev Gets information about an order: status, hash, and amount filled.
- /// @param order Order to gather information on.
- /// @return OrderInfo Information about the order and its state.
- /// See LibOrder.OrderInfo for a complete description.
- function getOrderInfo(Order memory order)
- public
- view
- returns (OrderInfo memory orderInfo)
- {
- // Compute the order hash
- orderInfo.orderHash = getOrderHash(order);
-
- // Fetch filled amount
- orderInfo.orderTakerAssetFilledAmount = filled[orderInfo.orderHash];
-
- // If order.makerAssetAmount is zero, we also reject the order.
- // While the Exchange contract handles them correctly, they create
- // edge cases in the supporting infrastructure because they have
- // an 'infinite' price when computed by a simple division.
- if (order.makerAssetAmount == 0) {
- orderInfo.orderStatus = uint8(OrderStatus.INVALID_MAKER_ASSET_AMOUNT);
- return orderInfo;
- }
-
- // If order.takerAssetAmount is zero, then the order will always
- // be considered filled because 0 == takerAssetAmount == orderTakerAssetFilledAmount
- // Instead of distinguishing between unfilled and filled zero taker
- // amount orders, we choose not to support them.
- if (order.takerAssetAmount == 0) {
- orderInfo.orderStatus = uint8(OrderStatus.INVALID_TAKER_ASSET_AMOUNT);
- return orderInfo;
- }
-
- // Validate order availability
- if (orderInfo.orderTakerAssetFilledAmount >= order.takerAssetAmount) {
- orderInfo.orderStatus = uint8(OrderStatus.FULLY_FILLED);
- return orderInfo;
- }
-
- // Validate order expiration
- // solhint-disable-next-line not-rely-on-time
- if (block.timestamp >= order.expirationTimeSeconds) {
- orderInfo.orderStatus = uint8(OrderStatus.EXPIRED);
- return orderInfo;
- }
-
- // Check if order has been cancelled
- if (cancelled[orderInfo.orderHash]) {
- orderInfo.orderStatus = uint8(OrderStatus.CANCELLED);
- return orderInfo;
- }
- if (orderEpoch[order.makerAddress][order.senderAddress] > order.salt) {
- orderInfo.orderStatus = uint8(OrderStatus.CANCELLED);
- return orderInfo;
- }
-
- // All other statuses are ruled out: order is Fillable
- orderInfo.orderStatus = uint8(OrderStatus.FILLABLE);
- return orderInfo;
- }
-
- /// @dev Fills the input order.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrderInternal(
- Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (FillResults memory fillResults)
- {
- // Fetch order info
- OrderInfo memory orderInfo = getOrderInfo(order);
-
- // Fetch taker address
- address takerAddress = getCurrentContextAddress();
-
- // Assert that the order is fillable by taker
- assertFillableOrder(
- order,
- orderInfo,
- takerAddress,
- signature
- );
-
- // Get amount of takerAsset to fill
- uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount);
- uint256 takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount);
-
- // Validate context
- assertValidFill(
- order,
- orderInfo,
- takerAssetFillAmount,
- takerAssetFilledAmount,
- fillResults.makerAssetFilledAmount
- );
-
- // Compute proportional fill amounts
- fillResults = calculateFillResults(order, takerAssetFilledAmount);
-
- // Update exchange internal state
- updateFilledState(
- order,
- takerAddress,
- orderInfo.orderHash,
- orderInfo.orderTakerAssetFilledAmount,
- fillResults
- );
-
- // Settle order
- settleOrder(
- order,
- takerAddress,
- fillResults
- );
-
- return fillResults;
- }
-
- /// @dev After calling, the order can not be filled anymore.
- /// Throws if order is invalid or sender does not have permission to cancel.
- /// @param order Order to cancel. Order must be OrderStatus.FILLABLE.
- function cancelOrderInternal(Order memory order)
- internal
- {
- // Fetch current order status
- OrderInfo memory orderInfo = getOrderInfo(order);
-
- // Validate context
- assertValidCancel(order, orderInfo);
-
- // Perform cancel
- updateCancelledState(order, orderInfo.orderHash);
- }
-
- /// @dev Updates state with results of a fill order.
- /// @param order that was filled.
- /// @param takerAddress Address of taker who filled the order.
- /// @param orderTakerAssetFilledAmount Amount of order already filled.
- function updateFilledState(
- Order memory order,
- address takerAddress,
- bytes32 orderHash,
- uint256 orderTakerAssetFilledAmount,
- FillResults memory fillResults
- )
- internal
- {
- // Update state
- filled[orderHash] = safeAdd(orderTakerAssetFilledAmount, fillResults.takerAssetFilledAmount);
-
- // Log order
- emit Fill(
- order.makerAddress,
- order.feeRecipientAddress,
- takerAddress,
- msg.sender,
- fillResults.makerAssetFilledAmount,
- fillResults.takerAssetFilledAmount,
- fillResults.makerFeePaid,
- fillResults.takerFeePaid,
- orderHash,
- order.makerAssetData,
- order.takerAssetData
- );
- }
-
- /// @dev Updates state with results of cancelling an order.
- /// State is only updated if the order is currently fillable.
- /// Otherwise, updating state would have no effect.
- /// @param order that was cancelled.
- /// @param orderHash Hash of order that was cancelled.
- function updateCancelledState(
- Order memory order,
- bytes32 orderHash
- )
- internal
- {
- // Perform cancel
- cancelled[orderHash] = true;
-
- // Log cancel
- emit Cancel(
- order.makerAddress,
- order.feeRecipientAddress,
- msg.sender,
- orderHash,
- order.makerAssetData,
- order.takerAssetData
- );
- }
-
- /// @dev Validates context for fillOrder. Succeeds or throws.
- /// @param order to be filled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- /// @param takerAddress Address of order taker.
- /// @param signature Proof that the orders was created by its maker.
- function assertFillableOrder(
- Order memory order,
- OrderInfo memory orderInfo,
- address takerAddress,
- bytes memory signature
- )
- internal
- view
- {
- // An order can only be filled if its status is FILLABLE.
- require(
- orderInfo.orderStatus == uint8(OrderStatus.FILLABLE),
- "ORDER_UNFILLABLE"
- );
-
- // Validate sender is allowed to fill this order
- if (order.senderAddress != address(0)) {
- require(
- order.senderAddress == msg.sender,
- "INVALID_SENDER"
- );
- }
-
- // Validate taker is allowed to fill this order
- if (order.takerAddress != address(0)) {
- require(
- order.takerAddress == takerAddress,
- "INVALID_TAKER"
- );
- }
-
- // Validate Maker signature (check only if first time seen)
- if (orderInfo.orderTakerAssetFilledAmount == 0) {
- require(
- isValidSignature(
- orderInfo.orderHash,
- order.makerAddress,
- signature
- ),
- "INVALID_ORDER_SIGNATURE"
- );
- }
- }
-
- /// @dev Validates context for fillOrder. Succeeds or throws.
- /// @param order to be filled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- /// @param takerAssetFillAmount Desired amount of order to fill by taker.
- /// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
- /// @param makerAssetFilledAmount Amount of makerAsset that will be transfered.
- function assertValidFill(
- Order memory order,
- OrderInfo memory orderInfo,
- uint256 takerAssetFillAmount, // TODO: use FillResults
- uint256 takerAssetFilledAmount,
- uint256 makerAssetFilledAmount
- )
- internal
- view
- {
- // Revert if fill amount is invalid
- // TODO: reconsider necessity for v2.1
- require(
- takerAssetFillAmount != 0,
- "INVALID_TAKER_AMOUNT"
- );
-
- // Make sure taker does not pay more than desired amount
- // NOTE: This assertion should never fail, it is here
- // as an extra defence against potential bugs.
- require(
- takerAssetFilledAmount <= takerAssetFillAmount,
- "TAKER_OVERPAY"
- );
-
- // Make sure order is not overfilled
- // NOTE: This assertion should never fail, it is here
- // as an extra defence against potential bugs.
- require(
- safeAdd(orderInfo.orderTakerAssetFilledAmount, takerAssetFilledAmount) <= order.takerAssetAmount,
- "ORDER_OVERFILL"
- );
-
- // Make sure order is filled at acceptable price.
- // The order has an implied price from the makers perspective:
- // order price = order.makerAssetAmount / order.takerAssetAmount
- // i.e. the number of makerAsset maker is paying per takerAsset. The
- // maker is guaranteed to get this price or a better (lower) one. The
- // actual price maker is getting in this fill is:
- // fill price = makerAssetFilledAmount / takerAssetFilledAmount
- // We need `fill price <= order price` for the fill to be fair to maker.
- // This amounts to:
- // makerAssetFilledAmount order.makerAssetAmount
- // ------------------------ <= -----------------------
- // takerAssetFilledAmount order.takerAssetAmount
- // or, equivalently:
- // makerAssetFilledAmount * order.takerAssetAmount <=
- // order.makerAssetAmount * takerAssetFilledAmount
- // NOTE: This assertion should never fail, it is here
- // as an extra defence against potential bugs.
- require(
- safeMul(makerAssetFilledAmount, order.takerAssetAmount)
- <=
- safeMul(order.makerAssetAmount, takerAssetFilledAmount),
- "INVALID_FILL_PRICE"
- );
- }
-
- /// @dev Validates context for cancelOrder. Succeeds or throws.
- /// @param order to be cancelled.
- /// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
- function assertValidCancel(
- Order memory order,
- OrderInfo memory orderInfo
- )
- internal
- view
- {
- // Ensure order is valid
- // An order can only be cancelled if its status is FILLABLE.
- require(
- orderInfo.orderStatus == uint8(OrderStatus.FILLABLE),
- "ORDER_UNFILLABLE"
- );
-
- // Validate sender is allowed to cancel this order
- if (order.senderAddress != address(0)) {
- require(
- order.senderAddress == msg.sender,
- "INVALID_SENDER"
- );
- }
-
- // Validate transaction signed by maker
- address makerAddress = getCurrentContextAddress();
- require(
- order.makerAddress == makerAddress,
- "INVALID_MAKER"
- );
- }
-
- /// @dev Calculates amounts filled and fees paid by maker and taker.
- /// @param order to be filled.
- /// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
- /// @return fillResults Amounts filled and fees paid by maker and taker.
- function calculateFillResults(
- Order memory order,
- uint256 takerAssetFilledAmount
- )
- internal
- pure
- returns (FillResults memory fillResults)
- {
- // Compute proportional transfer amounts
- fillResults.takerAssetFilledAmount = takerAssetFilledAmount;
- fillResults.makerAssetFilledAmount = safeGetPartialAmountFloor(
- takerAssetFilledAmount,
- order.takerAssetAmount,
- order.makerAssetAmount
- );
- fillResults.makerFeePaid = safeGetPartialAmountFloor(
- fillResults.makerAssetFilledAmount,
- order.makerAssetAmount,
- order.makerFee
- );
- fillResults.takerFeePaid = safeGetPartialAmountFloor(
- takerAssetFilledAmount,
- order.takerAssetAmount,
- order.takerFee
- );
-
- return fillResults;
- }
-
- /// @dev Settles an order by transferring assets between counterparties.
- /// @param order Order struct containing order specifications.
- /// @param takerAddress Address selling takerAsset and buying makerAsset.
- /// @param fillResults Amounts to be filled and fees paid by maker and taker.
- function settleOrder(
- LibOrder.Order memory order,
- address takerAddress,
- LibFillResults.FillResults memory fillResults
- )
- private
- {
- bytes memory zrxAssetData = ZRX_ASSET_DATA;
- dispatchTransferFrom(
- order.makerAssetData,
- order.makerAddress,
- takerAddress,
- fillResults.makerAssetFilledAmount
- );
- dispatchTransferFrom(
- order.takerAssetData,
- takerAddress,
- order.makerAddress,
- fillResults.takerAssetFilledAmount
- );
- dispatchTransferFrom(
- zrxAssetData,
- order.makerAddress,
- order.feeRecipientAddress,
- fillResults.makerFeePaid
- );
- dispatchTransferFrom(
- zrxAssetData,
- takerAddress,
- order.feeRecipientAddress,
- fillResults.takerFeePaid
- );
- }
-}
-
-contract MixinSignatureValidator is
- ReentrancyGuard,
- MSignatureValidator,
- MTransactions
-{
- using LibBytes for bytes;
-
- // Mapping of hash => signer => signed
- mapping (bytes32 => mapping (address => bool)) public preSigned;
-
- // Mapping of signer => validator => approved
- mapping (address => mapping (address => bool)) public allowedValidators;
-
- /// @dev Approves a hash on-chain using any valid signature type.
- /// After presigning a hash, the preSign signature type will become valid for that hash and signer.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- function preSign(
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- external
- {
- if (signerAddress != msg.sender) {
- require(
- isValidSignature(
- hash,
- signerAddress,
- signature
- ),
- "INVALID_SIGNATURE"
- );
- }
- preSigned[hash][signerAddress] = true;
- }
-
- /// @dev Approves/unnapproves a Validator contract to verify signatures on signer's behalf.
- /// @param validatorAddress Address of Validator contract.
- /// @param approval Approval or disapproval of Validator contract.
- function setSignatureValidatorApproval(
- address validatorAddress,
- bool approval
- )
- external
- nonReentrant
- {
- address signerAddress = getCurrentContextAddress();
- allowedValidators[signerAddress][validatorAddress] = approval;
- emit SignatureValidatorApproval(
- signerAddress,
- validatorAddress,
- approval
- );
- }
-
- /// @dev Verifies that a hash has been signed by the given signer.
- /// @param hash Any 32 byte hash.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if the address recovered from the provided signature matches the input signer address.
- function isValidSignature(
- bytes32 hash,
- address signerAddress,
- bytes memory signature
- )
- public
- view
- returns (bool isValid)
- {
- require(
- signature.length > 0,
- "LENGTH_GREATER_THAN_0_REQUIRED"
- );
-
- // Pop last byte off of signature byte array.
- uint8 signatureTypeRaw = uint8(signature.popLastByte());
-
- // Ensure signature is supported
- require(
- signatureTypeRaw < uint8(SignatureType.NSignatureTypes),
- "SIGNATURE_UNSUPPORTED"
- );
-
- SignatureType signatureType = SignatureType(signatureTypeRaw);
-
- // Variables are not scoped in Solidity.
- uint8 v;
- bytes32 r;
- bytes32 s;
- address recovered;
-
- // Always illegal signature.
- // This is always an implicit option since a signer can create a
- // signature array with invalid type or length. We may as well make
- // it an explicit option. This aids testing and analysis. It is
- // also the initialization value for the enum type.
- if (signatureType == SignatureType.Illegal) {
- revert("SIGNATURE_ILLEGAL");
-
- // Always invalid signature.
- // Like Illegal, this is always implicitly available and therefore
- // offered explicitly. It can be implicitly created by providing
- // a correctly formatted but incorrect signature.
- } else if (signatureType == SignatureType.Invalid) {
- require(
- signature.length == 0,
- "LENGTH_0_REQUIRED"
- );
- isValid = false;
- return isValid;
-
- // Signature using EIP712
- } else if (signatureType == SignatureType.EIP712) {
- require(
- signature.length == 65,
- "LENGTH_65_REQUIRED"
- );
- v = uint8(signature[0]);
- r = signature.readBytes32(1);
- s = signature.readBytes32(33);
- recovered = ecrecover(
- hash,
- v,
- r,
- s
- );
- isValid = signerAddress == recovered;
- return isValid;
-
- // Signed using web3.eth_sign
- } else if (signatureType == SignatureType.EthSign) {
- require(
- signature.length == 65,
- "LENGTH_65_REQUIRED"
- );
- v = uint8(signature[0]);
- r = signature.readBytes32(1);
- s = signature.readBytes32(33);
- recovered = ecrecover(
- keccak256(abi.encodePacked(
- "\x19Ethereum Signed Message:\n32",
- hash
- )),
- v,
- r,
- s
- );
- isValid = signerAddress == recovered;
- return isValid;
-
- // Signature verified by wallet contract.
- // If used with an order, the maker of the order is the wallet contract.
- } else if (signatureType == SignatureType.Wallet) {
- isValid = isValidWalletSignature(
- hash,
- signerAddress,
- signature
- );
- return isValid;
-
- // Signature verified by validator contract.
- // If used with an order, the maker of the order can still be an EOA.
- // A signature using this type should be encoded as:
- // | Offset | Length | Contents |
- // | 0x00 | x | Signature to validate |
- // | 0x00 + x | 20 | Address of validator contract |
- // | 0x14 + x | 1 | Signature type is always "\x06" |
- } else if (signatureType == SignatureType.Validator) {
- // Pop last 20 bytes off of signature byte array.
- address validatorAddress = signature.popLast20Bytes();
-
- // Ensure signer has approved validator.
- if (!allowedValidators[signerAddress][validatorAddress]) {
- return false;
- }
- isValid = isValidValidatorSignature(
- validatorAddress,
- hash,
- signerAddress,
- signature
- );
- return isValid;
-
- // Signer signed hash previously using the preSign function.
- } else if (signatureType == SignatureType.PreSigned) {
- isValid = preSigned[hash][signerAddress];
- return isValid;
- }
-
- // Anything else is illegal (We do not return false because
- // the signature may actually be valid, just not in a format
- // that we currently support. In this case returning false
- // may lead the caller to incorrectly believe that the
- // signature was invalid.)
- revert("SIGNATURE_UNSUPPORTED");
- }
-
- /// @dev Verifies signature using logic defined by Wallet contract.
- /// @param hash Any 32 byte hash.
- /// @param walletAddress Address that should have signed the given hash
- /// and defines its own signature verification method.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if signature is valid for given wallet..
- function isValidWalletSignature(
- bytes32 hash,
- address walletAddress,
- bytes signature
- )
- internal
- view
- returns (bool isValid)
- {
- bytes memory calldata = abi.encodeWithSelector(
- IWallet(walletAddress).isValidSignature.selector,
- hash,
- signature
- );
- assembly {
- let cdStart := add(calldata, 32)
- let success := staticcall(
- gas, // forward all gas
- walletAddress, // address of Wallet contract
- cdStart, // pointer to start of input
- mload(calldata), // length of input
- cdStart, // write output over input
- 32 // output size is 32 bytes
- )
-
- switch success
- case 0 {
- // Revert with `Error("WALLET_ERROR")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000000c57414c4c45545f4552524f5200000000000000000000000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
- case 1 {
- // Signature is valid if call did not revert and returned true
- isValid := mload(cdStart)
- }
- }
- return isValid;
- }
-
- /// @dev Verifies signature using logic defined by Validator contract.
- /// @param validatorAddress Address of validator contract.
- /// @param hash Any 32 byte hash.
- /// @param signerAddress Address that should have signed the given hash.
- /// @param signature Proof that the hash has been signed by signer.
- /// @return True if the address recovered from the provided signature matches the input signer address.
- function isValidValidatorSignature(
- address validatorAddress,
- bytes32 hash,
- address signerAddress,
- bytes signature
- )
- internal
- view
- returns (bool isValid)
- {
- bytes memory calldata = abi.encodeWithSelector(
- IValidator(signerAddress).isValidSignature.selector,
- hash,
- signerAddress,
- signature
- );
- assembly {
- let cdStart := add(calldata, 32)
- let success := staticcall(
- gas, // forward all gas
- validatorAddress, // address of Validator contract
- cdStart, // pointer to start of input
- mload(calldata), // length of input
- cdStart, // write output over input
- 32 // output size is 32 bytes
- )
-
- switch success
- case 0 {
- // Revert with `Error("VALIDATOR_ERROR")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000000f56414c494441544f525f4552524f5200000000000000000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
- case 1 {
- // Signature is valid if call did not revert and returned true
- isValid := mload(cdStart)
- }
- }
- return isValid;
- }
-}
-
-contract MixinWrapperFunctions is
- ReentrancyGuard,
- LibMath,
- LibFillResults,
- LibAbiEncoder,
- MExchangeCore,
- MWrapperFunctions
-{
- /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- function fillOrKillOrder(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- nonReentrant
- returns (FillResults memory fillResults)
- {
- fillResults = fillOrKillOrderInternal(
- order,
- takerAssetFillAmount,
- signature
- );
- return fillResults;
- }
-
- /// @dev Fills the input order.
- /// Returns false if the transaction would otherwise revert.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- /// @return Amounts filled and fees paid by maker and taker.
- function fillOrderNoThrow(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- public
- returns (FillResults memory fillResults)
- {
- // ABI encode calldata for `fillOrder`
- bytes memory fillOrderCalldata = abiEncodeFillOrder(
- order,
- takerAssetFillAmount,
- signature
- );
-
- // Delegate to `fillOrder` and handle any exceptions gracefully
- assembly {
- let success := delegatecall(
- gas, // forward all gas
- address, // call address of this contract
- add(fillOrderCalldata, 32), // pointer to start of input (skip array length in first 32 bytes)
- mload(fillOrderCalldata), // length of input
- fillOrderCalldata, // write output over input
- 128 // output size is 128 bytes
- )
- if success {
- mstore(fillResults, mload(fillOrderCalldata))
- mstore(add(fillResults, 32), mload(add(fillOrderCalldata, 32)))
- mstore(add(fillResults, 64), mload(add(fillOrderCalldata, 64)))
- mstore(add(fillResults, 96), mload(add(fillOrderCalldata, 96)))
- }
- }
- // fillResults values will be 0 by default if call was unsuccessful
- return fillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrder.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- /// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
- function batchFillOrders(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- nonReentrant
- returns (FillResults memory totalFillResults)
- {
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
- FillResults memory singleFillResults = fillOrderInternal(
- orders[i],
- takerAssetFillAmounts[i],
- signatures[i]
- );
- addFillResults(totalFillResults, singleFillResults);
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrKill.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- /// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
- function batchFillOrKillOrders(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- nonReentrant
- returns (FillResults memory totalFillResults)
- {
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
- FillResults memory singleFillResults = fillOrKillOrderInternal(
- orders[i],
- takerAssetFillAmounts[i],
- signatures[i]
- );
- addFillResults(totalFillResults, singleFillResults);
- }
- return totalFillResults;
- }
-
- /// @dev Fills an order with specified parameters and ECDSA signature.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- /// NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets.
- function batchFillOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures
- )
- public
- returns (FillResults memory totalFillResults)
- {
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
- FillResults memory singleFillResults = fillOrderNoThrow(
- orders[i],
- takerAssetFillAmounts[i],
- signatures[i]
- );
- addFillResults(totalFillResults, singleFillResults);
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signatures Proofs that orders have been created by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellOrders(
- LibOrder.Order[] memory orders,
- uint256 takerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- nonReentrant
- returns (FillResults memory totalFillResults)
- {
- bytes memory takerAssetData = orders[0].takerAssetData;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // We assume that asset being sold by taker is the same for each order.
- // Rather than passing this in as calldata, we use the takerAssetData from the first order in all later orders.
- orders[i].takerAssetData = takerAssetData;
-
- // Calculate the remaining amount of takerAsset to sell
- uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
-
- // Attempt to sell the remaining amount of takerAsset
- FillResults memory singleFillResults = fillOrderInternal(
- orders[i],
- remainingTakerAssetFillAmount,
- signatures[i]
- );
-
- // Update amounts filled and fees paid by maker and taker
- addFillResults(totalFillResults, singleFillResults);
-
- // Stop execution if the entire amount of takerAsset has been sold
- if (totalFillResults.takerAssetFilledAmount >= takerAssetFillAmount) {
- break;
- }
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketSellOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256 takerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (FillResults memory totalFillResults)
- {
- bytes memory takerAssetData = orders[0].takerAssetData;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // We assume that asset being sold by taker is the same for each order.
- // Rather than passing this in as calldata, we use the takerAssetData from the first order in all later orders.
- orders[i].takerAssetData = takerAssetData;
-
- // Calculate the remaining amount of takerAsset to sell
- uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
-
- // Attempt to sell the remaining amount of takerAsset
- FillResults memory singleFillResults = fillOrderNoThrow(
- orders[i],
- remainingTakerAssetFillAmount,
- signatures[i]
- );
-
- // Update amounts filled and fees paid by maker and taker
- addFillResults(totalFillResults, singleFillResults);
-
- // Stop execution if the entire amount of takerAsset has been sold
- if (totalFillResults.takerAssetFilledAmount >= takerAssetFillAmount) {
- break;
- }
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple calls of fillOrder until total amount of makerAsset is bought by taker.
- /// @param orders Array of order specifications.
- /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketBuyOrders(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- nonReentrant
- returns (FillResults memory totalFillResults)
- {
- bytes memory makerAssetData = orders[0].makerAssetData;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // We assume that asset being bought by taker is the same for each order.
- // Rather than passing this in as calldata, we copy the makerAssetData from the first order onto all later orders.
- orders[i].makerAssetData = makerAssetData;
-
- // Calculate the remaining amount of makerAsset to buy
- uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
-
- // Convert the remaining amount of makerAsset to buy into remaining amount
- // of takerAsset to sell, assuming entire amount can be sold in the current order
- uint256 remainingTakerAssetFillAmount = getPartialAmountFloor(
- orders[i].takerAssetAmount,
- orders[i].makerAssetAmount,
- remainingMakerAssetFillAmount
- );
-
- // Attempt to sell the remaining amount of takerAsset
- FillResults memory singleFillResults = fillOrderInternal(
- orders[i],
- remainingTakerAssetFillAmount,
- signatures[i]
- );
-
- // Update amounts filled and fees paid by maker and taker
- addFillResults(totalFillResults, singleFillResults);
-
- // Stop execution if the entire amount of makerAsset has been bought
- if (totalFillResults.makerAssetFilledAmount >= makerAssetFillAmount) {
- break;
- }
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
- /// Returns false if the transaction would otherwise revert.
- /// @param orders Array of order specifications.
- /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
- /// @param signatures Proofs that orders have been signed by makers.
- /// @return Amounts filled and fees paid by makers and taker.
- function marketBuyOrdersNoThrow(
- LibOrder.Order[] memory orders,
- uint256 makerAssetFillAmount,
- bytes[] memory signatures
- )
- public
- returns (FillResults memory totalFillResults)
- {
- bytes memory makerAssetData = orders[0].makerAssetData;
-
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
-
- // We assume that asset being bought by taker is the same for each order.
- // Rather than passing this in as calldata, we copy the makerAssetData from the first order onto all later orders.
- orders[i].makerAssetData = makerAssetData;
-
- // Calculate the remaining amount of makerAsset to buy
- uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
-
- // Convert the remaining amount of makerAsset to buy into remaining amount
- // of takerAsset to sell, assuming entire amount can be sold in the current order
- uint256 remainingTakerAssetFillAmount = getPartialAmountFloor(
- orders[i].takerAssetAmount,
- orders[i].makerAssetAmount,
- remainingMakerAssetFillAmount
- );
-
- // Attempt to sell the remaining amount of takerAsset
- FillResults memory singleFillResults = fillOrderNoThrow(
- orders[i],
- remainingTakerAssetFillAmount,
- signatures[i]
- );
-
- // Update amounts filled and fees paid by maker and taker
- addFillResults(totalFillResults, singleFillResults);
-
- // Stop execution if the entire amount of makerAsset has been bought
- if (totalFillResults.makerAssetFilledAmount >= makerAssetFillAmount) {
- break;
- }
- }
- return totalFillResults;
- }
-
- /// @dev Synchronously cancels multiple orders in a single transaction.
- /// @param orders Array of order specifications.
- function batchCancelOrders(LibOrder.Order[] memory orders)
- public
- nonReentrant
- {
- uint256 ordersLength = orders.length;
- for (uint256 i = 0; i != ordersLength; i++) {
- cancelOrderInternal(orders[i]);
- }
- }
-
- /// @dev Fetches information for all passed in orders.
- /// @param orders Array of order specifications.
- /// @return Array of OrderInfo instances that correspond to each order.
- function getOrdersInfo(LibOrder.Order[] memory orders)
- public
- view
- returns (LibOrder.OrderInfo[] memory)
- {
- uint256 ordersLength = orders.length;
- LibOrder.OrderInfo[] memory ordersInfo = new LibOrder.OrderInfo[](ordersLength);
- for (uint256 i = 0; i != ordersLength; i++) {
- ordersInfo[i] = getOrderInfo(orders[i]);
- }
- return ordersInfo;
- }
-
- /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
- /// @param order Order struct containing order specifications.
- /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
- /// @param signature Proof that order has been created by maker.
- function fillOrKillOrderInternal(
- LibOrder.Order memory order,
- uint256 takerAssetFillAmount,
- bytes memory signature
- )
- internal
- returns (FillResults memory fillResults)
- {
- fillResults = fillOrderInternal(
- order,
- takerAssetFillAmount,
- signature
- );
- require(
- fillResults.takerAssetFilledAmount == takerAssetFillAmount,
- "COMPLETE_FILL_FAILED"
- );
- return fillResults;
- }
-}
-
-contract MixinTransactions is
- LibEIP712,
- MSignatureValidator,
- MTransactions
-{
- // Mapping of transaction hash => executed
- // This prevents transactions from being executed more than once.
- mapping (bytes32 => bool) public transactions;
-
- // Address of current transaction signer
- address public currentContextAddress;
-
- /// @dev Executes an exchange method call in the context of signer.
- /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
- /// @param signerAddress Address of transaction signer.
- /// @param data AbiV2 encoded calldata.
- /// @param signature Proof of signer transaction by signer.
- function executeTransaction(
- uint256 salt,
- address signerAddress,
- bytes data,
- bytes signature
- )
- external
- {
- // Prevent reentrancy
- require(
- currentContextAddress == address(0),
- "REENTRANCY_ILLEGAL"
- );
-
- bytes32 transactionHash = hashEIP712Message(hashZeroExTransaction(
- salt,
- signerAddress,
- data
- ));
-
- // Validate transaction has not been executed
- require(
- !transactions[transactionHash],
- "INVALID_TX_HASH"
- );
-
- // Transaction always valid if signer is sender of transaction
- if (signerAddress != msg.sender) {
- // Validate signature
- require(
- isValidSignature(
- transactionHash,
- signerAddress,
- signature
- ),
- "INVALID_TX_SIGNATURE"
- );
-
- // Set the current transaction signer
- currentContextAddress = signerAddress;
- }
-
- // Execute transaction
- transactions[transactionHash] = true;
- require(
- address(this).delegatecall(data),
- "FAILED_EXECUTION"
- );
-
- // Reset current transaction signer if it was previously updated
- if (signerAddress != msg.sender) {
- currentContextAddress = address(0);
- }
- }
-
- /// @dev Calculates EIP712 hash of the Transaction.
- /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
- /// @param signerAddress Address of transaction signer.
- /// @param data AbiV2 encoded calldata.
- /// @return EIP712 hash of the Transaction.
- function hashZeroExTransaction(
- uint256 salt,
- address signerAddress,
- bytes memory data
- )
- internal
- pure
- returns (bytes32 result)
- {
- bytes32 schemaHash = EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH;
- bytes32 dataHash = keccak256(data);
-
- // Assembly for more efficiently computing:
- // keccak256(abi.encodePacked(
- // EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH,
- // salt,
- // bytes32(signerAddress),
- // keccak256(data)
- // ));
-
- assembly {
- // Load free memory pointer
- let memPtr := mload(64)
-
- mstore(memPtr, schemaHash) // hash of schema
- mstore(add(memPtr, 32), salt) // salt
- mstore(add(memPtr, 64), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff)) // signerAddress
- mstore(add(memPtr, 96), dataHash) // hash of data
-
- // Compute hash
- result := keccak256(memPtr, 128)
- }
- return result;
- }
-
- /// @dev The current function will be called in the context of this address (either 0x transaction signer or `msg.sender`).
- /// If calling a fill function, this address will represent the taker.
- /// If calling a cancel function, this address will represent the maker.
- /// @return Signer of 0x transaction if entry point is `executeTransaction`.
- /// `msg.sender` if entry point is any other function.
- function getCurrentContextAddress()
- internal
- view
- returns (address)
- {
- address currentContextAddress_ = currentContextAddress;
- address contextAddress = currentContextAddress_ == address(0) ? msg.sender : currentContextAddress_;
- return contextAddress;
- }
-}
-
-contract MixinAssetProxyDispatcher is
- Ownable,
- MAssetProxyDispatcher
-{
- // Mapping from Asset Proxy Id's to their respective Asset Proxy
- mapping (bytes4 => IAssetProxy) public assetProxies;
-
- /// @dev Registers an asset proxy to its asset proxy id.
- /// Once an asset proxy is registered, it cannot be unregistered.
- /// @param assetProxy Address of new asset proxy to register.
- function registerAssetProxy(address assetProxy)
- external
- onlyOwner
- {
- IAssetProxy assetProxyContract = IAssetProxy(assetProxy);
-
- // Ensure that no asset proxy exists with current id.
- bytes4 assetProxyId = assetProxyContract.getProxyId();
- address currentAssetProxy = assetProxies[assetProxyId];
- require(
- currentAssetProxy == address(0),
- "ASSET_PROXY_ALREADY_EXISTS"
- );
-
- // Add asset proxy and log registration.
- assetProxies[assetProxyId] = assetProxyContract;
- emit AssetProxyRegistered(
- assetProxyId,
- assetProxy
- );
- }
-
- /// @dev Gets an asset proxy.
- /// @param assetProxyId Id of the asset proxy.
- /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
- function getAssetProxy(bytes4 assetProxyId)
- external
- view
- returns (address)
- {
- return assetProxies[assetProxyId];
- }
-
- /// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
- /// @param assetData Byte array encoded for the asset.
- /// @param from Address to transfer token from.
- /// @param to Address to transfer token to.
- /// @param amount Amount of token to transfer.
- function dispatchTransferFrom(
- bytes memory assetData,
- address from,
- address to,
- uint256 amount
- )
- internal
- {
- // Do nothing if no amount should be transferred.
- if (amount > 0 && from != to) {
- // Ensure assetData length is valid
- require(
- assetData.length > 3,
- "LENGTH_GREATER_THAN_3_REQUIRED"
- );
-
- // Lookup assetProxy. We do not use `LibBytes.readBytes4` for gas efficiency reasons.
- bytes4 assetProxyId;
- assembly {
- assetProxyId := and(mload(
- add(assetData, 32)),
- 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000
- )
- }
- address assetProxy = assetProxies[assetProxyId];
-
- // Ensure that assetProxy exists
- require(
- assetProxy != address(0),
- "ASSET_PROXY_DOES_NOT_EXIST"
- );
-
- // We construct calldata for the `assetProxy.transferFrom` ABI.
- // The layout of this calldata is in the table below.
- //
- // | Area | Offset | Length | Contents |
- // | -------- |--------|---------|-------------------------------------------- |
- // | Header | 0 | 4 | function selector |
- // | Params | | 4 * 32 | function parameters: |
- // | | 4 | | 1. offset to assetData (*) |
- // | | 36 | | 2. from |
- // | | 68 | | 3. to |
- // | | 100 | | 4. amount |
- // | Data | | | assetData: |
- // | | 132 | 32 | assetData Length |
- // | | 164 | ** | assetData Contents |
-
- assembly {
- /////// Setup State ///////
- // `cdStart` is the start of the calldata for `assetProxy.transferFrom` (equal to free memory ptr).
- let cdStart := mload(64)
- // `dataAreaLength` is the total number of words needed to store `assetData`
- // As-per the ABI spec, this value is padded up to the nearest multiple of 32,
- // and includes 32-bytes for length.
- let dataAreaLength := and(add(mload(assetData), 63), 0xFFFFFFFFFFFE0)
- // `cdEnd` is the end of the calldata for `assetProxy.transferFrom`.
- let cdEnd := add(cdStart, add(132, dataAreaLength))
-
-
- /////// Setup Header Area ///////
- // This area holds the 4-byte `transferFromSelector`.
- // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
- mstore(cdStart, 0xa85e59e400000000000000000000000000000000000000000000000000000000)
-
- /////// Setup Params Area ///////
- // Each parameter is padded to 32-bytes. The entire Params Area is 128 bytes.
- // Notes:
- // 1. The offset to `assetData` is the length of the Params Area (128 bytes).
- // 2. A 20-byte mask is applied to addresses to zero-out the unused bytes.
- mstore(add(cdStart, 4), 128)
- mstore(add(cdStart, 36), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
- mstore(add(cdStart, 68), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
- mstore(add(cdStart, 100), amount)
-
- /////// Setup Data Area ///////
- // This area holds `assetData`.
- let dataArea := add(cdStart, 132)
- // solhint-disable-next-line no-empty-blocks
- for {} lt(dataArea, cdEnd) {} {
- mstore(dataArea, mload(assetData))
- dataArea := add(dataArea, 32)
- assetData := add(assetData, 32)
- }
-
- /////// Call `assetProxy.transferFrom` using the constructed calldata ///////
- let success := call(
- gas, // forward all gas
- assetProxy, // call address of asset proxy
- 0, // don't send any ETH
- cdStart, // pointer to start of input
- sub(cdEnd, cdStart), // length of input
- cdStart, // write output over input
- 512 // reserve 512 bytes for output
- )
- if iszero(success) {
- revert(cdStart, returndatasize())
- }
- }
- }
- }
-}
-
-contract MixinMatchOrders is
- ReentrancyGuard,
- LibConstants,
- LibMath,
- MAssetProxyDispatcher,
- MExchangeCore,
- MMatchOrders,
- MTransactions
-{
- /// @dev Match two complementary orders that have a profitable spread.
- /// Each order is filled at their respective price point. However, the calculations are
- /// carried out as though the orders are both being filled at the right order's price point.
- /// The profit made by the left order goes to the taker (who matched the two orders).
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- /// @param leftSignature Proof that order was created by the left maker.
- /// @param rightSignature Proof that order was created by the right maker.
- /// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders.
- function matchOrders(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- bytes memory leftSignature,
- bytes memory rightSignature
- )
- public
- nonReentrant
- returns (LibFillResults.MatchedFillResults memory matchedFillResults)
- {
- // We assume that rightOrder.takerAssetData == leftOrder.makerAssetData and rightOrder.makerAssetData == leftOrder.takerAssetData.
- // If this assumption isn't true, the match will fail at signature validation.
- rightOrder.makerAssetData = leftOrder.takerAssetData;
- rightOrder.takerAssetData = leftOrder.makerAssetData;
-
- // Get left & right order info
- LibOrder.OrderInfo memory leftOrderInfo = getOrderInfo(leftOrder);
- LibOrder.OrderInfo memory rightOrderInfo = getOrderInfo(rightOrder);
-
- // Fetch taker address
- address takerAddress = getCurrentContextAddress();
-
- // Either our context is valid or we revert
- assertFillableOrder(
- leftOrder,
- leftOrderInfo,
- takerAddress,
- leftSignature
- );
- assertFillableOrder(
- rightOrder,
- rightOrderInfo,
- takerAddress,
- rightSignature
- );
- assertValidMatch(leftOrder, rightOrder);
-
- // Compute proportional fill amounts
- matchedFillResults = calculateMatchedFillResults(
- leftOrder,
- rightOrder,
- leftOrderInfo.orderTakerAssetFilledAmount,
- rightOrderInfo.orderTakerAssetFilledAmount
- );
-
- // Validate fill contexts
- assertValidFill(
- leftOrder,
- leftOrderInfo,
- matchedFillResults.left.takerAssetFilledAmount,
- matchedFillResults.left.takerAssetFilledAmount,
- matchedFillResults.left.makerAssetFilledAmount
- );
- assertValidFill(
- rightOrder,
- rightOrderInfo,
- matchedFillResults.right.takerAssetFilledAmount,
- matchedFillResults.right.takerAssetFilledAmount,
- matchedFillResults.right.makerAssetFilledAmount
- );
-
- // Update exchange state
- updateFilledState(
- leftOrder,
- takerAddress,
- leftOrderInfo.orderHash,
- leftOrderInfo.orderTakerAssetFilledAmount,
- matchedFillResults.left
- );
- updateFilledState(
- rightOrder,
- takerAddress,
- rightOrderInfo.orderHash,
- rightOrderInfo.orderTakerAssetFilledAmount,
- matchedFillResults.right
- );
-
- // Settle matched orders. Succeeds or throws.
- settleMatchedOrders(
- leftOrder,
- rightOrder,
- takerAddress,
- matchedFillResults
- );
-
- return matchedFillResults;
- }
-
- /// @dev Validates context for matchOrders. Succeeds or throws.
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- function assertValidMatch(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder
- )
- internal
- pure
- {
- // Make sure there is a profitable spread.
- // There is a profitable spread iff the cost per unit bought (OrderA.MakerAmount/OrderA.TakerAmount) for each order is greater
- // than the profit per unit sold of the matched order (OrderB.TakerAmount/OrderB.MakerAmount).
- // This is satisfied by the equations below:
- // <leftOrder.makerAssetAmount> / <leftOrder.takerAssetAmount> >= <rightOrder.takerAssetAmount> / <rightOrder.makerAssetAmount>
- // AND
- // <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount> >= <leftOrder.takerAssetAmount> / <leftOrder.makerAssetAmount>
- // These equations can be combined to get the following:
- require(
- safeMul(leftOrder.makerAssetAmount, rightOrder.makerAssetAmount) >=
- safeMul(leftOrder.takerAssetAmount, rightOrder.takerAssetAmount),
- "NEGATIVE_SPREAD_REQUIRED"
- );
- }
-
- /// @dev Calculates fill amounts for the matched orders.
- /// Each order is filled at their respective price point. However, the calculations are
- /// carried out as though the orders are both being filled at the right order's price point.
- /// The profit made by the leftOrder order goes to the taker (who matched the two orders).
- /// @param leftOrder First order to match.
- /// @param rightOrder Second order to match.
- /// @param leftOrderTakerAssetFilledAmount Amount of left order already filled.
- /// @param rightOrderTakerAssetFilledAmount Amount of right order already filled.
- /// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
- function calculateMatchedFillResults(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- uint256 leftOrderTakerAssetFilledAmount,
- uint256 rightOrderTakerAssetFilledAmount
- )
- internal
- pure
- returns (LibFillResults.MatchedFillResults memory matchedFillResults)
- {
- // Derive maker asset amounts for left & right orders, given store taker assert amounts
- uint256 leftTakerAssetAmountRemaining = safeSub(leftOrder.takerAssetAmount, leftOrderTakerAssetFilledAmount);
- uint256 leftMakerAssetAmountRemaining = safeGetPartialAmountFloor(
- leftOrder.makerAssetAmount,
- leftOrder.takerAssetAmount,
- leftTakerAssetAmountRemaining
- );
- uint256 rightTakerAssetAmountRemaining = safeSub(rightOrder.takerAssetAmount, rightOrderTakerAssetFilledAmount);
- uint256 rightMakerAssetAmountRemaining = safeGetPartialAmountFloor(
- rightOrder.makerAssetAmount,
- rightOrder.takerAssetAmount,
- rightTakerAssetAmountRemaining
- );
-
- // Calculate fill results for maker and taker assets: at least one order will be fully filled.
- // The maximum amount the left maker can buy is `leftTakerAssetAmountRemaining`
- // The maximum amount the right maker can sell is `rightMakerAssetAmountRemaining`
- // We have two distinct cases for calculating the fill results:
- // Case 1.
- // If the left maker can buy more than the right maker can sell, then only the right order is fully filled.
- // If the left maker can buy exactly what the right maker can sell, then both orders are fully filled.
- // Case 2.
- // If the left maker cannot buy more than the right maker can sell, then only the left order is fully filled.
- if (leftTakerAssetAmountRemaining >= rightMakerAssetAmountRemaining) {
- // Case 1: Right order is fully filled
- matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining;
- matchedFillResults.right.takerAssetFilledAmount = rightTakerAssetAmountRemaining;
- matchedFillResults.left.takerAssetFilledAmount = matchedFillResults.right.makerAssetFilledAmount;
- // Round down to ensure the maker's exchange rate does not exceed the price specified by the order.
- // We favor the maker when the exchange rate must be rounded.
- matchedFillResults.left.makerAssetFilledAmount = safeGetPartialAmountFloor(
- leftOrder.makerAssetAmount,
- leftOrder.takerAssetAmount,
- matchedFillResults.left.takerAssetFilledAmount
- );
- } else {
- // Case 2: Left order is fully filled
- matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining;
- matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining;
- matchedFillResults.right.makerAssetFilledAmount = matchedFillResults.left.takerAssetFilledAmount;
- // Round up to ensure the maker's exchange rate does not exceed the price specified by the order.
- // We favor the maker when the exchange rate must be rounded.
- matchedFillResults.right.takerAssetFilledAmount = safeGetPartialAmountCeil(
- rightOrder.takerAssetAmount,
- rightOrder.makerAssetAmount,
- matchedFillResults.right.makerAssetFilledAmount
- );
- }
-
- // Calculate amount given to taker
- matchedFillResults.leftMakerAssetSpreadAmount = safeSub(
- matchedFillResults.left.makerAssetFilledAmount,
- matchedFillResults.right.takerAssetFilledAmount
- );
-
- // Compute fees for left order
- matchedFillResults.left.makerFeePaid = safeGetPartialAmountFloor(
- matchedFillResults.left.makerAssetFilledAmount,
- leftOrder.makerAssetAmount,
- leftOrder.makerFee
- );
- matchedFillResults.left.takerFeePaid = safeGetPartialAmountFloor(
- matchedFillResults.left.takerAssetFilledAmount,
- leftOrder.takerAssetAmount,
- leftOrder.takerFee
- );
-
- // Compute fees for right order
- matchedFillResults.right.makerFeePaid = safeGetPartialAmountFloor(
- matchedFillResults.right.makerAssetFilledAmount,
- rightOrder.makerAssetAmount,
- rightOrder.makerFee
- );
- matchedFillResults.right.takerFeePaid = safeGetPartialAmountFloor(
- matchedFillResults.right.takerAssetFilledAmount,
- rightOrder.takerAssetAmount,
- rightOrder.takerFee
- );
-
- // Return fill results
- return matchedFillResults;
- }
-
- /// @dev Settles matched order by transferring appropriate funds between order makers, taker, and fee recipient.
- /// @param leftOrder First matched order.
- /// @param rightOrder Second matched order.
- /// @param takerAddress Address that matched the orders. The taker receives the spread between orders as profit.
- /// @param matchedFillResults Struct holding amounts to transfer between makers, taker, and fee recipients.
- function settleMatchedOrders(
- LibOrder.Order memory leftOrder,
- LibOrder.Order memory rightOrder,
- address takerAddress,
- LibFillResults.MatchedFillResults memory matchedFillResults
- )
- private
- {
- bytes memory zrxAssetData = ZRX_ASSET_DATA;
- // Order makers and taker
- dispatchTransferFrom(
- leftOrder.makerAssetData,
- leftOrder.makerAddress,
- rightOrder.makerAddress,
- matchedFillResults.right.takerAssetFilledAmount
- );
- dispatchTransferFrom(
- rightOrder.makerAssetData,
- rightOrder.makerAddress,
- leftOrder.makerAddress,
- matchedFillResults.left.takerAssetFilledAmount
- );
- dispatchTransferFrom(
- leftOrder.makerAssetData,
- leftOrder.makerAddress,
- takerAddress,
- matchedFillResults.leftMakerAssetSpreadAmount
- );
-
- // Maker fees
- dispatchTransferFrom(
- zrxAssetData,
- leftOrder.makerAddress,
- leftOrder.feeRecipientAddress,
- matchedFillResults.left.makerFeePaid
- );
- dispatchTransferFrom(
- zrxAssetData,
- rightOrder.makerAddress,
- rightOrder.feeRecipientAddress,
- matchedFillResults.right.makerFeePaid
- );
-
- // Taker fees
- if (leftOrder.feeRecipientAddress == rightOrder.feeRecipientAddress) {
- dispatchTransferFrom(
- zrxAssetData,
- takerAddress,
- leftOrder.feeRecipientAddress,
- safeAdd(
- matchedFillResults.left.takerFeePaid,
- matchedFillResults.right.takerFeePaid
- )
- );
- } else {
- dispatchTransferFrom(
- zrxAssetData,
- takerAddress,
- leftOrder.feeRecipientAddress,
- matchedFillResults.left.takerFeePaid
- );
- dispatchTransferFrom(
- zrxAssetData,
- takerAddress,
- rightOrder.feeRecipientAddress,
- matchedFillResults.right.takerFeePaid
- );
- }
- }
-}
-
-// solhint-disable no-empty-blocks
-contract Exchange is
- MixinExchangeCore,
- MixinMatchOrders,
- MixinSignatureValidator,
- MixinTransactions,
- MixinAssetProxyDispatcher,
- MixinWrapperFunctions
-{
- string constant public VERSION = "2.0.0";
-
- // Mixins are instantiated in the order they are inherited
- constructor ()
- public
- MixinExchangeCore()
- MixinMatchOrders()
- MixinSignatureValidator()
- MixinTransactions()
- MixinAssetProxyDispatcher()
- MixinWrapperFunctions()
- {}
-}
-
-contract MAuthorizable is
- IAuthorizable
-{
- // Event logged when a new address is authorized.
- event AuthorizedAddressAdded(
- address indexed target,
- address indexed caller
- );
-
- // Event logged when a currently authorized address is unauthorized.
- event AuthorizedAddressRemoved(
- address indexed target,
- address indexed caller
- );
-
- /// @dev Only authorized addresses can invoke functions with this modifier.
- modifier onlyAuthorized { revert(); _; }
-}
-
-contract MixinAuthorizable is
- Ownable,
- MAuthorizable
-{
- /// @dev Only authorized addresses can invoke functions with this modifier.
- modifier onlyAuthorized {
- require(
- authorized[msg.sender],
- "SENDER_NOT_AUTHORIZED"
- );
- _;
- }
-
- mapping (address => bool) public authorized;
- address[] public authorities;
-
- /// @dev Authorizes an address.
- /// @param target Address to authorize.
- function addAuthorizedAddress(address target)
- external
- onlyOwner
- {
- require(
- !authorized[target],
- "TARGET_ALREADY_AUTHORIZED"
- );
-
- authorized[target] = true;
- authorities.push(target);
- emit AuthorizedAddressAdded(target, msg.sender);
- }
-
- /// @dev Removes authorizion of an address.
- /// @param target Address to remove authorization from.
- function removeAuthorizedAddress(address target)
- external
- onlyOwner
- {
- require(
- authorized[target],
- "TARGET_NOT_AUTHORIZED"
- );
-
- delete authorized[target];
- for (uint256 i = 0; i < authorities.length; i++) {
- if (authorities[i] == target) {
- authorities[i] = authorities[authorities.length - 1];
- authorities.length -= 1;
- break;
- }
- }
- emit AuthorizedAddressRemoved(target, msg.sender);
- }
-
- /// @dev Removes authorizion of an address.
- /// @param target Address to remove authorization from.
- /// @param index Index of target in authorities array.
- function removeAuthorizedAddressAtIndex(
- address target,
- uint256 index
- )
- external
- onlyOwner
- {
- require(
- authorized[target],
- "TARGET_NOT_AUTHORIZED"
- );
- require(
- index < authorities.length,
- "INDEX_OUT_OF_BOUNDS"
- );
- require(
- authorities[index] == target,
- "AUTHORIZED_ADDRESS_MISMATCH"
- );
-
- delete authorized[target];
- authorities[index] = authorities[authorities.length - 1];
- authorities.length -= 1;
- emit AuthorizedAddressRemoved(target, msg.sender);
- }
-
- /// @dev Gets all authorized addresses.
- /// @return Array of authorized addresses.
- function getAuthorizedAddresses()
- external
- view
- returns (address[] memory)
- {
- return authorities;
- }
-}
-
-contract ERC20Proxy is
- MixinAuthorizable
-{
- // Id of this proxy.
- bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
-
- // solhint-disable-next-line payable-fallback
- function ()
- external
- {
- assembly {
- // The first 4 bytes of calldata holds the function selector
- let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)
-
- // `transferFrom` will be called with the following parameters:
- // assetData Encoded byte array.
- // from Address to transfer asset from.
- // to Address to transfer asset to.
- // amount Amount of asset to transfer.
- // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
- if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) {
-
- // To lookup a value in a mapping, we load from the storage location keccak256(k, p),
- // where k is the key left padded to 32 bytes and p is the storage slot
- let start := mload(64)
- mstore(start, and(caller, 0xffffffffffffffffffffffffffffffffffffffff))
- mstore(add(start, 32), authorized_slot)
-
- // Revert if authorized[msg.sender] == false
- if iszero(sload(keccak256(start, 64))) {
- // Revert with `Error("SENDER_NOT_AUTHORIZED")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
-
- // `transferFrom`.
- // The function is marked `external`, so no abi decodeding is done for
- // us. Instead, we expect the `calldata` memory to contain the
- // following:
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Header | 0 | 4 | function selector |
- // | Params | | 4 * 32 | function parameters: |
- // | | 4 | | 1. offset to assetData (*) |
- // | | 36 | | 2. from |
- // | | 68 | | 3. to |
- // | | 100 | | 4. amount |
- // | Data | | | assetData: |
- // | | 132 | 32 | assetData Length |
- // | | 164 | ** | assetData Contents |
- //
- // (*): offset is computed from start of function parameters, so offset
- // by an additional 4 bytes in the calldata.
- //
- // (**): see table below to compute length of assetData Contents
- //
- // WARNING: The ABIv2 specification allows additional padding between
- // the Params and Data section. This will result in a larger
- // offset to assetData.
-
- // Asset data itself is encoded as follows:
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Header | 0 | 4 | function selector |
- // | Params | | 1 * 32 | function parameters: |
- // | | 4 | 12 + 20 | 1. token address |
-
- // We construct calldata for the `token.transferFrom` ABI.
- // The layout of this calldata is in the table below.
- //
- // | Area | Offset | Length | Contents |
- // |----------|--------|---------|-------------------------------------|
- // | Header | 0 | 4 | function selector |
- // | Params | | 3 * 32 | function parameters: |
- // | | 4 | | 1. from |
- // | | 36 | | 2. to |
- // | | 68 | | 3. amount |
-
- /////// Read token address from calldata ///////
- // * The token address is stored in `assetData`.
- //
- // * The "offset to assetData" is stored at offset 4 in the calldata (table 1).
- // [assetDataOffsetFromParams = calldataload(4)]
- //
- // * Notes that the "offset to assetData" is relative to the "Params" area of calldata;
- // add 4 bytes to account for the length of the "Header" area (table 1).
- // [assetDataOffsetFromHeader = assetDataOffsetFromParams + 4]
- //
- // * The "token address" is offset 32+4=36 bytes into "assetData" (tables 1 & 2).
- // [tokenOffset = assetDataOffsetFromHeader + 36 = calldataload(4) + 4 + 36]
- let token := calldataload(add(calldataload(4), 40))
-
- /////// Setup Header Area ///////
- // This area holds the 4-byte `transferFrom` selector.
- // Any trailing data in transferFromSelector will be
- // overwritten in the next `mstore` call.
- mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
-
- /////// Setup Params Area ///////
- // We copy the fields `from`, `to` and `amount` in bulk
- // from our own calldata to the new calldata.
- calldatacopy(4, 36, 96)
-
- /////// Call `token.transferFrom` using the calldata ///////
- let success := call(
- gas, // forward all gas
- token, // call address of token contract
- 0, // don't send any ETH
- 0, // pointer to start of input
- 100, // length of input
- 0, // write output over input
- 32 // output size should be 32 bytes
- )
-
- /////// Check return data. ///////
- // If there is no return data, we assume the token incorrectly
- // does not return a bool. In this case we expect it to revert
- // on failure, which was handled above.
- // If the token does return data, we require that it is a single
- // nonzero 32 bytes value.
- // So the transfer succeeded if the call succeeded and either
- // returned nothing, or returned a non-zero 32 byte value.
- success := and(success, or(
- iszero(returndatasize),
- and(
- eq(returndatasize, 32),
- gt(mload(0), 0)
- )
- ))
- if success {
- return(0, 0)
- }
-
- // Revert with `Error("TRANSFER_FAILED")`
- mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
- mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000)
- mstore(96, 0)
- revert(0, 100)
- }
-
- // Revert if undefined function is called
- revert(0, 0)
- }
- }
-
- /// @dev Gets the proxy id associated with the proxy address.
- /// @return Proxy id.
- function getProxyId()
- external
- pure
- returns (bytes4)
- {
- return PROXY_ID;
- }
-}
-
-contract UnlimitedAllowanceToken is StandardToken {
-
- uint constant MAX_UINT = 2**256 - 1;
-
- /// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.
- /// @param _from Address to transfer from.
- /// @param _to Address to transfer to.
- /// @param _value Amount to transfer.
- /// @return Success of transfer.
- function transferFrom(address _from, address _to, uint _value)
- public
- returns (bool)
- {
- uint allowance = allowed[_from][msg.sender];
- if (balances[_from] >= _value
- && allowance >= _value
- && balances[_to] + _value >= balances[_to]
- ) {
- balances[_to] += _value;
- balances[_from] -= _value;
- if (allowance < MAX_UINT) {
- allowed[_from][msg.sender] -= _value;
- }
- Transfer(_from, _to, _value);
- return true;
- } else {
- return false;
- }
- }
-}
-
-contract ZRXToken is UnlimitedAllowanceToken {
-
- uint8 constant public decimals = 18;
- uint public totalSupply = 10**27; // 1 billion tokens, 18 decimal places
- string constant public name = "0x Protocol Token";
- string constant public symbol = "ZRX";
-
- function ZRXToken() {
- balances[msg.sender] = totalSupply;
- }
-}
diff --git a/src/contracts/exchanges/third-party/0x/LibOrder.sol b/src/contracts/exchanges/third-party/0x/LibOrder.sol
deleted file mode 100644
index edb620f6..00000000
--- a/src/contracts/exchanges/third-party/0x/LibOrder.sol
+++ /dev/null
@@ -1,191 +0,0 @@
-pragma solidity ^0.4.21;
-
-contract LibEIP712 {
-
- // EIP191 header for EIP712 prefix
- string constant internal EIP191_HEADER = "\x19\x01";
-
- // EIP712 Domain Name value
- string constant internal EIP712_DOMAIN_NAME = "0x Protocol";
-
- // EIP712 Domain Version value
- string constant internal EIP712_DOMAIN_VERSION = "2";
-
- // Hash of the EIP712 Domain Separator Schema
- bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(
- "EIP712Domain(",
- "string name,",
- "string version,",
- "address verifyingContract",
- ")"
- ));
-
- // Hash of the EIP712 Domain Separator data
- // solhint-disable-next-line var-name-mixedcase
- bytes32 public EIP712_DOMAIN_HASH;
-
- constructor ()
- public
- {
- EIP712_DOMAIN_HASH = keccak256(abi.encodePacked(
- EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,
- keccak256(bytes(EIP712_DOMAIN_NAME)),
- keccak256(bytes(EIP712_DOMAIN_VERSION)),
- bytes32(address(this))
- ));
- }
-
- /// @dev Calculates EIP712 encoding for a hash struct in this EIP712 Domain.
- /// @param hashStruct The EIP712 hash struct.
- /// @return EIP712 hash applied to this EIP712 Domain.
- function hashEIP712Message(bytes32 hashStruct)
- internal
- view
- returns (bytes32 result)
- {
- bytes32 eip712DomainHash = EIP712_DOMAIN_HASH;
-
- // Assembly for more efficient computing:
- // keccak256(abi.encodePacked(
- // EIP191_HEADER,
- // EIP712_DOMAIN_HASH,
- // hashStruct
- // ));
-
- assembly {
- // Load free memory pointer
- let memPtr := mload(64)
-
- mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header
- mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash
- mstore(add(memPtr, 34), hashStruct) // Hash of struct
-
- // Compute hash
- result := keccak256(memPtr, 66)
- }
- return result;
- }
-}
-
-contract LibOrder is
- LibEIP712
-{
- // Hash for the EIP712 Order Schema
- bytes32 constant internal EIP712_ORDER_SCHEMA_HASH = keccak256(abi.encodePacked(
- "Order(",
- "address makerAddress,",
- "address takerAddress,",
- "address feeRecipientAddress,",
- "address senderAddress,",
- "uint256 makerAssetAmount,",
- "uint256 takerAssetAmount,",
- "uint256 makerFee,",
- "uint256 takerFee,",
- "uint256 expirationTimeSeconds,",
- "uint256 salt,",
- "bytes makerAssetData,",
- "bytes takerAssetData",
- ")"
- ));
-
- // A valid order remains fillable until it is expired, fully filled, or cancelled.
- // An order's state is unaffected by external factors, like account balances.
- enum OrderStatus {
- INVALID, // Default value
- INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount
- INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount
- FILLABLE, // Order is fillable
- EXPIRED, // Order has already expired
- FULLY_FILLED, // Order is fully filled
- CANCELLED // Order has been cancelled
- }
-
- // solhint-disable max-line-length
- struct Order {
- address makerAddress; // Address that created the order.
- address takerAddress; // Address that is allowed to fill the order. If set to 0, any address is allowed to fill the order.
- address feeRecipientAddress; // Address that will recieve fees when order is filled.
- address senderAddress; // Address that is allowed to call Exchange contract methods that affect this order. If set to 0, any address is allowed to call these methods.
- uint256 makerAssetAmount; // Amount of makerAsset being offered by maker. Must be greater than 0.
- uint256 takerAssetAmount; // Amount of takerAsset being bid on by maker. Must be greater than 0.
- uint256 makerFee; // Amount of ZRX paid to feeRecipient by maker when order is filled. If set to 0, no transfer of ZRX from maker to feeRecipient will be attempted.
- uint256 takerFee; // Amount of ZRX paid to feeRecipient by taker when order is filled. If set to 0, no transfer of ZRX from taker to feeRecipient will be attempted.
- uint256 expirationTimeSeconds; // Timestamp in seconds at which order expires.
- uint256 salt; // Arbitrary number to facilitate uniqueness of the order's hash.
- bytes makerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring makerAsset. The last byte references the id of this proxy.
- bytes takerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerAsset. The last byte references the id of this proxy.
- }
- // solhint-enable max-line-length
-
- struct OrderInfo {
- uint8 orderStatus; // Status that describes order's validity and fillability.
- bytes32 orderHash; // EIP712 hash of the order (see LibOrder.getOrderHash).
- uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled.
- }
-
- /// @dev Calculates Keccak-256 hash of the order.
- /// @param order The order structure.
- /// @return Keccak-256 EIP712 hash of the order.
- function getOrderHash(Order memory order)
- internal
- view
- returns (bytes32 orderHash)
- {
- orderHash = hashEIP712Message(hashOrder(order));
- return orderHash;
- }
-
- /// @dev Calculates EIP712 hash of the order.
- /// @param order The order structure.
- /// @return EIP712 hash of the order.
- function hashOrder(Order memory order)
- internal
- pure
- returns (bytes32 result)
- {
- bytes32 schemaHash = EIP712_ORDER_SCHEMA_HASH;
- bytes32 makerAssetDataHash = keccak256(order.makerAssetData);
- bytes32 takerAssetDataHash = keccak256(order.takerAssetData);
-
- // Assembly for more efficiently computing:
- // keccak256(abi.encodePacked(
- // EIP712_ORDER_SCHEMA_HASH,
- // bytes32(order.makerAddress),
- // bytes32(order.takerAddress),
- // bytes32(order.feeRecipientAddress),
- // bytes32(order.senderAddress),
- // order.makerAssetAmount,
- // order.takerAssetAmount,
- // order.makerFee,
- // order.takerFee,
- // order.expirationTimeSeconds,
- // order.salt,
- // keccak256(order.makerAssetData),
- // keccak256(order.takerAssetData)
- // ));
-
- assembly {
- // Calculate memory addresses that will be swapped out before hashing
- let pos1 := sub(order, 32)
- let pos2 := add(order, 320)
- let pos3 := add(order, 352)
-
- // Backup
- let temp1 := mload(pos1)
- let temp2 := mload(pos2)
- let temp3 := mload(pos3)
-
- // Hash in place
- mstore(pos1, schemaHash)
- mstore(pos2, makerAssetDataHash)
- mstore(pos3, takerAssetDataHash)
- result := keccak256(pos1, 416)
-
- // Restore
- mstore(pos1, temp1)
- mstore(pos2, temp2)
- mstore(pos3, temp3)
- }
- return result;
- }
-}
\ No newline at end of file
diff --git a/src/contracts/exchanges/third-party/0x/Ownable.sol b/src/contracts/exchanges/third-party/0x/Ownable.sol
deleted file mode 100644
index 16973c2a..00000000
--- a/src/contracts/exchanges/third-party/0x/Ownable.sol
+++ /dev/null
@@ -1,36 +0,0 @@
-pragma solidity ^0.4.21;
-
-contract IOwnable {
-
- function transferOwnership(address newOwner)
- public;
-}
-
-contract Ownable is
- IOwnable
-{
- address public owner;
-
- constructor ()
- public
- {
- owner = msg.sender;
- }
-
- modifier onlyOwner() {
- require(
- msg.sender == owner,
- "ONLY_CONTRACT_OWNER"
- );
- _;
- }
-
- function transferOwnership(address newOwner)
- public
- onlyOwner
- {
- if (newOwner != address(0)) {
- owner = newOwner;
- }
- }
-}
diff --git a/src/contracts/exchanges/third-party/ethfinex/WrapperDependencies.sol b/src/contracts/exchanges/third-party/ethfinex/WrapperDependencies.sol
deleted file mode 100644
index c18f3023..00000000
--- a/src/contracts/exchanges/third-party/ethfinex/WrapperDependencies.sol
+++ /dev/null
@@ -1,89 +0,0 @@
-pragma solidity ^0.4.21;
-
-import "SafeMath.sol";
-
-/**
- * @title ERC20Basic
- * @dev Simpler version of ERC20 interface
- * @dev see https://github.com/ethereum/EIPs/issues/179
- */
-contract ERC20Basic {
- function totalSupply() public view returns (uint256);
- function balanceOf(address who) public view returns (uint256);
- function transfer(address to, uint256 value) public returns (bool);
- event Transfer(address indexed from, address indexed to, uint256 value);
-}
-
-contract ERC20Extended is ERC20Basic {
- function allowance(address owner, address spender) public view returns (uint256);
- function transferFrom(address from, address to, uint256 value) public returns (bool);
- function approve(address spender, uint256 value) public returns (bool);
- event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-/**ERC20OldBasic.sol
- * @title ERC20Basic
- * @dev Simpler version of ERC20 interface
- */
-contract ERC20OldBasic {
- function totalSupply() public view returns (uint256);
- function balanceOf(address who) public view returns (uint256);
- function transfer(address to, uint256 value) public;
- event Transfer(address indexed from, address indexed to, uint256 value);
-}
-
-/**
- * @title ERC20 interface
- * @dev see https://github.com/ethereum/EIPs/issues/20
- */
-contract ERC20Old is ERC20OldBasic {
- function allowance(address owner, address spender) public view returns (uint256);
- function transferFrom(address from, address to, uint256 value) public;
- function approve(address spender, uint256 value) public returns (bool);
- event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-/**
- * @title Basic token
- * @dev Basic version of StandardToken, with no allowances.
- */
-contract BasicToken is ERC20Basic {
- using SafeMath for uint256;
-
- mapping(address => uint256) balances;
-
- uint256 totalSupply_;
-
- /**
- * @dev total number of tokens in existence
- */
- function totalSupply() public view returns (uint256) {
- return totalSupply_;
- }
-
- /**
- * @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) {
- require(_to != address(0));
- require(_value <= balances[msg.sender]);
-
- // SafeMath.sub will throw if there is not enough balance.
- balances[msg.sender] = balances[msg.sender].sub(_value);
- balances[_to] = balances[_to].add(_value);
- Transfer(msg.sender, _to, _value);
- return true;
- }
-
- /**
- * @dev Gets the balance of the specified address.
- * @param _owner The address to query the the balance of.
- * @return An uint256 representing the amount owned by the passed address.
- */
- function balanceOf(address _owner) public view returns (uint256 balance) {
- return balances[_owner];
- }
-
-}
\ No newline at end of file
diff --git a/src/contracts/exchanges/third-party/ethfinex/WrapperLock.sol b/src/contracts/exchanges/third-party/ethfinex/WrapperLock.sol
deleted file mode 100644
index 95caa1da..00000000
--- a/src/contracts/exchanges/third-party/ethfinex/WrapperLock.sol
+++ /dev/null
@@ -1,165 +0,0 @@
-pragma solidity ^0.4.21;
-
-import "WrapperDependencies.sol";
-import "SafeMath.sol";
-import "Ownable.sol";
-
-/*
-
- Copyright Ethfinex Inc 2018
-
- Licensed under the Apache License, Version 2.0
- http://www.apache.org/licenses/LICENSE-2.0
-
-*/
-
-contract WrapperLock is BasicToken, Ownable {
- using SafeMath for uint256;
-
- address public TRANSFER_PROXY_VEFX;
- address public TRANSFER_PROXY_V2;
- mapping (address => bool) public isSigner;
-
- bool public erc20old;
- string public name;
- string public symbol;
- uint public decimals;
- address public originalToken;
-
- mapping (address => uint256) public depositLock;
- mapping (address => uint256) public balances;
-
- function WrapperLock(
- address _originalToken,
- string _name,
- string _symbol,
- uint _decimals,
- bool _erc20old,
- address _proxyEfx,
- address _proxyV2
- )
- Ownable()
- {
- originalToken = _originalToken;
- name = _name;
- symbol = _symbol;
- decimals = _decimals;
- isSigner[msg.sender] = true;
- erc20old = _erc20old;
- TRANSFER_PROXY_VEFX = _proxyEfx;
- TRANSFER_PROXY_V2 = _proxyV2;
- }
-
- function deposit(uint _value, uint _forTime) public returns (bool success) {
- require(_forTime >= 1);
- require(now + _forTime * 1 hours >= depositLock[msg.sender]);
- if (erc20old) {
- ERC20Old(originalToken).transferFrom(msg.sender, address(this), _value);
- } else {
- require(ERC20Extended(originalToken).transferFrom(msg.sender, address(this), _value));
- }
- balances[msg.sender] = balances[msg.sender].add(_value);
- totalSupply_ = totalSupply_.add(_value);
- depositLock[msg.sender] = now + _forTime * 1 hours;
- return true;
- }
-
- function withdraw(
- uint _value,
- uint8 v,
- bytes32 r,
- bytes32 s,
- uint signatureValidUntilBlock
- )
- public
- returns
- (bool success)
- {
- require(balanceOf(msg.sender) >= _value);
- if (now <= depositLock[msg.sender]) {
- require(block.number < signatureValidUntilBlock);
- require(isValidSignature(keccak256(msg.sender, address(this), signatureValidUntilBlock), v, r, s));
- }
- balances[msg.sender] = balances[msg.sender].sub(_value);
- totalSupply_ = totalSupply_.sub(_value);
- depositLock[msg.sender] = 0;
- if (erc20old) {
- ERC20Old(originalToken).transfer(msg.sender, _value);
- } else {
- require(ERC20Extended(originalToken).transfer(msg.sender, _value));
- }
- return true;
- }
-
- function withdrawBalanceDifference() public onlyOwner returns (bool success) {
- require(ERC20Extended(originalToken).balanceOf(address(this)).sub(totalSupply_) > 0);
- if (erc20old) {
- ERC20Old(originalToken).transfer(msg.sender, ERC20Extended(originalToken).balanceOf(address(this)).sub(totalSupply_));
- } else {
- require(ERC20Extended(originalToken).transfer(msg.sender, ERC20Extended(originalToken).balanceOf(address(this)).sub(totalSupply_)));
- }
- return true;
- }
-
- function withdrawDifferentToken(address _differentToken, bool _erc20old) public onlyOwner returns (bool) {
- require(_differentToken != originalToken);
- require(ERC20Extended(_differentToken).balanceOf(address(this)) > 0);
- if (_erc20old) {
- ERC20Old(_differentToken).transfer(msg.sender, ERC20Extended(_differentToken).balanceOf(address(this)));
- } else {
- require(ERC20Extended(_differentToken).transfer(msg.sender, ERC20Extended(_differentToken).balanceOf(address(this))));
- }
- return true;
- }
-
- function transfer(address _to, uint256 _value) public returns (bool) {
- return false;
- }
-
- function transferFrom(address _from, address _to, uint _value) public {
- require(isSigner[_to] || isSigner[_from]);
- assert(msg.sender == TRANSFER_PROXY_VEFX || msg.sender == TRANSFER_PROXY_V2);
- balances[_to] = balances[_to].add(_value);
- depositLock[_to] = depositLock[_to] > now ? depositLock[_to] : now + 1 hours;
- balances[_from] = balances[_from].sub(_value);
- Transfer(_from, _to, _value);
- }
-
- function allowance(address _owner, address _spender) public constant returns (uint) {
- if (_spender == TRANSFER_PROXY_VEFX || _spender == TRANSFER_PROXY_V2) {
- return 2**256 - 1;
- }
- }
-
- function balanceOf(address _owner) public constant returns (uint256) {
- return balances[_owner];
- }
-
- function isValidSignature(
- bytes32 hash,
- uint8 v,
- bytes32 r,
- bytes32 s
- )
- public
- constant
- returns (bool)
- {
- return isSigner[ecrecover(
- keccak256("\x19Ethereum Signed Message:\n32", hash),
- v,
- r,
- s
- )];
- }
-
- function addSigner(address _newSigner) public {
- require(isSigner[msg.sender]);
- isSigner[_newSigner] = true;
- }
-
- function keccak(address _sender, address _wrapper, uint _validTill) public constant returns(bytes32) {
- return keccak256(_sender, _wrapper, _validTill);
- }
-
-}
\ No newline at end of file
diff --git a/src/contracts/exchanges/third-party/ethfinex/WrapperLockEth.sol b/src/contracts/exchanges/third-party/ethfinex/WrapperLockEth.sol
deleted file mode 100644
index eb63c459..00000000
--- a/src/contracts/exchanges/third-party/ethfinex/WrapperLockEth.sol
+++ /dev/null
@@ -1,136 +0,0 @@
-pragma solidity ^0.4.21;
-
-import "WrapperDependencies.sol";
-import "SafeMath.sol";
-import "Ownable.sol";
-
-/*
-
- Copyright Ethfinex Inc 2018
-
- Licensed under the Apache License, Version 2.0
- http://www.apache.org/licenses/LICENSE-2.0
-
- will@ethfinex.com
-
-*/
-
-contract WrapperLockEth is BasicToken, Ownable {
- using SafeMath for uint256;
-
- address public TRANSFER_PROXY_VEFX;
- address public TRANSFER_PROXY_V2;
- mapping (address => bool) public isSigner;
-
- string public name;
- string public symbol;
- uint public decimals;
- address public originalToken = 0x00;
-
- mapping (address => uint) public depositLock;
- mapping (address => uint256) public balances;
-
- function WrapperLockEth(string _name, string _symbol, uint _decimals, address _proxyEfx, address _proxyV2) Ownable() {
- name = _name;
- symbol = _symbol;
- decimals = _decimals;
- isSigner[msg.sender] = true;
- TRANSFER_PROXY_VEFX = _proxyEfx;
- TRANSFER_PROXY_V2 = _proxyV2;
- }
-
- function deposit(uint _value, uint _forTime) public payable returns (bool success) {
- require(_forTime >= 1);
- require(now + _forTime * 1 hours >= depositLock[msg.sender]);
- balances[msg.sender] = balances[msg.sender].add(msg.value);
- totalSupply_ = totalSupply_.add(msg.value);
- depositLock[msg.sender] = now + _forTime * 1 hours;
- return true;
- }
-
- function withdraw(
- uint _value,
- uint8 v,
- bytes32 r,
- bytes32 s,
- uint signatureValidUntilBlock
- )
- public
- returns
- (bool)
- {
- require(balanceOf(msg.sender) >= _value);
- if (now > depositLock[msg.sender]) {
- balances[msg.sender] = balances[msg.sender].sub(_value);
- totalSupply_ = totalSupply_.sub(msg.value);
- msg.sender.transfer(_value);
- } else {
- require(block.number < signatureValidUntilBlock);
- require(isValidSignature(keccak256(msg.sender, address(this), signatureValidUntilBlock), v, r, s));
- balances[msg.sender] = balances[msg.sender].sub(_value);
- totalSupply_ = totalSupply_.sub(msg.value);
- depositLock[msg.sender] = 0;
- msg.sender.transfer(_value);
- }
- return true;
- }
-
- function withdrawDifferentToken(address _token, bool _erc20old) public onlyOwner returns (bool) {
- require(ERC20Extended(_token).balanceOf(address(this)) > 0);
- if (_erc20old) {
- ERC20Old(_token).transfer(msg.sender, ERC20Extended(_token).balanceOf(address(this)));
- } else {
- ERC20Extended(_token).transfer(msg.sender, ERC20Extended(_token).balanceOf(address(this)));
- }
- return true;
- }
-
- function transfer(address _to, uint256 _value) public returns (bool) {
- return false;
- }
-
- function transferFrom(address _from, address _to, uint _value) public {
- require(isSigner[_to] || isSigner[_from]);
- assert(msg.sender == TRANSFER_PROXY_VEFX || msg.sender == TRANSFER_PROXY_V2);
- balances[_to] = balances[_to].add(_value);
- depositLock[_to] = depositLock[_to] > now ? depositLock[_to] : now + 1 hours;
- balances[_from] = balances[_from].sub(_value);
- Transfer(_from, _to, _value);
- }
-
- function allowance(address _owner, address _spender) public constant returns (uint) {
- if (_spender == TRANSFER_PROXY_VEFX || _spender == TRANSFER_PROXY_V2) {
- return 2**256 - 1;
- }
- }
-
- function balanceOf(address _owner) public constant returns (uint256) {
- return balances[_owner];
- }
-
- function isValidSignature(
- bytes32 hash,
- uint8 v,
- bytes32 r,
- bytes32 s)
- public
- constant
- returns (bool)
- {
- return isSigner[ecrecover(
- keccak256("\x19Ethereum Signed Message:\n32", hash),
- v,
- r,
- s
- )];
- }
-
- function addSigner(address _newSigner) public {
- require(isSigner[msg.sender]);
- isSigner[_newSigner] = true;
- }
-
- function keccak(address _sender, address _wrapper, uint _validTill) public constant returns(bytes32) {
- return keccak256(_sender, _wrapper, _validTill);
- }
-}
\ No newline at end of file
diff --git a/src/contracts/exchanges/third-party/ethfinex/WrapperRegistryEFX.sol b/src/contracts/exchanges/third-party/ethfinex/WrapperRegistryEFX.sol
deleted file mode 100644
index 4822eb67..00000000
--- a/src/contracts/exchanges/third-party/ethfinex/WrapperRegistryEFX.sol
+++ /dev/null
@@ -1,19 +0,0 @@
-pragma solidity ^0.4.21;
-
-import "Ownable.sol";
-
-contract WrapperRegistryEFX is Ownable{
-
- mapping (address => address) public wrapper2TokenLookup;
- mapping (address => address) public token2WrapperLookup;
- event AddNewPair(address token, address wrapper);
-
- function addNewWrapperPair(address[] memory originalTokens, address[] memory wrapperTokens) public onlyOwner {
- for (uint i = 0; i < originalTokens.length; i++) {
- require(token2WrapperLookup[originalTokens[i]] == address(0));
- wrapper2TokenLookup[wrapperTokens[i]] = originalTokens[i];
- token2WrapperLookup[originalTokens[i]] = wrapperTokens[i];
- emit AddNewPair(originalTokens[i],wrapperTokens[i]);
- }
- }
-}
\ No newline at end of file
diff --git a/src/contracts/exchanges/third-party/kyber/ConversionRates.sol b/src/contracts/exchanges/third-party/kyber/ConversionRates.sol
deleted file mode 100644
index be47664c..00000000
--- a/src/contracts/exchanges/third-party/kyber/ConversionRates.sol
+++ /dev/null
@@ -1,575 +0,0 @@
-pragma solidity ^0.4.21;
-
-import "KyberDependencies.sol";
-
-
-contract VolumeImbalanceRecorder is Withdrawable {
-
- uint constant internal SLIDING_WINDOW_SIZE = 5;
- uint constant internal POW_2_64 = 2 ** 64;
-
- struct TokenControlInfo {
- uint minimalRecordResolution; // can be roughly 1 cent
- uint maxPerBlockImbalance; // in twei resolution
- uint maxTotalImbalance; // max total imbalance (between rate updates)
- // before halting trade
- }
-
- mapping(address => TokenControlInfo) internal tokenControlInfo;
-
- struct TokenImbalanceData {
- int lastBlockBuyUnitsImbalance;
- uint lastBlock;
-
- int totalBuyUnitsImbalance;
- uint lastRateUpdateBlock;
- }
-
- mapping(address => mapping(uint=>uint)) public tokenImbalanceData;
-
- function VolumeImbalanceRecorder(address _admin) public {
- require(_admin != address(0));
- admin = _admin;
- }
-
- function setTokenControlInfo(
- ERC20Clone token,
- uint minimalRecordResolution,
- uint maxPerBlockImbalance,
- uint maxTotalImbalance
- )
- public
- onlyAdmin
- {
- tokenControlInfo[token] =
- TokenControlInfo(
- minimalRecordResolution,
- maxPerBlockImbalance,
- maxTotalImbalance
- );
- }
-
- function getTokenControlInfo(ERC20Clone token) public view returns(uint, uint, uint) {
- return (tokenControlInfo[token].minimalRecordResolution,
- tokenControlInfo[token].maxPerBlockImbalance,
- tokenControlInfo[token].maxTotalImbalance);
- }
-
- function addImbalance(
- ERC20Clone token,
- int buyAmount,
- uint rateUpdateBlock,
- uint currentBlock
- )
- internal
- {
- uint currentBlockIndex = currentBlock % SLIDING_WINDOW_SIZE;
- int recordedBuyAmount = int(buyAmount / int(tokenControlInfo[token].minimalRecordResolution));
-
- int prevImbalance = 0;
-
- TokenImbalanceData memory currentBlockData =
- decodeTokenImbalanceData(tokenImbalanceData[token][currentBlockIndex]);
-
- // first scenario - this is not the first tx in the current block
- if (currentBlockData.lastBlock == currentBlock) {
- if (uint(currentBlockData.lastRateUpdateBlock) == rateUpdateBlock) {
- // just increase imbalance
- currentBlockData.lastBlockBuyUnitsImbalance += recordedBuyAmount;
- currentBlockData.totalBuyUnitsImbalance += recordedBuyAmount;
- } else {
- // imbalance was changed in the middle of the block
- prevImbalance = getImbalanceInRange(token, rateUpdateBlock, currentBlock);
- currentBlockData.totalBuyUnitsImbalance = int(prevImbalance) + recordedBuyAmount;
- currentBlockData.lastBlockBuyUnitsImbalance += recordedBuyAmount;
- currentBlockData.lastRateUpdateBlock = uint(rateUpdateBlock);
- }
- } else {
- // first tx in the current block
- int currentBlockImbalance;
- (prevImbalance, currentBlockImbalance) = getImbalanceSinceRateUpdate(token, rateUpdateBlock, currentBlock);
-
- currentBlockData.lastBlockBuyUnitsImbalance = recordedBuyAmount;
- currentBlockData.lastBlock = uint(currentBlock);
- currentBlockData.lastRateUpdateBlock = uint(rateUpdateBlock);
- currentBlockData.totalBuyUnitsImbalance = int(prevImbalance) + recordedBuyAmount;
- }
-
- tokenImbalanceData[token][currentBlockIndex] = encodeTokenImbalanceData(currentBlockData);
- }
-
- function setGarbageToVolumeRecorder(ERC20Clone token) internal {
- for (uint i = 0; i < SLIDING_WINDOW_SIZE; i++) {
- tokenImbalanceData[token][i] = 0x1;
- }
- }
-
- function getImbalanceInRange(ERC20Clone token, uint startBlock, uint endBlock) internal view returns(int buyImbalance) {
- // check the imbalance in the sliding window
- require(startBlock <= endBlock);
-
- buyImbalance = 0;
-
- for (uint windowInd = 0; windowInd < SLIDING_WINDOW_SIZE; windowInd++) {
- TokenImbalanceData memory perBlockData = decodeTokenImbalanceData(tokenImbalanceData[token][windowInd]);
-
- if (perBlockData.lastBlock <= endBlock && perBlockData.lastBlock >= startBlock) {
- buyImbalance += int(perBlockData.lastBlockBuyUnitsImbalance);
- }
- }
- }
-
- function getImbalanceSinceRateUpdate(ERC20Clone token, uint rateUpdateBlock, uint currentBlock)
- internal view
- returns(int buyImbalance, int currentBlockImbalance)
- {
- buyImbalance = 0;
- currentBlockImbalance = 0;
- uint latestBlock = 0;
- int imbalanceInRange = 0;
- uint startBlock = rateUpdateBlock;
- uint endBlock = currentBlock;
-
- for (uint windowInd = 0; windowInd < SLIDING_WINDOW_SIZE; windowInd++) {
- TokenImbalanceData memory perBlockData = decodeTokenImbalanceData(tokenImbalanceData[token][windowInd]);
-
- if (perBlockData.lastBlock <= endBlock && perBlockData.lastBlock >= startBlock) {
- imbalanceInRange += perBlockData.lastBlockBuyUnitsImbalance;
- }
-
- if (perBlockData.lastRateUpdateBlock != rateUpdateBlock) continue;
- if (perBlockData.lastBlock < latestBlock) continue;
-
- latestBlock = perBlockData.lastBlock;
- buyImbalance = perBlockData.totalBuyUnitsImbalance;
- if (uint(perBlockData.lastBlock) == currentBlock) {
- currentBlockImbalance = perBlockData.lastBlockBuyUnitsImbalance;
- }
- }
-
- if (buyImbalance == 0) {
- buyImbalance = imbalanceInRange;
- }
- }
-
- function getImbalance(ERC20Clone token, uint rateUpdateBlock, uint currentBlock)
- internal view
- returns(int totalImbalance, int currentBlockImbalance)
- {
-
- int resolution = int(tokenControlInfo[token].minimalRecordResolution);
-
- (totalImbalance, currentBlockImbalance) =
- getImbalanceSinceRateUpdate(
- token,
- rateUpdateBlock,
- currentBlock);
-
- totalImbalance *= resolution;
- currentBlockImbalance *= resolution;
- }
-
- function getMaxPerBlockImbalance(ERC20Clone token) internal view returns(uint) {
- return tokenControlInfo[token].maxPerBlockImbalance;
- }
-
- function getMaxTotalImbalance(ERC20Clone token) internal view returns(uint) {
- return tokenControlInfo[token].maxTotalImbalance;
- }
-
- function encodeTokenImbalanceData(TokenImbalanceData data) internal pure returns(uint) {
- // check for overflows
- require(data.lastBlockBuyUnitsImbalance < int(POW_2_64 / 2));
- require(data.lastBlockBuyUnitsImbalance > int(-1 * int(POW_2_64) / 2));
- require(data.lastBlock < POW_2_64);
- require(data.totalBuyUnitsImbalance < int(POW_2_64 / 2));
- require(data.totalBuyUnitsImbalance > int(-1 * int(POW_2_64) / 2));
- require(data.lastRateUpdateBlock < POW_2_64);
-
- // do encoding
- uint result = uint(data.lastBlockBuyUnitsImbalance) & (POW_2_64 - 1);
- result |= data.lastBlock * POW_2_64;
- result |= (uint(data.totalBuyUnitsImbalance) & (POW_2_64 - 1)) * POW_2_64 * POW_2_64;
- result |= data.lastRateUpdateBlock * POW_2_64 * POW_2_64 * POW_2_64;
-
- return result;
- }
-
- function decodeTokenImbalanceData(uint input) internal pure returns(TokenImbalanceData) {
- TokenImbalanceData memory data;
-
- data.lastBlockBuyUnitsImbalance = int(int64(input & (POW_2_64 - 1)));
- data.lastBlock = uint(uint64((input / POW_2_64) & (POW_2_64 - 1)));
- data.totalBuyUnitsImbalance = int(int64((input / (POW_2_64 * POW_2_64)) & (POW_2_64 - 1)));
- data.lastRateUpdateBlock = uint(uint64((input / (POW_2_64 * POW_2_64 * POW_2_64))));
-
- return data;
- }
-}
-
-contract ConversionRates is ConversionRatesInterface, VolumeImbalanceRecorder, Utils {
-
- // bps - basic rate steps. one step is 1 / 10000 of the rate.
- struct StepFunction {
- int[] x; // quantity for each step. Quantity of each step includes previous steps.
- int[] y; // rate change per quantity step in bps.
- }
-
- struct TokenData {
- bool listed; // was added to reserve
- bool enabled; // whether trade is enabled
-
- // position in the compact data
- uint compactDataArrayIndex;
- uint compactDataFieldIndex;
-
- // rate data. base and changes according to quantity and reserve balance.
- // generally speaking. Sell rate is 1 / buy rate i.e. the buy in the other direction.
- uint baseBuyRate; // in PRECISION units. see KyberConstants
- uint baseSellRate; // PRECISION units. without (sell / buy) spread it is 1 / baseBuyRate
- StepFunction buyRateQtyStepFunction; // in bps. higher quantity - bigger the rate.
- StepFunction sellRateQtyStepFunction;// in bps. higher the qua
- StepFunction buyRateImbalanceStepFunction; // in BPS. higher reserve imbalance - bigger the rate.
- StepFunction sellRateImbalanceStepFunction;
- }
-
- /*
- this is the data for tokenRatesCompactData
- but solidity compiler optimizer is sub-optimal, and cannot write this structure in a single storage write
- so we represent it as bytes32 and do the byte tricks ourselves.
- struct TokenRatesCompactData {
- bytes14 buy; // change buy rate of token from baseBuyRate in 10 bps
- bytes14 sell; // change sell rate of token from baseSellRate in 10 bps
-
- uint32 blockNumber;
- } */
- uint public validRateDurationInBlocks = 10; // rates are valid for this amount of blocks
- ERC20Clone[] internal listedTokens;
- mapping(address=>TokenData) internal tokenData;
- bytes32[] internal tokenRatesCompactData;
- uint public numTokensInCurrentCompactData = 0;
- address public reserveContract;
- uint constant internal NUM_TOKENS_IN_COMPACT_DATA = 14;
- uint constant internal BYTES_14_OFFSET = (2 ** (8 * NUM_TOKENS_IN_COMPACT_DATA));
- uint constant internal MAX_STEPS_IN_FUNCTION = 10;
- int constant internal MAX_BPS_ADJUSTMENT = 10 ** 11; // 1B %
- int constant internal MIN_BPS_ADJUSTMENT = -100 * 100; // cannot go down by more than 100%
-
- function ConversionRates(address _admin) public VolumeImbalanceRecorder(_admin)
- { } // solhint-disable-line no-empty-blocks
-
- function addToken(ERC20Clone token) public onlyAdmin {
-
- require(!tokenData[token].listed);
- tokenData[token].listed = true;
- listedTokens.push(token);
-
- if (numTokensInCurrentCompactData == 0) {
- tokenRatesCompactData.length++; // add new structure
- }
-
- tokenData[token].compactDataArrayIndex = tokenRatesCompactData.length - 1;
- tokenData[token].compactDataFieldIndex = numTokensInCurrentCompactData;
-
- numTokensInCurrentCompactData = (numTokensInCurrentCompactData + 1) % NUM_TOKENS_IN_COMPACT_DATA;
-
- setGarbageToVolumeRecorder(token);
-
- setDecimals(token);
- }
-
- function setCompactData(bytes14[] buy, bytes14[] sell, uint blockNumber, uint[] indices) public onlyOperator {
-
- require(buy.length == sell.length);
- require(indices.length == buy.length);
- require(blockNumber <= 0xFFFFFFFF);
-
- uint bytes14Offset = BYTES_14_OFFSET;
-
- for (uint i = 0; i < indices.length; i++) {
- require(indices[i] < tokenRatesCompactData.length);
- uint data = uint(buy[i]) | uint(sell[i]) * bytes14Offset | (blockNumber * (bytes14Offset * bytes14Offset));
- tokenRatesCompactData[indices[i]] = bytes32(data);
- }
- }
-
- function setBaseRate(
- ERC20Clone[] tokens,
- uint[] baseBuy,
- uint[] baseSell,
- bytes14[] buy,
- bytes14[] sell,
- uint blockNumber,
- uint[] indices
- )
- public
- onlyOperator
- {
- require(tokens.length == baseBuy.length);
- require(tokens.length == baseSell.length);
- require(sell.length == buy.length);
- require(sell.length == indices.length);
-
- for (uint ind = 0; ind < tokens.length; ind++) {
- require(tokenData[tokens[ind]].listed);
- tokenData[tokens[ind]].baseBuyRate = baseBuy[ind];
- tokenData[tokens[ind]].baseSellRate = baseSell[ind];
- }
-
- setCompactData(buy, sell, blockNumber, indices);
- }
-
- function setQtyStepFunction(
- ERC20Clone token,
- int[] xBuy,
- int[] yBuy,
- int[] xSell,
- int[] ySell
- )
- public
- onlyOperator
- {
- require(xBuy.length == yBuy.length);
- require(xSell.length == ySell.length);
- require(xBuy.length <= MAX_STEPS_IN_FUNCTION);
- require(xSell.length <= MAX_STEPS_IN_FUNCTION);
- require(tokenData[token].listed);
-
- tokenData[token].buyRateQtyStepFunction = StepFunction(xBuy, yBuy);
- tokenData[token].sellRateQtyStepFunction = StepFunction(xSell, ySell);
- }
-
- function setImbalanceStepFunction(
- ERC20Clone token,
- int[] xBuy,
- int[] yBuy,
- int[] xSell,
- int[] ySell
- )
- public
- onlyOperator
- {
- require(xBuy.length == yBuy.length);
- require(xSell.length == ySell.length);
- require(xBuy.length <= MAX_STEPS_IN_FUNCTION);
- require(xSell.length <= MAX_STEPS_IN_FUNCTION);
- require(tokenData[token].listed);
-
- tokenData[token].buyRateImbalanceStepFunction = StepFunction(xBuy, yBuy);
- tokenData[token].sellRateImbalanceStepFunction = StepFunction(xSell, ySell);
- }
-
- function setValidRateDurationInBlocks(uint duration) public onlyAdmin {
- validRateDurationInBlocks = duration;
- }
-
- function enableTokenTrade(ERC20Clone token) public onlyAdmin {
- require(tokenData[token].listed);
- require(tokenControlInfo[token].minimalRecordResolution != 0);
- tokenData[token].enabled = true;
- }
-
- function disableTokenTrade(ERC20Clone token) public onlyAlerter {
- require(tokenData[token].listed);
- tokenData[token].enabled = false;
- }
-
- function setReserveAddress(address reserve) public onlyAdmin {
- reserveContract = reserve;
- }
-
- function recordImbalance(
- ERC20Clone token,
- int buyAmount,
- uint rateUpdateBlock,
- uint currentBlock
- )
- public
- {
- require(msg.sender == reserveContract);
-
- if (rateUpdateBlock == 0) rateUpdateBlock = getRateUpdateBlock(token);
-
- return addImbalance(token, buyAmount, rateUpdateBlock, currentBlock);
- }
-
- /* solhint-disable function-max-lines */
- function getRate(ERC20Clone token, uint currentBlockNumber, bool buy, uint qty) public view returns(uint) {
- // check if trade is enabled
- if (!tokenData[token].enabled) return 0;
- if (tokenControlInfo[token].minimalRecordResolution == 0) return 0; // token control info not set
-
- // get rate update block
- bytes32 compactData = tokenRatesCompactData[tokenData[token].compactDataArrayIndex];
-
- uint updateRateBlock = getLast4Bytes(compactData);
- if (currentBlockNumber >= updateRateBlock + validRateDurationInBlocks) return 0; // rate is expired
- // check imbalance
- int totalImbalance;
- int blockImbalance;
- (totalImbalance, blockImbalance) = getImbalance(token, updateRateBlock, currentBlockNumber);
-
- // calculate actual rate
- int imbalanceQty;
- int extraBps;
- int8 rateUpdate;
- uint rate;
-
- if (buy) {
- // start with base rate
- rate = tokenData[token].baseBuyRate;
-
- // add rate update
- rateUpdate = getRateByteFromCompactData(compactData, token, true);
- extraBps = int(rateUpdate) * 10;
- rate = addBps(rate, extraBps);
-
- // compute token qty
- qty = getTokenQty(token, rate, qty);
- imbalanceQty = int(qty);
- totalImbalance += imbalanceQty;
-
- // add qty overhead
- extraBps = executeStepFunction(tokenData[token].buyRateQtyStepFunction, int(qty));
- rate = addBps(rate, extraBps);
-
- // add imbalance overhead
- extraBps = executeStepFunction(tokenData[token].buyRateImbalanceStepFunction, totalImbalance);
- rate = addBps(rate, extraBps);
- } else {
- // start with base rate
- rate = tokenData[token].baseSellRate;
-
- // add rate update
- rateUpdate = getRateByteFromCompactData(compactData, token, false);
- extraBps = int(rateUpdate) * 10;
- rate = addBps(rate, extraBps);
-
- // compute token qty
- imbalanceQty = -1 * int(qty);
- totalImbalance += imbalanceQty;
-
- // add qty overhead
- extraBps = executeStepFunction(tokenData[token].sellRateQtyStepFunction, int(qty));
- rate = addBps(rate, extraBps);
-
- // add imbalance overhead
- extraBps = executeStepFunction(tokenData[token].sellRateImbalanceStepFunction, totalImbalance);
- rate = addBps(rate, extraBps);
- }
-
- if (abs(totalImbalance) >= getMaxTotalImbalance(token)) return 0;
- if (abs(blockImbalance + imbalanceQty) >= getMaxPerBlockImbalance(token)) return 0;
-
- return rate;
- }
- /* solhint-enable function-max-lines */
-
- function getBasicRate(ERC20Clone token, bool buy) public view returns(uint) {
- if (buy)
- return tokenData[token].baseBuyRate;
- else
- return tokenData[token].baseSellRate;
- }
-
- function getCompactData(ERC20Clone token) public view returns(uint, uint, byte, byte) {
- require(tokenData[token].listed);
-
- uint arrayIndex = tokenData[token].compactDataArrayIndex;
- uint fieldOffset = tokenData[token].compactDataFieldIndex;
-
- return (
- arrayIndex,
- fieldOffset,
- byte(getRateByteFromCompactData(tokenRatesCompactData[arrayIndex], token, true)),
- byte(getRateByteFromCompactData(tokenRatesCompactData[arrayIndex], token, false))
- );
- }
-
- function getTokenBasicData(ERC20Clone token) public view returns(bool, bool) {
- return (tokenData[token].listed, tokenData[token].enabled);
- }
-
- /* solhint-disable code-complexity */
- function getStepFunctionData(ERC20Clone token, uint command, uint param) public view returns(int) {
- if (command == 0) return int(tokenData[token].buyRateQtyStepFunction.x.length);
- if (command == 1) return tokenData[token].buyRateQtyStepFunction.x[param];
- if (command == 2) return int(tokenData[token].buyRateQtyStepFunction.y.length);
- if (command == 3) return tokenData[token].buyRateQtyStepFunction.y[param];
-
- if (command == 4) return int(tokenData[token].sellRateQtyStepFunction.x.length);
- if (command == 5) return tokenData[token].sellRateQtyStepFunction.x[param];
- if (command == 6) return int(tokenData[token].sellRateQtyStepFunction.y.length);
- if (command == 7) return tokenData[token].sellRateQtyStepFunction.y[param];
-
- if (command == 8) return int(tokenData[token].buyRateImbalanceStepFunction.x.length);
- if (command == 9) return tokenData[token].buyRateImbalanceStepFunction.x[param];
- if (command == 10) return int(tokenData[token].buyRateImbalanceStepFunction.y.length);
- if (command == 11) return tokenData[token].buyRateImbalanceStepFunction.y[param];
-
- if (command == 12) return int(tokenData[token].sellRateImbalanceStepFunction.x.length);
- if (command == 13) return tokenData[token].sellRateImbalanceStepFunction.x[param];
- if (command == 14) return int(tokenData[token].sellRateImbalanceStepFunction.y.length);
- if (command == 15) return tokenData[token].sellRateImbalanceStepFunction.y[param];
-
- revert();
- }
- /* solhint-enable code-complexity */
-
- function getRateUpdateBlock(ERC20Clone token) public view returns(uint) {
- bytes32 compactData = tokenRatesCompactData[tokenData[token].compactDataArrayIndex];
- return getLast4Bytes(compactData);
- }
-
- function getListedTokens() public view returns(ERC20Clone[]) {
- return listedTokens;
- }
-
- function getTokenQty(ERC20Clone token, uint ethQty, uint rate) internal view returns(uint) {
- uint dstDecimals = getDecimals(token);
- uint srcDecimals = ETH_DECIMALS;
-
- return calcDstQty(ethQty, srcDecimals, dstDecimals, rate);
- }
-
- function getLast4Bytes(bytes32 b) internal pure returns(uint) {
- // cannot trust compiler with not turning bit operations into EXP opcode
- return uint(b) / (BYTES_14_OFFSET * BYTES_14_OFFSET);
- }
-
- function getRateByteFromCompactData(bytes32 data, ERC20Clone token, bool buy) internal view returns(int8) {
- uint fieldOffset = tokenData[token].compactDataFieldIndex;
- uint byteOffset;
- if (buy)
- byteOffset = 32 - NUM_TOKENS_IN_COMPACT_DATA + fieldOffset;
- else
- byteOffset = 4 + fieldOffset;
-
- return int8(data[byteOffset]);
- }
-
- function executeStepFunction(StepFunction f, int x) internal pure returns(int) {
- uint len = f.y.length;
- for (uint ind = 0; ind < len; ind++) {
- if (x <= f.x[ind]) return f.y[ind];
- }
-
- return f.y[len-1];
- }
-
- function addBps(uint rate, int bps) internal pure returns(uint) {
- require(rate <= MAX_RATE);
- require(bps >= MIN_BPS_ADJUSTMENT);
- require(bps <= MAX_BPS_ADJUSTMENT);
-
- uint maxBps = 100 * 100;
- return (rate * uint(int(maxBps) + bps)) / maxBps;
- }
-
- function abs(int x) internal pure returns(uint) {
- if (x < 0)
- return uint(-1 * x);
- else
- return uint(x);
- }
-}
diff --git a/src/contracts/exchanges/third-party/kyber/ExpectedRate.sol b/src/contracts/exchanges/third-party/kyber/ExpectedRate.sol
deleted file mode 100644
index d0b29151..00000000
--- a/src/contracts/exchanges/third-party/kyber/ExpectedRate.sol
+++ /dev/null
@@ -1,80 +0,0 @@
-pragma solidity ^0.4.21;
-
-import "KyberDependencies.sol";
-import "KyberNetwork.sol";
-
-contract ExpectedRate is Withdrawable, ExpectedRateInterface, Utils {
-
- KyberNetwork public kyberNetwork;
- uint public quantityFactor = 2;
- uint public worstCaseRateFactorInBps = 50;
-
- function ExpectedRate(KyberNetwork _kyberNetwork, address _admin) public {
- require(_admin != address(0));
- require(_kyberNetwork != address(0));
- kyberNetwork = _kyberNetwork;
- admin = _admin;
- }
-
- event QuantityFactorSet (uint newFactor, uint oldFactor, address sender);
-
- function setQuantityFactor(uint newFactor) public onlyOperator {
- require(newFactor <= 100);
-
- QuantityFactorSet(newFactor, quantityFactor, msg.sender);
- quantityFactor = newFactor;
- }
-
- event MinSlippageFactorSet (uint newMin, uint oldMin, address sender);
-
- function setWorstCaseRateFactor(uint bps) public onlyOperator {
- require(bps <= 100 * 100);
-
- MinSlippageFactorSet(bps, worstCaseRateFactorInBps, msg.sender);
- worstCaseRateFactorInBps = bps;
- }
-
- //@dev when srcQty too small or 0 the expected rate will be calculated without quantity,
- // will enable rate reference before committing to any quantity
- //@dev when srcQty too small (no actual dest qty) slippage rate will be 0.
- function getExpectedRate(ERC20Clone src, ERC20Clone dest, uint srcQty)
- public view
- returns (uint expectedRate, uint slippageRate)
- {
- require(quantityFactor != 0);
- require(srcQty <= MAX_QTY);
- require(srcQty * quantityFactor <= MAX_QTY);
-
- if (srcQty == 0) srcQty = 1;
-
- uint bestReserve;
- uint worstCaseSlippageRate;
-
- (bestReserve, expectedRate) = kyberNetwork.findBestRate(src, dest, srcQty);
- (bestReserve, slippageRate) = kyberNetwork.findBestRate(src, dest, (srcQty * quantityFactor));
-
- if (expectedRate == 0) {
- expectedRate = expectedRateSmallQty(src, dest);
- }
-
- require(expectedRate <= MAX_RATE);
-
- worstCaseSlippageRate = ((10000 - worstCaseRateFactorInBps) * expectedRate) / 10000;
- if (slippageRate >= worstCaseSlippageRate) {
- slippageRate = worstCaseSlippageRate;
- }
-
- return (expectedRate, slippageRate);
- }
-
- //@dev for small src quantities dest qty might be 0, then returned rate is zero.
- //@dev for backward compatibility we would like to return non zero rate (correct one) for small src qty
- function expectedRateSmallQty(ERC20Clone src, ERC20Clone dest) internal view returns(uint) {
- address reserve;
- uint rateSrcToEth;
- uint rateEthToDest;
- (reserve, rateSrcToEth) = kyberNetwork.searchBestRate(src, ETH_TOKEN_ADDRESS, 0);
- (reserve, rateEthToDest) = kyberNetwork.searchBestRate(ETH_TOKEN_ADDRESS, dest, 0);
- return rateSrcToEth * rateEthToDest / PRECISION;
- }
-}
diff --git a/src/contracts/exchanges/third-party/kyber/KyberDependencies.sol b/src/contracts/exchanges/third-party/kyber/KyberDependencies.sol
deleted file mode 100644
index 73fee2da..00000000
--- a/src/contracts/exchanges/third-party/kyber/KyberDependencies.sol
+++ /dev/null
@@ -1,581 +0,0 @@
-pragma solidity ^0.4.21;
-
-import "StandardToken.sol";
-
-contract ERC20Clone is ERC20 {
- function totalSupply() public view returns (uint supply);
- function balanceOf(address _owner) public view returns (uint balance);
- function transfer(address _to, uint _value) public returns (bool success);
- function transferFrom(address _from, address _to, uint _value) public returns (bool success);
- function approve(address _spender, uint _value) public returns (bool success);
- function allowance(address _owner, address _spender) public view returns (uint remaining);
- function decimals() public view returns(uint digits);
- event Approval(address indexed _owner, address indexed _spender, uint _value);
-}
-
-/// @title Kyber Reserve contract
-interface KyberReserveInterface {
-
- function trade(
- ERC20Clone srcToken,
- uint srcAmount,
- ERC20Clone destToken,
- address destAddress,
- uint conversionRate,
- bool validate
- )
- public
- payable
- returns(bool);
-
- function getConversionRate(ERC20Clone src, ERC20Clone dest, uint srcQty, uint blockNumber) public view returns(uint);
-}
-
-/// @title Kyber Network interface
-interface KyberNetworkInterface {
- function maxGasPrice() public view returns(uint);
- function getUserCapInWei(address user) public view returns(uint);
- function getUserCapInTokenWei(address user, ERC20Clone token) public view returns(uint);
- function enabled() public view returns(bool);
- function info(bytes32 id) public view returns(uint);
-
- function getExpectedRate(ERC20Clone src, ERC20Clone dest, uint srcQty) public view
- returns (uint expectedRate, uint slippageRate);
-
- function tradeWithHint(address trader, ERC20Clone src, uint srcAmount, ERC20Clone dest, address destAddress,
- uint maxDestAmount, uint minConversionRate, address walletId, bytes hint) public payable returns(uint);
-}
-
-contract PermissionGroups {
-
- address public admin;
- address public pendingAdmin;
- mapping(address=>bool) internal operators;
- mapping(address=>bool) internal alerters;
- address[] internal operatorsGroup;
- address[] internal alertersGroup;
- uint constant internal MAX_GROUP_SIZE = 50;
-
- function PermissionGroups() public {
- admin = msg.sender;
- }
-
- modifier onlyAdmin() {
- require(msg.sender == admin);
- _;
- }
-
- modifier onlyOperator() {
- require(operators[msg.sender]);
- _;
- }
-
- modifier onlyAlerter() {
- require(alerters[msg.sender]);
- _;
- }
-
- function getOperators () external view returns(address[]) {
- return operatorsGroup;
- }
-
- function getAlerters () external view returns(address[]) {
- return alertersGroup;
- }
-
- event TransferAdminPending(address pendingAdmin);
-
- /**
- * @dev Allows the current admin to set the pendingAdmin address.
- * @param newAdmin The address to transfer ownership to.
- */
- function transferAdmin(address newAdmin) public onlyAdmin {
- require(newAdmin != address(0));
- TransferAdminPending(pendingAdmin);
- pendingAdmin = newAdmin;
- }
-
- /**
- * @dev Allows the current admin to set the admin in one tx. Useful initial deployment.
- * @param newAdmin The address to transfer ownership to.
- */
- function transferAdminQuickly(address newAdmin) public onlyAdmin {
- require(newAdmin != address(0));
- TransferAdminPending(newAdmin);
- AdminClaimed(newAdmin, admin);
- admin = newAdmin;
- }
-
- event AdminClaimed( address newAdmin, address previousAdmin);
-
- /**
- * @dev Allows the pendingAdmin address to finalize the change admin process.
- */
- function claimAdmin() public {
- require(pendingAdmin == msg.sender);
- AdminClaimed(pendingAdmin, admin);
- admin = pendingAdmin;
- pendingAdmin = address(0);
- }
-
- event AlerterAdded (address newAlerter, bool isAdd);
-
- function addAlerter(address newAlerter) public onlyAdmin {
- require(!alerters[newAlerter]); // prevent duplicates.
- require(alertersGroup.length < MAX_GROUP_SIZE);
-
- AlerterAdded(newAlerter, true);
- alerters[newAlerter] = true;
- alertersGroup.push(newAlerter);
- }
-
- function removeAlerter (address alerter) public onlyAdmin {
- require(alerters[alerter]);
- alerters[alerter] = false;
-
- for (uint i = 0; i < alertersGroup.length; ++i) {
- if (alertersGroup[i] == alerter) {
- alertersGroup[i] = alertersGroup[alertersGroup.length - 1];
- alertersGroup.length--;
- AlerterAdded(alerter, false);
- break;
- }
- }
- }
-
- event OperatorAdded(address newOperator, bool isAdd);
-
- function addOperator(address newOperator) public onlyAdmin {
- require(!operators[newOperator]); // prevent duplicates.
- require(operatorsGroup.length < MAX_GROUP_SIZE);
-
- OperatorAdded(newOperator, true);
- operators[newOperator] = true;
- operatorsGroup.push(newOperator);
- }
-
- function removeOperator (address operator) public onlyAdmin {
- require(operators[operator]);
- operators[operator] = false;
-
- for (uint i = 0; i < operatorsGroup.length; ++i) {
- if (operatorsGroup[i] == operator) {
- operatorsGroup[i] = operatorsGroup[operatorsGroup.length - 1];
- operatorsGroup.length -= 1;
- OperatorAdded(operator, false);
- break;
- }
- }
- }
-}
-
-/**
- * @title Contracts that should be able to recover tokens or ethers
- * @author Ilan Doron
- * @dev This allows to recover any tokens or Ethers received in a contract.
- * This will prevent any accidental loss of tokens.
- */
-contract Withdrawable is PermissionGroups {
-
- event TokenWithdraw(ERC20Clone token, uint amount, address sendTo);
-
- /**
- * @dev Withdraw all ERC20Clone compatible tokens
- * @param token ERC20Clone The address of the token contract
- */
- function withdrawToken(ERC20Clone token, uint amount, address sendTo) external onlyAdmin {
- require(token.transfer(sendTo, amount));
- TokenWithdraw(token, amount, sendTo);
- }
-
- event EtherWithdraw(uint amount, address sendTo);
-
- /**
- * @dev Withdraw Ethers
- */
- function withdrawEther(uint amount, address sendTo) external onlyAdmin {
- sendTo.transfer(amount);
- EtherWithdraw(amount, sendTo);
- }
-}
-
-contract Utils {
-
- ERC20Clone constant internal ETH_TOKEN_ADDRESS = ERC20Clone(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee);
- uint constant internal PRECISION = (10**18);
- uint constant internal MAX_QTY = (10**28); // 10B tokens
- uint constant internal MAX_RATE = (PRECISION * 10**6); // up to 1M tokens per ETH
- uint constant internal MAX_DECIMALS = 18;
- uint constant internal ETH_DECIMALS = 18;
- mapping(address=>uint) internal decimals;
-
- function setDecimals(ERC20Clone token) internal {
- if (token == ETH_TOKEN_ADDRESS) decimals[token] = ETH_DECIMALS;
- else decimals[token] = token.decimals();
- }
-
- function getDecimals(ERC20Clone token) internal view returns(uint) {
- if (token == ETH_TOKEN_ADDRESS) return ETH_DECIMALS; // save storage access
- uint tokenDecimals = decimals[token];
- // technically, there might be token with decimals 0
- // moreover, very possible that old tokens have decimals 0
- // these tokens will just have higher gas fees.
- if(tokenDecimals == 0) return token.decimals();
-
- return tokenDecimals;
- }
-
- function calcDstQty(uint srcQty, uint srcDecimals, uint dstDecimals, uint rate) internal pure returns(uint) {
- require(srcQty <= MAX_QTY);
- require(rate <= MAX_RATE);
-
- if (dstDecimals >= srcDecimals) {
- require((dstDecimals - srcDecimals) <= MAX_DECIMALS);
- return (srcQty * rate * (10**(dstDecimals - srcDecimals))) / PRECISION;
- } else {
- require((srcDecimals - dstDecimals) <= MAX_DECIMALS);
- return (srcQty * rate) / (PRECISION * (10**(srcDecimals - dstDecimals)));
- }
- }
-
- function calcSrcQty(uint dstQty, uint srcDecimals, uint dstDecimals, uint rate) internal pure returns(uint) {
- require(dstQty <= MAX_QTY);
- require(rate <= MAX_RATE);
-
- //source quantity is rounded up. to avoid dest quantity being too low.
- uint numerator;
- uint denominator;
- if (srcDecimals >= dstDecimals) {
- require((srcDecimals - dstDecimals) <= MAX_DECIMALS);
- numerator = (PRECISION * dstQty * (10**(srcDecimals - dstDecimals)));
- denominator = rate;
- } else {
- require((dstDecimals - srcDecimals) <= MAX_DECIMALS);
- numerator = (PRECISION * dstQty);
- denominator = (rate * (10**(dstDecimals - srcDecimals)));
- }
- return (numerator + denominator - 1) / denominator; //avoid rounding down errors
- }
-}
-
-contract Utils2 is Utils {
-
- /// @dev get the balance of a user.
- /// @param token The token type
- /// @return The balance
- function getBalance(ERC20Clone token, address user) public view returns(uint) {
- if (token == ETH_TOKEN_ADDRESS)
- return user.balance;
- else
- return token.balanceOf(user);
- }
-
- function getDecimalsSafe(ERC20Clone token) internal returns(uint) {
-
- if (decimals[token] == 0) {
- setDecimals(token);
- }
-
- return decimals[token];
- }
-
- /// @dev notice, overrides previous implementation.
- function setDecimals(ERC20Clone token) internal {
- uint decimal;
-
- if (token == ETH_TOKEN_ADDRESS) {
- decimal = ETH_DECIMALS;
- } else {
- if (!address(token).call(bytes4(keccak256("decimals()")))) {/* solhint-disable-line avoid-low-level-calls */
- //above code can only be performed with low level call. otherwise all operation will revert.
- // call failed
- decimal = 18;
- } else {
- decimal = token.decimals();
- }
- }
-
- decimals[token] = decimal;
- }
-
- function calcDestAmount(ERC20Clone src, ERC20Clone dest, uint srcAmount, uint rate) internal view returns(uint) {
- return calcDstQty(srcAmount, getDecimals(src), getDecimals(dest), rate);
- }
-
- function calcSrcAmount(ERC20Clone src, ERC20Clone dest, uint destAmount, uint rate) internal view returns(uint) {
- return calcSrcQty(destAmount, getDecimals(src), getDecimals(dest), rate);
- }
-
- function calcRateFromQty(uint srcAmount, uint destAmount, uint srcDecimals, uint dstDecimals)
- internal pure returns(uint)
- {
- require(srcAmount <= MAX_QTY);
- require(destAmount <= MAX_QTY);
-
- if (dstDecimals >= srcDecimals) {
- require((dstDecimals - srcDecimals) <= MAX_DECIMALS);
- return (destAmount * PRECISION / ((10 ** (dstDecimals - srcDecimals)) * srcAmount));
- } else {
- require((srcDecimals - dstDecimals) <= MAX_DECIMALS);
- return (destAmount * PRECISION * (10 ** (srcDecimals - dstDecimals)) / srcAmount);
- }
- }
-}
-
-contract WhiteListInterface {
- function getUserCapInWei(address user) external view returns (uint userCapWei);
-}
-
-interface ExpectedRateInterface {
- function getExpectedRate(ERC20Clone src, ERC20Clone dest, uint srcQty) public view
- returns (uint expectedRate, uint slippageRate);
-}
-
-interface FeeBurnerInterface {
- function handleFees (uint tradeWeiAmount, address reserve, address wallet) public returns(bool);
-}
-
-interface ConversionRatesInterface {
-
- function recordImbalance(
- ERC20Clone token,
- int buyAmount,
- uint rateUpdateBlock,
- uint currentBlock
- )
- public;
-
- function getRate(ERC20Clone token, uint currentBlockNumber, bool buy, uint qty) public view returns(uint);
-}
-
-interface SanityRatesInterface {
- function getSanityRate(ERC20Clone src, ERC20Clone dest) public view returns(uint);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-/*
- * SimpleToken
- *
- * Very simple ERC20Clone Token example, where all tokens are pre-assigned
- * to the creator. Note they can later distribute these tokens
- * as they wish using `transfer` and other `StandardToken` functions.
- */
-contract TestToken is StandardToken {
-
- string public name = "Test";
- string public symbol = "TST";
- uint public decimals = 18;
- uint public INITIAL_SUPPLY = 10 ** 27;
-
- function TestToken(string _name, string _symbol, uint _decimals) public {
- totalSupply_ = INITIAL_SUPPLY;
- balances[msg.sender] = INITIAL_SUPPLY;
- name = _name;
- symbol = _symbol;
- decimals = _decimals;
- }
-
- event Burn(address indexed _burner, uint _value);
-
- function burn(uint _value) public returns (bool) {
- balances[msg.sender] = balances[msg.sender].sub(_value);
- totalSupply_ = totalSupply_.sub(_value);
- Burn(msg.sender, _value);
- Transfer(msg.sender, address(0x0), _value);
- return true;
- }
-
- // save some gas by making only one contract call
- function burnFrom(address _from, uint256 _value) public returns (bool) {
- transferFrom( _from, msg.sender, _value );
- return burn(_value);
- }
-}
-
-contract KyberWhiteList is WhiteListInterface, Withdrawable {
-
- uint public weiPerSgd; // amount of weis in 1 singapore dollar
- mapping (address=>uint) public userCategory; // each user has a category defining cap on trade. 0 for standard.
- mapping (uint=>uint) public categoryCap; // will define cap on trade amount per category in singapore Dollar.
- uint constant public kgtHolderCategory = 2;
- ERC20Clone public kgtToken;
-
- function KyberWhiteList(address _admin, ERC20Clone _kgtToken) public {
- require(_admin != address(0));
- require(_kgtToken != address(0));
- kgtToken = _kgtToken;
- admin = _admin;
- }
-
- function getUserCapInWei(address user) external view returns (uint) {
- uint category = getUserCategory(user);
- return (categoryCap[category] * weiPerSgd);
- }
-
- event UserCategorySet(address user, uint category);
-
- function setUserCategory(address user, uint category) public onlyOperator {
- userCategory[user] = category;
- UserCategorySet(user, category);
- }
-
- event CategoryCapSet (uint category, uint sgdCap);
-
- function setCategoryCap(uint category, uint sgdCap) public onlyOperator {
- categoryCap[category] = sgdCap;
- CategoryCapSet(category, sgdCap);
- }
-
- event SgdToWeiRateSet (uint rate);
-
- function setSgdToEthRate(uint _sgdToWeiRate) public onlyOperator {
- weiPerSgd = _sgdToWeiRate;
- SgdToWeiRateSet(_sgdToWeiRate);
- }
-
- function getUserCategory (address user) public view returns(uint) {
- uint category = userCategory[user];
- if (category == 0) {
- //0 = default category. means category wasn't set.
- if (kgtToken.balanceOf(user) > 0) {
- category = kgtHolderCategory;
- }
- }
- return category;
- }
-}
-
-interface BurnableTokenClone {
- function transferFrom(address _from, address _to, uint _value) public returns (bool);
- function burnFrom(address _from, uint256 _value) public returns (bool);
-}
-
-
-contract FeeBurner is Withdrawable, FeeBurnerInterface, Utils {
-
- mapping(address=>uint) public reserveFeesInBps;
- mapping(address=>address) public reserveKNCWallet; //wallet holding knc per reserve. from here burn and send fees.
- mapping(address=>uint) public walletFeesInBps; // wallet that is the source of tx is entitled so some fees.
- mapping(address=>uint) public reserveFeeToBurn;
- mapping(address=>uint) public feePayedPerReserve; // track burned fees and sent wallet fees per reserve.
- mapping(address=>mapping(address=>uint)) public reserveFeeToWallet;
- address public taxWallet;
- uint public taxFeeBps = 0; // burned fees are taxed. % out of burned fees.
-
- BurnableTokenClone public knc;
- address public kyberNetwork;
- uint public kncPerETHRate = 300;
-
- function FeeBurner(address _admin, BurnableTokenClone kncToken, address _kyberNetwork) public {
- require(_admin != address(0));
- require(kncToken != address(0));
- require(_kyberNetwork != address(0));
- kyberNetwork = _kyberNetwork;
- admin = _admin;
- knc = kncToken;
- }
-
- event ReserveDataSet(address reserve, uint feeInBps, address kncWallet);
- function setReserveData(address reserve, uint feesInBps, address kncWallet) public onlyAdmin {
- require(feesInBps < 100); // make sure it is always < 1%
- require(kncWallet != address(0));
- reserveFeesInBps[reserve] = feesInBps;
- reserveKNCWallet[reserve] = kncWallet;
- ReserveDataSet(reserve, feesInBps, kncWallet);
- }
-
- event WalletFeesSet(address wallet, uint feesInBps);
- function setWalletFees(address wallet, uint feesInBps) public onlyAdmin {
- require(feesInBps < 10000); // under 100%
- walletFeesInBps[wallet] = feesInBps;
- WalletFeesSet(wallet, feesInBps);
- }
-
- event TaxFeesSet(uint feesInBps);
- function setTaxInBps(uint _taxFeeBps) public onlyAdmin {
- require(_taxFeeBps < 10000); // under 100%
- taxFeeBps = _taxFeeBps;
- TaxFeesSet(_taxFeeBps);
- }
-
- event TaxWalletSet(address taxWallet);
- function setTaxWallet(address _taxWallet) public onlyAdmin {
- require(_taxWallet != address(0));
- taxWallet = _taxWallet;
- TaxWalletSet(_taxWallet);
- }
-
- function setKNCRate(uint rate) public onlyAdmin {
- require(rate <= MAX_RATE);
- kncPerETHRate = rate;
- }
-
- event AssignFeeToWallet(address reserve, address wallet, uint walletFee);
- event AssignBurnFees(address reserve, uint burnFee);
-
- function handleFees(uint tradeWeiAmount, address reserve, address wallet) public returns(bool) {
- require(msg.sender == kyberNetwork);
- require(tradeWeiAmount <= MAX_QTY);
- require(kncPerETHRate <= MAX_RATE);
-
- uint kncAmount = tradeWeiAmount * kncPerETHRate;
- uint fee = kncAmount * reserveFeesInBps[reserve] / 10000;
-
- uint walletFee = fee * walletFeesInBps[wallet] / 10000;
- require(fee >= walletFee);
- uint feeToBurn = fee - walletFee;
-
- if (walletFee > 0) {
- reserveFeeToWallet[reserve][wallet] += walletFee;
- AssignFeeToWallet(reserve, wallet, walletFee);
- }
-
- if (feeToBurn > 0) {
- AssignBurnFees(reserve, feeToBurn);
- reserveFeeToBurn[reserve] += feeToBurn;
- }
-
- return true;
- }
-
- event BurnAssignedFees(address indexed reserve, address sender, uint quantity);
-
- event SendTaxFee(address indexed reserve, address sender, address taxWallet, uint quantity);
-
- // this function is callable by anyone
- function burnReserveFees(address reserve) public {
- uint burnAmount = reserveFeeToBurn[reserve];
- uint taxToSend = 0;
- require(burnAmount > 2);
- reserveFeeToBurn[reserve] = 1; // leave 1 twei to avoid spikes in gas fee
- if (taxWallet != address(0) && taxFeeBps != 0) {
- taxToSend = (burnAmount - 1) * taxFeeBps / 10000;
- require(burnAmount - 1 > taxToSend);
- burnAmount -= taxToSend;
- if (taxToSend > 0) {
- require(knc.transferFrom(reserveKNCWallet[reserve], taxWallet, taxToSend));
- SendTaxFee(reserve, msg.sender, taxWallet, taxToSend);
- }
- }
- require(knc.burnFrom(reserveKNCWallet[reserve], burnAmount - 1));
-
- //update reserve "payments" so far
- feePayedPerReserve[reserve] += (taxToSend + burnAmount - 1);
-
- BurnAssignedFees(reserve, msg.sender, (burnAmount - 1));
- }
-
- event SendWalletFees(address indexed wallet, address reserve, address sender);
-
- // this function is callable by anyone
- function sendFeeToWallet(address wallet, address reserve) public {
- uint feeAmount = reserveFeeToWallet[reserve][wallet];
- require(feeAmount > 1);
- reserveFeeToWallet[reserve][wallet] = 1; // leave 1 twei to avoid spikes in gas fee
- require(knc.transferFrom(reserveKNCWallet[reserve], wallet, feeAmount - 1));
-
- feePayedPerReserve[reserve] += (feeAmount - 1);
- SendWalletFees(wallet, reserve, msg.sender);
- }
-}
diff --git a/src/contracts/exchanges/third-party/kyber/KyberNetwork.sol b/src/contracts/exchanges/third-party/kyber/KyberNetwork.sol
deleted file mode 100644
index cbdf3e18..00000000
--- a/src/contracts/exchanges/third-party/kyber/KyberNetwork.sol
+++ /dev/null
@@ -1,523 +0,0 @@
-pragma solidity ^0.4.21;
-
-import "KyberDependencies.sol";
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////
-/// @title Kyber Network main contract
-contract KyberNetwork is Withdrawable, Utils2, KyberNetworkInterface {
-
- uint public negligibleRateDiff = 10; // basic rate steps will be in 0.01%
- KyberReserveInterface[] public reserves;
- mapping(address=>bool) public isReserve;
- WhiteListInterface public whiteListContract;
- ExpectedRateInterface public expectedRateContract;
- FeeBurnerInterface public feeBurnerContract;
- address public kyberNetworkProxyContract;
- uint public maxGasPriceValue = 50 * 1000 * 1000 * 1000; // 50 gwei
- bool public isEnabled = false; // network is enabled
- mapping(bytes32=>uint) public infoFields; // this is only a UI field for external app.
- mapping(address=>address[]) public reservesPerTokenSrc; //reserves supporting token to eth
- mapping(address=>address[]) public reservesPerTokenDest;//reserves support eth to token
-
- function KyberNetwork(address _admin) public {
- require(_admin != address(0));
- admin = _admin;
- }
-
- event EtherReceival(address indexed sender, uint amount);
-
- /* solhint-disable no-complex-fallback */
- // To avoid users trying to swap tokens using default payable function. We added this short code
- // to verify Ethers will be received only from reserves if transferred without a specific function call.
- function() public payable {
- require(isReserve[msg.sender]);
- EtherReceival(msg.sender, msg.value);
- }
- /* solhint-enable no-complex-fallback */
-
- struct TradeInput {
- address trader;
- ERC20Clone src;
- uint srcAmount;
- ERC20Clone dest;
- address destAddress;
- uint maxDestAmount;
- uint minConversionRate;
- address walletId;
- bytes hint;
- }
-
- function tradeWithHint(
- address trader,
- ERC20Clone src,
- uint srcAmount,
- ERC20Clone dest,
- address destAddress,
- uint maxDestAmount,
- uint minConversionRate,
- address walletId,
- bytes hint
- )
- public
- payable
- returns(uint)
- {
- require(hint.length == 0);
- require(msg.sender == kyberNetworkProxyContract);
-
- TradeInput memory tradeInput;
-
- tradeInput.trader = trader;
- tradeInput.src = src;
- tradeInput.srcAmount = srcAmount;
- tradeInput.dest = dest;
- tradeInput.destAddress = destAddress;
- tradeInput.maxDestAmount = maxDestAmount;
- tradeInput.minConversionRate = minConversionRate;
- tradeInput.walletId = walletId;
- tradeInput.hint = hint;
-
- return trade(tradeInput);
- }
-
- event AddReserveToNetwork(KyberReserveInterface reserve, bool add);
-
- /// @notice can be called only by admin
- /// @dev add or deletes a reserve to/from the network.
- /// @param reserve The reserve address.
- /// @param add If true, the add reserve. Otherwise delete reserve.
- function addReserve(KyberReserveInterface reserve, bool add) public onlyAdmin {
-
- if (add) {
- require(!isReserve[reserve]);
- reserves.push(reserve);
- isReserve[reserve] = true;
- AddReserveToNetwork(reserve, true);
- } else {
- isReserve[reserve] = false;
- // will have trouble if more than 50k reserves...
- for (uint i = 0; i < reserves.length; i++) {
- if (reserves[i] == reserve) {
- reserves[i] = reserves[reserves.length - 1];
- reserves.length--;
- AddReserveToNetwork(reserve, false);
- break;
- }
- }
- }
- }
-
- event ListReservePairs(address reserve, ERC20Clone src, ERC20Clone dest, bool add);
-
- /// @notice can be called only by admin
- /// @dev allow or prevent a specific reserve to trade a pair of tokens
- /// @param reserve The reserve address.
- /// @param token token address
- /// @param ethToToken will it support ether to token trade
- /// @param tokenToEth will it support token to ether trade
- /// @param add If true then list this pair, otherwise unlist it.
- function listPairForReserve(address reserve, ERC20Clone token, bool ethToToken, bool tokenToEth, bool add)
- public onlyAdmin
- {
- require(isReserve[reserve]);
-
- if (ethToToken) {
- listPairs(reserve, token, false, add);
-
- ListReservePairs(reserve, ETH_TOKEN_ADDRESS, token, add);
- }
-
- if (tokenToEth) {
- listPairs(reserve, token, true, add);
- if (add) {
- token.approve(reserve, 2**255); // approve infinity
- } else {
- token.approve(reserve, 0);
- }
-
- ListReservePairs(reserve, token, ETH_TOKEN_ADDRESS, add);
- }
-
- setDecimals(token);
- }
-
- function setWhiteList(WhiteListInterface whiteList) public onlyAdmin {
- require(whiteList != address(0));
- whiteListContract = whiteList;
- }
-
- function setExpectedRate(ExpectedRateInterface expectedRate) public onlyAdmin {
- require(expectedRate != address(0));
- expectedRateContract = expectedRate;
- }
-
- function setFeeBurner(FeeBurnerInterface feeBurner) public onlyAdmin {
- require(feeBurner != address(0));
- feeBurnerContract = feeBurner;
- }
-
- function setParams(
- uint _maxGasPrice,
- uint _negligibleRateDiff
- )
- public
- onlyAdmin
- {
- require(_negligibleRateDiff <= 100 * 100); // at most 100%
-
- maxGasPriceValue = _maxGasPrice;
- negligibleRateDiff = _negligibleRateDiff;
- }
-
- function setEnable(bool _enable) public onlyAdmin {
- if (_enable) {
- require(whiteListContract != address(0));
- require(feeBurnerContract != address(0));
- require(expectedRateContract != address(0));
- require(kyberNetworkProxyContract != address(0));
- }
- isEnabled = _enable;
- }
-
- function setInfo(bytes32 field, uint value) public onlyOperator {
- infoFields[field] = value;
- }
-
- event KyberProxySet(address proxy, address sender);
-
- function setKyberProxy(address networkProxy) public onlyAdmin {
- require(networkProxy != address(0));
- kyberNetworkProxyContract = networkProxy;
- KyberProxySet(kyberNetworkProxyContract, msg.sender);
- }
-
- /// @dev returns number of reserves
- /// @return number of reserves
- function getNumReserves() public view returns(uint) {
- return reserves.length;
- }
-
- /// @notice should be called off chain with as much gas as needed
- /// @dev get an array of all reserves
- /// @return An array of all reserves
- function getReserves() public view returns(KyberReserveInterface[]) {
- return reserves;
- }
-
- function maxGasPrice() public view returns(uint) {
- return maxGasPriceValue;
- }
-
- function getExpectedRate(ERC20Clone src, ERC20Clone dest, uint srcQty)
- public view
- returns(uint expectedRate, uint slippageRate)
- {
- require(expectedRateContract != address(0));
- return expectedRateContract.getExpectedRate(src, dest, srcQty);
- }
-
- function getUserCapInWei(address user) public view returns(uint) {
- return whiteListContract.getUserCapInWei(user);
- }
-
- function getUserCapInTokenWei(address user, ERC20Clone token) public view returns(uint) {
- //future feature
- user;
- token;
- require(false);
- }
-
- struct BestRateResult {
- uint rate;
- address reserve1;
- address reserve2;
- uint weiAmount;
- uint rateSrcToEth;
- uint rateEthToDest;
- uint destAmount;
- }
-
- /// @notice use token address ETH_TOKEN_ADDRESS for ether
- /// @dev best conversion rate for a pair of tokens, if number of reserves have small differences. randomize
- /// @param src Src token
- /// @param dest Destination token
- /// @return obsolete - used to return best reserve index. not relevant anymore for this API.
- function findBestRate(ERC20Clone src, ERC20Clone dest, uint srcAmount) public view returns(uint obsolete, uint rate) {
- BestRateResult memory result = findBestRateTokenToToken(src, dest, srcAmount);
- return(0, result.rate);
- }
-
- function enabled() public view returns(bool) {
- return isEnabled;
- }
-
- function info(bytes32 field) public view returns(uint) {
- return infoFields[field];
- }
-
- /* solhint-disable code-complexity */
- // Not sure how solhing defines complexity. Anyway, from our point of view, below code follows the required
- // algorithm to choose a reserve, it has been tested, reviewed and found to be clear enough.
- //@dev this function always src or dest are ether. can't do token to token
- function searchBestRate(ERC20Clone src, ERC20Clone dest, uint srcAmount) public view returns(address, uint) {
- uint bestRate = 0;
- uint bestReserve = 0;
- uint numRelevantReserves = 0;
-
- //return 1 for ether to ether
- if (src == dest) return (reserves[bestReserve], PRECISION);
-
- address[] memory reserveArr;
-
- if (src == ETH_TOKEN_ADDRESS) {
- reserveArr = reservesPerTokenDest[dest];
- } else {
- reserveArr = reservesPerTokenSrc[src];
- }
-
- if (reserveArr.length == 0) return (reserves[bestReserve], bestRate);
-
- uint[] memory rates = new uint[](reserveArr.length);
- uint[] memory reserveCandidates = new uint[](reserveArr.length);
-
- for (uint i = 0; i < reserveArr.length; i++) {
- //list all reserves that have this token.
- rates[i] = (KyberReserveInterface(reserveArr[i])).getConversionRate(src, dest, srcAmount, block.number);
-
- if (rates[i] > bestRate) {
- //best rate is highest rate
- bestRate = rates[i];
- }
- }
-
- if (bestRate > 0) {
- uint random = 0;
- uint smallestRelevantRate = (bestRate * 10000) / (10000 + negligibleRateDiff);
-
- for (i = 0; i < reserveArr.length; i++) {
- if (rates[i] >= smallestRelevantRate) {
- reserveCandidates[numRelevantReserves++] = i;
- }
- }
-
- if (numRelevantReserves > 1) {
- //when encountering small rate diff from bestRate. draw from relevant reserves
- random = uint(block.blockhash(block.number-1)) % numRelevantReserves;
- }
-
- bestReserve = reserveCandidates[random];
- bestRate = rates[bestReserve];
- }
-
- return (reserveArr[bestReserve], bestRate);
- }
- /* solhint-enable code-complexity */
-
- function findBestRateTokenToToken(ERC20Clone src, ERC20Clone dest, uint srcAmount) internal view
- returns(BestRateResult result)
- {
- (result.reserve1, result.rateSrcToEth) = searchBestRate(src, ETH_TOKEN_ADDRESS, srcAmount);
- result.weiAmount = calcDestAmount(src, ETH_TOKEN_ADDRESS, srcAmount, result.rateSrcToEth);
-
- (result.reserve2, result.rateEthToDest) = searchBestRate(ETH_TOKEN_ADDRESS, dest, result.weiAmount);
- result.destAmount = calcDestAmount(ETH_TOKEN_ADDRESS, dest, result.weiAmount, result.rateEthToDest);
-
- result.rate = calcRateFromQty(srcAmount, result.destAmount, getDecimals(src), getDecimals(dest));
- }
-
- function listPairs(address reserve, ERC20Clone token, bool isTokenToEth, bool add) internal {
- uint i;
- address[] storage reserveArr = reservesPerTokenDest[token];
-
- if (isTokenToEth) {
- reserveArr = reservesPerTokenSrc[token];
- }
-
- for (i = 0; i < reserveArr.length; i++) {
- if (reserve == reserveArr[i]) {
- if (add) {
- break; //already added
- } else {
- //remove
- reserveArr[i] = reserveArr[reserveArr.length - 1];
- reserveArr.length--;
- }
- }
- }
-
- if (add && i == reserveArr.length) {
- //if reserve wasn't found add it
- reserveArr.push(reserve);
- }
- }
-
- event KyberTrade(address srcAddress, ERC20Clone srcToken, uint srcAmount, address destAddress, ERC20Clone destToken,
- uint destAmount);
- /* solhint-disable function-max-lines */
- // Most of the lins here are functions calls spread over multiple lines. We find this function readable enough
- // and keep its size as is.
- /// @notice use token address ETH_TOKEN_ADDRESS for ether
- /// @dev trade api for kyber network.
- /// @param tradeInput structure of trade inputs
- function trade(TradeInput tradeInput) internal returns(uint) {
- require(isEnabled);
- require(tx.gasprice <= maxGasPriceValue);
- require(validateTradeInput(tradeInput.src, tradeInput.srcAmount, tradeInput.dest, tradeInput.destAddress));
-
- BestRateResult memory rateResult =
- findBestRateTokenToToken(tradeInput.src, tradeInput.dest, tradeInput.srcAmount);
-
- require(rateResult.rate > 0);
- require(rateResult.rate < MAX_RATE);
- require(rateResult.rate >= tradeInput.minConversionRate);
-
- uint actualDestAmount;
- uint weiAmount;
- uint actualSrcAmount;
-
- (actualSrcAmount, weiAmount, actualDestAmount) = calcActualAmounts(tradeInput.src,
- tradeInput.dest,
- tradeInput.srcAmount,
- tradeInput.maxDestAmount,
- rateResult);
-
- if (actualSrcAmount < tradeInput.srcAmount) {
- //if there is "change" send back to trader
- if (tradeInput.src == ETH_TOKEN_ADDRESS) {
- tradeInput.trader.transfer(tradeInput.srcAmount - actualSrcAmount);
- } else {
- tradeInput.src.transfer(tradeInput.trader, (tradeInput.srcAmount - actualSrcAmount));
- }
- }
-
- // verify trade size is smaller than user cap
- require(weiAmount <= getUserCapInWei(tradeInput.trader));
-
- //do the trade
- //src to ETH
- require(doReserveTrade(
- tradeInput.src,
- actualSrcAmount,
- ETH_TOKEN_ADDRESS,
- this,
- weiAmount,
- KyberReserveInterface(rateResult.reserve1),
- rateResult.rateSrcToEth,
- true));
-
- //Eth to dest
- require(doReserveTrade(
- ETH_TOKEN_ADDRESS,
- weiAmount,
- tradeInput.dest,
- tradeInput.destAddress,
- actualDestAmount,
- KyberReserveInterface(rateResult.reserve2),
- rateResult.rateEthToDest,
- true));
-
- //when src is ether, reserve1 is doing a "fake" trade. (ether to ether) - don't burn.
- //when dest is ether, reserve2 is doing a "fake" trade. (ether to ether) - don't burn.
- if (tradeInput.src != ETH_TOKEN_ADDRESS)
- require(feeBurnerContract.handleFees(weiAmount, rateResult.reserve1, tradeInput.walletId));
- if (tradeInput.dest != ETH_TOKEN_ADDRESS)
- require(feeBurnerContract.handleFees(weiAmount, rateResult.reserve2, tradeInput.walletId));
-
- KyberTrade(tradeInput.trader, tradeInput.src, actualSrcAmount, tradeInput.destAddress, tradeInput.dest,
- actualDestAmount);
-
- return actualDestAmount;
- }
- /* solhint-enable function-max-lines */
-
- function calcActualAmounts (ERC20Clone src, ERC20Clone dest, uint srcAmount, uint maxDestAmount, BestRateResult rateResult)
- internal view returns(uint actualSrcAmount, uint weiAmount, uint actualDestAmount)
- {
- if (rateResult.destAmount > maxDestAmount) {
- actualDestAmount = maxDestAmount;
- weiAmount = calcSrcAmount(ETH_TOKEN_ADDRESS, dest, actualDestAmount, rateResult.rateEthToDest);
- actualSrcAmount = calcSrcAmount(src, ETH_TOKEN_ADDRESS, weiAmount, rateResult.rateSrcToEth);
- require(actualSrcAmount <= srcAmount);
- } else {
- actualDestAmount = rateResult.destAmount;
- actualSrcAmount = srcAmount;
- weiAmount = rateResult.weiAmount;
- }
- }
-
- /// @notice use token address ETH_TOKEN_ADDRESS for ether
- /// @dev do one trade with a reserve
- /// @param src Src token
- /// @param amount amount of src tokens
- /// @param dest Destination token
- /// @param destAddress Address to send tokens to
- /// @param reserve Reserve to use
- /// @param validate If true, additional validations are applicable
- /// @return true if trade is successful
- function doReserveTrade(
- ERC20Clone src,
- uint amount,
- ERC20Clone dest,
- address destAddress,
- uint expectedDestAmount,
- KyberReserveInterface reserve,
- uint conversionRate,
- bool validate
- )
- internal
- returns(bool)
- {
- uint callValue = 0;
-
- if (src == dest) {
- //this is for a "fake" trade when both src and dest are ethers.
- if (destAddress != (address(this)))
- destAddress.transfer(amount);
- return true;
- }
-
- if (src == ETH_TOKEN_ADDRESS) {
- callValue = amount;
- }
-
- // reserve sends tokens/eth to network. network sends it to destination
- require(reserve.trade.value(callValue)(src, amount, dest, this, conversionRate, validate));
-
- if (destAddress != address(this)) {
- //for token to token dest address is network. and Ether / token already here...
- if (dest == ETH_TOKEN_ADDRESS) {
- destAddress.transfer(expectedDestAmount);
- } else {
- require(dest.transfer(destAddress, expectedDestAmount));
- }
- }
-
- return true;
- }
-
- /// @notice use token address ETH_TOKEN_ADDRESS for ether
- /// @dev checks that user sent ether/tokens to contract before trade
- /// @param src Src token
- /// @param srcAmount amount of src tokens
- /// @return true if tradeInput is valid
- function validateTradeInput(ERC20Clone src, uint srcAmount, ERC20Clone dest, address destAddress)
- internal
- view
- returns(bool)
- {
- require(srcAmount <= MAX_QTY);
- require(srcAmount != 0);
- require(destAddress != address(0));
- require(src != dest);
-
- if (src == ETH_TOKEN_ADDRESS) {
- require(msg.value == srcAmount);
- } else {
- require(msg.value == 0);
- //funds should have been moved to this contract already.
- require(src.balanceOf(this) >= srcAmount);
- }
-
- return true;
- }
-}
diff --git a/src/contracts/exchanges/third-party/kyber/KyberNetworkProxy.sol b/src/contracts/exchanges/third-party/kyber/KyberNetworkProxy.sol
deleted file mode 100644
index 11b09a95..00000000
--- a/src/contracts/exchanges/third-party/kyber/KyberNetworkProxy.sol
+++ /dev/null
@@ -1,285 +0,0 @@
-pragma solidity ^0.4.21;
-
-import "KyberDependencies.sol";
-
-/// @title Kyber Network interface
-interface KyberNetworkProxyInterface {
- function maxGasPrice() public view returns(uint);
- function getUserCapInWei(address user) public view returns(uint);
- function getUserCapInTokenWei(address user, ERC20Clone token) public view returns(uint);
- function enabled() public view returns(bool);
- function info(bytes32 id) public view returns(uint);
-
- function getExpectedRate(ERC20Clone src, ERC20Clone dest, uint srcQty) public view
- returns (uint expectedRate, uint slippageRate);
-
- function tradeWithHint(ERC20Clone src, uint srcAmount, ERC20Clone dest, address destAddress, uint maxDestAmount,
- uint minConversionRate, address walletId, bytes hint) public payable returns(uint);
-}
-
-
-/// @title simple interface for Kyber Network
-interface SimpleNetworkInterface {
- function swapTokenToToken(ERC20Clone src, uint srcAmount, ERC20Clone dest, uint minConversionRate) public returns(uint);
- function swapEtherToToken(ERC20Clone token, uint minConversionRate) public payable returns(uint);
- function swapTokenToEther(ERC20Clone token, uint srcAmount, uint minConversionRate) public returns(uint);
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////
-/// @title Kyber Network proxy for main contract
-contract KyberNetworkProxy is KyberNetworkProxyInterface, SimpleNetworkInterface, Withdrawable, Utils2 {
-
- KyberNetworkInterface public kyberNetworkContract;
-
- function KyberNetworkProxy(address _admin) public {
- require(_admin != address(0));
- admin = _admin;
- }
-
- /// @notice use token address ETH_TOKEN_ADDRESS for ether
- /// @dev makes a trade between src and dest token and send dest token to destAddress
- /// @param src Src token
- /// @param srcAmount amount of src tokens
- /// @param dest Destination token
- /// @param destAddress Address to send tokens to
- /// @param maxDestAmount A limit on the amount of dest tokens
- /// @param minConversionRate The minimal conversion rate. If actual rate is lower, trade is canceled.
- /// @param walletId is the wallet ID to send part of the fees
- /// @return amount of actual dest tokens
- function trade(
- ERC20Clone src,
- uint srcAmount,
- ERC20Clone dest,
- address destAddress,
- uint maxDestAmount,
- uint minConversionRate,
- address walletId
- )
- public
- payable
- returns(uint)
- {
- bytes memory hint;
-
- return tradeWithHint(
- src,
- srcAmount,
- dest,
- destAddress,
- maxDestAmount,
- minConversionRate,
- walletId,
- hint
- );
- }
-
- /// @dev makes a trade between src and dest token and send dest tokens to msg sender
- /// @param src Src token
- /// @param srcAmount amount of src tokens
- /// @param dest Destination token
- /// @param minConversionRate The minimal conversion rate. If actual rate is lower, trade is canceled.
- /// @return amount of actual dest tokens
- function swapTokenToToken(
- ERC20Clone src,
- uint srcAmount,
- ERC20Clone dest,
- uint minConversionRate
- )
- public
- returns(uint)
- {
- bytes memory hint;
-
- return tradeWithHint(
- src,
- srcAmount,
- dest,
- msg.sender,
- MAX_QTY,
- minConversionRate,
- 0,
- hint
- );
- }
-
- /// @dev makes a trade from Ether to token. Sends token to msg sender
- /// @param token Destination token
- /// @param minConversionRate The minimal conversion rate. If actual rate is lower, trade is canceled.
- /// @return amount of actual dest tokens
- function swapEtherToToken(ERC20Clone token, uint minConversionRate) public payable returns(uint) {
- bytes memory hint;
-
- return tradeWithHint(
- ETH_TOKEN_ADDRESS,
- msg.value,
- token,
- msg.sender,
- MAX_QTY,
- minConversionRate,
- 0,
- hint
- );
- }
-
- /// @dev makes a trade from token to Ether, sends Ether to msg sender
- /// @param token Src token
- /// @param srcAmount amount of src tokens
- /// @param minConversionRate The minimal conversion rate. If actual rate is lower, trade is canceled.
- /// @return amount of actual dest tokens
- function swapTokenToEther(ERC20Clone token, uint srcAmount, uint minConversionRate) public returns(uint) {
- bytes memory hint;
-
- return tradeWithHint(
- token,
- srcAmount,
- ETH_TOKEN_ADDRESS,
- msg.sender,
- MAX_QTY,
- minConversionRate,
- 0,
- hint
- );
- }
-
- struct UserBalance {
- uint srcBalance;
- uint destBalance;
- }
-
- event ExecuteTrade(address indexed trader, ERC20Clone src, ERC20Clone dest, uint actualSrcAmount, uint actualDestAmount);
-
- /// @notice use token address ETH_TOKEN_ADDRESS for ether
- /// @dev makes a trade between src and dest token and send dest token to destAddress
- /// @param src Src token
- /// @param srcAmount amount of src tokens
- /// @param dest Destination token
- /// @param destAddress Address to send tokens to
- /// @param maxDestAmount A limit on the amount of dest tokens
- /// @param minConversionRate The minimal conversion rate. If actual rate is lower, trade is canceled.
- /// @param walletId is the wallet ID to send part of the fees
- /// @param hint will give hints for the trade.
- /// @return amount of actual dest tokens
- function tradeWithHint(
- ERC20Clone src,
- uint srcAmount,
- ERC20Clone dest,
- address destAddress,
- uint maxDestAmount,
- uint minConversionRate,
- address walletId,
- bytes hint
- )
- public
- payable
- returns(uint)
- {
- require(src == ETH_TOKEN_ADDRESS || msg.value == 0);
-
- UserBalance memory userBalanceBefore;
-
- userBalanceBefore.srcBalance = getBalance(src, msg.sender);
- userBalanceBefore.destBalance = getBalance(dest, destAddress);
-
- if (src == ETH_TOKEN_ADDRESS) {
- userBalanceBefore.srcBalance += msg.value;
- } else {
- require(src.transferFrom(msg.sender, kyberNetworkContract, srcAmount));
- }
-
- uint reportedDestAmount = kyberNetworkContract.tradeWithHint.value(msg.value)(
- msg.sender,
- src,
- srcAmount,
- dest,
- destAddress,
- maxDestAmount,
- minConversionRate,
- walletId,
- hint
- );
-
- TradeOutcome memory tradeOutcome = calculateTradeOutcome(
- userBalanceBefore.srcBalance,
- userBalanceBefore.destBalance,
- src,
- dest,
- destAddress
- );
-
- require(reportedDestAmount == tradeOutcome.userDeltaDestAmount);
- require(tradeOutcome.userDeltaDestAmount <= maxDestAmount);
- require(tradeOutcome.actualRate >= minConversionRate);
-
- ExecuteTrade(msg.sender, src, dest, tradeOutcome.userDeltaSrcAmount, tradeOutcome.userDeltaDestAmount);
- return tradeOutcome.userDeltaDestAmount;
- }
-
- event KyberNetworkSet(address newNetworkContract, address oldNetworkContract);
-
- function setKyberNetworkContract(KyberNetworkInterface _kyberNetworkContract) public onlyAdmin {
-
- require(_kyberNetworkContract != address(0));
-
- KyberNetworkSet(_kyberNetworkContract, kyberNetworkContract);
-
- kyberNetworkContract = _kyberNetworkContract;
- }
-
- function getExpectedRate(ERC20Clone src, ERC20Clone dest, uint srcQty)
- public view
- returns(uint expectedRate, uint slippageRate)
- {
- return kyberNetworkContract.getExpectedRate(src, dest, srcQty);
- }
-
- function getUserCapInWei(address user) public view returns(uint) {
- return kyberNetworkContract.getUserCapInWei(user);
- }
-
- function getUserCapInTokenWei(address user, ERC20Clone token) public view returns(uint) {
- return kyberNetworkContract.getUserCapInTokenWei(user, token);
- }
-
- function maxGasPrice() public view returns(uint) {
- return kyberNetworkContract.maxGasPrice();
- }
-
- function enabled() public view returns(bool) {
- return kyberNetworkContract.enabled();
- }
-
- function info(bytes32 field) public view returns(uint) {
- return kyberNetworkContract.info(field);
- }
-
- struct TradeOutcome {
- uint userDeltaSrcAmount;
- uint userDeltaDestAmount;
- uint actualRate;
- }
-
- function calculateTradeOutcome (uint srcBalanceBefore, uint destBalanceBefore, ERC20Clone src, ERC20Clone dest,
- address destAddress)
- internal returns(TradeOutcome outcome)
- {
- uint userSrcBalanceAfter;
- uint userDestBalanceAfter;
-
- userSrcBalanceAfter = getBalance(src, msg.sender);
- userDestBalanceAfter = getBalance(dest, destAddress);
-
- //protect from underflow
- require(userDestBalanceAfter > destBalanceBefore);
- require(srcBalanceBefore > userSrcBalanceAfter);
-
- outcome.userDeltaDestAmount = userDestBalanceAfter - destBalanceBefore;
- outcome.userDeltaSrcAmount = srcBalanceBefore - userSrcBalanceAfter;
-
- outcome.actualRate = calcRateFromQty(
- outcome.userDeltaSrcAmount,
- outcome.userDeltaDestAmount,
- getDecimalsSafe(src),
- getDecimalsSafe(dest)
- );
- }
-}
diff --git a/src/contracts/exchanges/third-party/kyber/KyberReserve.sol b/src/contracts/exchanges/third-party/kyber/KyberReserve.sol
deleted file mode 100644
index f9f17fa2..00000000
--- a/src/contracts/exchanges/third-party/kyber/KyberReserve.sol
+++ /dev/null
@@ -1,256 +0,0 @@
-pragma solidity ^0.4.21;
-
-import "KyberDependencies.sol";
-
-/// @title Kyber Reserve contract
-contract KyberReserve is KyberReserveInterface, Withdrawable, Utils {
-
- address public kyberNetwork;
- bool public tradeEnabled;
- ConversionRatesInterface public conversionRatesContract;
- SanityRatesInterface public sanityRatesContract;
- mapping(bytes32=>bool) public approvedWithdrawAddresses; // sha3(token,address)=>bool
- mapping(address=>address) public tokenWallet;
-
- function KyberReserve(address _kyberNetwork, ConversionRatesInterface _ratesContract, address _admin) public {
- require(_admin != address(0));
- require(_ratesContract != address(0));
- require(_kyberNetwork != address(0));
- kyberNetwork = _kyberNetwork;
- conversionRatesContract = _ratesContract;
- admin = _admin;
- tradeEnabled = true;
- }
-
- event DepositToken(ERC20Clone token, uint amount);
-
- function() public payable {
- DepositToken(ETH_TOKEN_ADDRESS, msg.value);
- }
-
- event TradeExecute(
- address indexed origin,
- address src,
- uint srcAmount,
- address destToken,
- uint destAmount,
- address destAddress
- );
-
- function trade(
- ERC20Clone srcToken,
- uint srcAmount,
- ERC20Clone destToken,
- address destAddress,
- uint conversionRate,
- bool validate
- )
- public
- payable
- returns(bool)
- {
- require(tradeEnabled);
- require(msg.sender == kyberNetwork);
-
- require(doTrade(srcToken, srcAmount, destToken, destAddress, conversionRate, validate));
-
- return true;
- }
-
- event TradeEnabled(bool enable);
-
- function enableTrade() public onlyAdmin returns(bool) {
- tradeEnabled = true;
- TradeEnabled(true);
-
- return true;
- }
-
- function disableTrade() public onlyAlerter returns(bool) {
- tradeEnabled = false;
- TradeEnabled(false);
-
- return true;
- }
-
- event WithdrawAddressApproved(ERC20Clone token, address addr, bool approve);
-
- function approveWithdrawAddress(ERC20Clone token, address addr, bool approve) public onlyAdmin {
- approvedWithdrawAddresses[keccak256(token, addr)] = approve;
- WithdrawAddressApproved(token, addr, approve);
-
- setDecimals(token);
- if ((tokenWallet[token] == address(0x0)) && (token != ETH_TOKEN_ADDRESS)) {
- tokenWallet[token] = this; // by default
- require(token.approve(this, 2 ** 255));
- }
- }
-
- event NewTokenWallet(ERC20Clone token, address wallet);
-
- function setTokenWallet(ERC20Clone token, address wallet) public onlyAdmin {
- require(wallet != address(0x0));
- tokenWallet[token] = wallet;
- NewTokenWallet(token, wallet);
- }
-
- event WithdrawFunds(ERC20Clone token, uint amount, address destination);
-
- function withdraw(ERC20Clone token, uint amount, address destination) public onlyOperator returns(bool) {
- require(approvedWithdrawAddresses[keccak256(token, destination)]);
-
- if (token == ETH_TOKEN_ADDRESS) {
- destination.transfer(amount);
- } else {
- require(token.transferFrom(tokenWallet[token], destination, amount));
- }
-
- WithdrawFunds(token, amount, destination);
-
- return true;
- }
-
- event SetContractAddresses(address network, address rate, address sanity);
-
- function setContracts(
- address _kyberNetwork,
- ConversionRatesInterface _conversionRates,
- SanityRatesInterface _sanityRates
- )
- public
- onlyAdmin
- {
- require(_kyberNetwork != address(0));
- require(_conversionRates != address(0));
-
- kyberNetwork = _kyberNetwork;
- conversionRatesContract = _conversionRates;
- sanityRatesContract = _sanityRates;
-
- SetContractAddresses(kyberNetwork, conversionRatesContract, sanityRatesContract);
- }
-
- ////////////////////////////////////////////////////////////////////////////
- /// status functions ///////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- function getBalance(ERC20Clone token) public view returns(uint) {
- if (token == ETH_TOKEN_ADDRESS)
- return this.balance;
- else {
- address wallet = tokenWallet[token];
- uint balanceOfWallet = token.balanceOf(wallet);
- uint allowanceOfWallet = token.allowance(wallet, this);
-
- return (balanceOfWallet < allowanceOfWallet) ? balanceOfWallet : allowanceOfWallet;
- }
- }
-
- function getDestQty(ERC20Clone src, ERC20Clone dest, uint srcQty, uint rate) public view returns(uint) {
- uint dstDecimals = getDecimals(dest);
- uint srcDecimals = getDecimals(src);
-
- return calcDstQty(srcQty, srcDecimals, dstDecimals, rate);
- }
-
- function getSrcQty(ERC20Clone src, ERC20Clone dest, uint dstQty, uint rate) public view returns(uint) {
- uint dstDecimals = getDecimals(dest);
- uint srcDecimals = getDecimals(src);
-
- return calcSrcQty(dstQty, srcDecimals, dstDecimals, rate);
- }
-
- function getConversionRate(ERC20Clone src, ERC20Clone dest, uint srcQty, uint blockNumber) public view returns(uint) {
- ERC20Clone token;
- bool isBuy;
-
- if (!tradeEnabled) return 0;
-
- if (ETH_TOKEN_ADDRESS == src) {
- isBuy = true;
- token = dest;
- } else if (ETH_TOKEN_ADDRESS == dest) {
- isBuy = false;
- token = src;
- } else {
- return 0; // pair is not listed
- }
-
- uint rate = conversionRatesContract.getRate(token, blockNumber, isBuy, srcQty);
- uint destQty = getDestQty(src, dest, srcQty, rate);
-
- if (getBalance(dest) < destQty) return 0;
-
- if (sanityRatesContract != address(0)) {
- uint sanityRate = sanityRatesContract.getSanityRate(src, dest);
- if (rate > sanityRate) return 0;
- }
-
- return rate;
- }
-
- /// @dev do a trade
- /// @param srcToken Src token
- /// @param srcAmount Amount of src token
- /// @param destToken Destination token
- /// @param destAddress Destination address to send tokens to
- /// @param validate If true, additional validations are applicable
- /// @return true iff trade is successful
- function doTrade(
- ERC20Clone srcToken,
- uint srcAmount,
- ERC20Clone destToken,
- address destAddress,
- uint conversionRate,
- bool validate
- )
- internal
- returns(bool)
- {
- // can skip validation if done at kyber network level
- if (validate) {
- require(conversionRate > 0);
- if (srcToken == ETH_TOKEN_ADDRESS)
- require(msg.value == srcAmount);
- else
- require(msg.value == 0);
- }
-
- uint destAmount = getDestQty(srcToken, destToken, srcAmount, conversionRate);
- // sanity check
- require(destAmount > 0);
-
- // add to imbalance
- ERC20Clone token;
- int tradeAmount;
- if (srcToken == ETH_TOKEN_ADDRESS) {
- tradeAmount = int(destAmount);
- token = destToken;
- } else {
- tradeAmount = -1 * int(srcAmount);
- token = srcToken;
- }
-
- conversionRatesContract.recordImbalance(
- token,
- tradeAmount,
- 0,
- block.number
- );
-
- // collect src tokens
- if (srcToken != ETH_TOKEN_ADDRESS) {
- require(srcToken.transferFrom(msg.sender, tokenWallet[srcToken], srcAmount));
- }
-
- // send dest tokens
- if (destToken == ETH_TOKEN_ADDRESS) {
- destAddress.transfer(destAmount);
- } else {
- require(destToken.transferFrom(tokenWallet[destToken], destAddress, destAmount));
- }
-
- TradeExecute(msg.sender, srcToken, srcAmount, destToken, destAmount, destAddress);
-
- return true;
- }
-}
diff --git a/src/contracts/exchanges/third-party/kyber/SanityRates.sol b/src/contracts/exchanges/third-party/kyber/SanityRates.sol
deleted file mode 100644
index ba271016..00000000
--- a/src/contracts/exchanges/third-party/kyber/SanityRates.sol
+++ /dev/null
@@ -1,46 +0,0 @@
-pragma solidity ^0.4.21;
-
-import "KyberDependencies.sol";
-
-contract SanityRates is SanityRatesInterface, Withdrawable, Utils {
- mapping(address=>uint) public tokenRate;
- mapping(address=>uint) public reasonableDiffInBps;
-
- function SanityRates(address _admin) public {
- require(_admin != address(0));
- admin = _admin;
- }
-
- function setReasonableDiff(ERC20Clone[] srcs, uint[] diff) public onlyAdmin {
- require(srcs.length == diff.length);
- for (uint i = 0; i < srcs.length; i++) {
- require(diff[i] <= 100 * 100);
- reasonableDiffInBps[srcs[i]] = diff[i];
- }
- }
-
- function setSanityRates(ERC20Clone[] srcs, uint[] rates) public onlyOperator {
- require(srcs.length == rates.length);
-
- for (uint i = 0; i < srcs.length; i++) {
- require(rates[i] <= MAX_RATE);
- tokenRate[srcs[i]] = rates[i];
- }
- }
-
- function getSanityRate(ERC20Clone src, ERC20Clone dest) public view returns(uint) {
- if (src != ETH_TOKEN_ADDRESS && dest != ETH_TOKEN_ADDRESS) return 0;
-
- uint rate;
- address token;
- if (src == ETH_TOKEN_ADDRESS) {
- rate = (PRECISION*PRECISION)/tokenRate[dest];
- token = dest;
- } else {
- rate = tokenRate[src];
- token = src;
- }
-
- return rate * (10000 + reasonableDiffInBps[token])/10000;
- }
-}
diff --git a/src/contracts/exchanges/third-party/oasisdex/MatchingMarket.sol b/src/contracts/exchanges/third-party/oasisdex/MatchingMarket.sol
deleted file mode 100644
index b53321e4..00000000
--- a/src/contracts/exchanges/third-party/oasisdex/MatchingMarket.sol
+++ /dev/null
@@ -1,1021 +0,0 @@
-pragma solidity ^0.4.21;
-
-import "thing.sol";
-import "ERC20.i.sol";
-
-contract EventfulMarket {
- event LogItemUpdate(uint id);
- event LogTrade(uint pay_amt, address indexed pay_gem,
- uint buy_amt, address indexed buy_gem);
-
- event LogMake(
- bytes32 indexed id,
- bytes32 indexed pair,
- address indexed maker,
- ERC20 pay_gem,
- ERC20 buy_gem,
- uint128 pay_amt,
- uint128 buy_amt,
- uint64 timestamp
- );
-
- event LogBump(
- bytes32 indexed id,
- bytes32 indexed pair,
- address indexed maker,
- ERC20 pay_gem,
- ERC20 buy_gem,
- uint128 pay_amt,
- uint128 buy_amt,
- uint64 timestamp
- );
-
- event LogTake(
- bytes32 id,
- bytes32 indexed pair,
- address indexed maker,
- ERC20 pay_gem,
- ERC20 buy_gem,
- address indexed taker,
- uint128 take_amt,
- uint128 give_amt,
- uint64 timestamp
- );
-
- event LogKill(
- bytes32 indexed id,
- bytes32 indexed pair,
- address indexed maker,
- ERC20 pay_gem,
- ERC20 buy_gem,
- uint128 pay_amt,
- uint128 buy_amt,
- uint64 timestamp
- );
-}
-
-contract SimpleMarket is EventfulMarket, DSMath {
-
- uint public last_offer_id;
-
- mapping (uint => OfferInfo) public offers;
-
- bool locked;
-
- struct OfferInfo {
- uint pay_amt;
- ERC20 pay_gem;
- uint buy_amt;
- ERC20 buy_gem;
- address owner;
- uint64 timestamp;
- }
-
- modifier can_buy(uint id) {
- require(isActive(id));
- _;
- }
-
- modifier can_cancel(uint id) {
- require(isActive(id));
- require(getOwner(id) == msg.sender);
- _;
- }
-
- modifier can_offer {
- _;
- }
-
- modifier synchronized {
- require(!locked);
- locked = true;
- _;
- locked = false;
- }
-
- function isActive(uint id) public constant returns (bool active) {
- return offers[id].timestamp > 0;
- }
-
- function getOwner(uint id) public constant returns (address owner) {
- return offers[id].owner;
- }
-
- function getOffer(uint id) public constant returns (uint, ERC20, uint, ERC20) {
- var offer = offers[id];
- return (offer.pay_amt, offer.pay_gem,
- offer.buy_amt, offer.buy_gem);
- }
-
- // ---- Public entrypoints ---- //
-
- function bump(bytes32 id_)
- public
- can_buy(uint256(id_))
- {
- var id = uint256(id_);
- LogBump(
- id_,
- keccak256(offers[id].pay_gem, offers[id].buy_gem),
- offers[id].owner,
- offers[id].pay_gem,
- offers[id].buy_gem,
- uint128(offers[id].pay_amt),
- uint128(offers[id].buy_amt),
- offers[id].timestamp
- );
- }
-
- // Accept given `quantity` of an offer. Transfers funds from caller to
- // offer maker, and from market to caller.
- function buy(uint id, uint quantity)
- public
- can_buy(id)
- synchronized
- returns (bool)
- {
- OfferInfo memory offer = offers[id];
- uint spend = mul(quantity, offer.buy_amt) / offer.pay_amt;
-
- require(uint128(spend) == spend);
- require(uint128(quantity) == quantity);
-
- // For backwards semantic compatibility.
- if (quantity == 0 || spend == 0 ||
- quantity > offer.pay_amt || spend > offer.buy_amt)
- {
- return false;
- }
-
- offers[id].pay_amt = sub(offer.pay_amt, quantity);
- offers[id].buy_amt = sub(offer.buy_amt, spend);
- require( offer.buy_gem.transferFrom(msg.sender, offer.owner, spend) );
- require( offer.pay_gem.transfer(msg.sender, quantity) );
-
- LogItemUpdate(id);
- LogTake(
- bytes32(id),
- keccak256(offer.pay_gem, offer.buy_gem),
- offer.owner,
- offer.pay_gem,
- offer.buy_gem,
- msg.sender,
- uint128(quantity),
- uint128(spend),
- uint64(now)
- );
- LogTrade(quantity, offer.pay_gem, spend, offer.buy_gem);
-
- if (offers[id].pay_amt == 0) {
- delete offers[id];
- }
-
- return true;
- }
-
- // Cancel an offer. Refunds offer maker.
- function cancel(uint id)
- public
- can_cancel(id)
- synchronized
- returns (bool success)
- {
- // read-only offer. Modify an offer by directly accessing offers[id]
- OfferInfo memory offer = offers[id];
- delete offers[id];
-
- require( offer.pay_gem.transfer(offer.owner, offer.pay_amt) );
-
- LogItemUpdate(id);
- LogKill(
- bytes32(id),
- keccak256(offer.pay_gem, offer.buy_gem),
- offer.owner,
- offer.pay_gem,
- offer.buy_gem,
- uint128(offer.pay_amt),
- uint128(offer.buy_amt),
- uint64(now)
- );
-
- success = true;
- }
-
- function kill(bytes32 id)
- public
- {
- require(cancel(uint256(id)));
- }
-
- function make(
- ERC20 pay_gem,
- ERC20 buy_gem,
- uint128 pay_amt,
- uint128 buy_amt
- )
- public
- returns (bytes32 id)
- {
- return bytes32(offer(pay_amt, pay_gem, buy_amt, buy_gem));
- }
-
- // Make a new offer. Takes funds from the caller into market escrow.
- function offer(uint pay_amt, ERC20 pay_gem, uint buy_amt, ERC20 buy_gem)
- public
- can_offer
- synchronized
- returns (uint id)
- {
- require(uint128(pay_amt) == pay_amt);
- require(uint128(buy_amt) == buy_amt);
- require(pay_amt > 0);
- require(pay_gem != ERC20(0x0));
- require(buy_amt > 0);
- require(buy_gem != ERC20(0x0));
- require(pay_gem != buy_gem);
-
- OfferInfo memory info;
- info.pay_amt = pay_amt;
- info.pay_gem = pay_gem;
- info.buy_amt = buy_amt;
- info.buy_gem = buy_gem;
- info.owner = msg.sender;
- info.timestamp = uint64(now);
- id = _next_id();
- offers[id] = info;
-
- require( pay_gem.transferFrom(msg.sender, this, pay_amt) );
-
- LogItemUpdate(id);
- LogMake(
- bytes32(id),
- keccak256(pay_gem, buy_gem),
- msg.sender,
- pay_gem,
- buy_gem,
- uint128(pay_amt),
- uint128(buy_amt),
- uint64(now)
- );
- }
-
- function take(bytes32 id, uint128 maxTakeAmount)
- public
- {
- require(buy(uint256(id), maxTakeAmount));
- }
-
- function _next_id()
- internal
- returns (uint)
- {
- last_offer_id++; return last_offer_id;
- }
-}
-
-// Simple Market with a market lifetime. When the close_time has been reached,
-// offers can only be cancelled (offer and buy will throw).
-
-contract ExpiringMarket is DSAuth, SimpleMarket {
- uint64 public close_time;
- bool public stopped;
-
- // after close_time has been reached, no new offers are allowed
- modifier can_offer {
- require(!isClosed());
- _;
- }
-
- // after close, no new buys are allowed
- modifier can_buy(uint id) {
- require(isActive(id));
- require(!isClosed());
- _;
- }
-
- // after close, anyone can cancel an offer
- modifier can_cancel(uint id) {
- require(isActive(id));
- require(isClosed() || (msg.sender == getOwner(id)));
- _;
- }
-
- function ExpiringMarket(uint64 _close_time)
- public
- {
- close_time = _close_time;
- }
-
- function isClosed() public constant returns (bool closed) {
- return stopped || getTime() > close_time;
- }
-
- function getTime() public constant returns (uint64) {
- return uint64(now);
- }
-
- function stop() public auth {
- stopped = true;
- }
-}
-
-contract MatchingEvents {
- event LogBuyEnabled(bool isEnabled);
- event LogMinSell(address pay_gem, uint min_amount);
- event LogMatchingEnabled(bool isEnabled);
- event LogUnsortedOffer(uint id);
- event LogSortedOffer(uint id);
- event LogAddTokenPairWhitelist(ERC20 baseToken, ERC20 quoteToken);
- event LogRemTokenPairWhitelist(ERC20 baseToken, ERC20 quoteToken);
- event LogInsert(address keeper, uint id);
- event LogDelete(address keeper, uint id);
-}
-
-contract MatchingMarket is MatchingEvents, ExpiringMarket, DSNote {
- bool public buyEnabled = true; //buy enabled
- bool public matchingEnabled = true; //true: enable matching,
- //false: revert to expiring market
- struct sortInfo {
- uint next; //points to id of next higher offer
- uint prev; //points to id of previous lower offer
- uint delb; //the blocknumber where this entry was marked for delete
- }
- mapping(uint => sortInfo) public _rank; //doubly linked lists of sorted offer ids
- mapping(address => mapping(address => uint)) public _best; //id of the highest offer for a token pair
- mapping(address => mapping(address => uint)) public _span; //number of offers stored for token pair in sorted orderbook
- mapping(address => uint) public _dust; //minimum sell amount for a token to avoid dust offers
- mapping(uint => uint) public _near; //next unsorted offer id
- mapping(bytes32 => bool) public _menu; //whitelist tracking which token pairs can be traded
- uint _head; //first unsorted offer id
-
- //check if token pair is enabled
- modifier isWhitelist(ERC20 buy_gem, ERC20 pay_gem) {
- require(_menu[keccak256(buy_gem, pay_gem)] || _menu[keccak256(pay_gem, buy_gem)]);
- _;
- }
-
- function MatchingMarket(uint64 close_time) ExpiringMarket(close_time) public {
- }
-
- // ---- Public entrypoints ---- //
-
- function make(
- ERC20 pay_gem,
- ERC20 buy_gem,
- uint128 pay_amt,
- uint128 buy_amt
- )
- public
- returns (bytes32)
- {
- return bytes32(offer(pay_amt, pay_gem, buy_amt, buy_gem));
- }
-
- function take(bytes32 id, uint128 maxTakeAmount) public {
- require(buy(uint256(id), maxTakeAmount));
- }
-
- function kill(bytes32 id) public {
- require(cancel(uint256(id)));
- }
-
- // Make a new offer. Takes funds from the caller into market escrow.
- //
- // If matching is enabled:
- // * creates new offer without putting it in
- // the sorted list.
- // * available to authorized contracts only!
- // * keepers should call insert(id,pos)
- // to put offer in the sorted list.
- //
- // If matching is disabled:
- // * calls expiring market's offer().
- // * available to everyone without authorization.
- // * no sorting is done.
- //
- function offer(
- uint pay_amt, //maker (ask) sell how much
- ERC20 pay_gem, //maker (ask) sell which token
- uint buy_amt, //taker (ask) buy how much
- ERC20 buy_gem //taker (ask) buy which token
- )
- public
- isWhitelist(pay_gem, buy_gem)
- /* NOT synchronized!!! */
- returns (uint)
- {
- var fn = matchingEnabled ? _offeru : super.offer;
- return fn(pay_amt, pay_gem, buy_amt, buy_gem);
- }
-
- // Make a new offer. Takes funds from the caller into market escrow.
- function offer(
- uint pay_amt, //maker (ask) sell how much
- ERC20 pay_gem, //maker (ask) sell which token
- uint buy_amt, //maker (ask) buy how much
- ERC20 buy_gem, //maker (ask) buy which token
- uint pos //position to insert offer, 0 should be used if unknown
- )
- public
- isWhitelist(pay_gem, buy_gem)
- /*NOT synchronized!!! */
- can_offer
- returns (uint)
- {
- return offer(pay_amt, pay_gem, buy_amt, buy_gem, pos, false);
- }
-
- function offer(
- uint pay_amt, //maker (ask) sell how much
- ERC20 pay_gem, //maker (ask) sell which token
- uint buy_amt, //maker (ask) buy how much
- ERC20 buy_gem, //maker (ask) buy which token
- uint pos, //position to insert offer, 0 should be used if unknown
- bool rounding //match "close enough" orders?
- )
- public
- isWhitelist(pay_gem, buy_gem)
- /*NOT synchronized!!! */
- can_offer
- returns (uint)
- {
- require(_dust[pay_gem] <= pay_amt);
-
- if (matchingEnabled) {
- return _matcho(pay_amt, pay_gem, buy_amt, buy_gem, pos, rounding);
- }
- return super.offer(pay_amt, pay_gem, buy_amt, buy_gem);
- }
-
- //Transfers funds from caller to offer maker, and from market to caller.
- function buy(uint id, uint amount)
- public
- /*NOT synchronized!!! */
- can_buy(id)
- returns (bool)
- {
- var fn = matchingEnabled ? _buys : super.buy;
- return fn(id, amount);
- }
-
- // Cancel an offer. Refunds offer maker.
- function cancel(uint id)
- public
- /*NOT synchronized!!! */
- can_cancel(id)
- returns (bool success)
- {
- if (matchingEnabled) {
- if (isOfferSorted(id)) {
- require(_unsort(id));
- } else {
- require(_hide(id));
- }
- }
- return super.cancel(id); //delete the offer.
- }
-
- //insert offer into the sorted list
- //keepers need to use this function
- function insert(
- uint id, //maker (ask) id
- uint pos //position to insert into
- )
- public
- returns (bool)
- {
- require(!isOfferSorted(id)); //make sure offers[id] is not yet sorted
- require(isActive(id)); //make sure offers[id] is active
-
- _hide(id); //remove offer from unsorted offers list
- _sort(id, pos); //put offer into the sorted offers list
- LogInsert(msg.sender, id);
- return true;
- }
-
- //deletes _rank [id]
- // Function should be called by keepers.
- function del_rank(uint id)
- public
- returns (bool)
- {
- require(!isActive(id) && _rank[id].delb != 0 && _rank[id].delb < block.number - 10);
- delete _rank[id];
- LogDelete(msg.sender, id);
- return true;
- }
-
- //returns true if token is succesfully added to whitelist
- // Function is used to add a token pair to the whitelist
- // All incoming offers are checked against the whitelist.
- function addTokenPairWhitelist(
- ERC20 baseToken,
- ERC20 quoteToken
- )
- public
- auth
- note
- returns (bool)
- {
- require(!isTokenPairWhitelisted(baseToken, quoteToken));
- require(address(baseToken) != 0x0 && address(quoteToken) != 0x0);
-
- _menu[keccak256(baseToken, quoteToken)] = true;
- LogAddTokenPairWhitelist(baseToken, quoteToken);
- return true;
- }
-
- //returns true if token is successfully removed from whitelist
- // Function is used to remove a token pair from the whitelist.
- // All incoming offers are checked against the whitelist.
- function remTokenPairWhitelist(
- ERC20 baseToken,
- ERC20 quoteToken
- )
- public
- auth
- note
- returns (bool)
- {
- require(isTokenPairWhitelisted(baseToken, quoteToken));
-
- delete _menu[keccak256(baseToken, quoteToken)];
- delete _menu[keccak256(quoteToken, baseToken)];
- LogRemTokenPairWhitelist(baseToken, quoteToken);
- return true;
- }
-
- function isTokenPairWhitelisted(
- ERC20 baseToken,
- ERC20 quoteToken
- )
- public
- constant
- returns (bool)
- {
- return (_menu[keccak256(baseToken, quoteToken)] || _menu[keccak256(quoteToken, baseToken)]);
- }
-
- //set the minimum sell amount for a token
- // Function is used to avoid "dust offers" that have
- // very small amount of tokens to sell, and it would
- // cost more gas to accept the offer, than the value
- // of tokens received.
- function setMinSell(
- ERC20 pay_gem, //token to assign minimum sell amount to
- uint dust //maker (ask) minimum sell amount
- )
- public
- auth
- note
- returns (bool)
- {
- _dust[pay_gem] = dust;
- LogMinSell(pay_gem, dust);
- return true;
- }
-
- //returns the minimum sell amount for an offer
- function getMinSell(
- ERC20 pay_gem //token for which minimum sell amount is queried
- )
- public
- constant
- returns (uint)
- {
- return _dust[pay_gem];
- }
-
- //set buy functionality enabled/disabled
- function setBuyEnabled(bool buyEnabled_) public auth returns (bool) {
- buyEnabled = buyEnabled_;
- LogBuyEnabled(buyEnabled);
- return true;
- }
-
- //set matching enabled/disabled
- // If matchingEnabled true(default), then inserted offers are matched.
- // Except the ones inserted by contracts, because those end up
- // in the unsorted list of offers, that must be later sorted by
- // keepers using insert().
- // If matchingEnabled is false then MatchingMarket is reverted to ExpiringMarket,
- // and matching is not done, and sorted lists are disabled.
- function setMatchingEnabled(bool matchingEnabled_) public auth returns (bool) {
- matchingEnabled = matchingEnabled_;
- LogMatchingEnabled(matchingEnabled);
- return true;
- }
-
- //return the best offer for a token pair
- // the best offer is the lowest one if it's an ask,
- // and highest one if it's a bid offer
- function getBestOffer(ERC20 sell_gem, ERC20 buy_gem) public constant returns(uint) {
- return _best[sell_gem][buy_gem];
- }
-
- //return the next worse offer in the sorted list
- // the worse offer is the higher one if its an ask,
- // a lower one if its a bid offer,
- // and in both cases the newer one if they're equal.
- function getWorseOffer(uint id) public constant returns(uint) {
- return _rank[id].prev;
- }
-
- //return the next better offer in the sorted list
- // the better offer is in the lower priced one if its an ask,
- // the next higher priced one if its a bid offer
- // and in both cases the older one if they're equal.
- function getBetterOffer(uint id) public constant returns(uint) {
-
- return _rank[id].next;
- }
-
- //return the amount of better offers for a token pair
- function getOfferCount(ERC20 sell_gem, ERC20 buy_gem) public constant returns(uint) {
- return _span[sell_gem][buy_gem];
- }
-
- //get the first unsorted offer that was inserted by a contract
- // Contracts can't calculate the insertion position of their offer because it is not an O(1) operation.
- // Their offers get put in the unsorted list of offers.
- // Keepers can calculate the insertion position offchain and pass it to the insert() function to insert
- // the unsorted offer into the sorted list. Unsorted offers will not be matched, but can be bought with buy().
- function getFirstUnsortedOffer() public constant returns(uint) {
- return _head;
- }
-
- //get the next unsorted offer
- // Can be used to cycle through all the unsorted offers.
- function getNextUnsortedOffer(uint id) public constant returns(uint) {
- return _near[id];
- }
-
- function isOfferSorted(uint id) public constant returns(bool) {
- return _rank[id].next != 0
- || _rank[id].prev != 0
- || _best[offers[id].pay_gem][offers[id].buy_gem] == id;
- }
-
- function sellAllAmount(ERC20 pay_gem, uint pay_amt, ERC20 buy_gem, uint min_fill_amount)
- public
- returns (uint fill_amt)
- {
- uint offerId;
- while (pay_amt > 0) { //while there is amount to sell
- offerId = getBestOffer(buy_gem, pay_gem); //Get the best offer for the token pair
- require(offerId != 0); //Fails if there are not more offers
-
- // There is a chance that pay_amt is smaller than 1 wei of the other token
- if (pay_amt * 1 ether < wdiv(offers[offerId].buy_amt, offers[offerId].pay_amt)) {
- break; //We consider that all amount is sold
- }
- if (pay_amt >= offers[offerId].buy_amt) { //If amount to sell is higher or equal than current offer amount to buy
- fill_amt = add(fill_amt, offers[offerId].pay_amt); //Add amount bought to acumulator
- pay_amt = sub(pay_amt, offers[offerId].buy_amt); //Decrease amount to sell
- take(bytes32(offerId), uint128(offers[offerId].pay_amt)); //We take the whole offer
- } else { // if lower
- var baux = rmul(pay_amt * 10 ** 9, rdiv(offers[offerId].pay_amt, offers[offerId].buy_amt)) / 10 ** 9;
- fill_amt = add(fill_amt, baux); //Add amount bought to acumulator
- take(bytes32(offerId), uint128(baux)); //We take the portion of the offer that we need
- pay_amt = 0; //All amount is sold
- }
- }
- require(fill_amt >= min_fill_amount);
- }
-
- function buyAllAmount(ERC20 buy_gem, uint buy_amt, ERC20 pay_gem, uint max_fill_amount)
- public
- returns (uint fill_amt)
- {
- uint offerId;
- while (buy_amt > 0) { //Meanwhile there is amount to buy
- offerId = getBestOffer(buy_gem, pay_gem); //Get the best offer for the token pair
- require(offerId != 0);
-
- // There is a chance that buy_amt is smaller than 1 wei of the other token
- if (buy_amt * 1 ether < wdiv(offers[offerId].pay_amt, offers[offerId].buy_amt)) {
- break; //We consider that all amount is sold
- }
- if (buy_amt >= offers[offerId].pay_amt) { //If amount to buy is higher or equal than current offer amount to sell
- fill_amt = add(fill_amt, offers[offerId].buy_amt); //Add amount sold to acumulator
- buy_amt = sub(buy_amt, offers[offerId].pay_amt); //Decrease amount to buy
- take(bytes32(offerId), uint128(offers[offerId].pay_amt)); //We take the whole offer
- } else { //if lower
- fill_amt = add(fill_amt, rmul(buy_amt * 10 ** 9, rdiv(offers[offerId].buy_amt, offers[offerId].pay_amt)) / 10 ** 9); //Add amount sold to acumulator
- take(bytes32(offerId), uint128(buy_amt)); //We take the portion of the offer that we need
- buy_amt = 0; //All amount is bought
- }
- }
- require(fill_amt <= max_fill_amount);
- }
-
- function getBuyAmount(ERC20 buy_gem, ERC20 pay_gem, uint pay_amt) public constant returns (uint fill_amt) {
- var offerId = getBestOffer(buy_gem, pay_gem); //Get best offer for the token pair
- while (pay_amt > offers[offerId].buy_amt) {
- fill_amt = add(fill_amt, offers[offerId].pay_amt); //Add amount to buy accumulator
- pay_amt = sub(pay_amt, offers[offerId].buy_amt); //Decrease amount to pay
- if (pay_amt > 0) { //If we still need more offers
- offerId = getWorseOffer(offerId); //We look for the next best offer
- require(offerId != 0); //Fails if there are not enough offers to complete
- }
- }
- fill_amt = add(fill_amt, rmul(pay_amt * 10 ** 9, rdiv(offers[offerId].pay_amt, offers[offerId].buy_amt)) / 10 ** 9); //Add proportional amount of last offer to buy accumulator
- }
-
- function getPayAmount(ERC20 pay_gem, ERC20 buy_gem, uint buy_amt) public constant returns (uint fill_amt) {
- var offerId = getBestOffer(buy_gem, pay_gem); //Get best offer for the token pair
- while (buy_amt > offers[offerId].pay_amt) {
- fill_amt = add(fill_amt, offers[offerId].buy_amt); //Add amount to pay accumulator
- buy_amt = sub(buy_amt, offers[offerId].pay_amt); //Decrease amount to buy
- if (buy_amt > 0) { //If we still need more offers
- offerId = getWorseOffer(offerId); //We look for the next best offer
- require(offerId != 0); //Fails if there are not enough offers to complete
- }
- }
- fill_amt = add(fill_amt, rmul(buy_amt * 10 ** 9, rdiv(offers[offerId].buy_amt, offers[offerId].pay_amt)) / 10 ** 9); //Add proportional amount of last offer to pay accumulator
- }
-
- // ---- Internal Functions ---- //
-
- function _buys(uint id, uint amount)
- internal
- returns (bool)
- {
- require(buyEnabled);
-
- if (amount == offers[id].pay_amt && isOfferSorted(id)) {
- //offers[id] must be removed from sorted list because all of it is bought
- _unsort(id);
- }
- require(super.buy(id, amount));
- return true;
- }
-
- //find the id of the next higher offer after offers[id]
- function _find(uint id)
- internal
- view
- returns (uint)
- {
- require( id > 0 );
-
- address buy_gem = address(offers[id].buy_gem);
- address pay_gem = address(offers[id].pay_gem);
- uint top = _best[pay_gem][buy_gem];
- uint old_top = 0;
-
- // Find the larger-than-id order whose successor is less-than-id.
- while (top != 0 && _isPricedLtOrEq(id, top)) {
- old_top = top;
- top = _rank[top].prev;
- }
- return old_top;
- }
-
- //find the id of the next higher offer after offers[id]
- function _findpos(uint id, uint pos)
- internal
- view
- returns (uint)
- {
- require(id > 0);
-
- // Look for an active order.
- while (pos != 0 && !isActive(pos)) {
- pos = _rank[pos].prev;
- }
-
- if (pos == 0) {
- //if we got to the end of list without a single active offer
- return _find(id);
-
- } else {
- // if we did find a nearby active offer
- // Walk the order book down from there...
- if(_isPricedLtOrEq(id, pos)) {
- uint old_pos;
-
- // Guaranteed to run at least once because of
- // the prior if statements.
- while (pos != 0 && _isPricedLtOrEq(id, pos)) {
- old_pos = pos;
- pos = _rank[pos].prev;
- }
- return old_pos;
-
- // ...or walk it up.
- } else {
- while (pos != 0 && !_isPricedLtOrEq(id, pos)) {
- pos = _rank[pos].next;
- }
- return pos;
- }
- }
- }
-
- //return true if offers[low] priced less than or equal to offers[high]
- function _isPricedLtOrEq(
- uint low, //lower priced offer's id
- uint high //higher priced offer's id
- )
- internal
- view
- returns (bool)
- {
- return mul(offers[low].buy_amt, offers[high].pay_amt)
- >= mul(offers[high].buy_amt, offers[low].pay_amt);
- }
-
- //these variables are global only because of solidity local variable limit
-
- //match offers with taker offer, and execute token transactions
- function _matcho(
- uint t_pay_amt, //taker sell how much
- ERC20 t_pay_gem, //taker sell which token
- uint t_buy_amt, //taker buy how much
- ERC20 t_buy_gem, //taker buy which token
- uint pos, //position id
- bool rounding //match "close enough" orders?
- )
- internal
- returns (uint id)
- {
- uint best_maker_id; //highest maker id
- uint t_buy_amt_old; //taker buy how much saved
- uint m_buy_amt; //maker offer wants to buy this much token
- uint m_pay_amt; //maker offer wants to sell this much token
-
- // there is at least one offer stored for token pair
- while (_best[t_buy_gem][t_pay_gem] > 0) {
- best_maker_id = _best[t_buy_gem][t_pay_gem];
- m_buy_amt = offers[best_maker_id].buy_amt;
- m_pay_amt = offers[best_maker_id].pay_amt;
-
- // Ugly hack to work around rounding errors. Based on the idea that
- // the furthest the amounts can stray from their "true" values is 1.
- // Ergo the worst case has t_pay_amt and m_pay_amt at +1 away from
- // their "correct" values and m_buy_amt and t_buy_amt at -1.
- // Since (c - 1) * (d - 1) > (a + 1) * (b + 1) is equivalent to
- // c * d > a * b + a + b + c + d, we write...
- if (mul(m_buy_amt, t_buy_amt) > mul(t_pay_amt, m_pay_amt) +
- (rounding ? m_buy_amt + t_buy_amt + t_pay_amt + m_pay_amt : 0))
- {
- break;
- }
- // ^ The `rounding` parameter is a compromise borne of a couple days
- // of discussion.
-
- buy(best_maker_id, min(m_pay_amt, t_buy_amt));
- t_buy_amt_old = t_buy_amt;
- t_buy_amt = sub(t_buy_amt, min(m_pay_amt, t_buy_amt));
- t_pay_amt = mul(t_buy_amt, t_pay_amt) / t_buy_amt_old;
-
- if (t_pay_amt == 0 || t_buy_amt == 0) {
- break;
- }
- }
-
- if (t_buy_amt > 0 && t_pay_amt > 0) {
- //new offer should be created
- id = super.offer(t_pay_amt, t_pay_gem, t_buy_amt, t_buy_gem);
- //insert offer into the sorted list
- _sort(id, pos);
- }
- }
-
- // Make a new offer without putting it in the sorted list.
- // Takes funds from the caller into market escrow.
- // ****Available to authorized contracts only!**********
- // Keepers should call insert(id,pos) to put offer in the sorted list.
- function _offeru(
- uint pay_amt, //maker (ask) sell how much
- ERC20 pay_gem, //maker (ask) sell which token
- uint buy_amt, //maker (ask) buy how much
- ERC20 buy_gem //maker (ask) buy which token
- )
- internal
- /*NOT synchronized!!! */
- returns (uint id)
- {
- require(_dust[pay_gem] <= pay_amt);
- id = super.offer(pay_amt, pay_gem, buy_amt, buy_gem);
- _near[id] = _head;
- _head = id;
- LogUnsortedOffer(id);
- }
-
- //put offer into the sorted list
- function _sort(
- uint id, //maker (ask) id
- uint pos //position to insert into
- )
- internal
- {
- require(isActive(id));
-
- address buy_gem = address(offers[id].buy_gem);
- address pay_gem = address(offers[id].pay_gem);
- uint prev_id; //maker (ask) id
-
- if (pos == 0 || !isOfferSorted(pos)) {
- pos = _find(id);
- } else {
- pos = _findpos(id, pos);
-
- //if user has entered a `pos` that belongs to another currency pair
- //we start from scratch
- if(pos != 0 && (offers[pos].pay_gem != offers[id].pay_gem
- || offers[pos].buy_gem != offers[id].buy_gem))
- {
- pos = 0;
- pos=_find(id);
- }
- }
-
-
- //requirement below is satisfied by statements above
- //require(pos == 0 || isOfferSorted(pos));
-
-
- if (pos != 0) { //offers[id] is not the highest offer
- //requirement below is satisfied by statements above
- //require(_isPricedLtOrEq(id, pos));
- prev_id = _rank[pos].prev;
- _rank[pos].prev = id;
- _rank[id].next = pos;
- } else { //offers[id] is the highest offer
- prev_id = _best[pay_gem][buy_gem];
- _best[pay_gem][buy_gem] = id;
- }
-
- if (prev_id != 0) { //if lower offer does exist
- //requirement below is satisfied by statements above
- //require(!_isPricedLtOrEq(id, prev_id));
- _rank[prev_id].next = id;
- _rank[id].prev = prev_id;
- }
-
- _span[pay_gem][buy_gem]++;
- LogSortedOffer(id);
- }
-
- // Remove offer from the sorted list (does not cancel offer)
- function _unsort(
- uint id //id of maker (ask) offer to remove from sorted list
- )
- internal
- returns (bool)
- {
- address buy_gem = address(offers[id].buy_gem);
- address pay_gem = address(offers[id].pay_gem);
- require(_span[pay_gem][buy_gem] > 0);
-
- require(_rank[id].delb == 0 && //assert id is in the sorted list
- isOfferSorted(id));
-
- if (id != _best[pay_gem][buy_gem]) { // offers[id] is not the highest offer
- require(_rank[_rank[id].next].prev == id);
- _rank[_rank[id].next].prev = _rank[id].prev;
- } else { //offers[id] is the highest offer
- _best[pay_gem][buy_gem] = _rank[id].prev;
- }
-
- if (_rank[id].prev != 0) { //offers[id] is not the lowest offer
- require(_rank[_rank[id].prev].next == id);
- _rank[_rank[id].prev].next = _rank[id].next;
- }
-
- _span[pay_gem][buy_gem]--;
- _rank[id].delb = block.number; //mark _rank[id] for deletion
- return true;
- }
-
- //Hide offer from the unsorted order book (does not cancel offer)
- function _hide(
- uint id //id of maker offer to remove from unsorted list
- )
- internal
- returns (bool)
- {
- uint uid = _head; //id of an offer in unsorted offers list
- uint pre = uid; //id of previous offer in unsorted offers list
-
- require(!isOfferSorted(id)); //make sure offer id is not in sorted offers list
-
- if (_head == id) { //check if offer is first offer in unsorted offers list
- _head = _near[id]; //set head to new first unsorted offer
- _near[id] = 0; //delete order from unsorted order list
- return true;
- }
- while (uid > 0 && uid != id) { //find offer in unsorted order list
- pre = uid;
- uid = _near[uid];
- }
- if (uid != id) { //did not find offer id in unsorted offers list
- return false;
- }
- _near[pre] = _near[id]; //set previous unsorted offer to point to offer after offer id
- _near[id] = 0; //delete order from unsorted order list
- return true;
- }
-}
diff --git a/src/contracts/factory/FundRanking.sol b/src/contracts/factory/FundRanking.sol
deleted file mode 100644
index 7e7db349..00000000
--- a/src/contracts/factory/FundRanking.sol
+++ /dev/null
@@ -1,75 +0,0 @@
-pragma solidity ^0.4.25;
-pragma experimental ABIEncoderV2;
-
-import "FundFactory.sol";
-import "Accounting.sol";
-
-contract FundRanking {
- function getFundDetails(address _factory)
- external
- view
- returns(address[], uint[], uint[], string[], address[])
- {
- FundFactory factory = FundFactory(_factory);
- uint numberOfFunds = factory.getLastFundId() + 1;
- address[] memory hubs = new address[](numberOfFunds);
- uint[] memory sharePrices = new uint[](numberOfFunds);
- uint[] memory creationTimes = new uint[](numberOfFunds);
- string[] memory names = new string[](numberOfFunds);
- address[] memory denominationAssets = new address[](numberOfFunds);
-
- for (uint i = 0; i < numberOfFunds; i++) {
- address hubAddress = factory.funds(i);
- Hub hub = Hub(hubAddress);
- hubs[i] = hubAddress;
- sharePrices[i] = Accounting(hub.accounting()).calcSharePrice();
- denominationAssets[i] = Accounting(hub.accounting()).DENOMINATION_ASSET();
- creationTimes[i] = hub.creationTime();
- names[i] = hub.name();
- }
- return (hubs, sharePrices, creationTimes, names, denominationAssets);
- }
-
- function getFundGavs(address _factory)
- external
- view
- returns(address[], uint[])
- {
- FundFactory factory = FundFactory(_factory);
- uint numberOfFunds = factory.getLastFundId() + 1;
- address[] memory hubs = new address[](numberOfFunds);
- uint[] memory gavs = new uint[](numberOfFunds);
-
- for (uint i = 0; i < numberOfFunds; i++) {
- address hubAddress = factory.funds(i);
- Hub hub = Hub(hubAddress);
- uint gav = Accounting(hub.accounting()).calcGav();
-
- hubs[i] = hubAddress;
- gavs[i] = gav;
- }
- return (hubs, gavs);
- }
-
- function getFundVersions(address _factory)
- external
- view
- returns(address[], bytes32[])
- {
- FundFactory factory = FundFactory(_factory);
- uint numberOfFunds = factory.getLastFundId() + 1;
- address[] memory hubs = new address[](numberOfFunds);
- bytes32[] memory versions = new bytes32[](numberOfFunds);
-
- for (uint i = 0; i < numberOfFunds; i++) {
- address hubAddress = factory.funds(i);
- Hub hub = Hub(hubAddress);
-
- (, bytes32 version) = Registry(hub.registry()).versionInformation(hub.version());
-
- hubs[i] = hubAddress;
- versions[i] = version;
- }
- return (hubs, versions);
- }
-}
diff --git a/src/contracts/fund/accounting/Accounting.i.sol b/src/contracts/fund/accounting/Accounting.i.sol
deleted file mode 100644
index 3bddbf87..00000000
--- a/src/contracts/fund/accounting/Accounting.i.sol
+++ /dev/null
@@ -1,30 +0,0 @@
-pragma solidity ^0.4.25;
-
-/// @notice Gives metrics about a Fund
-interface AccountingInterface {
-
- event AssetAddition(
- address indexed asset
- );
-
- event AssetRemoval(
- address indexed asset
- );
-
- function getOwnedAssetsLength() external view returns (uint);
- function getFundHoldings() external returns (uint[], address[]);
- function calcAssetGAV(address ofAsset) external returns (uint);
- function calcGav() public returns (uint gav);
- function calcNav(uint gav, uint unclaimedFees) pure returns (uint);
- function valuePerShare(uint totalValue, uint numShares) public view returns (uint);
- function performCalculations() public returns (
- uint gav,
- uint unclaimedFees,
- uint feesInShares,
- uint nav,
- uint sharePrice,
- uint gavPerShareNetManagementFee
- );
- function calcSharePrice() external returns (uint);
- function calcGavPerShareNetManagementFee() public returns (uint);
-}
diff --git a/src/contracts/fund/participation/Participation.i.sol b/src/contracts/fund/participation/Participation.i.sol
deleted file mode 100644
index c2134915..00000000
--- a/src/contracts/fund/participation/Participation.i.sol
+++ /dev/null
@@ -1,46 +0,0 @@
-pragma solidity ^0.4.25;
-
-/// @notice Investor Fund interactions
-/// @notice Handles redemptions and requests for investment
-interface ParticipationInterface {
- event EnableInvestment (address[] asset);
- event DisableInvestment (address[] assets);
-
- event InvestmentRequest (
- address indexed requestOwner,
- address indexed investmentAsset,
- uint requestedShares,
- uint investmentAmount
- );
-
- event RequestExecution (
- address indexed requestOwner,
- address indexed executor,
- address indexed investmentAsset,
- uint investmentAmount,
- uint requestedShares
- );
-
- event CancelRequest (
- address indexed requestOwner
- );
-
- event Redemption (
- address indexed redeemer,
- address[] assets,
- uint[] assetQuantities,
- uint redeemedShares
- );
-
- function requestInvestment(
- uint requestedShares,
- uint investmentAmount,
- address investmentAsset
- ) external payable;
- function hasRequest(address) view returns (bool);
- function cancelRequest() external payable;
- function executeRequestFor(address requestOwner) external payable;
- function redeem() external;
- function redeemWithConstraints(uint shareQuantity, address[] requestedAssets) public;
-}
-
diff --git a/src/contracts/fund/policies/BooleanPolicy.sol b/src/contracts/fund/policies/BooleanPolicy.sol
deleted file mode 100644
index f99ffc47..00000000
--- a/src/contracts/fund/policies/BooleanPolicy.sol
+++ /dev/null
@@ -1,23 +0,0 @@
-pragma solidity ^0.4.25;
-
-import "Policy.sol";
-
-contract BooleanPolicy is Policy {
- bool allowed;
-
- function rule(bytes4 sig, address[5] addresses, uint[3] values, bytes32 identifier) external view returns (bool) {
- return allowed;
- }
-
- function position() external view returns (Applied) { return Applied.pre; }
-}
-
-contract TruePolicy is BooleanPolicy {
- constructor() { allowed = true; }
- function identifier() external view returns (string) { "TruePolicy"; }
-}
-
-contract FalsePolicy is BooleanPolicy {
- constructor() { allowed = false; }
- function identifier() external view returns (string) { "FalsePolicy"; }
-}
diff --git a/src/contracts/fund/policies/TradingSignatures.sol b/src/contracts/fund/policies/TradingSignatures.sol
deleted file mode 100644
index 3abf7a50..00000000
--- a/src/contracts/fund/policies/TradingSignatures.sol
+++ /dev/null
@@ -1,6 +0,0 @@
-pragma solidity ^0.4.25;
-
-contract TradingSignatures {
- bytes4 constant public MAKE_ORDER = 0x79705be7; // makeOrderSignature
- bytes4 constant public TAKE_ORDER = 0xe51be6e8; // takeOrderSignature
-}
\ No newline at end of file
diff --git a/src/contracts/fund/shares/Shares.i.sol b/src/contracts/fund/shares/Shares.i.sol
deleted file mode 100644
index 054eeb89..00000000
--- a/src/contracts/fund/shares/Shares.i.sol
+++ /dev/null
@@ -1,8 +0,0 @@
-pragma solidity ^0.4.25;
-
-/// @notice Token representing ownership of the Fund
-interface SharesInterface {
- function createFor(address who, uint amount);
- function destroyFor(address who, uint amount);
-}
-
diff --git a/src/contracts/fund/trading/Trading.i.sol b/src/contracts/fund/trading/Trading.i.sol
deleted file mode 100644
index 94c2eabf..00000000
--- a/src/contracts/fund/trading/Trading.i.sol
+++ /dev/null
@@ -1,40 +0,0 @@
-pragma solidity ^0.4.25;
-
-/// @notice Mediation between a Fund and exchanges
-interface TradingInterface {
- event ExchangeMethodCall(
- address indexed exchangeAddress,
- string indexed methodSignature,
- address[6] orderAddresses,
- uint[8] orderValues,
- bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
- );
-
- function callOnExchange(
- uint exchangeIndex,
- string methodSignature,
- address[6] orderAddresses,
- uint[8] orderValues,
- bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
- ) public;
-
- function addOpenMakeOrder(
- address ofExchange,
- address ofSellAsset,
- address ofBuyAsset,
- uint orderId,
- uint expiryTime
- ) public;
-
- function removeOpenMakeOrder(
- address ofExchange,
- address ofSellAsset
- ) public;
-}
-
diff --git a/src/contracts/fund/vault/Vault.i.sol b/src/contracts/fund/vault/Vault.i.sol
deleted file mode 100644
index 6ee3c14f..00000000
--- a/src/contracts/fund/vault/Vault.i.sol
+++ /dev/null
@@ -1,7 +0,0 @@
-pragma solidity ^0.4.25;
-
-/// @notice Custody component
-interface VaultInterface {
- function withdraw(address token, uint amount) external;
-}
-
diff --git a/src/contracts/prices/CanonicalPriceFeed.sol b/src/contracts/prices/CanonicalPriceFeed.sol
deleted file mode 100644
index 3f6c732e..00000000
--- a/src/contracts/prices/CanonicalPriceFeed.sol
+++ /dev/null
@@ -1,428 +0,0 @@
-pragma solidity ^0.4.25;
-
-import "CanonicalRegistrar.sol";
-import "SimplePriceFeed.sol";
-import "StakingPriceFeed.sol";
-import "OperatorStaking.sol";
-import "ERC20.i.sol";
-
-/// @author Melonport AG <team@melonport.com>
-/// @notice Routes external data to smart contracts
-/// @notice PriceFeed operator could be staked and sharePrice input validated on chain
-contract CanonicalPriceFeed is PriceSourceInterface, OperatorStaking, SimplePriceFeed, CanonicalRegistrar {
-
- // EVENTS
- event SetupPriceFeed(address ofPriceFeed);
-
- struct HistoricalPrices {
- address[] assets;
- uint[] prices;
- uint timestamp;
- }
-
- // FIELDS
- bool public updatesAreAllowed = true;
- uint public minimumPriceCount = 1;
- uint public VALIDITY;
- uint public INTERVAL;
- mapping (address => bool) public isStakingFeed; // If the Staking Feed has been created through this contract
- HistoricalPrices[] public priceHistory;
- uint public lastUpdate;
-
- // METHODS
-
- // CONSTRUCTOR
-
- /// @dev Define and register a quote asset against which all prices are measured/based against
- /// @param ofStakingAsset Address of staking asset (may or may not be quoteAsset)
- /// @param ofQuoteAsset Address of quote asset
- /// @param quoteAssetName Name of quote asset
- /// @param quoteAssetSymbol Symbol for quote asset
- /// @param quoteAssetUrl URL related to quote asset
- /// @param quoteAssetIpfsHash IPFS hash associated with quote asset
- /// @param quoteAssetBreakInBreakOut Break-in/break-out for quote asset on destination chain
- /// @param quoteAssetStandards EIP standards quote asset adheres to
- /// @param quoteAssetFunctionSignatures Whitelisted functions of quote asset contract
- // /// @param interval Number of seconds between pricefeed updates (this interval is not enforced on-chain, but should be followed by the datafeed maintainer)
- // /// @param validity Number of seconds that datafeed update information is valid for
- /// @param ofGovernance Address of contract governing the Canonical PriceFeed
- constructor(
- address ofStakingAsset,
- address ofQuoteAsset, // Inital entry in asset registrar contract is Melon (QUOTE_ASSET)
- bytes32 quoteAssetName,
- bytes8 quoteAssetSymbol,
- string quoteAssetUrl,
- string quoteAssetIpfsHash,
- address[2] quoteAssetBreakInBreakOut,
- uint[] quoteAssetStandards,
- bytes4[] quoteAssetFunctionSignatures,
- uint[2] updateInfo, // interval, validity
- uint[3] stakingInfo, // minStake, numOperators, unstakeDelay
- address ofGovernance
- )
- OperatorStaking(
- ERC20(ofStakingAsset), stakingInfo[0], stakingInfo[1], stakingInfo[2]
- )
- SimplePriceFeed(address(this), ofQuoteAsset, address(0))
- {
- registerAsset(
- ofQuoteAsset,
- quoteAssetName,
- quoteAssetSymbol,
- quoteAssetUrl,
- quoteAssetIpfsHash,
- quoteAssetBreakInBreakOut,
- quoteAssetStandards,
- quoteAssetFunctionSignatures
- );
- INTERVAL = updateInfo[0];
- VALIDITY = updateInfo[1];
- setOwner(ofGovernance);
- }
-
- // EXTERNAL METHODS
-
- /// @notice Create a new StakingPriceFeed
- function setupStakingPriceFeed() external {
- address ofStakingPriceFeed = new StakingPriceFeed(
- address(this),
- stakingToken,
- address(this)
- );
- isStakingFeed[ofStakingPriceFeed] = true;
- StakingPriceFeed(ofStakingPriceFeed).setOwner(msg.sender);
- emit SetupPriceFeed(ofStakingPriceFeed);
- }
-
- /// @dev override inherited update function to prevent manual update from authority
- function update(address[] ofAssets, uint[] newPrices) external { revert("Unimplemented"); }
-
- /// @dev Burn state for a pricefeed operator
- /// @param user Address of pricefeed operator to burn the stake from
- function burnStake(address user)
- external
- auth
- {
- uint totalToBurn = add(stakedAmounts[user], stakeToWithdraw[user]);
- stakedAmounts[user] = 0;
- stakeToWithdraw[user] = 0;
- updateStakerRanking(user);
- emit StakeBurned(user, totalToBurn, "");
- }
-
- // PUBLIC METHODS
-
- // STAKING
-
- function stake(
- uint amount,
- bytes data
- )
- public
- {
- require(
- isStakingFeed[msg.sender],
- "Only staking feeds can call this"
- );
- OperatorStaking.stake(amount, data);
- }
-
- // AGGREGATION
-
- /// @dev Only Owner; Same sized input arrays
- /// @dev Updates price of asset relative to QUOTE_ASSET
- /** Ex:
- * Let QUOTE_ASSET == MLN (base units), let asset == EUR-T,
- * let Value of 1 EUR-T := 1 EUR == 0.080456789 MLN, hence price 0.080456789 MLN / EUR-T
- * and let EUR-T decimals == 8.
- * Input would be: information[EUR-T].price = 8045678 [MLN/ (EUR-T * 10**8)]
- */
- /// @param ofAssets list of asset addresses
- function collectAndUpdate(address[] ofAssets)
- public
- auth
- {
- require(
- updatesAreAllowed,
- "Updates are not allowed right now"
- );
- uint[] memory newPrices = pricesToCommit(ofAssets);
- priceHistory.push(
- HistoricalPrices({assets: ofAssets, prices: newPrices, timestamp: block.timestamp})
- );
- _updatePrices(ofAssets, newPrices);
- lastUpdate = block.timestamp;
- PriceUpdate(ofAssets, newPrices);
- }
-
- function pricesToCommit(address[] ofAssets)
- public
- view
- returns (uint[])
- {
- address[] memory operators = getOperators();
- uint[] memory newPrices = new uint[](ofAssets.length);
- for (uint i = 0; i < ofAssets.length; i++) {
- uint[] memory assetPrices = new uint[](operators.length);
- for (uint j = 0; j < operators.length; j++) {
- SimplePriceFeed feed = SimplePriceFeed(operators[j]);
- uint price;
- uint timestamp;
- (price, timestamp) = feed.assetsToPrices(ofAssets[i]);
- if (now > add(timestamp, VALIDITY)) {
- continue; // leaves a zero in the array (dealt with later)
- }
- assetPrices[j] = price;
- }
- newPrices[i] = medianize(assetPrices);
- }
- return newPrices;
- }
-
- /// @dev from MakerDao medianizer contract
- function medianize(uint[] unsorted)
- public
- view
- returns (uint)
- {
- uint numValidEntries;
- for (uint i = 0; i < unsorted.length; i++) {
- if (unsorted[i] != 0) {
- numValidEntries++;
- }
- }
- require(numValidEntries > minimumPriceCount, "Not enough prices");
- uint counter;
- uint[] memory out = new uint[](numValidEntries);
- for (uint j = 0; j < unsorted.length; j++) {
- uint item = unsorted[j];
- if (item != 0) { // skip zero (invalid) entries
- if (counter == 0 || item >= out[counter - 1]) {
- out[counter] = item; // item is larger than last in array (we are home)
- } else {
- uint k = 0;
- while (item >= out[k]) {
- k++; // get to where element belongs (between smaller and larger items)
- }
- for (uint m = counter; m > k; m--) {
- out[m] = out[m - 1]; // bump larger elements rightward to leave slot
- }
- out[k] = item;
- }
- counter++;
- }
- }
-
- uint value;
- if (counter % 2 == 0) {
- uint value1 = uint(out[(counter / 2) - 1]);
- uint value2 = uint(out[(counter / 2)]);
- value = add(value1, value2) / 2;
- } else {
- value = out[(counter - 1) / 2];
- }
- return value;
- }
-
- function setMinimumPriceCount(uint newCount) public auth { minimumPriceCount = newCount; }
- function enableUpdates() public auth { updatesAreAllowed = true; }
- function disableUpdates() public auth { updatesAreAllowed = false; }
-
- // PUBLIC VIEW METHODS
-
- // FEED INFORMATION
-
- function getQuoteAsset() public view returns (address) { return QUOTE_ASSET; }
- function getInterval() public view returns (uint) { return INTERVAL; }
- function getValidity() public view returns (uint) { return VALIDITY; }
- function getLastUpdateId() public view returns (uint) { return updateId; }
-
- // PRICES
-
- /// @notice Whether price of asset has been updated less than VALIDITY seconds ago
- /// @param ofAsset Asset in registrar
- /// @return isValid Price information ofAsset is recent
- function hasValidPrice(address ofAsset)
- public
- view
- returns (bool isValid)
- {
- require(
- assetIsRegistered(ofAsset),
- "Asset is not registered"
- );
- uint timestamp;
- ( , timestamp) = getPrice(ofAsset);
- return (sub(now, timestamp) <= VALIDITY);
- }
-
- /// @notice Whether prices of assets have been updated less than VALIDITY seconds ago
- /// @param ofAssets All assets in registrar
- /// @return isValid Price information ofAssets array is recent
- function hasValidPrices(address[] ofAssets)
- public
- view
- returns (bool areRecent)
- {
- for (uint i; i < ofAssets.length; i++) {
- if (!hasValidPrice(ofAssets[i])) {
- return false;
- }
- }
- return true;
- }
-
- function getPriceInfo(address ofAsset)
- public
- view
- returns (uint price, uint assetDecimals)
- {
- (price, ) = getPrice(ofAsset);
- assetDecimals = getDecimals(ofAsset);
- }
-
- /**
- @notice Gets inverted price of an asset
- @dev Asset has been initialised and its price is non-zero
- @dev Existing price ofAssets quoted in QUOTE_ASSET (convention)
- @param ofAsset Asset for which inverted price should be return
- @return {
- "isValid": "Whether the price is fresh, given VALIDITY interval",
- "invertedPrice": "Price based (instead of quoted) against QUOTE_ASSET",
- "assetDecimals": "Decimal places for this asset"
- }
- */
- function getInvertedPriceInfo(address ofAsset)
- public
- view
- returns (uint invertedPrice, uint assetDecimals)
- {
- uint inputPrice;
- // inputPrice quoted in QUOTE_ASSET and multiplied by 10 ** assetDecimal
- (inputPrice, assetDecimals) = getPriceInfo(ofAsset);
-
- // outputPrice based in QUOTE_ASSET and multiplied by 10 ** quoteDecimal
- uint quoteDecimals = getDecimals(QUOTE_ASSET);
-
- return (
- mul(
- 10 ** uint(quoteDecimals),
- 10 ** uint(assetDecimals)
- ) / inputPrice,
- quoteDecimals
- );
- }
-
- /**
- @notice Gets reference price of an asset pair
- @dev One of the address is equal to quote asset
- @dev either ofBase == QUOTE_ASSET or ofQuote == QUOTE_ASSET
- @param ofBase Address of base asset
- @param ofQuote Address of quote asset
- @return {
- "isValid": "Whether the price is fresh, given VALIDITY interval",
- "referencePrice": "Reference price",
- "decimal": "Decimal places for this asset"
- }
- */
- function getReferencePriceInfo(address ofBase, address ofQuote)
- public
- view
- returns (uint referencePrice, uint decimal)
- {
- require(hasValidPrice(ofBase));
- require(hasValidPrice(ofQuote));
- if (getQuoteAsset() == ofQuote) {
- (referencePrice, decimal) = getPriceInfo(ofBase);
- } else if (getQuoteAsset() == ofBase) {
- (referencePrice, decimal) = getInvertedPriceInfo(ofQuote);
- } else {
- revert("One of the parameters must be quoteAsset");
- }
- }
-
- /// @notice Gets price of Order
- /// @param sellAsset Address of the asset to be sold
- /// @param buyAsset Address of the asset to be bought
- /// @param sellQuantity Quantity in base units being sold of sellAsset
- /// @param buyQuantity Quantity in base units being bought of buyAsset
- /// @return orderPrice Price as determined by an order
- function getOrderPriceInfo(
- address sellAsset,
- address buyAsset,
- uint sellQuantity,
- uint buyQuantity
- )
- public
- view
- returns (uint orderPrice)
- {
- return mul(buyQuantity, 10 ** uint(getDecimals(sellAsset))) / sellQuantity;
- }
-
- /// @notice Checks whether data exists for a given asset pair
- /// @dev Prices are only upated against QUOTE_ASSET
- /// @param sellAsset Asset for which check to be done if data exists
- /// @param buyAsset Asset for which check to be done if data exists
- /// @return Whether assets exist for given asset pair
- function existsPriceOnAssetPair(address sellAsset, address buyAsset)
- public
- view
- returns (bool isExistent)
- {
- return
- hasValidPrice(sellAsset) &&
- hasValidPrice(buyAsset) &&
- (buyAsset == QUOTE_ASSET || sellAsset == QUOTE_ASSET) && // One asset must be QUOTE_ASSET
- (buyAsset != QUOTE_ASSET || sellAsset != QUOTE_ASSET); // Pair must consists of diffrent assets
- }
-
- /// @return Sparse array of addresses of owned pricefeeds
- function getPriceFeedsByOwner(address _owner)
- public
- view
- returns(address[])
- {
- address[] memory ofPriceFeeds = new address[](numStakers);
- if (numStakers == 0) return ofPriceFeeds;
- uint current = stakeNodes[0].next;
- for (uint i; i < numStakers; i++) {
- StakingPriceFeed stakingFeed = StakingPriceFeed(stakeNodes[current].data.staker);
- if (stakingFeed.owner() == _owner) {
- ofPriceFeeds[i] = address(stakingFeed);
- }
- current = stakeNodes[current].next;
- }
- return ofPriceFeeds;
- }
-
- function getHistoryLength() public returns (uint) { return priceHistory.length; }
-
- function getHistoryAt(uint id) public returns (address[], uint[], uint) {
- address[] memory assets = priceHistory[id].assets;
- uint[] memory prices = priceHistory[id].prices;
- uint timestamp = priceHistory[id].timestamp;
- return (assets, prices, timestamp);
- }
-
- /// @notice Get quantity of toAsset equal in value to given quantity of fromAsset
- function convertQuantity(
- uint fromAssetQuantity,
- address fromAsset,
- address toAsset
- )
- public
- view
- returns (uint)
- {
- uint fromAssetPrice;
- (fromAssetPrice,) = getReferencePriceInfo(fromAsset, toAsset);
- uint fromAssetDecimals = ERC20WithFields(fromAsset).decimals();
- return mul(
- fromAssetQuantity,
- fromAssetPrice
- ) / (10 ** uint(fromAssetDecimals));
- }
-
- function getLastUpdate() public view returns (uint) { return lastUpdate; }
-}
diff --git a/src/contracts/prices/CanonicalRegistrar.sol b/src/contracts/prices/CanonicalRegistrar.sol
deleted file mode 100644
index 08d3ffdc..00000000
--- a/src/contracts/prices/CanonicalRegistrar.sol
+++ /dev/null
@@ -1,288 +0,0 @@
-pragma solidity ^0.4.25;
-
-import "thing.sol";
-import "ERC20.i.sol";
-
-
-/// @title Asset Registar Contract
-/// @author Melonport AG <team@melonport.com>
-/// @notice Chain independent asset registrar for the Melon protocol
-contract CanonicalRegistrar is DSThing {
-
- // TYPES
-
- struct Asset {
- bool exists; // True if asset is registered here
- bytes32 name; // Human-readable name of the Asset
- bytes8 symbol; // Human-readable symbol of the Asset
- uint decimals; // Decimal, order of magnitude of precision, of the Asset
- string url; // URL for additional information of Asset
- string ipfsHash; // Same as url but for ipfs
- address breakIn; // Break in contract on destination chain
- address breakOut; // Break out contract on this chain; A way to leave
- uint[] standards; // compliance with standards like ERC20, ERC223, ERC777, etc. (the uint is the standard number)
- bytes4[] functionSignatures; // Whitelisted function signatures that can be called using `useExternalFunction` in Fund contract. Note: Adhere to a naming convention for `Fund<->Asset` as much as possible. I.e. name same concepts with the same functionSignature.
- uint price; // Price of asset quoted against `QUOTE_ASSET` * 10 ** decimals
- uint timestamp; // Timestamp of last price update of this asset
- }
-
- struct Exchange {
- bool exists;
- address adapter; // adapter contract for this exchange
- // One-time note: takesCustody is inverse case of isApproveOnly
- bool takesCustody; // True in case of exchange implementation which requires are approved when an order is made instead of transfer
- bytes4[] functionSignatures; // Whitelisted function signatures that can be called using `useExternalFunction` in Fund contract. Note: Adhere to a naming convention for `Fund<->ExchangeAdapter` as much as possible. I.e. name same concepts with the same functionSignature.
- }
-
- // FIELDS
-
- // Methods fields
- mapping (address => Asset) public assetInformation;
- address[] public registeredAssets;
-
- mapping (address => Exchange) public exchangeInformation;
- address[] public registeredExchanges;
-
- // METHODS
-
- // PUBLIC METHODS
-
- /// @notice Registers an Asset information entry
- /// @dev Pre: Only registrar owner should be able to register
- /// @dev Post: Address ofAsset is registered
- /// @param ofAsset Address of asset to be registered
- /// @param inputName Human-readable name of the Asset
- /// @param inputSymbol Human-readable symbol of the Asset
- /// @param inputUrl Url for extended information of the asset
- /// @param inputIpfsHash Same as url but for ipfs
- /// @param breakInBreakOut Address of break in and break out contracts on destination chain
- /// @param inputStandards Integers of EIP standards this asset adheres to
- /// @param inputFunctionSignatures Function signatures for whitelisted asset functions
- function registerAsset(
- address ofAsset,
- bytes32 inputName,
- bytes8 inputSymbol,
- string inputUrl,
- string inputIpfsHash,
- address[2] breakInBreakOut,
- uint[] inputStandards,
- bytes4[] inputFunctionSignatures
- )
- public
- auth
- {
- require(
- !assetInformation[ofAsset].exists,
- "Asset is already registered"
- );
- assetInformation[ofAsset].exists = true;
- registeredAssets.push(ofAsset);
- updateAsset(
- ofAsset,
- inputName,
- inputSymbol,
- inputUrl,
- inputIpfsHash,
- breakInBreakOut,
- inputStandards,
- inputFunctionSignatures
- );
- assert(assetInformation[ofAsset].exists);
- }
-
- /// @notice Register an exchange information entry
- /// @dev Pre: Only registrar owner should be able to register
- /// @dev Post: Address ofExchange is registered
- /// @param ofExchange Address of the exchange
- /// @param ofExchangeAdapter Address of exchange adapter for this exchange
- /// @param inputTakesCustody Whether this exchange takes custody of tokens before trading
- /// @param inputFunctionSignatures Function signatures for whitelisted exchange functions
- function registerExchange(
- address ofExchange,
- address ofExchangeAdapter,
- bool inputTakesCustody,
- bytes4[] inputFunctionSignatures
- )
- public
- auth
- {
- require(
- !exchangeInformation[ofExchange].exists,
- "Exchange is already registered"
- );
- exchangeInformation[ofExchange].exists = true;
- registeredExchanges.push(ofExchange);
- updateExchange(
- ofExchange,
- ofExchangeAdapter,
- inputTakesCustody,
- inputFunctionSignatures
- );
- assert(exchangeInformation[ofExchange].exists);
- }
-
- /// @notice Updates description information of a registered Asset
- /// @dev Pre: Owner can change an existing entry
- /// @dev Post: Changed Name, Symbol, URL and/or IPFSHash
- /// @param ofAsset Address of the asset to be updated
- /// @param inputName Human-readable name of the Asset
- /// @param inputSymbol Human-readable symbol of the Asset
- /// @param inputUrl Url for extended information of the asset
- /// @param inputIpfsHash Same as url but for ipfs
- function updateAsset(
- address ofAsset,
- bytes32 inputName,
- bytes8 inputSymbol,
- string inputUrl,
- string inputIpfsHash,
- address[2] ofBreakInBreakOut,
- uint[] inputStandards,
- bytes4[] inputFunctionSignatures
- )
- public
- auth
- {
- require(
- assetInformation[ofAsset].exists,
- "Asset is not registered"
- );
- Asset asset = assetInformation[ofAsset];
- asset.name = inputName;
- asset.symbol = inputSymbol;
- asset.decimals = ERC20WithFields(ofAsset).decimals();
- asset.url = inputUrl;
- asset.ipfsHash = inputIpfsHash;
- asset.breakIn = ofBreakInBreakOut[0];
- asset.breakOut = ofBreakInBreakOut[1];
- asset.standards = inputStandards;
- asset.functionSignatures = inputFunctionSignatures;
- }
-
- function updateExchange(
- address ofExchange,
- address ofExchangeAdapter,
- bool inputTakesCustody,
- bytes4[] inputFunctionSignatures
- )
- public
- auth
- {
- require(
- exchangeInformation[ofExchange].exists,
- "Exchange is not registered"
- );
- Exchange exchange = exchangeInformation[ofExchange];
- exchange.adapter = ofExchangeAdapter;
- exchange.takesCustody = inputTakesCustody;
- exchange.functionSignatures = inputFunctionSignatures;
- }
-
- /// @notice Deletes an existing entry
- /// @dev Owner can delete an existing entry
- /// @param ofAsset address for which specific information is requested
- function removeAsset(
- address ofAsset,
- uint assetIndex
- )
- external
- auth
- {
- require(
- assetInformation[ofAsset].exists,
- "Asset is not registered"
- );
- require(registeredAssets[assetIndex] == ofAsset, "Array slot mismatch");
- delete assetInformation[ofAsset]; // Sets exists boolean to false
- delete registeredAssets[assetIndex];
- for (uint i = assetIndex; i < registeredAssets.length-1; i++) {
- registeredAssets[i] = registeredAssets[i+1];
- }
- registeredAssets.length--;
- assert(!assetInformation[ofAsset].exists);
- }
-
- /// @notice Deletes an existing entry
- /// @dev Owner can delete an existing entry
- /// @param ofExchange address for which specific information is requested
- /// @param exchangeIndex index of the exchange in array
- function removeExchange(
- address ofExchange,
- uint exchangeIndex
- )
- external
- auth
- {
- require(
- exchangeInformation[ofExchange].exists,
- "Exchange is not registered"
- );
- require(registeredExchanges[exchangeIndex] == ofExchange, "Array slot mismatch");
- delete exchangeInformation[ofExchange];
- delete registeredExchanges[exchangeIndex];
- for (uint i = exchangeIndex; i < registeredExchanges.length-1; i++) {
- registeredExchanges[i] = registeredExchanges[i+1];
- }
- registeredExchanges.length--;
- assert(!exchangeInformation[ofExchange].exists);
- }
-
- // PUBLIC VIEW METHODS
-
- // get asset specific information
- function getName(address ofAsset) external view returns (bytes32) { return assetInformation[ofAsset].name; }
- function getSymbol(address ofAsset) external view returns (bytes8) { return assetInformation[ofAsset].symbol; }
- function getDecimals(address ofAsset) public view returns (uint) { return assetInformation[ofAsset].decimals; }
- function assetIsRegistered(address ofAsset) public view returns (bool) { return assetInformation[ofAsset].exists; }
- function getRegisteredAssets() external view returns (address[]) { return registeredAssets; }
- function assetMethodIsAllowed(
- address ofAsset, bytes4 querySignature
- )
- external
- returns (bool)
- {
- bytes4[] memory signatures = assetInformation[ofAsset].functionSignatures;
- for (uint i = 0; i < signatures.length; i++) {
- if (signatures[i] == querySignature) {
- return true;
- }
- }
- return false;
- }
-
- // get exchange-specific information
- function exchangeIsRegistered(address ofExchange) external view returns (bool) { return exchangeInformation[ofExchange].exists; }
- function getRegisteredExchanges() external view returns (address[]) { return registeredExchanges; }
- function getExchangeInformation(address ofExchange)
- external
- view
- returns (address, bool)
- {
- Exchange exchange = exchangeInformation[ofExchange];
- return (
- exchange.adapter,
- exchange.takesCustody
- );
- }
- function getExchangeFunctionSignatures(address ofExchange)
- external
- view
- returns (bytes4[])
- {
- return exchangeInformation[ofExchange].functionSignatures;
- }
- function exchangeMethodIsAllowed(
- address ofExchange, bytes4 querySignature
- )
- external
- view
- returns (bool)
- {
- bytes4[] memory signatures = exchangeInformation[ofExchange].functionSignatures;
- for (uint i = 0; i < signatures.length; i++) {
- if (signatures[i] == querySignature) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/src/contracts/prices/OperatorStaking.sol b/src/contracts/prices/OperatorStaking.sol
deleted file mode 100644
index efa6b080..00000000
--- a/src/contracts/prices/OperatorStaking.sol
+++ /dev/null
@@ -1,269 +0,0 @@
-pragma solidity ^0.4.25;
-
-import "group.sol";
-import "Owned.sol";
-import "ERC20.i.sol";
-
-/// @title Operator Staking Contract
-/// @author Melonport AG <team@melonport.com>
-/// @notice Enables pricefeed operators to self-select via staking
-contract OperatorStaking {
-
- // EVENTS
-
- event Staked(address indexed user, uint256 amount, uint256 total, bytes data);
- event Unstaked(address indexed user, uint256 amount, uint256 total, bytes data);
- event StakeBurned(address indexed user, uint256 amount, bytes data);
-
- // TYPES
-
- struct StakeData {
- uint amount;
- address staker;
- }
-
- // Circular linked list
- struct Node {
- StakeData data;
- uint prev;
- uint next;
- }
-
- // FIELDS
-
- // INTERNAL FIELDS
- Node[] internal stakeNodes; // Sorted circular linked list nodes containing stake data (Built on top https://programtheblockchain.com/posts/2018/03/30/storage-patterns-doubly-linked-list/)
-
- // PUBLIC FIELDS
- uint public minimumStake;
- uint public numOperators;
- uint public withdrawalDelay;
- mapping (address => bool) public isRanked;
- mapping (address => uint) public latestUnstakeTime;
- mapping (address => uint) public stakeToWithdraw;
- mapping (address => uint) public stakedAmounts;
- uint public numStakers; // Current number of stakers (Needed because of array holes)
- ERC20 public stakingToken;
-
- // (i.e. is pricefeed staking itself?)
- constructor(
- ERC20 _stakingToken,
- uint _minimumStake,
- uint _numOperators,
- uint _withdrawalDelay
- )
- public
- {
- require(address(_stakingToken) != address(0), "Staking token is null");
- stakingToken = _stakingToken;
- minimumStake = _minimumStake;
- numOperators = _numOperators;
- withdrawalDelay = _withdrawalDelay;
- StakeData memory temp = StakeData({ amount: 0, staker: address(0) });
- stakeNodes.push(Node(temp, 0, 0));
- }
-
- // METHODS : STAKING
-
- function stake(
- uint amount,
- bytes data
- )
- public
- {
- require(amount >= minimumStake, "Stake must be above minimum");
- stakedAmounts[msg.sender] += amount;
- updateStakerRanking(msg.sender);
- require(
- stakingToken.transferFrom(msg.sender, address(this), amount),
- "Transferring staking token failed"
- );
- }
-
- function unstake(
- uint amount,
- bytes data
- )
- public
- {
- uint preStake = stakedAmounts[msg.sender];
- uint postStake = preStake - amount;
- require(
- postStake >= minimumStake || postStake == 0,
- "Unstaking would put remaining amount below minimum"
- );
- require(
- stakedAmounts[msg.sender] >= amount,
- "Cannot unstake more than has been staked"
- );
- latestUnstakeTime[msg.sender] = block.timestamp;
- stakedAmounts[msg.sender] -= amount;
- stakeToWithdraw[msg.sender] += amount;
- updateStakerRanking(msg.sender);
- emit Unstaked(msg.sender, amount, stakedAmounts[msg.sender], data);
- }
-
- function withdrawStake()
- public
- {
- require(
- stakeToWithdraw[msg.sender] > 0,
- "Must withdraw some amount"
- );
- require(
- block.timestamp >= latestUnstakeTime[msg.sender] + withdrawalDelay,
- "Withdrawal delay has not passed"
- );
- uint amount = stakeToWithdraw[msg.sender];
- stakeToWithdraw[msg.sender] = 0;
- require(
- stakingToken.transfer(msg.sender, amount),
- "Staking token transfer failed"
- );
- }
-
- // VIEW FUNCTIONS
-
- function isValidNode(uint id) public view returns (bool) {
- // 0 is a sentinel and therefore invalid.
- // A valid node is the head or has a previous node.
- return id != 0 && (id == stakeNodes[0].next || stakeNodes[id].prev != 0);
- }
-
- function searchNode(address staker) public view returns (uint) {
- uint current = stakeNodes[0].next;
- while (isValidNode(current)) {
- if (staker == stakeNodes[current].data.staker) {
- return current;
- }
- current = stakeNodes[current].next;
- }
- return 0;
- }
-
- function isOperator(address user) public view returns (bool) {
- address[] memory operators = getOperators();
- for (uint i; i < operators.length; i++) {
- if (operators[i] == user) {
- return true;
- }
- }
- return false;
- }
-
- function getOperators()
- public
- view
- returns (address[])
- {
- uint arrLength = (numOperators > numStakers) ?
- numStakers :
- numOperators;
- address[] memory operators = new address[](arrLength);
- uint current = stakeNodes[0].next;
- for (uint i; i < arrLength; i++) {
- operators[i] = stakeNodes[current].data.staker;
- current = stakeNodes[current].next;
- }
- return operators;
- }
-
- function getStakersAndAmounts()
- public
- view
- returns (address[], uint[])
- {
- address[] memory stakers = new address[](numStakers);
- uint[] memory amounts = new uint[](numStakers);
- uint current = stakeNodes[0].next;
- for (uint i; i < numStakers; i++) {
- stakers[i] = stakeNodes[current].data.staker;
- amounts[i] = stakeNodes[current].data.amount;
- current = stakeNodes[current].next;
- }
- return (stakers, amounts);
- }
-
- function totalStakedFor(address user)
- public
- view
- returns (uint)
- {
- return stakedAmounts[user];
- }
-
- // INTERNAL METHODS
-
- // DOUBLY-LINKED LIST
-
- function insertNodeSorted(uint amount, address staker) internal returns (uint) {
- uint current = stakeNodes[0].next;
- if (current == 0) return insertNodeAfter(0, amount, staker);
- while (isValidNode(current)) {
- if (amount > stakeNodes[current].data.amount) {
- break;
- }
- current = stakeNodes[current].next;
- }
- return insertNodeBefore(current, amount, staker);
- }
-
- function insertNodeAfter(uint id, uint amount, address staker) internal returns (uint newID) {
-
- // 0 is allowed here to insert at the beginning.
- require(id == 0 || isValidNode(id), "Invalid node ID");
-
- Node storage node = stakeNodes[id];
-
- stakeNodes.push(Node({
- data: StakeData(amount, staker),
- prev: id,
- next: node.next
- }));
-
- newID = stakeNodes.length - 1;
-
- stakeNodes[node.next].prev = newID;
- node.next = newID;
- numStakers++;
- }
-
- function insertNodeBefore(uint id, uint amount, address staker) internal returns (uint) {
- return insertNodeAfter(stakeNodes[id].prev, amount, staker);
- }
-
- function removeNode(uint id) internal {
- require(isValidNode(id), "Invalid node ID");
-
- Node storage node = stakeNodes[id];
-
- stakeNodes[node.next].prev = node.prev;
- stakeNodes[node.prev].next = node.next;
-
- delete stakeNodes[id];
- numStakers--;
- }
-
- // UPDATING OPERATORS
-
- function updateStakerRanking(address _staker) internal {
- uint newStakedAmount = stakedAmounts[_staker];
- if (newStakedAmount == 0) {
- isRanked[_staker] = false;
- removeStakerFromArray(_staker);
- } else if (isRanked[_staker]) {
- removeStakerFromArray(_staker);
- insertNodeSorted(newStakedAmount, _staker);
- } else {
- isRanked[_staker] = true;
- insertNodeSorted(newStakedAmount, _staker);
- }
- }
-
- function removeStakerFromArray(address _staker) internal {
- uint id = searchNode(_staker);
- require(id > 0, "Node ID cannot be zero");
- removeNode(id);
- }
-
-}
diff --git a/src/contracts/prices/PriceSource.i.sol b/src/contracts/prices/PriceSource.i.sol
deleted file mode 100644
index c5550b64..00000000
--- a/src/contracts/prices/PriceSource.i.sol
+++ /dev/null
@@ -1,30 +0,0 @@
-pragma solidity ^0.4.25;
-
-/// @notice Must return a value for an asset
-interface PriceSourceInterface {
- event PriceUpdate(address[] token, uint[] price);
-
- function getQuoteAsset() external view returns (address);
- function getLastUpdate() external view returns (uint);
-
- /// @notice Returns false if asset not applicable, or price not recent
- function hasValidPrice(address) public view returns (bool);
- function hasValidPrices(address[]) public view returns (bool);
-
- /// @notice Return the last known price, and when it was issued
- function getPrice(address _asset) public view returns (uint price, uint timestamp);
- function getPrices(address[] _assets) public view returns (uint[] prices, uint[] timestamps);
-
- /// @notice Get price info, and revert if not valid
- function getPriceInfo(address _asset) view returns (uint price, uint decimals);
- function getInvertedPriceInfo(address ofAsset) view returns (uint price, uint decimals);
-
- function getReferencePriceInfo(address _base, address _quote) public view returns (uint referencePrice, uint decimal);
- function getOrderPriceInfo(address sellAsset, address buyAsset, uint sellQuantity, uint buyQuantity) public view returns (uint orderPrice);
- function existsPriceOnAssetPair(address sellAsset, address buyAsset) public view returns (bool isExistent);
- function convertQuantity(
- uint fromAssetQuantity,
- address fromAsset,
- address toAsset
- ) public view returns (uint);
-}
diff --git a/src/contracts/prices/SimplePriceFeed.sol b/src/contracts/prices/SimplePriceFeed.sol
deleted file mode 100644
index fefdd006..00000000
--- a/src/contracts/prices/SimplePriceFeed.sol
+++ /dev/null
@@ -1,140 +0,0 @@
-pragma solidity ^0.4.25;
-
-import "PriceSource.i.sol";
-import "UpdatableFeed.i.sol";
-import "CanonicalPriceFeed.sol";
-import "thing.sol";
-import "Registry.sol";
-
-/// @title Price Feed Template
-/// @author Melonport AG <team@melonport.com>
-/// @notice Updates and exposes price information for consuming contracts
-contract SimplePriceFeed is UpdatableFeedInterface, DSThing {
-
- // TYPES
- struct Data {
- uint price;
- uint timestamp;
- }
-
- // FIELDS
- mapping(address => Data) public assetsToPrices;
-
- // Constructor fields
- address public QUOTE_ASSET; // Asset of a portfolio against which all other assets are priced
-
- // Contract-level variables
- uint public updateId; // Update counter for this pricefeed; used as a check during investment
- Registry public registry;
- CanonicalPriceFeed public superFeed;
-
- // METHODS
-
- // CONSTRUCTOR
-
- /// @param ofQuoteAsset Address of quote asset
- /// @param ofRegistrar Address of canonical registrar
- /// @param ofSuperFeed Address of superfeed
- constructor(
- address ofRegistrar,
- address ofQuoteAsset,
- address ofSuperFeed
- ) public {
- registry = Registry(ofRegistrar);
- QUOTE_ASSET = ofQuoteAsset;
- superFeed = CanonicalPriceFeed(ofSuperFeed);
- }
-
- // EXTERNAL METHODS
-
- /// @dev Only Owner; Same sized input arrays
- /// @dev Updates price of asset relative to QUOTE_ASSET
- /** Ex:
- * Let QUOTE_ASSET == MLN (base units), let asset == EUR-T,
- * let Value of 1 EUR-T := 1 EUR == 0.080456789 MLN, hence price 0.080456789 MLN / EUR-T
- * and let EUR-T decimals == 8.
- * Input would be: information[EUR-T].price = 8045678 [MLN/ (EUR-T * 10**8)]
- */
- /// @param ofAssets list of asset addresses
- /// @param newPrices list of prices for each of the assets
- function update(address[] ofAssets, uint[] newPrices)
- external
- auth
- {
- _updatePrices(ofAssets, newPrices);
- }
-
- // PUBLIC VIEW METHODS
-
- // Get pricefeed specific information
- function getQuoteAsset() public view returns (address) { return QUOTE_ASSET; }
- function getLastUpdateId() public view returns (uint) { return updateId; }
-
- /**
- @notice Gets price of an asset multiplied by ten to the power of assetDecimals
- @dev Asset has been registered
- @param ofAsset Asset for which price should be returned
- @return {
- "price": "Price formatting: mul(exchangePrice, 10 ** decimal), to avoid floating numbers",
- "timestamp": "When the asset's price was updated"
- }
- */
- function getPrice(address ofAsset)
- public
- view
- returns (uint price, uint timestamp)
- {
- Data data = assetsToPrices[ofAsset];
- return (data.price, data.timestamp);
- }
-
- /**
- @notice Price of a registered asset in format (bool areRecent, uint[] prices, uint[] decimals)
- @dev Convention for price formatting: mul(price, 10 ** decimal), to avoid floating numbers
- @param ofAssets Assets for which prices should be returned
- @return {
- "prices": "Array of prices",
- "timestamps": "Array of timestamps",
- }
- */
- function getPrices(address[] ofAssets)
- public
- view
- returns (uint[], uint[])
- {
- uint[] memory prices = new uint[](ofAssets.length);
- uint[] memory timestamps = new uint[](ofAssets.length);
- for (uint i; i < ofAssets.length; i++) {
- uint price;
- uint timestamp;
- (price, timestamp) = getPrice(ofAssets[i]);
- prices[i] = price;
- timestamps[i] = timestamp;
- }
- return (prices, timestamps);
- }
-
- // INTERNAL METHODS
-
- /// @dev Internal so that feeds inheriting this one are not obligated to have an exposed update(...) method, but can still perform updates
- function _updatePrices(address[] ofAssets, uint[] newPrices) internal {
- require(
- ofAssets.length == newPrices.length,
- "Arrays must be same length"
- );
- updateId++;
- for (uint i = 0; i < ofAssets.length; ++i) {
- require(
- registry.assetIsRegistered(ofAssets[i]),
- "Asset is not registered"
- );
- require(
- assetsToPrices[ofAssets[i]].timestamp != now,
- "Cannot update twice in one block"
- );
- assetsToPrices[ofAssets[i]].timestamp = now;
- assetsToPrices[ofAssets[i]].price = newPrices[i];
- }
- emit PriceUpdated(keccak256(ofAssets, newPrices));
- }
-}
diff --git a/src/contracts/prices/StakingPriceFeed.sol b/src/contracts/prices/StakingPriceFeed.sol
deleted file mode 100644
index 6f7da3ee..00000000
--- a/src/contracts/prices/StakingPriceFeed.sol
+++ /dev/null
@@ -1,71 +0,0 @@
-pragma solidity ^0.4.25;
-
-import "SimplePriceFeed.sol";
-import "OperatorStaking.sol";
-import "ERC20.i.sol";
-
-/// @title Staking Price Feed
-/// @author Melonport AG <team@melonport.com>
-/// @notice Simple pricefeed that can increase and decrease stake
-contract StakingPriceFeed is SimplePriceFeed {
-
- OperatorStaking public stakingContract;
- ERC20 public stakingToken;
-
- // CONSTRUCTOR
-
- /// @param ofQuoteAsset Address of quote asset
- /// @param ofRegistrar Address of canonical registrar
- /// @param ofSuperFeed Address of superfeed
- constructor(
- address ofRegistrar,
- address ofQuoteAsset,
- address ofSuperFeed
- )
- public
- SimplePriceFeed(ofRegistrar, ofQuoteAsset, ofSuperFeed)
- {
- stakingContract = OperatorStaking(ofSuperFeed); // canonical feed *is* staking contract
- stakingToken = ERC20(stakingContract.stakingToken());
- }
-
- // EXTERNAL METHODS
-
- /// @param amount Number of tokens to stake for this feed
- /// @param data Data may be needed for some future applications (can be empty for now)
- function depositStake(uint amount, bytes data)
- external
- auth
- {
- require(
- stakingToken.transferFrom(msg.sender, address(this), amount),
- "Transferring staking token to fee failed"
- );
- require(
- stakingToken.approve(stakingContract, amount),
- "Approving staking token for staking contract failed"
- );
- stakingContract.stake(amount, data);
- }
-
- /// @param amount Number of tokens to unstake for this feed
- /// @param data Data may be needed for some future applications (can be empty for now)
- function unstake(uint amount, bytes data)
- external
- auth
- {
- stakingContract.unstake(amount, data);
- }
-
- function withdrawStake()
- external
- auth
- {
- uint amountToWithdraw = stakingContract.stakeToWithdraw(address(this));
- stakingContract.withdrawStake();
- require(
- stakingToken.transfer(msg.sender, amountToWithdraw),
- "Staking token transfer to sender failed"
- );
- }
-}
diff --git a/src/contracts/prices/UpdatableFeed.i.sol b/src/contracts/prices/UpdatableFeed.i.sol
deleted file mode 100644
index 2c5864d1..00000000
--- a/src/contracts/prices/UpdatableFeed.i.sol
+++ /dev/null
@@ -1,8 +0,0 @@
-pragma solidity ^0.4.25;
-
-/// @notice Updates values stored internally
-interface UpdatableFeedInterface {
- event PriceUpdated(bytes32 hash);
- function update(address[] _assets, uint[] _prices) external;
- function getLastUpdateId() public view returns (uint);
-}
diff --git a/src/contracts/version/Version.i.sol b/src/contracts/version/Version.i.sol
deleted file mode 100644
index ec5cc9ec..00000000
--- a/src/contracts/version/Version.i.sol
+++ /dev/null
@@ -1,6 +0,0 @@
-pragma solidity ^0.4.25;
-
-interface VersionInterface {
- function shutDownFund(address) external;
-}
-
diff --git a/src/contracts/dependencies/auth.sol b/src/dependencies/DSAuth.sol
similarity index 98%
rename from src/contracts/dependencies/auth.sol
rename to src/dependencies/DSAuth.sol
index 8a5ebcb5..ef8c7e87 100644
--- a/src/contracts/dependencies/auth.sol
+++ b/src/dependencies/DSAuth.sol
@@ -1,6 +1,6 @@
/// @notice Retrieved from DappHub (https://git.io/fpwrq)
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
contract DSAuthority {
function canCall(
diff --git a/src/contracts/dependencies/guard.sol b/src/dependencies/DSGuard.sol
similarity index 97%
rename from src/contracts/dependencies/guard.sol
rename to src/dependencies/DSGuard.sol
index b2b20ed6..b9302c21 100644
--- a/src/contracts/dependencies/guard.sol
+++ b/src/dependencies/DSGuard.sol
@@ -1,8 +1,8 @@
/// @notice Retrieved from DappHub (https://git.io/fpwMi)
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "auth.sol";
+import "./DSAuth.sol";
contract DSGuardEvents {
event LogPermit(
diff --git a/src/contracts/dependencies/math.sol b/src/dependencies/DSMath.sol
similarity index 98%
rename from src/contracts/dependencies/math.sol
rename to src/dependencies/DSMath.sol
index 0d12e179..5afbfb32 100644
--- a/src/contracts/dependencies/math.sol
+++ b/src/dependencies/DSMath.sol
@@ -1,4 +1,4 @@
-/// math.sol -- mixin for inline numerical wizardry
+/// DSMath.sol -- mixin for inline numerical wizardry
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
diff --git a/src/contracts/dependencies/SafeMath.sol b/src/dependencies/SafeMath.sol
similarity index 98%
rename from src/contracts/dependencies/SafeMath.sol
rename to src/dependencies/SafeMath.sol
index f4b43631..5c32b4e2 100644
--- a/src/contracts/dependencies/SafeMath.sol
+++ b/src/dependencies/SafeMath.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
/**
diff --git a/src/contracts/dependencies/TokenUser.sol b/src/dependencies/TokenUser.sol
similarity index 60%
rename from src/contracts/dependencies/TokenUser.sol
rename to src/dependencies/TokenUser.sol
index bf8d4076..36756011 100644
--- a/src/contracts/dependencies/TokenUser.sol
+++ b/src/dependencies/TokenUser.sol
@@ -1,7 +1,7 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "ERC20.i.sol";
-import "math.sol";
+import "./token/IERC20.sol";
+import "./DSMath.sol";
/// @notice Wrapper to ensure tokens are received
contract TokenUser is DSMath {
@@ -10,9 +10,9 @@ contract TokenUser is DSMath {
address _to,
uint _value
) internal {
- uint receiverPreBalance = ERC20(_token).balanceOf(_to);
- ERC20(_token).transfer(_to, _value);
- uint receiverPostBalance = ERC20(_token).balanceOf(_to);
+ uint receiverPreBalance = IERC20(_token).balanceOf(_to);
+ IERC20(_token).transfer(_to, _value);
+ uint receiverPostBalance = IERC20(_token).balanceOf(_to);
require(
add(receiverPreBalance, _value) == receiverPostBalance,
"Receiver did not receive tokens in transfer"
@@ -25,9 +25,9 @@ contract TokenUser is DSMath {
address _to,
uint _value
) internal {
- uint receiverPreBalance = ERC20(_token).balanceOf(_to);
- ERC20(_token).transferFrom(_from, _to, _value);
- uint receiverPostBalance = ERC20(_token).balanceOf(_to);
+ uint receiverPreBalance = IERC20(_token).balanceOf(_to);
+ IERC20(_token).transferFrom(_from, _to, _value);
+ uint receiverPostBalance = IERC20(_token).balanceOf(_to);
require(
add(receiverPreBalance, _value) == receiverPostBalance,
"Receiver did not receive tokens in transferFrom"
diff --git a/src/contracts/dependencies/Weth.sol b/src/dependencies/WETH.sol
similarity index 85%
rename from src/contracts/dependencies/Weth.sol
rename to src/dependencies/WETH.sol
index 6ef1e129..2635e900 100644
--- a/src/contracts/dependencies/Weth.sol
+++ b/src/dependencies/WETH.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
contract WETH {
string public name = "Wrapped Ether";
@@ -13,27 +13,27 @@ contract WETH {
mapping (address => uint) public balanceOf;
mapping (address => mapping (address => uint)) public allowance;
- function() public payable {
+ function() external payable {
deposit();
}
function deposit() public payable {
balanceOf[msg.sender] += msg.value;
- Deposit(msg.sender, msg.value);
+ emit Deposit(msg.sender, msg.value);
}
function withdraw(uint wad) public {
require(balanceOf[msg.sender] >= wad);
balanceOf[msg.sender] -= wad;
msg.sender.transfer(wad);
- Withdrawal(msg.sender, wad);
+ emit Withdrawal(msg.sender, wad);
}
function totalSupply() public view returns (uint) {
- return this.balance;
+ return address(this).balance;
}
function approve(address guy, uint wad) public returns (bool) {
allowance[msg.sender][guy] = wad;
- Approval(msg.sender, guy, wad);
+ emit Approval(msg.sender, guy, wad);
return true;
}
@@ -55,7 +55,7 @@ contract WETH {
balanceOf[src] -= wad;
balanceOf[dst] += wad;
- Transfer(src, dst, wad);
+ emit Transfer(src, dst, wad);
return true;
}
diff --git a/src/contracts/dependencies/token/BurnableToken.sol b/src/dependencies/token/BurnableToken.sol
similarity index 73%
rename from src/contracts/dependencies/token/BurnableToken.sol
rename to src/dependencies/token/BurnableToken.sol
index fb959b97..6b6f92bd 100644
--- a/src/contracts/dependencies/token/BurnableToken.sol
+++ b/src/dependencies/token/BurnableToken.sol
@@ -1,10 +1,10 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "PreminedToken.sol";
+import "./PreminedToken.sol";
/// @dev Just a wrapper for premined tokens which can actually be burnt
contract BurnableToken is PreminedToken {
- constructor(string _symbol, uint8 _decimals, string _name)
+ constructor(string memory _symbol, uint8 _decimals, string memory _name)
public
PreminedToken(_symbol, _decimals, _name)
{}
@@ -12,7 +12,7 @@ contract BurnableToken is PreminedToken {
function burn(uint _amount) public {
_burn(msg.sender, _amount);
}
-
+
function burnFrom(address from, uint256 value) public {
_burnFrom(from, value);
}
diff --git a/src/contracts/dependencies/token/ERC20.i.sol b/src/dependencies/token/IERC20.sol
similarity index 61%
rename from src/contracts/dependencies/token/ERC20.i.sol
rename to src/dependencies/token/IERC20.sol
index bf7e955b..f085c9bd 100644
--- a/src/contracts/dependencies/token/ERC20.i.sol
+++ b/src/dependencies/token/IERC20.sol
@@ -1,23 +1,23 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
* Altered from https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a466e76d26c394b1faa6e2797aefe34668566392/contracts/token/ERC20/ERC20.sol
*/
-interface ERC20 {
- function totalSupply() public view returns (uint256);
+interface IERC20 {
+ function totalSupply() external view returns (uint256);
- function balanceOf(address _who) public view returns (uint256);
+ function balanceOf(address _who) external view returns (uint256);
function allowance(address _owner, address _spender)
- public view returns (uint256);
+ external view returns (uint256);
- function transfer(address _to, uint256 _value) public returns (bool);
+ function transfer(address _to, uint256 _value) external returns (bool);
- function approve(address _spender, uint256 _value) public returns (bool);
+ function approve(address _spender, uint256 _value) external returns (bool);
- function transferFrom(address _from, address _to, uint256 _value) public returns (bool);
+ function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
event Transfer(
address indexed from,
@@ -33,7 +33,7 @@ interface ERC20 {
}
/// @dev Just adds extra functions that we use elsewhere
-contract ERC20WithFields is ERC20 {
+contract ERC20WithFields is IERC20 {
string public symbol;
string public name;
uint8 public decimals;
diff --git a/src/contracts/dependencies/token/PreminedToken.sol b/src/dependencies/token/PreminedToken.sol
similarity index 72%
rename from src/contracts/dependencies/token/PreminedToken.sol
rename to src/dependencies/token/PreminedToken.sol
index a7d68477..0925a705 100644
--- a/src/contracts/dependencies/token/PreminedToken.sol
+++ b/src/dependencies/token/PreminedToken.sol
@@ -1,13 +1,13 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "StandardToken.sol";
+import "./StandardToken.sol";
contract PreminedToken is StandardToken {
string public symbol;
string public name;
uint8 public decimals;
- constructor(string _symbol, uint8 _decimals, string _name) public {
+ constructor(string memory _symbol, uint8 _decimals, string memory _name) public {
symbol = _symbol;
decimals = _decimals;
name = _name;
diff --git a/src/contracts/dependencies/token/StandardToken.sol b/src/dependencies/token/StandardToken.sol
similarity index 97%
rename from src/contracts/dependencies/token/StandardToken.sol
rename to src/dependencies/token/StandardToken.sol
index faa56978..2cce35d6 100644
--- a/src/contracts/dependencies/token/StandardToken.sol
+++ b/src/dependencies/token/StandardToken.sol
@@ -1,7 +1,7 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "ERC20.i.sol";
-import "SafeMath.sol";
+import "./IERC20.sol";
+import "../SafeMath.sol";
/**
* @title Standard ERC20 token
@@ -11,7 +11,7 @@ import "SafeMath.sol";
* Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
* Rearranged from https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a466e76d26c394b1faa6e2797aefe34668566392/contracts/token/ERC20/StandardToken.sol
*/
-contract StandardToken is ERC20 {
+contract StandardToken is IERC20 {
using SafeMath for uint256;
mapping (address => uint256) balances;
@@ -164,7 +164,7 @@ contract StandardToken is ERC20 {
* @param _amount The amount that will be created.
*/
function _mint(address _account, uint256 _amount) internal {
- require(_account != 0);
+ require(_account != address(0));
totalSupply_ = totalSupply_.add(_amount);
balances[_account] = balances[_account].add(_amount);
emit Transfer(address(0), _account, _amount);
@@ -177,7 +177,7 @@ contract StandardToken is ERC20 {
* @param _amount The amount that will be burnt.
*/
function _burn(address _account, uint256 _amount) internal {
- require(_account != 0);
+ require(_account != address(0));
require(_amount <= balances[_account]);
totalSupply_ = totalSupply_.sub(_amount);
diff --git a/src/contracts/engine/AmguConsumer.sol b/src/engine/AmguConsumer.sol
similarity index 58%
rename from src/contracts/engine/AmguConsumer.sol
rename to src/engine/AmguConsumer.sol
index 67c89509..55434ebd 100644
--- a/src/contracts/engine/AmguConsumer.sol
+++ b/src/engine/AmguConsumer.sol
@@ -1,26 +1,33 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "math.sol";
-import "ERC20.i.sol";
-import "PriceSource.i.sol";
-import "Version.i.sol";
-import "Engine.sol";
-import "Registry.sol";
+import "../dependencies/DSMath.sol";
+import "../dependencies/token/IERC20.sol";
+import "../prices/IPriceSource.sol";
+import "../version/IVersion.sol";
+import "./IEngine.sol";
+import "../version/Registry.sol";
+/// @notice Abstract contracts
/// @notice inherit this to pay AMGU on a function call
contract AmguConsumer is DSMath {
+ /// @dev each of these must be implemented by the inheriting contract
+ function engine() public view returns (address);
+ function mlnToken() public view returns (address);
+ function priceSource() public view returns (address);
+ function registry() public view returns (address);
+
/// bool deductIncentive is used when sending extra eth beyond amgu
modifier amguPayable(bool deductIncentive) {
uint initialGas = gasleft();
_;
- uint mlnPerAmgu = Engine(engine()).getAmguPrice();
+ uint mlnPerAmgu = IEngine(engine()).getAmguPrice();
uint mlnQuantity = mul(
mlnPerAmgu,
sub(initialGas, gasleft())
);
address nativeAsset = Registry(registry()).nativeAsset();
- uint ethToPay = PriceSourceInterface(priceSource()).convertQuantity(
+ uint ethToPay = IPriceSource(priceSource()).convertQuantity(
mlnQuantity,
mlnToken(),
nativeAsset
@@ -35,7 +42,7 @@ contract AmguConsumer is DSMath {
msg.value >= add(ethToPay, incentiveAmount),
"Insufficent AMGU and/or incentive"
);
- Engine(engine()).payAmguInEther.value(ethToPay)();
+ IEngine(engine()).payAmguInEther.value(ethToPay)();
require(
msg.sender.send(
@@ -47,10 +54,4 @@ contract AmguConsumer is DSMath {
"Refund failed"
);
}
-
- function engine() view returns (address);
- function mlnToken() view returns (address);
- function priceSource() view returns (address);
- function registry() view returns (address);
}
-
diff --git a/src/contracts/engine/Engine.sol b/src/engine/Engine.sol
similarity index 92%
rename from src/contracts/engine/Engine.sol
rename to src/engine/Engine.sol
index 948457bd..ab1e90ee 100644
--- a/src/contracts/engine/Engine.sol
+++ b/src/engine/Engine.sol
@@ -1,9 +1,9 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "math.sol";
-import "BurnableToken.sol";
-import "PriceSource.i.sol";
-import "Registry.sol";
+import "../dependencies/DSMath.sol";
+import "../dependencies/token/BurnableToken.sol";
+import "../prices/IPriceSource.sol";
+import "../version/Registry.sol";
/// @notice Liquidity contract and token sink
contract Engine is DSMath {
@@ -26,7 +26,7 @@ contract Engine is DSMath {
uint public totalAmguConsumed;
uint public totalMlnBurned;
- constructor(uint _delay, address _registry) {
+ constructor(uint _delay, address _registry) public {
lastThaw = block.timestamp;
thawingDelay = _delay;
_setRegistry(_registry);
@@ -51,7 +51,7 @@ contract Engine is DSMath {
function _setRegistry(address _registry) internal {
registry = Registry(_registry);
- emit RegistryChange(registry);
+ emit RegistryChange(address(registry));
}
/// @dev only callable by MTC
@@ -163,9 +163,9 @@ contract Engine is DSMath {
function priceSource()
public
view
- returns (PriceSourceInterface)
+ returns (IPriceSource)
{
- return PriceSourceInterface(registry.priceSource());
+ return IPriceSource(registry.priceSource());
}
}
diff --git a/src/engine/IEngine.sol b/src/engine/IEngine.sol
new file mode 100644
index 00000000..c68718fd
--- /dev/null
+++ b/src/engine/IEngine.sol
@@ -0,0 +1,7 @@
+pragma solidity 0.5.15;
+
+
+interface IEngine {
+ function payAmguInEther() external payable;
+ function getAmguPrice() external view returns (uint256);
+}
diff --git a/src/contracts/exchanges/EngineAdapter.sol b/src/exchanges/EngineAdapter.sol
similarity index 64%
rename from src/contracts/exchanges/EngineAdapter.sol
rename to src/exchanges/EngineAdapter.sol
index 6ea2cfb7..fc5bf960 100644
--- a/src/contracts/exchanges/EngineAdapter.sol
+++ b/src/exchanges/EngineAdapter.sol
@@ -1,14 +1,15 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
+pragma experimental ABIEncoderV2;
-import "Engine.sol";
-import "Hub.sol";
-import "Trading.sol";
-import "Vault.sol";
-import "math.sol";
-import "Weth.sol";
-import "ERC20.i.sol";
-import "ExchangeAdapter.sol";
-import "TokenUser.sol";
+import "../engine/Engine.sol";
+import "../fund/hub/Hub.sol";
+import "../fund/trading/Trading.sol";
+import "../fund/vault/Vault.sol";
+import "../dependencies/DSMath.sol";
+import "../dependencies/WETH.sol";
+import "../dependencies/token/IERC20.sol";
+import "./ExchangeAdapter.sol";
+import "../dependencies/TokenUser.sol";
/// @notice Trading adapter to Melon Engine
contract EngineAdapter is DSMath, TokenUser, ExchangeAdapter {
@@ -22,12 +23,11 @@ contract EngineAdapter is DSMath, TokenUser, ExchangeAdapter {
/// @param orderAddresses [3] MLN token
function takeOrder (
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public onlyManager notShutDown {
Hub hub = getHub();
@@ -36,40 +36,40 @@ contract EngineAdapter is DSMath, TokenUser, ExchangeAdapter {
uint minEthToReceive = orderValues[0];
uint mlnQuantity = orderValues[1];
- require(
- wethAddress == Registry(hub.registry()).nativeAsset(),
- "maker asset doesnt match nativeAsset on registry"
+ require(
+ wethAddress == Registry(hub.registry()).nativeAsset(),
+ "maker asset doesnt match nativeAsset on registry"
);
- require(
- orderValues[1] == orderValues[6],
- "fillTakerQuantity must equal takerAssetQuantity"
+ require(
+ orderValues[1] == orderValues[6],
+ "fillTakerQuantity must equal takerAssetQuantity"
);
Vault vault = Vault(hub.vault());
vault.withdraw(mlnAddress, mlnQuantity);
require(
- ERC20(mlnAddress).approve(targetExchange, mlnQuantity),
+ IERC20(mlnAddress).approve(targetExchange, mlnQuantity),
"MLN could not be approved"
);
uint ethToReceive = Engine(targetExchange).ethPayoutForMlnAmount(mlnQuantity);
-
+
require(
ethToReceive >= minEthToReceive,
"Expected ETH to receive is less than takerQuantity (minEthToReceive)"
);
-
+
Engine(targetExchange).sellAndBurnMln(mlnQuantity);
- WETH(wethAddress).deposit.value(ethToReceive)();
+ WETH(address(uint160(wethAddress))).deposit.value(ethToReceive)();
safeTransfer(wethAddress, address(vault), ethToReceive);
-
+
getAccounting().addAssetToOwnedAssets(wethAddress);
getAccounting().updateOwnedAssets();
getTrading().orderUpdateHook(
targetExchange,
bytes32(0),
Trading.UpdateType.take,
- [wethAddress, mlnAddress],
+ [address(uint160(wethAddress)), address(uint160(mlnAddress))],
[ethToReceive, mlnQuantity, mlnQuantity]
);
}
diff --git a/src/contracts/exchanges/EthfinexAdapter.sol b/src/exchanges/EthfinexAdapter.sol
similarity index 66%
rename from src/contracts/exchanges/EthfinexAdapter.sol
rename to src/exchanges/EthfinexAdapter.sol
index b1144a1f..19a40818 100644
--- a/src/contracts/exchanges/EthfinexAdapter.sol
+++ b/src/exchanges/EthfinexAdapter.sol
@@ -1,19 +1,17 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
pragma experimental ABIEncoderV2;
-import "ERC20.i.sol";
-import "Trading.sol";
-import "Hub.sol";
-import "Vault.sol";
-import "Accounting.sol";
-import "Registry.sol";
-import "Weth.sol";
-import "math.sol";
-import "Exchange.sol";
-import "WrapperLock.sol";
-import "WrapperLockEth.sol";
-import "ExchangeAdapter.sol";
-import "WrapperRegistryEFX.sol";
+import "../dependencies/token/IERC20.sol";
+import "../fund/trading/Trading.sol";
+import "../fund/hub/Hub.sol";
+import "../fund/vault/Vault.sol";
+import "../fund/accounting/Accounting.sol";
+import "../version/Registry.sol";
+import "../dependencies/WETH.sol";
+import "../dependencies/DSMath.sol";
+import "./interfaces/IZeroExV2.sol";
+import "./interfaces/IEthfinex.sol";
+import "./ExchangeAdapter.sol";
/// @title EthfinexAdapter Contract
/// @author Melonport AG <team@melonport.com>
@@ -27,17 +25,17 @@ contract EthfinexAdapter is DSMath, ExchangeAdapter {
/// @notice Make order by pre-approving signatures
function makeOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes wrappedMakerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public onlyManager notShutDown {
ensureCanMakeOrder(orderAddresses[2]);
Hub hub = getHub();
-
- LibOrder.Order memory order = constructOrderStruct(orderAddresses, orderValues, wrappedMakerAssetData, takerAssetData);
+ IZeroExV2.Order memory order = constructOrderStruct(orderAddresses, orderValues, orderData);
+ bytes memory wrappedMakerAssetData = orderData[0];
+ bytes memory takerAssetData = orderData[1];
address makerAsset = orderAddresses[2];
address takerAsset = getAssetAddress(takerAssetData);
require(
@@ -49,11 +47,11 @@ contract EthfinexAdapter is DSMath, ExchangeAdapter {
ensureNotInOpenMakeOrder(makerAsset);
wrapMakerAsset(targetExchange, makerAsset, wrappedMakerAssetData, order.makerAssetAmount, order.expirationTimeSeconds);
- LibOrder.OrderInfo memory orderInfo = Exchange(targetExchange).getOrderInfo(order);
- Exchange(targetExchange).preSign(orderInfo.orderHash, address(this), signature);
+ IZeroExV2.OrderInfo memory orderInfo = IZeroExV2(targetExchange).getOrderInfo(order);
+ IZeroExV2(targetExchange).preSign(orderInfo.orderHash, address(this), signature);
require(
- Exchange(targetExchange).isValidSignature(
+ IZeroExV2(targetExchange).isValidSignature(
orderInfo.orderHash,
address(this),
signature
@@ -65,33 +63,32 @@ contract EthfinexAdapter is DSMath, ExchangeAdapter {
targetExchange,
orderInfo.orderHash,
Trading.UpdateType.make,
- [address(makerAsset), address(takerAsset)],
+ [address(uint160(makerAsset)), address(uint160(takerAsset))],
[order.makerAssetAmount, order.takerAssetAmount, uint(0)]
);
getTrading().addOpenMakeOrder(
- targetExchange,
+ targetExchange,
makerAsset,
takerAsset,
- uint256(orderInfo.orderHash),
+ uint256(orderInfo.orderHash),
order.expirationTimeSeconds
);
- getTrading().addZeroExOrderData(orderInfo.orderHash, order);
+ getTrading().addZeroExV2OrderData(orderInfo.orderHash, order);
}
/// @notice Cancel the 0x make order
function cancelOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes wrappedMakerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public onlyCancelPermitted(targetExchange, orderAddresses[2]) {
Hub hub = getHub();
- LibOrder.Order memory order = getTrading().getZeroExOrderDetails(identifier);
- Exchange(targetExchange).cancelOrder(order);
+ IZeroExV2.Order memory order = getTrading().getZeroExV2OrderDetails(identifier);
+ IZeroExV2(targetExchange).cancelOrder(order);
getAccounting().updateOwnedAssets();
// Order is not removed from OpenMakeOrder mapping as it's needed for accounting (wrapped tokens)
@@ -107,12 +104,11 @@ contract EthfinexAdapter is DSMath, ExchangeAdapter {
/// @notice Unwrap (withdraw) tokens, uses orderAddresses for input list of tokens to be unwrapped
function withdrawTokens(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public {
Hub hub = getHub();
address nativeAsset = Accounting(hub.accounting()).NATIVE_ASSET();
@@ -121,11 +117,11 @@ contract EthfinexAdapter is DSMath, ExchangeAdapter {
// Check if the input token address is null address
if (orderAddresses[i] == address(0)) continue;
address wrappedToken = getWrapperToken(orderAddresses[i]);
- uint balance = WrapperLock(wrappedToken).balanceOf(address(this));
+ uint balance = IWrapperLock(wrappedToken).balanceOf(address(this));
require(balance > 0, "Insufficient balance");
- WrapperLock(wrappedToken).withdraw(balance, 0, bytes32(0), bytes32(0), 0);
+ IWrapperLock(wrappedToken).withdraw(balance, 0, bytes32(0), bytes32(0), 0);
if (orderAddresses[i] == nativeAsset) {
- WETH(nativeAsset).deposit.value(balance)();
+ WETH(address(uint160(nativeAsset))).deposit.value(balance)();
}
getTrading().removeOpenMakeOrder(targetExchange, orderAddresses[i]);
getTrading().returnAssetToVault(orderAddresses[i]);
@@ -133,10 +129,10 @@ contract EthfinexAdapter is DSMath, ExchangeAdapter {
}
/// @notice Minor: Wrapped tokens directly sent to the fund are not accounted. To be called by Trading spoke
- function getOrder(address targetExchange, uint id, address makerAsset)
+ function getOrder(address targetExchange, uint256 id, address makerAsset)
public
view
- returns (address, address, uint, uint)
+ returns (address, address, uint256, uint256)
{
uint orderId;
uint orderIndex;
@@ -147,13 +143,13 @@ contract EthfinexAdapter is DSMath, ExchangeAdapter {
(, takerAsset, makerQuantity, takerQuantity) = Trading(msg.sender).getOrderDetails(orderIndex);
// Check if order has been completely filled
- uint takerAssetFilledAmount = Exchange(targetExchange).filled(bytes32(orderId));
+ uint takerAssetFilledAmount = IZeroExV2(targetExchange).filled(bytes32(orderId));
if (sub(takerQuantity, takerAssetFilledAmount) == 0) {
return (makerAsset, takerAsset, 0, 0);
}
// Check if tokens have been withdrawn (cancelled order may still need to be accounted if there is balance)
- uint balance = WrapperLock(getWrapperTokenFromAdapterContext(makerAsset)).balanceOf(msg.sender);
+ uint balance = IWrapperLock(getWrapperTokenFromAdapterContext(makerAsset)).balanceOf(msg.sender);
if (balance == 0) {
return (makerAsset, takerAsset, 0, 0);
}
@@ -164,7 +160,7 @@ contract EthfinexAdapter is DSMath, ExchangeAdapter {
/// @notice needed to avoid stack too deep error
/// @dev deposit time should be greater than 1 hour
- function wrapMakerAsset(address targetExchange, address makerAsset, bytes wrappedMakerAssetData, uint makerQuantity, uint orderExpirationTime)
+ function wrapMakerAsset(address targetExchange, address makerAsset, bytes memory wrappedMakerAssetData, uint makerQuantity, uint orderExpirationTime)
internal
{
Hub hub = getHub();
@@ -183,27 +179,26 @@ contract EthfinexAdapter is DSMath, ExchangeAdapter {
// Handle case for WETH
address nativeAsset = Accounting(hub.accounting()).NATIVE_ASSET();
if (makerAsset == nativeAsset) {
- WETH(nativeAsset).withdraw(makerQuantity);
- WrapperLockEth(wrappedToken).deposit.value(makerQuantity)(makerQuantity, depositTime);
+ WETH(address(uint160(nativeAsset))).withdraw(makerQuantity);
+ IWrapperLockEth(wrappedToken).deposit.value(makerQuantity)(makerQuantity, depositTime);
} else {
- ERC20(makerAsset).approve(wrappedToken, makerQuantity);
- WrapperLock(wrappedToken).deposit(makerQuantity, depositTime);
+ IERC20(makerAsset).approve(wrappedToken, makerQuantity);
+ IWrapperLock(wrappedToken).deposit(makerQuantity, depositTime);
}
}
// VIEW METHODS
function constructOrderStruct(
- address[6] orderAddresses,
- uint[8] orderValues,
- bytes makerAssetData,
- bytes takerAssetData
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData
)
internal
view
- returns (LibOrder.Order memory order)
+ returns (IZeroExV2.Order memory order)
{
- order = LibOrder.Order({
+ order = IZeroExV2.Order({
makerAddress: orderAddresses[0],
takerAddress: orderAddresses[1],
feeRecipientAddress: orderAddresses[4],
@@ -214,12 +209,12 @@ contract EthfinexAdapter is DSMath, ExchangeAdapter {
takerFee: orderValues[3],
expirationTimeSeconds: orderValues[4],
salt: orderValues[5],
- makerAssetData: makerAssetData,
- takerAssetData: takerAssetData
+ makerAssetData: orderData[0],
+ takerAssetData: orderData[1]
});
}
- function getAssetProxy(address targetExchange, bytes assetData)
+ function getAssetProxy(address targetExchange, bytes memory assetData)
internal
view
returns (address assetProxy)
@@ -231,10 +226,10 @@ contract EthfinexAdapter is DSMath, ExchangeAdapter {
0xFFFFFFFF00000000000000000000000000000000000000000000000000000000
)
}
- assetProxy = Exchange(targetExchange).getAssetProxy(assetProxyId);
+ assetProxy = IZeroExV2(targetExchange).getAssetProxy(assetProxyId);
}
- function getAssetAddress(bytes assetData)
+ function getAssetAddress(bytes memory assetData)
internal
view
returns (address assetAddress)
@@ -250,8 +245,8 @@ contract EthfinexAdapter is DSMath, ExchangeAdapter {
view
returns (address wrapperToken)
{
- address wrapperRegistry = Registry(Trading(address(this)).registry()).ethfinexWrapperRegistry();
- return WrapperRegistryEFX(wrapperRegistry).token2WrapperLookup(token);
+ address wrapperRegistry = Registry(getTrading().registry()).ethfinexWrapperRegistry();
+ return IWrapperRegistryEFX(wrapperRegistry).token2WrapperLookup(token);
}
/// @dev Function to be called by Trading spoke without change of context (Non delegate call)
@@ -261,6 +256,6 @@ contract EthfinexAdapter is DSMath, ExchangeAdapter {
returns (address wrapperToken)
{
address wrapperRegistry = Registry(Trading(msg.sender).registry()).ethfinexWrapperRegistry();
- return WrapperRegistryEFX(wrapperRegistry).token2WrapperLookup(token);
+ return IWrapperRegistryEFX(wrapperRegistry).token2WrapperLookup(token);
}
}
diff --git a/src/contracts/exchanges/ExchangeAdapter.sol b/src/exchanges/ExchangeAdapter.sol
similarity index 81%
rename from src/contracts/exchanges/ExchangeAdapter.sol
rename to src/exchanges/ExchangeAdapter.sol
index f0c56137..5571fce9 100644
--- a/src/contracts/exchanges/ExchangeAdapter.sol
+++ b/src/exchanges/ExchangeAdapter.sol
@@ -1,8 +1,9 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
+pragma experimental ABIEncoderV2;
-import "Accounting.sol";
-import "Hub.sol";
-import "Trading.sol";
+import "../fund/accounting/Accounting.sol";
+import "../fund/hub/Hub.sol";
+import "../fund/trading/Trading.sol";
/// @title Exchange Adapter base contract
/// @author Melonport AG <team@melonport.com>
@@ -37,7 +38,7 @@ contract ExchangeAdapter {
}
function getTrading() internal view returns (Trading) {
- return Trading(address(this));
+ return Trading(address(uint160(address(this))));
}
function getHub() internal view returns (Hub) {
@@ -76,6 +77,8 @@ contract ExchangeAdapter {
/// @param orderAddresses [3] Order taker asset
/// @param orderAddresses [4] feeRecipientAddress
/// @param orderAddresses [5] senderAddress
+ /// @param orderAddresses [6] maker fee asset
+ /// @param orderAddresses [7] taker fee asset
/// @param orderValues [0] makerAssetAmount
/// @param orderValues [1] takerAssetAmount
/// @param orderValues [2] Maker fee
@@ -84,9 +87,11 @@ contract ExchangeAdapter {
/// @param orderValues [5] Salt/nonce
/// @param orderValues [6] Fill amount: amount of taker token to be traded
/// @param orderValues [7] Dexy signature mode
+ /// @param orderData [0] Encoded data specific to maker asset
+ /// @param orderData [1] Encoded data specific to taker asset
+ /// @param orderData [2] Encoded data specific to maker asset fee
+ /// @param orderData [3] Encoded data specific to taker asset fee
/// @param identifier Order identifier
- /// @param makerAssetData Encoded data specific to makerAsset
- /// @param takerAssetData Encoded data specific to takerAsset
/// @param signature Signature of order maker
// Responsibilities of makeOrder are:
@@ -100,12 +105,11 @@ contract ExchangeAdapter {
// - place asset in ownedAssets if not already tracked
function makeOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public { revert("Unimplemented"); }
// Responsibilities of takeOrder are:
@@ -121,12 +125,11 @@ contract ExchangeAdapter {
// - place asset in ownedAssets if not already tracked
function takeOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public { revert("Unimplemented"); }
// responsibilities of cancelOrder are:
@@ -135,12 +138,11 @@ contract ExchangeAdapter {
// - cancel order on exchange
function cancelOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public { revert("Unimplemented"); }
// PUBLIC METHODS
diff --git a/src/contracts/exchanges/KyberAdapter.sol b/src/exchanges/KyberAdapter.sol
similarity index 79%
rename from src/contracts/exchanges/KyberAdapter.sol
rename to src/exchanges/KyberAdapter.sol
index 16960739..330e7b3c 100644
--- a/src/contracts/exchanges/KyberAdapter.sol
+++ b/src/exchanges/KyberAdapter.sol
@@ -1,17 +1,18 @@
-pragma solidity ^0.4.25;
-
-import "Weth.sol";
-import "Trading.sol";
-import "Hub.sol";
-import "Vault.sol";
-import "Accounting.sol";
-import "PriceSource.i.sol";
-import "KyberNetworkProxy.sol";
-import "ExchangeAdapter.sol";
+pragma solidity 0.5.15;
+pragma experimental ABIEncoderV2;
+
+import "../dependencies/WETH.sol";
+import "../dependencies/token/IERC20.sol";
+import "../fund/trading/Trading.sol";
+import "../fund/hub/Hub.sol";
+import "../fund/vault/Vault.sol";
+import "../fund/accounting/Accounting.sol";
+import "../prices/IPriceSource.sol";
+import "./interfaces/IKyberNetworkProxy.sol";
+import "./ExchangeAdapter.sol";
contract KyberAdapter is DSMath, ExchangeAdapter {
-
- address public constant ETH_TOKEN_ADDRESS = 0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee;
+ address public constant ETH_TOKEN_ADDRESS = address(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee);
// NON-CONSTANT METHODS
@@ -31,18 +32,17 @@ contract KyberAdapter is DSMath, ExchangeAdapter {
/// @param orderValues [1] Taker asset quantity (Src token amount)
function takeOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public onlyManager notShutDown {
Hub hub = getHub();
- require(
- orderValues[1] == orderValues[6],
- "fillTakerQuantity must equal takerAssetQuantity"
+ require(
+ orderValues[1] == orderValues[6],
+ "fillTakerQuantity must equal takerAssetQuantity"
);
address makerAsset = orderAddresses[2];
@@ -66,13 +66,13 @@ contract KyberAdapter is DSMath, ExchangeAdapter {
);
getAccounting().addAssetToOwnedAssets(makerAsset);
- getAccounting().updateOwnedAssets();
+ getAccounting().updateOwnedAssets();
getTrading().returnAssetToVault(makerAsset);
getTrading().orderUpdateHook(
targetExchange,
bytes32(0),
Trading.UpdateType.take,
- [makerAsset, takerAsset],
+ [address(uint160(makerAsset)), address(uint160(takerAsset))],
[actualReceiveAmount, takerAssetAmount, takerAssetAmount]
);
}
@@ -126,8 +126,8 @@ contract KyberAdapter is DSMath, ExchangeAdapter {
Hub hub = getHub();
Vault vault = Vault(hub.vault());
vault.withdraw(nativeAsset, srcAmount);
- WETH(nativeAsset).withdraw(srcAmount);
- receivedAmount = KyberNetworkProxy(targetExchange).swapEtherToToken.value(srcAmount)(ERC20Clone(destToken), minRate);
+ WETH(address(uint160(nativeAsset))).withdraw(srcAmount);
+ receivedAmount = IKyberNetworkProxy(targetExchange).swapEtherToToken.value(srcAmount)(destToken, minRate);
}
/// @dev If minRate is not defined, uses expected rate from the network
@@ -150,11 +150,11 @@ contract KyberAdapter is DSMath, ExchangeAdapter {
Hub hub = getHub();
Vault vault = Vault(hub.vault());
vault.withdraw(srcToken, srcAmount);
- ERC20Clone(srcToken).approve(targetExchange, srcAmount);
- receivedAmount = KyberNetworkProxy(targetExchange).swapTokenToEther(ERC20Clone(srcToken), srcAmount, minRate);
+ IERC20(srcToken).approve(targetExchange, srcAmount);
+ receivedAmount = IKyberNetworkProxy(targetExchange).swapTokenToEther(srcToken, srcAmount, minRate);
// Convert ETH to WETH
- WETH(nativeAsset).deposit.value(receivedAmount)();
+ WETH(address(uint160(nativeAsset))).deposit.value(receivedAmount)();
}
/// @dev If minRate is not defined, uses expected rate from the network
@@ -177,8 +177,8 @@ contract KyberAdapter is DSMath, ExchangeAdapter {
Hub hub = getHub();
Vault vault = Vault(hub.vault());
vault.withdraw(srcToken, srcAmount);
- ERC20Clone(srcToken).approve(targetExchange, srcAmount);
- receivedAmount = KyberNetworkProxy(targetExchange).swapTokenToToken(ERC20Clone(srcToken), srcAmount, ERC20Clone(destToken), minRate);
+ IERC20(srcToken).approve(targetExchange, srcAmount);
+ receivedAmount = IKyberNetworkProxy(targetExchange).swapTokenToToken(srcToken, srcAmount, destToken, minRate);
}
/// @dev Calculate min rate to be supplied to the network based on provided order parameters
@@ -196,7 +196,7 @@ contract KyberAdapter is DSMath, ExchangeAdapter {
view
returns (uint minRate)
{
- PriceSourceInterface pricefeed = PriceSourceInterface(Hub(Trading(address(this)).hub()).priceSource());
+ IPriceSource pricefeed = IPriceSource(getHub().priceSource());
minRate = pricefeed.getOrderPriceInfo(
srcToken,
destToken,
diff --git a/src/contracts/exchanges/MatchingMarketAccessor.sol b/src/exchanges/OasisDexAccessor.sol
similarity index 81%
rename from src/contracts/exchanges/MatchingMarketAccessor.sol
rename to src/exchanges/OasisDexAccessor.sol
index 0286fc1a..6cf27740 100644
--- a/src/contracts/exchanges/MatchingMarketAccessor.sol
+++ b/src/exchanges/OasisDexAccessor.sol
@@ -1,9 +1,8 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "ERC20.i.sol";
-import "MatchingMarket.sol";
+import "./interfaces/IOasisDex.sol";
-contract MatchingMarketAccessor {
+contract OasisDexAccessor {
function getUnsortedOfferIds(
address targetExchange,
address sellAsset,
@@ -11,9 +10,9 @@ contract MatchingMarketAccessor {
)
public
view
- returns (uint[])
+ returns (uint[] memory)
{
- MatchingMarket market = MatchingMarket(targetExchange);
+ IOasisDex market = IOasisDex(targetExchange);
uint[] memory ids = new uint[](1000);
uint count = 0;
@@ -40,7 +39,7 @@ contract MatchingMarketAccessor {
// Create a new array of offers with the correct size.
uint[] memory copy = new uint[](count);
- for (i = 0; i < count; i++) {
+ for (uint i = 0; i < count; i++) {
copy[i] = ids[i];
}
@@ -54,14 +53,14 @@ contract MatchingMarketAccessor {
)
public
view
- returns(uint[])
+ returns(uint[] memory)
{
- MatchingMarket market = MatchingMarket(targetExchange);
+ IOasisDex market = IOasisDex(targetExchange);
uint[] memory ids = new uint[](1000);
uint count = 0;
// Iterate over all sorted offers.
- uint id = market.getBestOffer(ERC20(sellAsset), ERC20(buyAsset));
+ uint id = market.getBestOffer(sellAsset, buyAsset);
for (uint i = 0; i < 1000 ; i++ ) {
if (id == 0) {
break;
@@ -77,7 +76,7 @@ contract MatchingMarketAccessor {
// Create a new array of offers with the correct size.
uint[] memory copy = new uint[](count);
- for (i = 0; i < count; i++) {
+ for (uint i = 0; i < count; i++) {
copy[i] = ids[i];
}
@@ -91,8 +90,8 @@ contract MatchingMarketAccessor {
)
public
view
- returns (uint[], uint[], uint[]) {
- MatchingMarket market = MatchingMarket(targetExchange);
+ returns (uint[] memory, uint[] memory, uint[] memory) {
+ IOasisDex market = IOasisDex(targetExchange);
uint[] memory sIds = getSortedOfferIds(targetExchange, sellAsset, buyAsset);
uint[] memory uIds = getUnsortedOfferIds(targetExchange, sellAsset, buyAsset);
uint[] memory ids = new uint[](uIds.length + sIds.length);
@@ -103,11 +102,11 @@ contract MatchingMarketAccessor {
ids[i] = sIds[i];
}
- for (i = 0; i < uIds.length; i++) {
+ for (uint i = 0; i < uIds.length; i++) {
ids[i + sIds.length] = uIds[i];
}
- for (i = 0; i < ids.length; i++) {
+ for (uint i = 0; i < ids.length; i++) {
uint sellQty;
uint buyQty;
(sellQty, , buyQty,) = market.getOffer(ids[i]);
diff --git a/src/contracts/exchanges/MatchingMarketAdapter.sol b/src/exchanges/OasisDexAdapter.sol
similarity index 65%
rename from src/contracts/exchanges/MatchingMarketAdapter.sol
rename to src/exchanges/OasisDexAdapter.sol
index b95fd573..d7523f48 100644
--- a/src/contracts/exchanges/MatchingMarketAdapter.sol
+++ b/src/exchanges/OasisDexAdapter.sol
@@ -1,19 +1,20 @@
-pragma solidity ^0.4.25;
-
-import "Hub.sol";
-import "Trading.sol";
-import "Vault.sol";
-import "Accounting.sol";
-import "math.sol";
-import "MatchingMarket.sol";
-import "ExchangeAdapter.sol";
-
-/// @title MatchingMarketAdapter Contract
+pragma solidity 0.5.15;
+pragma experimental ABIEncoderV2;
+
+import "../fund/hub/Hub.sol";
+import "../fund/trading/Trading.sol";
+import "../fund/vault/Vault.sol";
+import "../fund/accounting/Accounting.sol";
+import "../dependencies/DSMath.sol";
+import "./interfaces/IOasisDex.sol";
+import "./ExchangeAdapter.sol";
+
+/// @title OasisDexAdapter Contract
/// @author Melonport AG <team@melonport.com>
/// @notice Adapter between Melon and OasisDex Matching Market
-contract MatchingMarketAdapter is DSMath, ExchangeAdapter {
+contract OasisDexAdapter is DSMath, ExchangeAdapter {
- event OrderCreated(uint id);
+ event OrderCreated(uint256 id);
// METHODS
@@ -37,18 +38,17 @@ contract MatchingMarketAdapter is DSMath, ExchangeAdapter {
/// @param orderValues [1] Taker token quantity
function makeOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public onlyManager notShutDown {
ensureCanMakeOrder(orderAddresses[2]);
- ERC20 makerAsset = ERC20(orderAddresses[2]);
- ERC20 takerAsset = ERC20(orderAddresses[3]);
- uint makerQuantity = orderValues[0];
- uint takerQuantity = orderValues[1];
+ address makerAsset = orderAddresses[2];
+ address takerAsset = orderAddresses[3];
+ uint256 makerQuantity = orderValues[0];
+ uint256 takerQuantity = orderValues[1];
// Order parameter checks
getTrading().updateAndGetQuantityBeingTraded(makerAsset);
@@ -56,11 +56,11 @@ contract MatchingMarketAdapter is DSMath, ExchangeAdapter {
Vault(Hub(getHub()).vault()).withdraw(makerAsset, makerQuantity);
require(
- makerAsset.approve(targetExchange, makerQuantity),
+ IERC20(makerAsset).approve(targetExchange, makerQuantity),
"Could not approve maker asset"
);
- uint orderId = MatchingMarket(targetExchange).offer(makerQuantity, makerAsset, takerQuantity, takerAsset);
+ uint256 orderId = IOasisDex(targetExchange).offer(makerQuantity, makerAsset, takerQuantity, takerAsset);
// defines success in MatchingMarket
require(orderId != 0, "Order ID should not be zero");
@@ -70,8 +70,8 @@ contract MatchingMarketAdapter is DSMath, ExchangeAdapter {
targetExchange,
bytes32(orderId),
Trading.UpdateType.make,
- [address(makerAsset), address(takerAsset)],
- [makerQuantity, takerQuantity, uint(0)]
+ [address(uint160(makerAsset)), address(uint160(takerAsset))],
+ [makerQuantity, takerQuantity, uint256(0)]
);
getTrading().addOpenMakeOrder(targetExchange, makerAsset, takerAsset, orderId, orderValues[4]);
emit OrderCreated(orderId);
@@ -95,33 +95,32 @@ contract MatchingMarketAdapter is DSMath, ExchangeAdapter {
/// @param identifier Active order id
function takeOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public onlyManager notShutDown {
Hub hub = getHub();
- uint fillTakerQuantity = orderValues[6];
- uint maxMakerQuantity;
- ERC20 makerAsset;
- uint maxTakerQuantity;
- ERC20 takerAsset;
+ uint256 fillTakerQuantity = orderValues[6];
+ uint256 maxMakerQuantity;
+ address makerAsset;
+ uint256 maxTakerQuantity;
+ address takerAsset;
(
maxMakerQuantity,
makerAsset,
maxTakerQuantity,
takerAsset
- ) = MatchingMarket(targetExchange).getOffer(uint(identifier));
- uint fillMakerQuantity = mul(fillTakerQuantity, maxMakerQuantity) / maxTakerQuantity;
+ ) = IOasisDex(targetExchange).getOffer(uint256(identifier));
+ uint256 fillMakerQuantity = mul(fillTakerQuantity, maxMakerQuantity) / maxTakerQuantity;
require(
- address(makerAsset) == orderAddresses[2] && address(takerAsset) == orderAddresses[3],
+ makerAsset == orderAddresses[2] && takerAsset == orderAddresses[3],
"Maker and taker assets do not match the order addresses"
);
require(
- address(makerAsset) != address(takerAsset),
+ makerAsset != takerAsset,
"Maker and taker assets cannot be the same"
);
require(fillMakerQuantity <= maxMakerQuantity, "Maker amount to fill above max");
@@ -129,11 +128,11 @@ contract MatchingMarketAdapter is DSMath, ExchangeAdapter {
Vault(hub.vault()).withdraw(takerAsset, fillTakerQuantity);
require(
- takerAsset.approve(targetExchange, fillTakerQuantity),
+ IERC20(takerAsset).approve(targetExchange, fillTakerQuantity),
"Taker asset could not be approved"
);
require(
- MatchingMarket(targetExchange).buy(uint(identifier), fillMakerQuantity),
+ IOasisDex(targetExchange).buy(uint256(identifier), fillMakerQuantity),
"Buy on matching market failed"
);
@@ -144,7 +143,7 @@ contract MatchingMarketAdapter is DSMath, ExchangeAdapter {
targetExchange,
bytes32(identifier),
Trading.UpdateType.take,
- [address(makerAsset), address(takerAsset)],
+ [address(uint160(makerAsset)), address(uint160(takerAsset))],
[maxMakerQuantity, maxTakerQuantity, fillTakerQuantity]
);
}
@@ -159,18 +158,17 @@ contract MatchingMarketAdapter is DSMath, ExchangeAdapter {
/// @param identifier Order ID on the exchange
function cancelOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public onlyCancelPermitted(targetExchange, orderAddresses[2]) {
Hub hub = getHub();
- require(uint(identifier) != 0, "ID cannot be zero");
+ require(uint256(identifier) != 0, "ID cannot be zero");
address makerAsset;
- (, makerAsset, ,) = MatchingMarket(targetExchange).getOffer(uint(identifier));
+ (, makerAsset, ,) = IOasisDex(targetExchange).getOffer(uint256(identifier));
require(
address(makerAsset) == orderAddresses[2],
@@ -178,8 +176,8 @@ contract MatchingMarketAdapter is DSMath, ExchangeAdapter {
);
getTrading().removeOpenMakeOrder(targetExchange, makerAsset);
- MatchingMarket(targetExchange).cancel(
- uint(identifier)
+ IOasisDex(targetExchange).cancel(
+ uint256(identifier)
);
getTrading().returnAssetToVault(makerAsset);
getAccounting().updateOwnedAssets();
@@ -188,30 +186,30 @@ contract MatchingMarketAdapter is DSMath, ExchangeAdapter {
bytes32(identifier),
Trading.UpdateType.cancel,
[address(0), address(0)],
- [uint(0), uint(0), uint(0)]
+ [uint256(0), uint256(0), uint256(0)]
);
}
// VIEW METHODS
- function getOrder(address targetExchange, uint id, address makerAsset)
+ function getOrder(address targetExchange, uint256 id, address makerAsset)
public
view
- returns (address, address, uint, uint)
+ returns (address, address, uint256, uint256)
{
- uint sellQuantity;
- ERC20 sellAsset;
- uint buyQuantity;
- ERC20 buyAsset;
+ uint256 sellQuantity;
+ address sellAsset;
+ uint256 buyQuantity;
+ address buyAsset;
(
sellQuantity,
sellAsset,
buyQuantity,
buyAsset
- ) = MatchingMarket(targetExchange).getOffer(id);
+ ) = IOasisDex(targetExchange).getOffer(id);
return (
- address(sellAsset),
- address(buyAsset),
+ sellAsset,
+ buyAsset,
sellQuantity,
buyQuantity
);
diff --git a/src/exchanges/UniswapAdapter.sol b/src/exchanges/UniswapAdapter.sol
new file mode 100644
index 00000000..143d78e0
--- /dev/null
+++ b/src/exchanges/UniswapAdapter.sol
@@ -0,0 +1,258 @@
+pragma solidity 0.5.15;
+pragma experimental ABIEncoderV2;
+
+import "../dependencies/token/IERC20.sol";
+import "../dependencies/WETH.sol";
+import "../fund/accounting/Accounting.sol";
+import "../fund/hub/Hub.sol";
+import "../fund/trading/Trading.sol";
+import "../fund/vault/Vault.sol";
+import "./interfaces/IUniswapFactory.sol";
+import "./interfaces/IUniswapExchange.sol";
+import "./ExchangeAdapter.sol";
+
+contract UniswapAdapter is DSMath, ExchangeAdapter {
+ /// @notice Take order that uses a user-defined src token amount to trade for a dest token amount
+ /// @dev For the purpose of PriceTolerance, _orderValues [1] == _orderValues [6] = Dest token amount
+ /// @param _targetExchange Address of Uniswap factory contract
+ /// @param _orderAddresses [2] Maker asset (Dest token)
+ /// @param _orderAddresses [3] Taker asset (Src token)
+ /// @param _orderValues [0] Maker asset quantity (Dest token amount)
+ /// @param _orderValues [1] Taker asset quantity (Src token amount)
+ /// @param _orderValues [6] Taker asset fill amount
+ function takeOrder(
+ address _targetExchange,
+ address[8] memory _orderAddresses,
+ uint[8] memory _orderValues,
+ bytes[4] memory _orderData,
+ bytes32 _identifier,
+ bytes memory _signature
+ )
+ public
+ onlyManager
+ notShutDown
+ {
+ Hub hub = getHub();
+
+ require(
+ _orderValues[1] == _orderValues[6],
+ "Taker asset amount must equal taker asset fill amount"
+ );
+
+ address makerAsset = _orderAddresses[2];
+ address takerAsset = _orderAddresses[3];
+ uint makerAssetAmount = _orderValues[0];
+ uint takerAssetAmount = _orderValues[1];
+
+ uint actualReceiveAmount = dispatchSwap(
+ _targetExchange, takerAsset, takerAssetAmount, makerAsset, makerAssetAmount
+ );
+ require(
+ actualReceiveAmount >= makerAssetAmount,
+ "Received less than expected from Uniswap exchange"
+ );
+
+ updateStateTakeOrder(
+ _targetExchange,
+ makerAsset,
+ takerAsset,
+ takerAssetAmount,
+ actualReceiveAmount
+ );
+ }
+
+ // INTERNAL FUNCTIONS
+ function approveAsset(
+ address _asset,
+ address _target,
+ uint256 _amount,
+ string memory _assetType
+ )
+ internal
+ {
+ Hub hub = getHub();
+ Vault vault = Vault(hub.vault());
+
+ require(
+ IERC20(_asset).balanceOf(address(vault)) >= _amount,
+ string(abi.encodePacked("Insufficient balance: ", _assetType))
+ );
+
+ vault.withdraw(_asset, _amount);
+ uint256 allowance = IERC20(_asset).allowance(address(this), _target);
+ require(
+ IERC20(_asset).approve(_target, add(allowance, _amount)),
+ string(abi.encodePacked("Approval failed: ", _assetType))
+ );
+ }
+
+ /// @notice Call different functions based on type of assets supplied
+ /// @param _targetExchange Address of Uniswap factory contract
+ /// @param _srcToken Address of src token
+ /// @param _srcAmount Amount of src token supplied
+ /// @param _destToken Address of dest token
+ /// @param _minDestAmount Minimum amount of dest token to receive
+ /// @return actualReceiveAmount_ Actual amount of _destToken received
+ function dispatchSwap(
+ address _targetExchange,
+ address _srcToken,
+ uint _srcAmount,
+ address _destToken,
+ uint _minDestAmount
+ )
+ internal
+ returns (uint actualReceiveAmount_)
+ {
+ require(
+ _srcToken != _destToken,
+ "Src token cannot be the same as dest token"
+ );
+
+ Hub hub = getHub();
+ address nativeAsset = Accounting(hub.accounting()).NATIVE_ASSET();
+
+ if (_srcToken == nativeAsset) {
+ actualReceiveAmount_ = swapNativeAssetToToken(
+ _targetExchange,
+ nativeAsset,
+ _srcAmount,
+ _destToken,
+ _minDestAmount
+ );
+ } else if (_destToken == nativeAsset) {
+ actualReceiveAmount_ = swapTokenToNativeAsset(
+ _targetExchange,
+ _srcToken,
+ _srcAmount,
+ nativeAsset,
+ _minDestAmount
+ );
+ } else {
+ actualReceiveAmount_ = swapTokenToToken(
+ _targetExchange,
+ _srcToken,
+ _srcAmount,
+ _destToken,
+ _minDestAmount
+ );
+ }
+ }
+
+ /// @param _targetExchange Address of Uniswap factory contract
+ /// @param _nativeAsset Native asset address as src token
+ /// @param _srcAmount Amount of native asset supplied
+ /// @param _destToken Address of dest token
+ /// @param _minDestAmount Minimum amount of dest token to get back
+ /// @return actualReceiveAmount_ Actual amount of _destToken received
+ function swapNativeAssetToToken(
+ address _targetExchange,
+ address _nativeAsset,
+ uint _srcAmount,
+ address _destToken,
+ uint _minDestAmount
+ )
+ internal
+ returns (uint actualReceiveAmount_)
+ {
+ // Convert WETH to ETH
+ Hub hub = getHub();
+ Vault vault = Vault(hub.vault());
+ vault.withdraw(_nativeAsset, _srcAmount);
+ WETH(address(uint160(_nativeAsset))).withdraw(_srcAmount);
+
+ address tokenExchange = IUniswapFactory(_targetExchange).getExchange(_destToken);
+ actualReceiveAmount_ = IUniswapExchange(tokenExchange).ethToTokenTransferInput.value(
+ _srcAmount
+ )
+ (
+ _minDestAmount,
+ add(block.timestamp, 1),
+ address(vault)
+ );
+ }
+
+ /// @param _targetExchange Address of Uniswap factory contract
+ /// @param _srcToken Address of src token
+ /// @param _srcAmount Amount of src token supplied
+ /// @param _nativeAsset Native asset address as dest token
+ /// @param _minDestAmount Minimum amount of dest token to get back
+ /// @return actualReceiveAmount_ Actual amount of _destToken received
+ function swapTokenToNativeAsset(
+ address _targetExchange,
+ address _srcToken,
+ uint _srcAmount,
+ address _nativeAsset,
+ uint _minDestAmount
+ )
+ internal
+ returns (uint actualReceiveAmount_)
+ {
+ Hub hub = getHub();
+ Vault vault = Vault(hub.vault());
+ vault.withdraw(_srcToken, _srcAmount);
+
+ address tokenExchange = IUniswapFactory(_targetExchange).getExchange(_srcToken);
+ approveAsset(_srcToken, tokenExchange, _srcAmount, "takerAsset");
+ actualReceiveAmount_ = IUniswapExchange(tokenExchange).tokenToEthSwapInput(
+ _srcAmount,
+ _minDestAmount,
+ add(block.timestamp, 1)
+ );
+
+ // Convert ETH to WETH and move to Vault
+ WETH(address(uint160(_nativeAsset))).deposit.value(actualReceiveAmount_)();
+ getTrading().returnAssetToVault(_nativeAsset);
+ }
+
+ /// @param _targetExchange Address of Uniswap factory contract
+ /// @param _srcToken Address of src token
+ /// @param _srcAmount Amount of src token supplied
+ /// @param _destToken Address of dest token
+ /// @param _minDestAmount Minimum amount of dest token to get back
+ /// @return actualReceiveAmount_ Actual amount of _destToken received
+ function swapTokenToToken(
+ address _targetExchange,
+ address _srcToken,
+ uint _srcAmount,
+ address _destToken,
+ uint _minDestAmount
+ )
+ internal
+ returns (uint actualReceiveAmount_)
+ {
+ Hub hub = getHub();
+ Vault vault = Vault(hub.vault());
+ vault.withdraw(_srcToken, _srcAmount);
+
+ address tokenExchange = IUniswapFactory(_targetExchange).getExchange(_srcToken);
+ approveAsset(_srcToken, tokenExchange, _srcAmount, "takerAsset");
+ actualReceiveAmount_ = IUniswapExchange(tokenExchange).tokenToTokenTransferInput(
+ _srcAmount,
+ _minDestAmount,
+ 1,
+ add(block.timestamp, 1),
+ address(vault),
+ _destToken
+ );
+ }
+
+ function updateStateTakeOrder(
+ address _targetExchange,
+ address _makerAsset,
+ address _takerAsset,
+ uint256 _takerAssetAmount,
+ uint256 _actualReceiveAmount
+ )
+ internal
+ {
+ getAccounting().addAssetToOwnedAssets(_makerAsset);
+ getAccounting().updateOwnedAssets();
+ getTrading().orderUpdateHook(
+ _targetExchange,
+ bytes32(0),
+ Trading.UpdateType.take,
+ [address(uint160(_makerAsset)), address(uint160(_takerAsset))],
+ [_actualReceiveAmount, _takerAssetAmount, _takerAssetAmount]
+ );
+ }
+}
diff --git a/src/contracts/exchanges/ZeroExV2Adapter.sol b/src/exchanges/ZeroExV2Adapter.sol
similarity index 67%
rename from src/contracts/exchanges/ZeroExV2Adapter.sol
rename to src/exchanges/ZeroExV2Adapter.sol
index 98e013af..30eeff54 100644
--- a/src/contracts/exchanges/ZeroExV2Adapter.sol
+++ b/src/exchanges/ZeroExV2Adapter.sol
@@ -1,14 +1,14 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
pragma experimental ABIEncoderV2;
-import "ERC20.i.sol";
-import "Trading.sol";
-import "Hub.sol";
-import "Vault.sol";
-import "Accounting.sol";
-import "math.sol";
-import "Exchange.sol";
-import "ExchangeAdapter.sol";
+import "../dependencies/token/IERC20.sol";
+import "../fund/trading/Trading.sol";
+import "../fund/hub/Hub.sol";
+import "../fund/vault/Vault.sol";
+import "../fund/accounting/Accounting.sol";
+import "../dependencies/DSMath.sol";
+import "./interfaces/IZeroExV2.sol";
+import "./ExchangeAdapter.sol";
/// @title ZeroExV2Adapter Contract
/// @author Melonport AG <team@melonport.com>
@@ -22,18 +22,18 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
/// @notice Make order by pre-approving signatures
function makeOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public onlyManager notShutDown {
ensureCanMakeOrder(orderAddresses[2]);
Hub hub = getHub();
- LibOrder.Order memory order = constructOrderStruct(orderAddresses, orderValues, makerAssetData, takerAssetData);
- address makerAsset = getAssetAddress(makerAssetData);
- address takerAsset = getAssetAddress(takerAssetData);
+
+ IZeroExV2.Order memory order = constructOrderStruct(orderAddresses, orderValues, orderData);
+ address makerAsset = getAssetAddress(orderData[0]);
+ address takerAsset = getAssetAddress(orderData[1]);
require(
makerAsset == orderAddresses[2],
"Maker asset data does not match order address in array"
@@ -47,12 +47,12 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
getTrading().updateAndGetQuantityBeingTraded(makerAsset);
ensureNotInOpenMakeOrder(makerAsset);
- approveMakerAsset(targetExchange, makerAsset, makerAssetData, order.makerAssetAmount);
- LibOrder.OrderInfo memory orderInfo = Exchange(targetExchange).getOrderInfo(order);
- Exchange(targetExchange).preSign(orderInfo.orderHash, address(this), signature);
+ approveMakerAsset(targetExchange, makerAsset, orderData[0], order.makerAssetAmount);
+ IZeroExV2.OrderInfo memory orderInfo = IZeroExV2(targetExchange).getOrderInfo(order);
+ IZeroExV2(targetExchange).preSign(orderInfo.orderHash, address(this), signature);
require(
- Exchange(targetExchange).isValidSignature(
+ IZeroExV2(targetExchange).isValidSignature(
orderInfo.orderHash,
address(this),
signature
@@ -64,17 +64,17 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
targetExchange,
orderInfo.orderHash,
Trading.UpdateType.make,
- [address(makerAsset), address(takerAsset)],
+ [address(uint160(makerAsset)), address(uint160(takerAsset))],
[order.makerAssetAmount, order.takerAssetAmount, uint(0)]
);
- Trading(address(this)).addOpenMakeOrder(
- targetExchange,
+ getTrading().addOpenMakeOrder(
+ targetExchange,
makerAsset,
takerAsset,
- uint256(orderInfo.orderHash),
+ uint256(orderInfo.orderHash),
order.expirationTimeSeconds
);
- Trading(address(this)).addZeroExOrderData(orderInfo.orderHash, order);
+ getTrading().addZeroExV2OrderData(orderInfo.orderHash, order);
}
// Responsibilities of takeOrder are:
@@ -105,25 +105,26 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
/// @param orderValues [5] Salt/nonce
/// @param orderValues [6] Fill amount: amount of taker token to be traded
/// @param orderValues [7] Dexy signature mode
+ /// @param orderData [0] Encoded data specific to maker asset
+ /// @param orderData [1] Encoded data specific to taker asset
+ /// @param orderData [2] Encoded data specific to maker asset fee
+ /// @param orderData [3] Encoded data specific to taker asset fee
/// @param identifier Order identifier
- /// @param makerAssetData Encoded data specific to makerAsset.
- /// @param takerAssetData Encoded data specific to takerAsset.
/// @param signature Signature of the order.
function takeOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public onlyManager notShutDown {
Hub hub = getHub();
- LibOrder.Order memory order = constructOrderStruct(orderAddresses, orderValues, makerAssetData, takerAssetData);
+ IZeroExV2.Order memory order = constructOrderStruct(orderAddresses, orderValues, orderData);
uint fillTakerQuantity = orderValues[6];
- address makerAsset = getAssetAddress(makerAssetData);
- address takerAsset = getAssetAddress(takerAssetData);
+ address makerAsset = getAssetAddress(orderData[0]);
+ address takerAsset = getAssetAddress(orderData[1]);
require(
makerAsset == orderAddresses[2],
"Maker asset data does not match order address in array"
@@ -132,8 +133,8 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
takerAsset == orderAddresses[3],
"Taker asset data does not match order address in array"
);
- approveTakerAsset(targetExchange, takerAsset, takerAssetData, fillTakerQuantity);
- LibOrder.OrderInfo memory orderInfo = Exchange(targetExchange).getOrderInfo(order);
+ approveTakerAsset(targetExchange, takerAsset, orderData[1], fillTakerQuantity);
+ IZeroExV2.OrderInfo memory orderInfo = IZeroExV2(targetExchange).getOrderInfo(order);
uint takerAssetFilledAmount = executeFill(targetExchange, order, fillTakerQuantity, signature);
require(
@@ -147,7 +148,7 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
targetExchange,
orderInfo.orderHash,
Trading.UpdateType.take,
- [makerAsset, takerAsset],
+ [address(uint160(makerAsset)), address(uint160(takerAsset))],
[order.makerAssetAmount, order.takerAssetAmount, fillTakerQuantity]
);
}
@@ -155,19 +156,18 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
/// @notice Cancel the 0x make order
function cancelOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public onlyCancelPermitted(targetExchange, orderAddresses[2]) {
Hub hub = getHub();
- LibOrder.Order memory order = Trading(address(this)).getZeroExOrderDetails(identifier);
+ IZeroExV2.Order memory order = getTrading().getZeroExV2OrderDetails(identifier);
address makerAsset = getAssetAddress(order.makerAssetData);
if (order.expirationTimeSeconds > block.timestamp) {
- Exchange(targetExchange).cancelOrder(order);
+ IZeroExV2(targetExchange).cancelOrder(order);
}
// Set the approval back to 0
@@ -185,10 +185,10 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
}
/// @dev Get order details
- function getOrder(address targetExchange, uint id, address makerAsset)
+ function getOrder(address targetExchange, uint256 id, address makerAsset)
public
view
- returns (address, address, uint, uint)
+ returns (address, address, uint256, uint256)
{
uint orderId;
uint orderIndex;
@@ -197,9 +197,9 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
uint takerQuantity;
(orderId, , orderIndex) = Trading(msg.sender).getOpenOrderInfo(targetExchange, makerAsset);
(, takerAsset, makerQuantity, takerQuantity) = Trading(msg.sender).getOrderDetails(orderIndex);
- uint takerAssetFilledAmount = Exchange(targetExchange).filled(bytes32(orderId));
+ uint takerAssetFilledAmount = IZeroExV2(targetExchange).filled(bytes32(orderId));
uint makerAssetFilledAmount = mul(takerAssetFilledAmount, makerQuantity) / takerQuantity;
- if (Exchange(targetExchange).cancelled(bytes32(orderId)) || sub(takerQuantity, takerAssetFilledAmount) == 0) {
+ if (IZeroExV2(targetExchange).cancelled(bytes32(orderId)) || sub(takerQuantity, takerAssetFilledAmount) == 0) {
return (makerAsset, takerAsset, 0, 0);
}
return (
@@ -214,7 +214,7 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
/// @notice needed to avoid stack too deep error
- function approveTakerAsset(address targetExchange, address takerAsset, bytes takerAssetData, uint fillTakerQuantity)
+ function approveTakerAsset(address targetExchange, address takerAsset, bytes memory takerAssetData, uint256 fillTakerQuantity)
internal
{
Hub hub = getHub();
@@ -222,13 +222,13 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
vault.withdraw(takerAsset, fillTakerQuantity);
address assetProxy = getAssetProxy(targetExchange, takerAssetData);
require(
- ERC20(takerAsset).approve(assetProxy, fillTakerQuantity),
+ IERC20(takerAsset).approve(assetProxy, fillTakerQuantity),
"Taker asset could not be approved"
);
}
/// @notice needed to avoid stack too deep error
- function approveMakerAsset(address targetExchange, address makerAsset, bytes makerAssetData, uint makerQuantity)
+ function approveMakerAsset(address targetExchange, address makerAsset, bytes memory makerAssetData, uint256 makerQuantity)
internal
{
Hub hub = getHub();
@@ -236,7 +236,7 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
vault.withdraw(makerAsset, makerQuantity);
address assetProxy = getAssetProxy(targetExchange, makerAssetData);
require(
- ERC20(makerAsset).approve(assetProxy, makerQuantity),
+ IERC20(makerAsset).approve(assetProxy, makerQuantity),
"Maker asset could not be approved"
);
}
@@ -244,36 +244,36 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
/// @dev needed to avoid stack too deep error
function executeFill(
address targetExchange,
- LibOrder.Order memory order,
+ IZeroExV2.Order memory order,
uint256 takerAssetFillAmount,
- bytes signature
+ bytes memory signature
)
internal
- returns (uint)
+ returns (uint256)
{
uint takerFee = order.takerFee;
if (takerFee > 0) {
- bytes memory assetData = Exchange(targetExchange).ZRX_ASSET_DATA();
+ bytes memory assetData = IZeroExV2(targetExchange).ZRX_ASSET_DATA();
address zrxProxy = getAssetProxy(targetExchange, assetData);
Hub hub = getHub();
Vault vault = Vault(hub.vault());
vault.withdraw(getAssetAddress(assetData), takerFee);
require(
- ERC20(getAssetAddress(assetData)).approve(zrxProxy, takerFee),
+ IERC20(getAssetAddress(assetData)).approve(zrxProxy, takerFee),
"Fee asset could not be approved"
);
}
address makerAsset = getAssetAddress(order.makerAssetData);
- uint preMakerAssetBalance = ERC20(makerAsset).balanceOf(this);
+ uint preMakerAssetBalance = IERC20(makerAsset).balanceOf(address(this));
- LibFillResults.FillResults memory fillResults = Exchange(targetExchange).fillOrder(
+ IZeroExV2.FillResults memory fillResults = IZeroExV2(targetExchange).fillOrder(
order,
takerAssetFillAmount,
signature
);
- uint postMakerAssetBalance = ERC20(makerAsset).balanceOf(this);
+ uint256 postMakerAssetBalance = IERC20(makerAsset).balanceOf(address(this));
require(
postMakerAssetBalance == add(preMakerAssetBalance, fillResults.makerAssetFilledAmount),
"Maker asset balance different than expected"
@@ -285,16 +285,15 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
// VIEW METHODS
function constructOrderStruct(
- address[6] orderAddresses,
- uint[8] orderValues,
- bytes makerAssetData,
- bytes takerAssetData
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData
)
internal
view
- returns (LibOrder.Order memory order)
+ returns (IZeroExV2.Order memory order)
{
- order = LibOrder.Order({
+ order = IZeroExV2.Order({
makerAddress: orderAddresses[0],
takerAddress: orderAddresses[1],
feeRecipientAddress: orderAddresses[4],
@@ -305,12 +304,12 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
takerFee: orderValues[3],
expirationTimeSeconds: orderValues[4],
salt: orderValues[5],
- makerAssetData: makerAssetData,
- takerAssetData: takerAssetData
+ makerAssetData: orderData[0],
+ takerAssetData: orderData[1]
});
}
- function getAssetProxy(address targetExchange, bytes assetData)
+ function getAssetProxy(address targetExchange, bytes memory assetData)
internal
view
returns (address assetProxy)
@@ -322,10 +321,10 @@ contract ZeroExV2Adapter is DSMath, ExchangeAdapter {
0xFFFFFFFF00000000000000000000000000000000000000000000000000000000
)
}
- assetProxy = Exchange(targetExchange).getAssetProxy(assetProxyId);
+ assetProxy = IZeroExV2(targetExchange).getAssetProxy(assetProxyId);
}
- function getAssetAddress(bytes assetData)
+ function getAssetAddress(bytes memory assetData)
internal
view
returns (address assetAddress)
diff --git a/src/exchanges/ZeroExV3Adapter.sol b/src/exchanges/ZeroExV3Adapter.sol
new file mode 100644
index 00000000..d512f166
--- /dev/null
+++ b/src/exchanges/ZeroExV3Adapter.sol
@@ -0,0 +1,466 @@
+pragma solidity 0.5.15;
+pragma experimental ABIEncoderV2;
+
+import "../dependencies/token/IERC20.sol";
+import "../fund/trading/Trading.sol";
+import "../fund/hub/Hub.sol";
+import "../fund/vault/Vault.sol";
+import "../fund/accounting/Accounting.sol";
+import "../dependencies/DSMath.sol";
+import "./interfaces/IZeroExV3.sol";
+import "./ExchangeAdapter.sol";
+
+/// @title ZeroExV3Adapter Contract
+/// @author Melonport AG <team@melonport.com>
+/// @notice Adapter to 0xV3 Exchange Contract
+contract ZeroExV3Adapter is DSMath, ExchangeAdapter {
+
+ /// @param _orderAddresses [2] Order maker asset
+ /// @param _orderAddresses [3] Order taker asset
+ /// @param _orderAddresses [6] Order maker fee asset
+ /// @param _orderAddresses [7] Order taker fee asset
+ /// @param _orderValues [2] Order maker fee amount
+ /// @param _orderValues [3] Order taker fee amount
+ modifier orderAddressesMatchOrderData(
+ address[8] memory _orderAddresses,
+ uint[8] memory _orderValues,
+ bytes[4] memory _orderData
+ )
+ {
+ require(
+ getAssetAddress(_orderData[0]) == _orderAddresses[2],
+ "Maker asset data does not match order address in array"
+ );
+ require(
+ getAssetAddress(_orderData[1]) == _orderAddresses[3],
+ "Taker asset data does not match order address in array"
+ );
+ if (_orderValues[2] > 0) {
+ require(
+ getAssetAddress(_orderData[2]) == _orderAddresses[6],
+ "Maker fee asset data does not match order address in array"
+ );
+ }
+ if (_orderValues[3] > 0) {
+ require(
+ getAssetAddress(_orderData[3]) == _orderAddresses[7],
+ "Taker fee asset data does not match order address in array"
+ );
+ }
+ _;
+ }
+
+ // METHODS
+
+ // PUBLIC METHODS
+
+ /// @notice Make order by pre-approving signatures
+ /// @param _targetExchange Address of the exchange
+ /// @param _orderAddresses [2] Maker asset (Dest token)
+ /// @param _orderAddresses [3] Taker asset (Src token)
+ /// @param _orderData [0] Encoded data specific to maker asset
+ /// @param _orderData [1] Encoded data specific to taker asset
+ /// @param _signature _signature of the order.
+ function makeOrder(
+ address _targetExchange,
+ address[8] memory _orderAddresses,
+ uint[8] memory _orderValues,
+ bytes[4] memory _orderData,
+ bytes32 _identifier,
+ bytes memory _signature
+ )
+ public
+ onlyManager
+ notShutDown
+ orderAddressesMatchOrderData(_orderAddresses, _orderValues, _orderData)
+ {
+ ensureCanMakeOrder(_orderAddresses[2]);
+ Hub hub = getHub();
+
+ IZeroExV3.Order memory order = constructOrderStruct(_orderAddresses, _orderValues, _orderData);
+ address makerAsset = getAssetAddress(_orderData[0]);
+ address takerAsset = getAssetAddress(_orderData[1]);
+
+ // Order parameter checks
+ getTrading().updateAndGetQuantityBeingTraded(makerAsset);
+ ensureNotInOpenMakeOrder(makerAsset);
+
+ approveAssetsMakeOrder(_targetExchange, order);
+
+ IZeroExV3.OrderInfo memory orderInfo = IZeroExV3(_targetExchange).getOrderInfo(order);
+ IZeroExV3(_targetExchange).preSign(orderInfo.orderHash);
+
+ require(
+ IZeroExV3(_targetExchange).isValidOrderSignature(order, _signature),
+ "INVALID_ORDER_SIGNATURE"
+ );
+
+ updateStateMakeOrder(_targetExchange, order);
+ }
+
+ /// @notice Takes an active order on the selected exchange
+ /// @dev These orders are expected to settle immediately
+ /// @param _targetExchange Address of the exchange
+ /// @param _orderAddresses [2] Order maker asset
+ /// @param _orderAddresses [3] Order taker asset
+ /// @param _orderValues [6] Fill amount: amount of taker token to be traded
+ /// @param _signature _signature of the order.
+ function takeOrder(
+ address _targetExchange,
+ address[8] memory _orderAddresses,
+ uint[8] memory _orderValues,
+ bytes[4] memory _orderData,
+ bytes32 _identifier,
+ bytes memory _signature
+ )
+ public
+ onlyManager
+ notShutDown
+ orderAddressesMatchOrderData(_orderAddresses, _orderValues, _orderData)
+ {
+ IZeroExV3.Order memory order = constructOrderStruct(_orderAddresses, _orderValues, _orderData);
+ require(IZeroExV3(_targetExchange).isValidOrderSignature(order, _signature), "Order _signature is invalid");
+
+ uint256 fillTakerQuantity = _orderValues[6];
+
+ approveAssetsTakeOrder(_targetExchange, order);
+
+ uint256 takerAssetFilledAmount = executeFill(_targetExchange, order, fillTakerQuantity, _signature);
+ require(
+ takerAssetFilledAmount == fillTakerQuantity,
+ "Filled amount does not match desired fill amount"
+ );
+
+ updateStateTakeOrder(_targetExchange, order, fillTakerQuantity);
+ }
+
+ /// @notice Cancel the 0x make order
+ /// @param _targetExchange Address of the exchange
+ /// @param _orderAddresses [2] Order maker asset
+ /// @param _identifier Order _identifier
+ function cancelOrder(
+ address _targetExchange,
+ address[8] memory _orderAddresses,
+ uint[8] memory _orderValues,
+ bytes[4] memory _orderData,
+ bytes32 _identifier,
+ bytes memory _signature
+ )
+ public
+ onlyCancelPermitted(_targetExchange, _orderAddresses[2])
+ {
+ Hub hub = getHub();
+ IZeroExV3.Order memory order = getTrading().getZeroExV3OrderDetails(_identifier);
+ address makerAsset = getAssetAddress(order.makerAssetData);
+ address makerFeeAsset = getAssetAddress(order.makerFeeAssetData);
+
+ if (order.expirationTimeSeconds > block.timestamp) {
+ IZeroExV3(_targetExchange).cancelOrder(order);
+ }
+
+ // Revoke asset approvals and return assets to vault
+ revokeApproveAsset(
+ makerAsset,
+ getAssetProxy(_targetExchange, order.takerAssetData),
+ order.makerAssetAmount,
+ "makerAsset"
+ );
+ getTrading().returnAssetToVault(makerAsset);
+
+ if (order.makerFee > 0) {
+ revokeApproveAsset(
+ makerFeeAsset,
+ getAssetProxy(_targetExchange, order.makerFeeAssetData),
+ order.makerFee,
+ "makerFeeAsset"
+ );
+ if (makerFeeAsset != makerAsset) getTrading().returnAssetToVault(makerFeeAsset);
+ }
+
+ updateStateCancelOrder(_targetExchange, order);
+ }
+
+ /// @dev Get order details
+ function getOrder(address _targetExchange, uint256 _id, address _makerAsset)
+ public
+ view
+ returns (address, address, uint256, uint256)
+ {
+ uint orderId;
+ uint orderIndex;
+ address takerAsset;
+ uint makerQuantity;
+ uint takerQuantity;
+ (orderId, , orderIndex) = Trading(msg.sender).getOpenOrderInfo(_targetExchange, _makerAsset);
+ (, takerAsset, makerQuantity, takerQuantity) = Trading(msg.sender).getOrderDetails(orderIndex);
+ uint takerAssetFilledAmount = IZeroExV3(_targetExchange).filled(bytes32(orderId));
+ uint makerAssetFilledAmount = mul(takerAssetFilledAmount, makerQuantity) / takerQuantity;
+ if (IZeroExV3(_targetExchange).cancelled(bytes32(orderId)) || sub(takerQuantity, takerAssetFilledAmount) == 0) {
+ return (_makerAsset, takerAsset, 0, 0);
+ }
+ return (
+ _makerAsset,
+ takerAsset,
+ sub(makerQuantity, makerAssetFilledAmount),
+ sub(takerQuantity, takerAssetFilledAmount)
+ );
+ }
+
+ // INTERNAL METHODS
+ function approveAsset(
+ address _asset,
+ address _target,
+ uint256 _amount,
+ string memory _assetType
+ )
+ internal
+ {
+ Hub hub = getHub();
+ Vault vault = Vault(hub.vault());
+
+ require(
+ IERC20(_asset).balanceOf(address(vault)) >= _amount,
+ string(abi.encodePacked("Insufficient balance: ", _assetType))
+ );
+
+ vault.withdraw(_asset, _amount);
+ uint256 allowance = IERC20(_asset).allowance(address(this), _target);
+ require(
+ IERC20(_asset).approve(_target, add(allowance, _amount)),
+ string(abi.encodePacked("Approval failed: ", _assetType))
+ );
+ }
+
+ // @notice Approves makerAsset, makerFeeAsset
+ function approveAssetsMakeOrder(address _targetExchange, IZeroExV3.Order memory _order)
+ internal
+ {
+ approveAsset(
+ getAssetAddress(_order.makerAssetData),
+ getAssetProxy(_targetExchange, _order.makerAssetData),
+ _order.makerAssetAmount,
+ "makerAsset"
+ );
+ if (_order.makerFee > 0) {
+ approveAsset(
+ getAssetAddress(_order.makerFeeAssetData),
+ getAssetProxy(_targetExchange, _order.makerFeeAssetData),
+ _order.makerFee,
+ "makerFeeAsset"
+ );
+ }
+ }
+
+ // @notice Approves takerAsset, takerFeeAsset, protocolFee
+ function approveAssetsTakeOrder(address _targetExchange, IZeroExV3.Order memory _order)
+ internal
+ {
+ approveProtocolFeeAsset(_targetExchange);
+ approveAsset(
+ getAssetAddress(_order.takerAssetData),
+ getAssetProxy(_targetExchange, _order.takerAssetData),
+ _order.takerAssetAmount,
+ "takerAsset"
+ );
+ if (_order.takerFee > 0) {
+ approveAsset(
+ getAssetAddress(_order.takerFeeAssetData),
+ getAssetProxy(_targetExchange, _order.takerFeeAssetData),
+ _order.takerFee,
+ "takerFeeAsset"
+ );
+ }
+ }
+
+ function approveProtocolFeeAsset(address _targetExchange) internal {
+ address protocolFeeCollector = IZeroExV3(_targetExchange).protocolFeeCollector();
+ uint256 protocolFeeAmount = calcProtocolFeeAmount(_targetExchange);
+ if (protocolFeeCollector == address(0) || protocolFeeAmount == 0) return;
+
+ Hub hub = getHub();
+ address nativeAsset = Accounting(hub.accounting()).NATIVE_ASSET();
+
+ approveAsset(nativeAsset, protocolFeeCollector, protocolFeeAmount, "protocolFee");
+ }
+
+ function executeFill(
+ address _targetExchange,
+ IZeroExV3.Order memory _order,
+ uint256 _takerAssetFillAmount,
+ bytes memory _signature
+ )
+ internal
+ returns (uint256)
+ {
+ Hub hub = getHub();
+ address makerAsset = getAssetAddress(_order.makerAssetData);
+ uint preMakerAssetBalance = IERC20(makerAsset).balanceOf(address(this));
+
+ IZeroExV3.FillResults memory fillResults = IZeroExV3(_targetExchange).fillOrder(
+ _order,
+ _takerAssetFillAmount,
+ _signature
+ );
+
+ uint256 postMakerAssetBalance = IERC20(makerAsset).balanceOf(address(this));
+
+ // Account for case where makerAsset, takerFee, protocolFee are the same
+ uint256 makerAssetFeesTotal;
+ if (
+ makerAsset == Accounting(hub.accounting()).NATIVE_ASSET() &&
+ IZeroExV3(_targetExchange).protocolFeeCollector() != address(0)
+ )
+ {
+ makerAssetFeesTotal = calcProtocolFeeAmount(_targetExchange);
+ }
+ if (makerAsset == getAssetAddress(_order.takerFeeAssetData)) {
+ makerAssetFeesTotal = add(makerAssetFeesTotal, _order.takerFee);
+ }
+
+ require(
+ postMakerAssetBalance == sub(
+ add(preMakerAssetBalance, fillResults.makerAssetFilledAmount),
+ makerAssetFeesTotal
+ ),
+ "Maker asset balance different than expected"
+ );
+
+ return fillResults.takerAssetFilledAmount;
+ }
+
+ function revokeApproveAsset(
+ address _asset,
+ address _target,
+ uint256 _amount,
+ string memory _assetType
+ )
+ internal
+ {
+ uint256 allowance = IERC20(_asset).allowance(address(this), _target);
+ require(
+ IERC20(_asset).approve(_target, sub(allowance, _amount)),
+ string(abi.encodePacked("Revoke approval failed: ", _assetType))
+ );
+ }
+
+ function updateStateCancelOrder(address _targetExchange, IZeroExV3.Order memory _order)
+ internal
+ {
+ address makerAsset = getAssetAddress(_order.makerAssetData);
+
+ getTrading().removeOpenMakeOrder(_targetExchange, makerAsset);
+ getAccounting().updateOwnedAssets();
+ getTrading().orderUpdateHook(
+ _targetExchange,
+ IZeroExV3(_targetExchange).getOrderInfo(_order).orderHash,
+ Trading.UpdateType.cancel,
+ [address(0), address(0)],
+ [uint(0), uint(0), uint(0)]
+ );
+ }
+
+ function updateStateMakeOrder(address _targetExchange, IZeroExV3.Order memory _order)
+ internal
+ {
+ address makerAsset = getAssetAddress(_order.makerAssetData);
+ address takerAsset = getAssetAddress(_order.takerAssetData);
+ IZeroExV3.OrderInfo memory orderInfo = IZeroExV3(_targetExchange).getOrderInfo(_order);
+
+ getAccounting().addAssetToOwnedAssets(takerAsset);
+ getTrading().orderUpdateHook(
+ _targetExchange,
+ orderInfo.orderHash,
+ Trading.UpdateType.make,
+ [address(uint160(makerAsset)), address(uint160(takerAsset))],
+ [_order.makerAssetAmount, _order.takerAssetAmount, uint(0)]
+ );
+ getTrading().addOpenMakeOrder(
+ _targetExchange,
+ makerAsset,
+ takerAsset,
+ uint256(orderInfo.orderHash),
+ _order.expirationTimeSeconds
+ );
+ getTrading().addZeroExV3OrderData(orderInfo.orderHash, _order);
+ }
+
+ // @dev avoids stack too deep error
+ function updateStateTakeOrder(
+ address _targetExchange,
+ IZeroExV3.Order memory _order,
+ uint256 _fillTakerQuantity
+ )
+ internal
+ {
+ address makerAsset = getAssetAddress(_order.makerAssetData);
+ address takerAsset = getAssetAddress(_order.takerAssetData);
+
+ getAccounting().addAssetToOwnedAssets(makerAsset);
+ getAccounting().updateOwnedAssets();
+ getTrading().returnAssetToVault(makerAsset);
+ getTrading().orderUpdateHook(
+ _targetExchange,
+ IZeroExV3(_targetExchange).getOrderInfo(_order).orderHash,
+ Trading.UpdateType.take,
+ [address(uint160(makerAsset)), address(uint160(takerAsset))],
+ [_order.makerAssetAmount, _order.takerAssetAmount, _fillTakerQuantity]
+ );
+ }
+
+ // VIEW METHODS
+ function calcProtocolFeeAmount(address _targetExchange) internal view returns (uint256) {
+ return mul(IZeroExV3(_targetExchange).protocolFeeMultiplier(), tx.gasprice);
+ }
+
+ function constructOrderStruct(
+ address[8] memory _orderAddresses,
+ uint[8] memory _orderValues,
+ bytes[4] memory _orderData
+ )
+ internal
+ view
+ returns (IZeroExV3.Order memory order_)
+ {
+ order_ = IZeroExV3.Order({
+ makerAddress: _orderAddresses[0],
+ takerAddress: _orderAddresses[1],
+ feeRecipientAddress: _orderAddresses[4],
+ senderAddress: _orderAddresses[5],
+ makerAssetAmount: _orderValues[0],
+ takerAssetAmount: _orderValues[1],
+ makerFee: _orderValues[2],
+ takerFee: _orderValues[3],
+ expirationTimeSeconds: _orderValues[4],
+ salt: _orderValues[5],
+ makerAssetData: _orderData[0],
+ takerAssetData: _orderData[1],
+ makerFeeAssetData: _orderData[2],
+ takerFeeAssetData: _orderData[3]
+ });
+ }
+
+ function getAssetProxy(address _targetExchange, bytes memory _assetData)
+ internal
+ view
+ returns (address assetProxy_)
+ {
+ bytes4 assetProxyId;
+ assembly {
+ assetProxyId := and(mload(
+ add(_assetData, 32)),
+ 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000
+ )
+ }
+ assetProxy_ = IZeroExV3(_targetExchange).getAssetProxy(assetProxyId);
+ }
+
+ function getAssetAddress(bytes memory _assetData)
+ internal
+ view
+ returns (address assetAddress_)
+ {
+ assembly {
+ assetAddress_ := mload(add(_assetData, 36))
+ }
+ }
+}
diff --git a/src/exchanges/interfaces/IEthfinex.sol b/src/exchanges/interfaces/IEthfinex.sol
new file mode 100644
index 00000000..7c26b57d
--- /dev/null
+++ b/src/exchanges/interfaces/IEthfinex.sol
@@ -0,0 +1,20 @@
+pragma solidity 0.5.15;
+// pragma experimental ABIEncoderV2;
+
+/// @dev Minimal interface for our interactions with EthFinex WrapperLock
+interface IWrapperLock {
+ function balanceOf(address) external view returns (uint256);
+ function withdraw(uint256, uint8, bytes32, bytes32, uint256) external returns (bool);
+ function deposit(uint256, uint256) external returns (bool);
+}
+
+/// @dev Minimal interface for our interactions with EthFinex WrapperLockEth
+interface IWrapperLockEth {
+ function balanceOf(address) external view returns (uint256);
+ function deposit(uint256, uint256) external payable returns (bool);
+}
+
+/// @dev Minimal interface for our interactions with EthFinex WrapperRegistryEFX
+interface IWrapperRegistryEFX {
+ function token2WrapperLookup(address) external view returns (address);
+}
diff --git a/src/exchanges/interfaces/IKyberNetworkProxy.sol b/src/exchanges/interfaces/IKyberNetworkProxy.sol
new file mode 100644
index 00000000..8c0750a4
--- /dev/null
+++ b/src/exchanges/interfaces/IKyberNetworkProxy.sol
@@ -0,0 +1,18 @@
+pragma solidity 0.5.15;
+
+
+/// @title Kyber Network interface
+interface IKyberNetworkProxy {
+ function maxGasPrice() external view returns(uint256);
+ function getUserCapInWei(address) external view returns(uint256);
+ function getUserCapInTokenWei(address, address) external view returns(uint256);
+ function enabled() external view returns(bool);
+ function info(bytes32) external view returns(uint256);
+ function swapEtherToToken(address, uint256) external payable returns(uint256);
+ function swapTokenToEther(address, uint256, uint256) external returns(uint256);
+ function swapTokenToToken(address, uint256, address, uint256) external returns(uint);
+ function getExpectedRate(address, address, uint256) external view returns (uint256, uint256);
+ function tradeWithHint(
+ address, uint256, address, address, uint256, uint256, address, bytes calldata
+ ) external payable returns(uint256);
+}
diff --git a/src/exchanges/interfaces/IOasisDex.sol b/src/exchanges/interfaces/IOasisDex.sol
new file mode 100644
index 00000000..fca4b960
--- /dev/null
+++ b/src/exchanges/interfaces/IOasisDex.sol
@@ -0,0 +1,14 @@
+pragma solidity 0.5.15;
+
+/// @dev Minimal interface for our interactions with OasisDex MatchingMarket
+interface IOasisDex {
+ function getFirstUnsortedOffer() external view returns(uint256);
+ function getNextUnsortedOffer(uint256) external view returns(uint256);
+ function getBestOffer(address, address) external view returns(uint256);
+ function getOffer(uint256) external view returns (uint256, address, uint256, address);
+ function getWorseOffer(uint256) external view returns(uint256);
+ function isActive(uint256) external view returns (bool);
+ function buy(uint256, uint256) external returns (bool);
+ function cancel(uint256) external returns (bool);
+ function offer(uint256, address, uint256, address) external returns (uint256);
+}
diff --git a/src/exchanges/interfaces/IUniswapExchange.sol b/src/exchanges/interfaces/IUniswapExchange.sol
new file mode 100644
index 00000000..2fddff33
--- /dev/null
+++ b/src/exchanges/interfaces/IUniswapExchange.sol
@@ -0,0 +1,41 @@
+pragma solidity 0.5.15;
+
+/// @dev Minimal interface for our interactions with UniswapExchange
+interface IUniswapExchange {
+ // Trade ETH to ERC20
+ function ethToTokenTransferInput(uint256 min_tokens, uint256 deadline, address recipient)
+ external
+ payable
+ returns (uint256 tokens_bought);
+ // Trade ERC20 to ETH
+ function tokenToEthSwapInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline)
+ external
+ returns (uint256 eth_bought);
+ // Trade ERC20 to ERC20
+ function tokenToTokenTransferInput(
+ uint256 tokens_sold,
+ uint256 min_tokens_bought,
+ uint256 min_eth_bought,
+ uint256 deadline,
+ address recipient,
+ address token_addr
+ )
+ external
+ returns (uint256 tokens_bought);
+
+ /// @dev The following functions are only used in tests
+ // Provide Liquidity
+ function addLiquidity(uint256 min_liquidity, uint256 max_tokens, uint256 deadline)
+ external
+ payable
+ returns (uint256);
+ // Get Prices
+ function getEthToTokenInputPrice(uint256 eth_sold)
+ external
+ view
+ returns (uint256 tokens_bought);
+ function getTokenToEthInputPrice(uint256 tokens_sold)
+ external
+ view
+ returns (uint256 eth_bought);
+}
diff --git a/src/exchanges/interfaces/IUniswapFactory.sol b/src/exchanges/interfaces/IUniswapFactory.sol
new file mode 100644
index 00000000..dc1829af
--- /dev/null
+++ b/src/exchanges/interfaces/IUniswapFactory.sol
@@ -0,0 +1,6 @@
+pragma solidity 0.5.15;
+
+/// @dev Minimal interface for our interactions with UniswapFactory
+interface IUniswapFactory {
+ function getExchange(address token) external view returns (address exchange);
+}
diff --git a/src/exchanges/interfaces/IZeroExV2.sol b/src/exchanges/interfaces/IZeroExV2.sol
new file mode 100644
index 00000000..56d70c9e
--- /dev/null
+++ b/src/exchanges/interfaces/IZeroExV2.sol
@@ -0,0 +1,43 @@
+pragma solidity 0.5.15;
+pragma experimental ABIEncoderV2;
+
+/// @dev Minimal interface for our interactions with the ZeroEx Exchange contract
+interface IZeroExV2 {
+ struct Order {
+ address makerAddress;
+ address takerAddress;
+ address feeRecipientAddress;
+ address senderAddress;
+ uint256 makerAssetAmount;
+ uint256 takerAssetAmount;
+ uint256 makerFee;
+ uint256 takerFee;
+ uint256 expirationTimeSeconds;
+ uint256 salt;
+ bytes makerAssetData;
+ bytes takerAssetData;
+ }
+
+ struct OrderInfo {
+ uint8 orderStatus;
+ bytes32 orderHash;
+ uint256 orderTakerAssetFilledAmount;
+ }
+
+ struct FillResults {
+ uint256 makerAssetFilledAmount;
+ uint256 takerAssetFilledAmount;
+ uint256 makerFeePaid;
+ uint256 takerFeePaid;
+ }
+
+ function ZRX_ASSET_DATA() external view returns (bytes memory);
+ function filled(bytes32) external view returns (uint256);
+ function cancelled(bytes32) external view returns (bool);
+ function getOrderInfo(Order calldata) external view returns (OrderInfo memory);
+ function getAssetProxy(bytes4) external view returns (address);
+ function isValidSignature(bytes32, address, bytes calldata) external view returns (bool);
+ function preSign(bytes32, address, bytes calldata) external;
+ function cancelOrder(Order calldata) external;
+ function fillOrder(Order calldata, uint256, bytes calldata) external returns (FillResults memory);
+}
diff --git a/src/exchanges/interfaces/IZeroExV3.sol b/src/exchanges/interfaces/IZeroExV3.sol
new file mode 100644
index 00000000..b858b458
--- /dev/null
+++ b/src/exchanges/interfaces/IZeroExV3.sol
@@ -0,0 +1,47 @@
+pragma solidity 0.5.15;
+pragma experimental ABIEncoderV2;
+
+/// @dev Minimal interface for our interactions with the ZeroEx Exchange contract
+interface IZeroExV3 {
+ struct Order {
+ address makerAddress;
+ address takerAddress;
+ address feeRecipientAddress;
+ address senderAddress;
+ uint256 makerAssetAmount;
+ uint256 takerAssetAmount;
+ uint256 makerFee;
+ uint256 takerFee;
+ uint256 expirationTimeSeconds;
+ uint256 salt;
+ bytes makerAssetData;
+ bytes takerAssetData;
+ bytes makerFeeAssetData;
+ bytes takerFeeAssetData;
+ }
+
+ struct OrderInfo {
+ uint8 orderStatus;
+ bytes32 orderHash;
+ uint256 orderTakerAssetFilledAmount;
+ }
+
+ struct FillResults {
+ uint256 makerAssetFilledAmount;
+ uint256 takerAssetFilledAmount;
+ uint256 makerFeePaid;
+ uint256 takerFeePaid;
+ uint256 protocolFeePaid;
+ }
+
+ function cancelled(bytes32) external view returns (bool);
+ function cancelOrder(Order calldata) external;
+ function filled(bytes32) external view returns (uint256);
+ function fillOrder(Order calldata, uint256, bytes calldata) external payable returns (FillResults memory);
+ function getAssetProxy(bytes4) external view returns (address);
+ function getOrderInfo(Order calldata) external view returns (OrderInfo memory);
+ function isValidOrderSignature(Order calldata, bytes calldata) external view returns (bool);
+ function preSign(bytes32) external;
+ function protocolFeeCollector() external view returns (address);
+ function protocolFeeMultiplier() external view returns (uint256);
+}
diff --git a/src/contracts/factory/Factory.sol b/src/factory/Factory.sol
similarity index 77%
rename from src/contracts/factory/Factory.sol
rename to src/factory/Factory.sol
index 2d37be6e..ec82dfce 100644
--- a/src/contracts/factory/Factory.sol
+++ b/src/factory/Factory.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
contract Factory {
@@ -12,7 +12,4 @@ contract Factory {
function isInstance(address _child) public view returns (bool) {
return childExists[_child];
}
-
- // function createInstance() returns (address);
}
-
diff --git a/src/contracts/factory/FundFactory.sol b/src/factory/FundFactory.sol
similarity index 73%
rename from src/contracts/factory/FundFactory.sol
rename to src/factory/FundFactory.sol
index 903abe91..c0abf6c1 100644
--- a/src/contracts/factory/FundFactory.sol
+++ b/src/factory/FundFactory.sol
@@ -1,17 +1,17 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
pragma experimental ABIEncoderV2;
-import "Accounting.sol";
-import "FeeManager.sol";
-import "Hub.sol";
-import "PolicyManager.sol";
-import "Participation.sol";
-import "Shares.sol";
-import "Trading.sol";
-import "Vault.sol";
-import "Version.i.sol";
-import "AmguConsumer.sol";
-import "Factory.sol";
+import "../fund/accounting/IAccounting.sol";
+import "../fund/fees/IFeeManager.sol";
+import "../fund/hub/Hub.sol";
+import "../fund/policies/IPolicyManager.sol";
+import "../fund/participation/IParticipation.sol";
+import "../fund/shares/IShares.sol";
+import "../fund/trading/ITrading.sol";
+import "../fund/vault/IVault.sol";
+import "../version/IVersion.sol";
+import "../engine/AmguConsumer.sol";
+import "./Factory.sol";
/// @notice Creates fund routes and links them together
contract FundFactory is AmguConsumer, Factory {
@@ -22,15 +22,15 @@ contract FundFactory is AmguConsumer, Factory {
address[12] routes
);
- VersionInterface public version;
- address public registry;
- AccountingFactory public accountingFactory;
- FeeManagerFactory public feeManagerFactory;
- ParticipationFactory public participationFactory;
- PolicyManagerFactory public policyManagerFactory;
- SharesFactory public sharesFactory;
- TradingFactory public tradingFactory;
- VaultFactory public vaultFactory;
+ IVersion public version;
+ Registry public associatedRegistry;
+ IAccountingFactory public accountingFactory;
+ IFeeManagerFactory public feeManagerFactory;
+ IParticipationFactory public participationFactory;
+ IPolicyManagerFactory public policyManagerFactory;
+ ISharesFactory public sharesFactory;
+ ITradingFactory public tradingFactory;
+ IVaultFactory public vaultFactory;
address[] public funds;
mapping (address => address) public managersToHubs;
@@ -43,7 +43,7 @@ contract FundFactory is AmguConsumer, Factory {
address[] exchanges;
address[] adapters;
address denominationAsset;
- address[] defaultAssets;
+ address[] defaultInvestmentAssets;
address[] fees;
uint[] feeRates;
uint[] feePeriods;
@@ -74,56 +74,58 @@ contract FundFactory is AmguConsumer, Factory {
address _vaultFactory,
address _policyManagerFactory,
address _version
- ) {
- accountingFactory = AccountingFactory(_accountingFactory);
- feeManagerFactory = FeeManagerFactory(_feeManagerFactory);
- participationFactory = ParticipationFactory(_participationFactory);
- sharesFactory = SharesFactory(_sharesFactory);
- tradingFactory = TradingFactory(_tradingFactory);
- vaultFactory = VaultFactory(_vaultFactory);
- policyManagerFactory = PolicyManagerFactory(_policyManagerFactory);
- version = VersionInterface(_version);
+ )
+ public
+ {
+ accountingFactory = IAccountingFactory(_accountingFactory);
+ feeManagerFactory = IFeeManagerFactory(_feeManagerFactory);
+ participationFactory = IParticipationFactory(_participationFactory);
+ sharesFactory = ISharesFactory(_sharesFactory);
+ tradingFactory = ITradingFactory(_tradingFactory);
+ vaultFactory = IVaultFactory(_vaultFactory);
+ policyManagerFactory = IPolicyManagerFactory(_policyManagerFactory);
+ version = IVersion(_version);
}
- function componentExists(address _component) internal returns (bool) {
+ function componentExists(address _component) internal pure returns (bool) {
return _component != address(0);
}
function beginSetup(
- string _name,
- address[] _fees,
- uint[] _feeRates,
- uint[] _feePeriods,
- address[] _exchanges,
- address[] _adapters,
+ string memory _name,
+ address[] memory _fees,
+ uint[] memory _feeRates,
+ uint[] memory _feePeriods,
+ address[] memory _exchanges,
+ address[] memory _adapters,
address _denominationAsset,
- address[] _defaultAssets
+ address[] memory _defaultInvestmentAssets
)
public
componentNotSet(managersToHubs[msg.sender])
{
- Registry(registry).reserveFundName(
+ associatedRegistry.reserveFundName(
msg.sender,
_name
);
require(
- Registry(registry).assetIsRegistered(_denominationAsset),
+ associatedRegistry.assetIsRegistered(_denominationAsset),
"Denomination asset must be registered"
);
- managersToHubs[msg.sender] = new Hub(msg.sender, _name);
+ managersToHubs[msg.sender] = address(new Hub(msg.sender, _name));
managersToSettings[msg.sender] = Settings(
_name,
_exchanges,
_adapters,
_denominationAsset,
- _defaultAssets,
+ _defaultInvestmentAssets,
_fees,
_feeRates,
_feePeriods
);
managersToRoutes[msg.sender].priceSource = priceSource();
- managersToRoutes[msg.sender].registry = registry;
+ managersToRoutes[msg.sender].registry = address(associatedRegistry);
managersToRoutes[msg.sender].version = address(version);
managersToRoutes[msg.sender].engine = engine();
managersToRoutes[msg.sender].mlnToken = mlnToken();
@@ -139,8 +141,7 @@ contract FundFactory is AmguConsumer, Factory {
managersToRoutes[msg.sender].accounting = accountingFactory.createInstance(
managersToHubs[msg.sender],
managersToSettings[msg.sender].denominationAsset,
- Registry(registry).nativeAsset(),
- managersToSettings[msg.sender].defaultAssets
+ associatedRegistry.nativeAsset()
);
}
@@ -157,7 +158,7 @@ contract FundFactory is AmguConsumer, Factory {
managersToSettings[msg.sender].fees,
managersToSettings[msg.sender].feeRates,
managersToSettings[msg.sender].feePeriods,
- registry
+ managersToRoutes[msg.sender].registry
);
}
@@ -170,7 +171,7 @@ contract FundFactory is AmguConsumer, Factory {
{
managersToRoutes[msg.sender].participation = participationFactory.createInstance(
managersToHubs[msg.sender],
- managersToSettings[msg.sender].defaultAssets,
+ managersToSettings[msg.sender].defaultInvestmentAssets,
managersToRoutes[msg.sender].registry
);
}
@@ -227,11 +228,11 @@ contract FundFactory is AmguConsumer, Factory {
}
function completeSetup() external amguPayable(false) payable {
- Hub.Routes routes = managersToRoutes[msg.sender];
+ Hub.Routes memory routes = managersToRoutes[msg.sender];
Hub hub = Hub(managersToHubs[msg.sender]);
require(!childExists[address(hub)], "Setup already complete");
require(
- componentExists(hub) &&
+ componentExists(address(hub)) &&
componentExists(routes.accounting) &&
componentExists(routes.feeManager) &&
componentExists(routes.participation) &&
@@ -258,8 +259,8 @@ contract FundFactory is AmguConsumer, Factory {
]);
hub.setRouting();
hub.setPermissions();
- funds.push(hub);
- Registry(registry).registerFund(
+ funds.push(address(hub));
+ associatedRegistry.registerFund(
address(hub),
msg.sender,
managersToSettings[msg.sender].name
@@ -267,7 +268,7 @@ contract FundFactory is AmguConsumer, Factory {
emit NewFund(
msg.sender,
- hub,
+ address(hub),
[
routes.accounting,
routes.feeManager,
@@ -289,18 +290,17 @@ contract FundFactory is AmguConsumer, Factory {
function getLastFundId() external view returns (uint) { return funds.length - 1; }
function mlnToken() public view returns (address) {
- return address(Registry(registry).mlnToken());
+ return address(associatedRegistry.mlnToken());
}
function engine() public view returns (address) {
- return address(Registry(registry).engine());
+ return address(associatedRegistry.engine());
}
function priceSource() public view returns (address) {
- return address(Registry(registry).priceSource());
+ return address(associatedRegistry.priceSource());
}
- function version() public view returns (address) { return address(version); }
- function registry() public view returns (address) { return address(registry); }
- function getExchangesInfo(address user) public view returns (address[]) {
- return (managersToSettings[user].exchanges);
+ function registry() public view returns (address) { return address(associatedRegistry); }
+ function getExchangesInfo(address user) public view returns (address[] memory) {
+ return (managersToSettings[user].exchanges);
}
}
diff --git a/src/contracts/fund/accounting/Accounting.sol b/src/fund/accounting/Accounting.sol
similarity index 82%
rename from src/contracts/fund/accounting/Accounting.sol
rename to src/fund/accounting/Accounting.sol
index 04bc6a55..5a41afb0 100644
--- a/src/contracts/fund/accounting/Accounting.sol
+++ b/src/fund/accounting/Accounting.sol
@@ -1,17 +1,19 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "StandardToken.sol";
-import "Factory.sol";
-import "PriceSource.i.sol";
-import "FeeManager.sol";
-import "Spoke.sol";
-import "Shares.sol";
-import "Trading.sol";
-import "Vault.sol";
-import "Accounting.i.sol";
-import "AmguConsumer.sol";
+import "../../dependencies/token/StandardToken.sol";
+import "../../factory/Factory.sol";
+import "../../prices/IPriceSource.sol";
+import "../fees/FeeManager.sol";
+import "../hub/Spoke.sol";
+import "../shares/Shares.sol";
+import "../trading/ITrading.sol";
+import "../vault/Vault.sol";
+import "../../engine/AmguConsumer.sol";
-contract Accounting is AccountingInterface, AmguConsumer, Spoke {
+contract Accounting is AmguConsumer, Spoke {
+
+ event AssetAddition(address indexed asset);
+ event AssetRemoval(address indexed asset);
struct Calculations {
uint gav;
@@ -31,12 +33,10 @@ contract Accounting is AccountingInterface, AmguConsumer, Spoke {
uint public DEFAULT_SHARE_PRICE;
Calculations public atLastAllocation;
- constructor(address _hub, address _denominationAsset, address _nativeAsset, address[] _defaultAssets)
+ constructor(address _hub, address _denominationAsset, address _nativeAsset)
+ public
Spoke(_hub)
{
- for (uint i = 0; i < _defaultAssets.length; i++) {
- _addAssetToOwnedAssets(_defaultAssets[i]);
- }
DENOMINATION_ASSET = _denominationAsset;
NATIVE_ASSET = _nativeAsset;
DENOMINATION_ASSET_DECIMALS = ERC20WithFields(DENOMINATION_ASSET).decimals();
@@ -47,15 +47,15 @@ contract Accounting is AccountingInterface, AmguConsumer, Spoke {
return ownedAssets.length;
}
- function assetHoldings(address _asset) public returns (uint) {
+ function assetHoldings(address _asset) public returns (uint256) {
return add(
- uint(ERC20WithFields(_asset).balanceOf(Vault(routes.vault))),
- Trading(routes.trading).updateAndGetQuantityBeingTraded(_asset)
+ uint256(ERC20WithFields(_asset).balanceOf(routes.vault)),
+ ITrading(routes.trading).updateAndGetQuantityBeingTraded(_asset)
);
}
/// @dev Returns sparse array
- function getFundHoldings() external returns (uint[], address[]) {
+ function getFundHoldings() external returns (uint[] memory, address[] memory) {
uint[] memory _quantities = new uint[](ownedAssets.length);
address[] memory _assets = new address[](ownedAssets.length);
for (uint i = 0; i < ownedAssets.length; i++) {
@@ -70,7 +70,7 @@ contract Accounting is AccountingInterface, AmguConsumer, Spoke {
function calcAssetGAV(address _queryAsset) external returns (uint) {
uint queryAssetQuantityHeld = assetHoldings(_queryAsset);
- return PriceSourceInterface(routes.priceSource).convertQuantity(
+ return IPriceSource(routes.priceSource).convertQuantity(
queryAssetQuantityHeld, _queryAsset, DENOMINATION_ASSET
);
}
@@ -88,7 +88,7 @@ contract Accounting is AccountingInterface, AmguConsumer, Spoke {
// gav as sum of mul(assetHoldings, assetPrice) with formatting: mul(mul(exchangeHoldings, exchangePrice), 10 ** shareDecimals)
gav = add(
gav,
- PriceSourceInterface(routes.priceSource).convertQuantity(
+ IPriceSource(routes.priceSource).convertQuantity(
quantityHeld, asset, DENOMINATION_ASSET
)
);
@@ -100,7 +100,7 @@ contract Accounting is AccountingInterface, AmguConsumer, Spoke {
return sub(gav, unclaimedFeesInDenominationAsset);
}
- function valuePerShare(uint totalValue, uint numShares) public view returns (uint) {
+ function valuePerShare(uint totalValue, uint numShares) public pure returns (uint) {
require(numShares > 0, "No shares to calculate value for");
return (totalValue * 10 ** uint(SHARES_DECIMALS)) / numShares;
}
@@ -156,7 +156,7 @@ contract Accounting is AccountingInterface, AmguConsumer, Spoke {
_numShares,
calcGavPerShareNetManagementFee()
) / 10 ** uint(SHARES_DECIMALS);
- return PriceSourceInterface(routes.priceSource).convertQuantity(
+ return IPriceSource(routes.priceSource).convertQuantity(
denominationAssetQuantity, DENOMINATION_ASSET, _altAsset
);
}
@@ -169,12 +169,12 @@ contract Accounting is AccountingInterface, AmguConsumer, Spoke {
payable
{
updateOwnedAssets();
- uint gav;
- uint feesInDenomination;
- uint feesInShares;
- uint nav;
- (gav, feesInDenomination, feesInShares, nav, ) = performCalculations();
- uint totalSupply = Shares(routes.shares).totalSupply();
+ uint256 gav;
+ uint256 feesInDenomination;
+ uint256 feesInShares;
+ uint256 nav;
+ (gav, feesInDenomination, feesInShares, nav,,) = performCalculations();
+ uint256 totalSupply = Shares(routes.shares).totalSupply();
FeeManager(routes.feeManager).rewardAllFees();
atLastAllocation = Calculations({
gav: gav,
@@ -192,7 +192,7 @@ contract Accounting is AccountingInterface, AmguConsumer, Spoke {
if (
assetHoldings(asset) == 0 &&
!(asset == address(DENOMINATION_ASSET)) &&
- Trading(routes.trading).openMakeOrdersAgainstAsset(asset) == 0
+ ITrading(routes.trading).getOpenMakeOrdersAgainstAsset(asset) == 0
) {
_removeFromOwnedAssets(asset);
}
@@ -241,14 +241,13 @@ contract AccountingFactory is Factory {
address indexed hub,
address indexed instance,
address denominationAsset,
- address nativeAsset,
- address[] defaultAssets
+ address nativeAsset
);
- function createInstance(address _hub, address _denominationAsset, address _nativeAsset, address[] _defaultAssets) external returns (address) {
- address accounting = new Accounting(_hub, _denominationAsset, _nativeAsset, _defaultAssets);
+ function createInstance(address _hub, address _denominationAsset, address _nativeAsset) external returns (address) {
+ address accounting = address(new Accounting(_hub, _denominationAsset, _nativeAsset));
childExists[accounting] = true;
- emit NewInstance(_hub, accounting, _denominationAsset, _nativeAsset, _defaultAssets);
+ emit NewInstance(_hub, accounting, _denominationAsset, _nativeAsset);
return accounting;
}
}
diff --git a/src/fund/accounting/IAccounting.sol b/src/fund/accounting/IAccounting.sol
new file mode 100644
index 00000000..de1e3804
--- /dev/null
+++ b/src/fund/accounting/IAccounting.sol
@@ -0,0 +1,25 @@
+pragma solidity 0.5.15;
+
+/// @notice Gives metrics about a Fund
+interface IAccounting {
+ function getOwnedAssetsLength() external view returns (uint);
+ function getFundHoldings() external returns (uint[] memory, address[] memory);
+ function calcAssetGAV(address ofAsset) external returns (uint);
+ function calcGav() external returns (uint gav);
+ function calcNav(uint gav, uint unclaimedFees) external pure returns (uint);
+ function valuePerShare(uint totalValue, uint numShares) external view returns (uint);
+ function performCalculations() external returns (
+ uint gav,
+ uint unclaimedFees,
+ uint feesInShares,
+ uint nav,
+ uint sharePrice,
+ uint gavPerShareNetManagementFee
+ );
+ function calcSharePrice() external returns (uint);
+ function calcGavPerShareNetManagementFee() external returns (uint);
+}
+
+interface IAccountingFactory {
+ function createInstance(address _hub, address _denominationAsset, address _nativeAsset) external returns (address);
+}
diff --git a/src/contracts/fund/fees/FeeManager.sol b/src/fund/fees/FeeManager.sol
similarity index 72%
rename from src/contracts/fund/fees/FeeManager.sol
rename to src/fund/fees/FeeManager.sol
index ce673753..2c1ac40f 100644
--- a/src/contracts/fund/fees/FeeManager.sol
+++ b/src/fund/fees/FeeManager.sol
@@ -1,12 +1,13 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
pragma experimental ABIEncoderV2;
-import "Fee.i.sol";
-import "Spoke.sol";
-import "Shares.sol";
-import "Factory.sol";
-import "Registry.sol";
-import "math.sol";
+import "./IFee.sol";
+import "../hub/Spoke.sol";
+import "../shares/Shares.sol";
+import "../../factory/Factory.sol";
+import "../../version/Registry.sol";
+import "../../dependencies/DSMath.sol";
+import "./IFeeManager.sol";
/// @notice Manages and allocates fees for a particular fund
contract FeeManager is DSMath, Spoke {
@@ -20,10 +21,10 @@ contract FeeManager is DSMath, Spoke {
uint feePeriod;
}
- Fee[] public fees;
+ IFee[] public fees;
mapping (address => bool) public feeIsRegistered;
- constructor(address _hub, address _denominationAsset, address[] _fees, uint[] _rates, uint[] _periods, address _registry) Spoke(_hub) public {
+ constructor(address _hub, address _denominationAsset, address[] memory _fees, uint[] memory _rates, uint[] memory _periods, address _registry) Spoke(_hub) public {
for (uint i = 0; i < _fees.length; i++) {
require(
Registry(_registry).isFeeRegistered(_fees[i]),
@@ -48,12 +49,12 @@ contract FeeManager is DSMath, Spoke {
function register(address feeAddress, uint feeRate, uint feePeriod, address denominationAsset) internal {
require(!feeIsRegistered[feeAddress], "Fee already registered");
feeIsRegistered[feeAddress] = true;
- fees.push(Fee(feeAddress));
- Fee(feeAddress).initializeForUser(feeRate, feePeriod, denominationAsset); // initialize state
+ fees.push(IFee(feeAddress));
+ IFee(feeAddress).initializeForUser(feeRate, feePeriod, denominationAsset); // initialize state
emit FeeRegistration(feeAddress);
}
- function totalFeeAmount() public view returns (uint total) {
+ function totalFeeAmount() external returns (uint total) {
for (uint i = 0; i < fees.length; i++) {
total = add(total, fees[i].feeAmount());
}
@@ -61,8 +62,8 @@ contract FeeManager is DSMath, Spoke {
}
/// @dev Shares to be inflated after update state
- function _rewardFee(Fee fee) internal {
- require(feeIsRegistered[fee], "Fee is not registered");
+ function _rewardFee(IFee fee) internal {
+ require(feeIsRegistered[address(fee)], "Fee is not registered");
uint rewardShares = fee.feeAmount();
fee.updateState();
Shares(routes.shares).createFor(hub.manager(), rewardShares);
@@ -86,14 +87,14 @@ contract FeeManager is DSMath, Spoke {
/// @dev Convenience function
/// @dev Convention that management fee is 0
- function managementFeeAmount() public view returns (uint) {
+ function managementFeeAmount() external returns (uint) {
if (fees.length < 1) return 0;
return fees[0].feeAmount();
}
/// @dev Convenience function
/// @dev Convention that performace fee is 1
- function performanceFeeAmount() public view returns (uint) {
+ function performanceFeeAmount() external returns (uint) {
if (fees.length < 2) return 0;
return fees[1].feeAmount();
}
@@ -103,15 +104,16 @@ contract FeeManagerFactory is Factory {
function createInstance(
address _hub,
address _denominationAsset,
- address[] _fees,
- uint[] _feeRates,
- uint[] _feePeriods,
+ address[] memory _fees,
+ uint[] memory _feeRates,
+ uint[] memory _feePeriods,
address _registry
) public returns (address) {
- address feeManager = new FeeManager(_hub, _denominationAsset, _fees, _feeRates, _feePeriods, _registry);
+ address feeManager = address(
+ new FeeManager(_hub, _denominationAsset, _fees, _feeRates, _feePeriods, _registry)
+ );
childExists[feeManager] = true;
emit NewInstance(_hub, feeManager);
return feeManager;
}
}
-
diff --git a/src/contracts/fund/fees/Fee.i.sol b/src/fund/fees/IFee.sol
similarity index 71%
rename from src/contracts/fund/fees/Fee.i.sol
rename to src/fund/fees/IFee.sol
index 9ffdf5e6..cbe05183 100644
--- a/src/contracts/fund/fees/Fee.i.sol
+++ b/src/fund/fees/IFee.sol
@@ -1,10 +1,11 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
/// @dev Exposes "feeAmount", which maps fund state and fee state to uint
+/// @dev Notice that "feeAmount" *may* change contract state
/// @dev Also exposes "updateState", which changes fee's internal state
-interface Fee {
- function feeAmount() public view returns (uint);
+interface IFee {
function initializeForUser(uint feeRate, uint feePeriod, address denominationAsset) external;
+ function feeAmount() external returns (uint);
function updateState() external;
/// @notice Used to enforce a convention
diff --git a/src/fund/fees/IFeeManager.sol b/src/fund/fees/IFeeManager.sol
new file mode 100644
index 00000000..899c5203
--- /dev/null
+++ b/src/fund/fees/IFeeManager.sol
@@ -0,0 +1,12 @@
+pragma solidity 0.5.15;
+
+interface IFeeManagerFactory {
+ function createInstance(
+ address _hub,
+ address _denominationAsset,
+ address[] calldata _fees,
+ uint[] calldata _feeRates,
+ uint[] calldata _feePeriods,
+ address _registry
+ ) external returns (address);
+}
diff --git a/src/contracts/fund/fees/ManagementFee.sol b/src/fund/fees/ManagementFee.sol
similarity index 74%
rename from src/contracts/fund/fees/ManagementFee.sol
rename to src/fund/fees/ManagementFee.sol
index c1cfeaff..a8cd684d 100644
--- a/src/contracts/fund/fees/ManagementFee.sol
+++ b/src/fund/fees/ManagementFee.sol
@@ -1,26 +1,25 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "Fee.i.sol";
-import "FeeManager.sol";
-import "Hub.sol";
-import "Shares.sol";
-import "math.sol";
+import "./FeeManager.sol";
+import "../hub/Hub.sol";
+import "../shares/Shares.sol";
+import "../../dependencies/DSMath.sol";
-contract ManagementFee is DSMath, Fee {
+contract ManagementFee is DSMath {
uint public DIVISOR = 10 ** 18;
mapping (address => uint) public managementFeeRate;
mapping (address => uint) public lastPayoutTime;
- function feeAmount() public view returns (uint feeInShares) {
+ function feeAmount() external view returns (uint feeInShares) {
Hub hub = FeeManager(msg.sender).hub();
Shares shares = Shares(hub.shares());
if (shares.totalSupply() == 0 || managementFeeRate[msg.sender] == 0) {
feeInShares = 0;
} else {
uint timePassed = sub(block.timestamp, lastPayoutTime[msg.sender]);
- uint preDilutionFeeShares = mul(mul(shares.totalSupply(), managementFeeRate[msg.sender]) / DIVISOR, timePassed) / 1 years;
+ uint preDilutionFeeShares = mul(mul(shares.totalSupply(), managementFeeRate[msg.sender]) / DIVISOR, timePassed) / 365 days;
feeInShares =
mul(preDilutionFeeShares, shares.totalSupply()) /
sub(shares.totalSupply(), preDilutionFeeShares);
@@ -38,7 +37,7 @@ contract ManagementFee is DSMath, Fee {
lastPayoutTime[msg.sender] = block.timestamp;
}
- function identifier() external view returns (uint) {
+ function identifier() external pure returns (uint) {
return 0;
}
}
diff --git a/src/contracts/fund/fees/PerformanceFee.sol b/src/fund/fees/PerformanceFee.sol
similarity index 91%
rename from src/contracts/fund/fees/PerformanceFee.sol
rename to src/fund/fees/PerformanceFee.sol
index 3bd1f344..b62b1323 100644
--- a/src/contracts/fund/fees/PerformanceFee.sol
+++ b/src/fund/fees/PerformanceFee.sol
@@ -1,13 +1,12 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "Fee.i.sol";
-import "FeeManager.sol";
-import "Accounting.sol";
-import "Hub.sol";
-import "Shares.sol";
-import "math.sol";
+import "./FeeManager.sol";
+import "../accounting/Accounting.sol";
+import "../hub/Hub.sol";
+import "../shares/Shares.sol";
+import "../../dependencies/DSMath.sol";
-contract PerformanceFee is DSMath, Fee {
+contract PerformanceFee is DSMath {
event HighWaterMarkUpdate(address indexed feeManager, uint indexed hwm);
@@ -31,7 +30,7 @@ contract PerformanceFee is DSMath, Fee {
}
/// @notice Assumes management fee is zero
- function feeAmount() public view returns (uint feeInShares) {
+ function feeAmount() external returns (uint feeInShares) {
Hub hub = FeeManager(msg.sender).hub();
Accounting accounting = Accounting(hub.accounting());
Shares shares = Shares(hub.shares());
@@ -92,7 +91,7 @@ contract PerformanceFee is DSMath, Fee {
emit HighWaterMarkUpdate(msg.sender, currentGavPerShare);
}
- function identifier() external view returns (uint) {
+ function identifier() external pure returns (uint) {
return 1;
}
}
diff --git a/src/contracts/fund/hub/Hub.sol b/src/fund/hub/Hub.sol
similarity index 94%
rename from src/contracts/fund/hub/Hub.sol
rename to src/fund/hub/Hub.sol
index bf85de42..0dff6cbb 100644
--- a/src/contracts/fund/hub/Hub.sol
+++ b/src/fund/hub/Hub.sol
@@ -1,7 +1,7 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "guard.sol";
-import "Spoke.sol";
+import "../../dependencies/DSGuard.sol";
+import "./Spoke.sol";
/// @notice Router for communication between components
/// @notice Has one or more Spokes
@@ -35,7 +35,7 @@ contract Hub is DSGuard {
uint public creationTime;
mapping (address => bool) public isSpoke;
- constructor(address _manager, string _name) {
+ constructor(address _manager, string memory _name) public {
creator = msg.sender;
manager = _manager;
name = _name;
@@ -53,7 +53,7 @@ contract Hub is DSGuard {
emit FundShutDown();
}
- function setSpokes(address[12] _spokes) external onlyCreator {
+ function setSpokes(address[12] calldata _spokes) external onlyCreator {
require(!spokesSet, "Spokes already set");
for (uint i = 0; i < _spokes.length; i++) {
isSpoke[_spokes[i]] = true;
@@ -109,6 +109,7 @@ contract Hub is DSGuard {
permit(manager, routes.policyManager, bytes4(keccak256('batchRegister(bytes4[],address[])')));
permit(manager, routes.participation, bytes4(keccak256('enableInvestment(address[])')));
permit(manager, routes.participation, bytes4(keccak256('disableInvestment(address[])')));
+ permit(manager, routes.trading, bytes4(keccak256('addExchange(address,address)')));
permissionsSet = true;
}
diff --git a/src/contracts/fund/hub/Spoke.sol b/src/fund/hub/Spoke.sol
similarity index 83%
rename from src/contracts/fund/hub/Spoke.sol
rename to src/fund/hub/Spoke.sol
index 79c55ada..1de598c5 100644
--- a/src/contracts/fund/hub/Spoke.sol
+++ b/src/fund/hub/Spoke.sol
@@ -1,7 +1,7 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "Hub.sol";
-import "auth.sol";
+import "./Hub.sol";
+import "../../dependencies/DSAuth.sol";
/// @notice Has one Hub
contract Spoke is DSAuth {
@@ -19,13 +19,13 @@ contract Spoke is DSAuth {
_;
}
- constructor(address _hub) {
+ constructor(address _hub) public {
hub = Hub(_hub);
setAuthority(hub);
- setOwner(hub); // temporary, to allow initialization
+ setOwner(address(hub)); // temporary, to allow initialization
}
- function initialize(address[12] _spokes) external auth {
+ function initialize(address[12] calldata _spokes) external auth {
require(msg.sender == address(hub));
require(!initialized, "Already initialized");
routes = Hub.Routes(
diff --git a/src/fund/participation/IParticipation.sol b/src/fund/participation/IParticipation.sol
new file mode 100644
index 00000000..ddcb7b24
--- /dev/null
+++ b/src/fund/participation/IParticipation.sol
@@ -0,0 +1,20 @@
+pragma solidity 0.5.15;
+
+/// @notice Investor Fund interactions
+/// @notice Handles redemptions and requests for investment
+interface IParticipation {
+ function requestInvestment(
+ uint requestedShares,
+ uint investmentAmount,
+ address investmentAsset
+ ) external payable;
+ function hasRequest(address) external view returns (bool);
+ function cancelRequest() external payable;
+ function executeRequestFor(address requestOwner) external payable;
+ function redeem() external;
+ function redeemWithConstraints(uint shareQuantity, address[] calldata requestedAssets) external;
+}
+
+interface IParticipationFactory {
+ function createInstance(address _hub, address[] calldata _defaultAssets, address _registry) external returns (address);
+}
diff --git a/src/contracts/fund/participation/Participation.sol b/src/fund/participation/Participation.sol
similarity index 79%
rename from src/contracts/fund/participation/Participation.sol
rename to src/fund/participation/Participation.sol
index e371d3c1..f4de9fb8 100644
--- a/src/contracts/fund/participation/Participation.sol
+++ b/src/fund/participation/Participation.sol
@@ -1,19 +1,48 @@
-pragma solidity ^0.4.25;
-
-import "Spoke.sol";
-import "Shares.sol";
-import "Accounting.sol";
-import "Vault.sol";
-import "ERC20.i.sol";
-import "Factory.sol";
-import "math.sol";
-import "PriceSource.i.sol";
-import "AmguConsumer.sol";
-import "Participation.i.sol";
-import "TokenUser.sol";
+pragma solidity 0.5.15;
+
+import "../vault/Vault.sol";
+import "../shares/Shares.sol";
+import "../policies/PolicyManager.sol";
+import "../hub/Spoke.sol";
+import "../accounting/Accounting.sol";
+import "../../prices/IPriceSource.sol";
+import "../../factory/Factory.sol";
+import "../../engine/AmguConsumer.sol";
+import "../../dependencies/token/IERC20.sol";
+import "../../dependencies/DSMath.sol";
+import "../../dependencies/TokenUser.sol";
/// @notice Entry and exit point for investors
-contract Participation is ParticipationInterface, TokenUser, AmguConsumer, Spoke {
+contract Participation is TokenUser, AmguConsumer, Spoke {
+ event EnableInvestment (address[] asset);
+ event DisableInvestment (address[] assets);
+
+ event InvestmentRequest (
+ address indexed requestOwner,
+ address indexed investmentAsset,
+ uint requestedShares,
+ uint investmentAmount
+ );
+
+ event RequestExecution (
+ address indexed requestOwner,
+ address indexed executor,
+ address indexed investmentAsset,
+ uint investmentAmount,
+ uint requestedShares
+ );
+
+ event CancelRequest (
+ address indexed requestOwner
+ );
+
+ event Redemption (
+ address indexed redeemer,
+ address[] assets,
+ uint[] assetQuantities,
+ uint redeemedShares
+ );
+
struct Request {
address investmentAsset;
uint investmentAmount;
@@ -30,14 +59,17 @@ contract Participation is ParticipationInterface, TokenUser, AmguConsumer, Spoke
address[] public historicalInvestors; // for information purposes only (read)
- constructor(address _hub, address[] _defaultAssets, address _registry) Spoke(_hub) {
+ constructor(address _hub, address[] memory _defaultAssets, address _registry)
+ public
+ Spoke(_hub)
+ {
routes.registry = _registry;
_enableInvestment(_defaultAssets);
}
- function() public payable {}
+ function() external payable {}
- function _enableInvestment(address[] _assets) internal {
+ function _enableInvestment(address[] memory _assets) internal {
for (uint i = 0; i < _assets.length; i++) {
require(
Registry(routes.registry).assetIsRegistered(_assets[i]),
@@ -48,11 +80,11 @@ contract Participation is ParticipationInterface, TokenUser, AmguConsumer, Spoke
emit EnableInvestment(_assets);
}
- function enableInvestment(address[] _assets) external auth {
+ function enableInvestment(address[] calldata _assets) external auth {
_enableInvestment(_assets);
}
- function disableInvestment(address[] _assets) external auth {
+ function disableInvestment(address[] calldata _assets) external auth {
for (uint i = 0; i < _assets.length; i++) {
investAllowed[_assets[i]] = false;
}
@@ -71,7 +103,7 @@ contract Participation is ParticipationInterface, TokenUser, AmguConsumer, Spoke
/// @dev Request valid if price update happened since request and not expired
/// @dev If no shares exist and not expired, request can be executed immediately
function hasValidRequest(address _who) public view returns (bool) {
- PriceSourceInterface priceSource = PriceSourceInterface(routes.priceSource);
+ IPriceSource priceSource = IPriceSource(routes.priceSource);
bool delayRespectedOrNoShares = requests[_who].timestamp < priceSource.getLastUpdate() ||
Shares(routes.shares).totalSupply() == 0;
@@ -131,25 +163,37 @@ contract Participation is ParticipationInterface, TokenUser, AmguConsumer, Spoke
);
}
- /// @notice Can only cancel when no price, request expired or fund shut down
- /// @dev Only request owner can cancel their request
- function cancelRequest() external payable amguPayable(false) {
- require(hasRequest(msg.sender), "No request to cancel");
- PriceSourceInterface priceSource = PriceSourceInterface(routes.priceSource);
- Request request = requests[msg.sender];
+ function _cancelRequestFor(address requestOwner) internal {
+ require(hasRequest(requestOwner), "No request to cancel");
+ IPriceSource priceSource = IPriceSource(routes.priceSource);
+ Request memory request = requests[requestOwner];
require(
!priceSource.hasValidPrice(request.investmentAsset) ||
- hasExpiredRequest(msg.sender) ||
+ hasExpiredRequest(requestOwner) ||
hub.isShutDown(),
"No cancellation condition was met"
);
- ERC20 investmentAsset = ERC20(request.investmentAsset);
+ IERC20 investmentAsset = IERC20(request.investmentAsset);
uint investmentAmount = request.investmentAmount;
- delete requests[msg.sender];
+ delete requests[requestOwner];
msg.sender.transfer(Registry(routes.registry).incentive());
- safeTransfer(investmentAsset, msg.sender, investmentAmount);
+ safeTransfer(address(investmentAsset), requestOwner, investmentAmount);
+
+ emit CancelRequest(requestOwner);
+ }
- emit CancelRequest(msg.sender);
+ /// @notice Can only cancel when no price, request expired or fund shut down
+ /// @dev Only request owner can cancel their request
+ function cancelRequest() external payable amguPayable(false) {
+ _cancelRequestFor(msg.sender);
+ }
+
+ function cancelRequestFor(address requestOwner)
+ external
+ payable
+ amguPayable(false)
+ {
+ _cancelRequestFor(requestOwner);
}
function executeRequestFor(address requestOwner)
@@ -164,7 +208,7 @@ contract Participation is ParticipationInterface, TokenUser, AmguConsumer, Spoke
"No valid request for this address"
);
require(
- PriceSourceInterface(routes.priceSource).hasValidPrice(request.investmentAsset),
+ IPriceSource(routes.priceSource).hasValidPrice(request.investmentAsset),
"Price not valid"
);
@@ -223,7 +267,6 @@ contract Participation is ParticipationInterface, TokenUser, AmguConsumer, Spoke
function getOwedPerformanceFees(uint shareQuantity)
public
- view
returns (uint remainingShareQuantity)
{
Shares shares = Shares(routes.shares);
@@ -258,7 +301,7 @@ contract Participation is ParticipationInterface, TokenUser, AmguConsumer, Spoke
// TODO: reconsider the scenario where the user has enough funds to force shutdown on a large trade (any way around this?)
/// @dev Redeem only selected assets (used only when an asset throws)
- function redeemWithConstraints(uint shareQuantity, address[] requestedAssets) public {
+ function redeemWithConstraints(uint shareQuantity, address[] memory requestedAssets) public {
Shares shares = Shares(routes.shares);
require(
shares.balanceOf(msg.sender) >= shareQuantity &&
@@ -268,7 +311,8 @@ contract Participation is ParticipationInterface, TokenUser, AmguConsumer, Spoke
uint owedPerformanceFees = 0;
if (
- PriceSourceInterface(routes.priceSource).hasValidPrices(requestedAssets)
+ IPriceSource(routes.priceSource).hasValidPrices(requestedAssets) &&
+ msg.sender != hub.manager()
) {
FeeManager(routes.feeManager).rewardManagementFee();
owedPerformanceFees = getOwedPerformanceFees(shareQuantity);
@@ -323,7 +367,7 @@ contract Participation is ParticipationInterface, TokenUser, AmguConsumer, Spoke
);
}
- function getHistoricalInvestors() external view returns (address[]) {
+ function getHistoricalInvestors() external view returns (address[] memory) {
return historicalInvestors;
}
}
@@ -336,11 +380,13 @@ contract ParticipationFactory is Factory {
address registry
);
- function createInstance(address _hub, address[] _defaultAssets, address _registry)
+ function createInstance(address _hub, address[] calldata _defaultAssets, address _registry)
external
returns (address)
{
- address participation = new Participation(_hub, _defaultAssets, _registry);
+ address participation = address(
+ new Participation(_hub, _defaultAssets, _registry)
+ );
childExists[participation] = true;
emit NewInstance(_hub, participation, _defaultAssets, _registry);
return participation;
diff --git a/src/contracts/fund/policies/AddressList.sol b/src/fund/policies/AddressList.sol
similarity index 80%
rename from src/contracts/fund/policies/AddressList.sol
rename to src/fund/policies/AddressList.sol
index 308d2b91..a905171a 100644
--- a/src/contracts/fund/policies/AddressList.sol
+++ b/src/fund/policies/AddressList.sol
@@ -1,6 +1,6 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "auth.sol";
+import "../../dependencies/DSAuth.sol";
/// @notice Generic AddressList
contract AddressList is DSAuth {
@@ -10,7 +10,7 @@ contract AddressList is DSAuth {
mapping(address => bool) internal list;
address[] internal mirror;
- constructor(address[] _assets) {
+ constructor(address[] memory _assets) public {
for (uint i = 0; i < _assets.length; i++) {
if (!isMember(_assets[i])) { // filter duplicates in _assets
list[_assets[i]] = true;
@@ -31,5 +31,5 @@ contract AddressList is DSAuth {
}
/// @return array of all listed asset addresses
- function getMembers() external view returns (address[]) { return mirror; }
+ function getMembers() external view returns (address[] memory) { return mirror; }
}
diff --git a/src/contracts/fund/policies/Policy.sol b/src/fund/policies/IPolicy.sol
similarity index 62%
rename from src/contracts/fund/policies/Policy.sol
rename to src/fund/policies/IPolicy.sol
index 500df7f7..1dce5b3e 100644
--- a/src/contracts/fund/policies/Policy.sol
+++ b/src/fund/policies/IPolicy.sol
@@ -1,6 +1,6 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-contract Policy {
+interface IPolicy {
enum Applied { pre, post }
// In Trading context:
@@ -9,8 +9,8 @@ contract Policy {
// In Participation context:
// address[0]: Investor address, address[3]: Investment asset
- function rule(bytes4 sig, address[5] addresses, uint[3] values, bytes32 identifier) external view returns (bool);
+ function rule(bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier) external returns (bool);
function position() external view returns (Applied);
- function identifier() external view returns (string);
+ function identifier() external view returns (string memory);
}
diff --git a/src/fund/policies/IPolicyManager.sol b/src/fund/policies/IPolicyManager.sol
new file mode 100644
index 00000000..37a0bc81
--- /dev/null
+++ b/src/fund/policies/IPolicyManager.sol
@@ -0,0 +1,7 @@
+pragma solidity 0.5.15;
+
+
+interface IPolicyManagerFactory {
+ function createInstance(address _hub) external returns (address);
+}
+
diff --git a/src/contracts/fund/policies/PolicyManager.sol b/src/fund/policies/PolicyManager.sol
similarity index 54%
rename from src/contracts/fund/policies/PolicyManager.sol
rename to src/fund/policies/PolicyManager.sol
index 13167818..a5d1400d 100644
--- a/src/contracts/fund/policies/PolicyManager.sol
+++ b/src/fund/policies/PolicyManager.sol
@@ -1,46 +1,46 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "Factory.sol";
-import "Spoke.sol";
-import "Policy.sol";
+import "../../factory/Factory.sol";
+import "../hub/Spoke.sol";
+import "./IPolicy.sol";
contract PolicyManager is Spoke {
event Registration(
bytes4 indexed sig,
- Policy.Applied position,
+ IPolicy.Applied position,
address indexed policy
);
struct Entry {
- Policy[] pre;
- Policy[] post;
+ IPolicy[] pre;
+ IPolicy[] post;
}
mapping(bytes4 => Entry) policies;
- constructor (address _hub) Spoke(_hub) {}
+ constructor (address _hub) public Spoke(_hub) {}
function register(bytes4 sig, address _policy) public auth {
- Policy.Applied position = Policy(_policy).position();
- if (position == Policy.Applied.pre) {
- policies[sig].pre.push(Policy(_policy));
- } else if (position == Policy.Applied.post) {
- policies[sig].post.push(Policy(_policy));
+ IPolicy.Applied position = IPolicy(_policy).position();
+ if (position == IPolicy.Applied.pre) {
+ policies[sig].pre.push(IPolicy(_policy));
+ } else if (position == IPolicy.Applied.post) {
+ policies[sig].post.push(IPolicy(_policy));
} else {
revert("Only pre and post allowed");
}
emit Registration(sig, position, _policy);
}
- function batchRegister(bytes4[] sig, address[] _policies) public auth {
+ function batchRegister(bytes4[] memory sig, address[] memory _policies) public auth {
require(sig.length == _policies.length, "Arrays lengths unequal");
for (uint i = 0; i < sig.length; i++) {
register(sig[i], _policies[i]);
}
}
- function PoliciesToAddresses(Policy[] storage _policies) internal view returns (address[]) {
+ function PoliciesToAddresses(IPolicy[] storage _policies) internal view returns (address[] memory) {
address[] memory res = new address[](_policies.length);
for(uint i = 0; i < _policies.length; i++) {
res[i] = address(_policies[i]);
@@ -48,31 +48,31 @@ contract PolicyManager is Spoke {
return res;
}
- function getPoliciesBySig(bytes4 sig) public view returns (address[], address[]) {
+ function getPoliciesBySig(bytes4 sig) public view returns (address[] memory, address[] memory) {
return (PoliciesToAddresses(policies[sig].pre), PoliciesToAddresses(policies[sig].post));
}
- modifier isValidPolicyBySig(bytes4 sig, address[5] addresses, uint[3] values, bytes32 identifier) {
+ modifier isValidPolicyBySig(bytes4 sig, address[5] memory addresses, uint[3] memory values, bytes32 identifier) {
preValidate(sig, addresses, values, identifier);
_;
postValidate(sig, addresses, values, identifier);
}
- modifier isValidPolicy(address[5] addresses, uint[3] values, bytes32 identifier) {
+ modifier isValidPolicy(address[5] memory addresses, uint[3] memory values, bytes32 identifier) {
preValidate(msg.sig, addresses, values, identifier);
_;
postValidate(msg.sig, addresses, values, identifier);
}
- function preValidate(bytes4 sig, address[5] addresses, uint[3] values, bytes32 identifier) view public {
+ function preValidate(bytes4 sig, address[5] memory addresses, uint[3] memory values, bytes32 identifier) public {
validate(policies[sig].pre, sig, addresses, values, identifier);
}
- function postValidate(bytes4 sig, address[5] addresses, uint[3] values, bytes32 identifier) view public {
+ function postValidate(bytes4 sig, address[5] memory addresses, uint[3] memory values, bytes32 identifier) public {
validate(policies[sig].post, sig, addresses, values, identifier);
}
- function validate(Policy[] storage aux, bytes4 sig, address[5] addresses, uint[3] values, bytes32 identifier) view internal {
+ function validate(IPolicy[] storage aux, bytes4 sig, address[5] memory addresses, uint[3] memory values, bytes32 identifier) internal {
for(uint i = 0; i < aux.length; i++) {
require(
aux[i].rule(sig, addresses, values, identifier),
@@ -83,8 +83,8 @@ contract PolicyManager is Spoke {
}
contract PolicyManagerFactory is Factory {
- function createInstance(address _hub) public returns (address) {
- address policyManager = new PolicyManager(_hub);
+ function createInstance(address _hub) external returns (address) {
+ address policyManager = address(new PolicyManager(_hub));
childExists[policyManager] = true;
emit NewInstance(_hub, policyManager);
return policyManager;
diff --git a/src/fund/policies/TradingSignatures.sol b/src/fund/policies/TradingSignatures.sol
new file mode 100644
index 00000000..a509359f
--- /dev/null
+++ b/src/fund/policies/TradingSignatures.sol
@@ -0,0 +1,6 @@
+pragma solidity 0.5.15;
+
+contract TradingSignatures {
+ bytes4 constant public MAKE_ORDER = 0x5f08e909; // makeOrderSignature
+ bytes4 constant public TAKE_ORDER = 0x63b24ef1; // takeOrderSignature
+}
diff --git a/src/contracts/fund/policies/compliance/UserWhitelist.sol b/src/fund/policies/compliance/UserWhitelist.sol
similarity index 54%
rename from src/contracts/fund/policies/compliance/UserWhitelist.sol
rename to src/fund/policies/compliance/UserWhitelist.sol
index 8c870636..1573413b 100644
--- a/src/contracts/fund/policies/compliance/UserWhitelist.sol
+++ b/src/fund/policies/compliance/UserWhitelist.sol
@@ -1,16 +1,16 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "auth.sol";
-import "Policy.sol";
+import "../../../dependencies/DSAuth.sol";
-contract UserWhitelist is Policy, DSAuth {
+contract UserWhitelist is DSAuth {
+ enum Applied { pre, post }
event ListAddition(address indexed who);
event ListRemoval(address indexed who);
mapping (address => bool) public whitelisted;
- constructor(address[] _preApproved) public {
+ constructor(address[] memory _preApproved) public {
batchAddToWhitelist(_preApproved);
}
@@ -24,23 +24,23 @@ contract UserWhitelist is Policy, DSAuth {
emit ListRemoval(_who);
}
- function batchAddToWhitelist(address[] _members) public auth {
+ function batchAddToWhitelist(address[] memory _members) public auth {
for (uint i = 0; i < _members.length; i++) {
addToWhitelist(_members[i]);
}
}
- function batchRemoveFromWhitelist(address[] _members) public auth {
+ function batchRemoveFromWhitelist(address[] memory _members) public auth {
for (uint i = 0; i < _members.length; i++) {
removeFromWhitelist(_members[i]);
}
}
- function rule(bytes4 sig, address[5] addresses, uint[3] values, bytes32 identifier) external view returns (bool) {
+ function rule(bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier) external returns (bool) {
return whitelisted[addresses[0]];
}
- function position() external view returns (Applied) { return Applied.pre; }
- function identifier() external view returns (string) { return 'UserWhitelist'; }
+ function position() external pure returns (Applied) { return Applied.pre; }
+ function identifier() external pure returns (string memory) { return 'UserWhitelist'; }
}
diff --git a/src/contracts/fund/policies/risk-management/AssetBlacklist.sol b/src/fund/policies/risk-management/AssetBlacklist.sol
similarity index 50%
rename from src/contracts/fund/policies/risk-management/AssetBlacklist.sol
rename to src/fund/policies/risk-management/AssetBlacklist.sol
index a32bf6a3..c41df600 100644
--- a/src/contracts/fund/policies/risk-management/AssetBlacklist.sol
+++ b/src/fund/policies/risk-management/AssetBlacklist.sol
@@ -1,16 +1,16 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "Policy.sol";
-import "AddressList.sol";
-import "TradingSignatures.sol";
+import "../AddressList.sol";
+import "../TradingSignatures.sol";
/// @notice Assets can be added but not removed from blacklist
-contract AssetBlacklist is TradingSignatures, AddressList, Policy {
+contract AssetBlacklist is TradingSignatures, AddressList {
+ enum Applied { pre, post }
// bytes4 constant public MAKE_ORDER = 0x79705be7; // makeOrderSignature
// bytes4 constant public TAKE_ORDER = 0xe51be6e8; // takeOrderSignature
- constructor(address[] _assets) AddressList(_assets) {}
+ constructor(address[] memory _assets) AddressList(_assets) public {}
function addToBlacklist(address _asset) external auth {
require(!isMember(_asset), "Asset already in blacklist");
@@ -18,11 +18,11 @@ contract AssetBlacklist is TradingSignatures, AddressList, Policy {
mirror.push(_asset);
}
- function rule(bytes4 sig, address[5] addresses, uint[3] values, bytes32 identifier) external view returns (bool) {
+ function rule(bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier) external returns (bool) {
address incomingToken = (sig == TAKE_ORDER) ? addresses[2] : addresses[3];
return !isMember(incomingToken);
}
- function position() external view returns (Applied) { return Applied.pre; }
- function identifier() external view returns (string) { return 'Asset blacklist'; }
+ function position() external pure returns (Applied) { return Applied.pre; }
+ function identifier() external pure returns (string memory) { return 'Asset blacklist'; }
}
diff --git a/src/contracts/fund/policies/risk-management/AssetWhitelist.sol b/src/fund/policies/risk-management/AssetWhitelist.sol
similarity index 57%
rename from src/contracts/fund/policies/risk-management/AssetWhitelist.sol
rename to src/fund/policies/risk-management/AssetWhitelist.sol
index 9fb280d8..96f3fc56 100644
--- a/src/contracts/fund/policies/risk-management/AssetWhitelist.sol
+++ b/src/fund/policies/risk-management/AssetWhitelist.sol
@@ -1,12 +1,13 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "Policy.sol";
-import "AddressList.sol";
-import "TradingSignatures.sol";
+import "../AddressList.sol";
+import "../TradingSignatures.sol";
/// @notice Assets can be removed from but not added to whitelist
-contract AssetWhitelist is TradingSignatures, AddressList, Policy {
- constructor(address[] _assets) AddressList(_assets) {}
+contract AssetWhitelist is TradingSignatures, AddressList {
+ enum Applied { pre, post }
+
+ constructor(address[] memory _assets) public AddressList(_assets) {}
function removeFromWhitelist(address _asset) external auth {
require(isMember(_asset), "Asset not in whitelist");
@@ -24,11 +25,11 @@ contract AssetWhitelist is TradingSignatures, AddressList, Policy {
}
}
- function rule(bytes4 sig, address[5] addresses, uint[3] values, bytes32 identifier) external view returns (bool) {
+ function rule(bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier) external returns (bool) {
address incomingToken = (sig == TAKE_ORDER) ? addresses[2] : addresses[3];
return isMember(incomingToken);
}
- function position() external view returns (Applied) { return Applied.pre; }
- function identifier() external view returns (string) { return 'Asset whitelist'; }
+ function position() external pure returns (Applied) { return Applied.pre; }
+ function identifier() external pure returns (string memory) { return 'Asset whitelist'; }
}
diff --git a/src/contracts/fund/policies/risk-management/MaxConcentration.sol b/src/fund/policies/risk-management/MaxConcentration.sol
similarity index 59%
rename from src/contracts/fund/policies/risk-management/MaxConcentration.sol
rename to src/fund/policies/risk-management/MaxConcentration.sol
index bc121139..4a44b12e 100644
--- a/src/contracts/fund/policies/risk-management/MaxConcentration.sol
+++ b/src/fund/policies/risk-management/MaxConcentration.sol
@@ -1,17 +1,18 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "math.sol";
-import "PriceSource.i.sol";
-import "Accounting.sol";
-import "Trading.sol";
-import "TradingSignatures.sol";
-import "Policy.sol";
+import "../../../dependencies/DSMath.sol";
+import "../../../prices/IPriceSource.sol";
+import "../../accounting/Accounting.sol";
+import "../../trading/Trading.sol";
+import "../TradingSignatures.sol";
+
+contract MaxConcentration is TradingSignatures, DSMath {
+ enum Applied { pre, post }
-contract MaxConcentration is TradingSignatures, DSMath, Policy {
uint internal constant ONE_HUNDRED_PERCENT = 10 ** 18; // 100%
uint public maxConcentration;
- constructor(uint _maxConcentration) {
+ constructor(uint _maxConcentration) public {
require(
_maxConcentration <= ONE_HUNDRED_PERCENT,
"Max concentration cannot exceed 100%"
@@ -19,9 +20,8 @@ contract MaxConcentration is TradingSignatures, DSMath, Policy {
maxConcentration = _maxConcentration;
}
- function rule(bytes4 sig, address[5] addresses, uint[3] values, bytes32 identifier)
+ function rule(bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier)
external
- view
returns (bool)
{
Accounting accounting = Accounting(Hub(Trading(msg.sender).hub()).accounting());
@@ -36,6 +36,6 @@ contract MaxConcentration is TradingSignatures, DSMath, Policy {
return concentration <= maxConcentration;
}
- function position() external view returns (Applied) { return Applied.post; }
- function identifier() external view returns (string) { return 'Max concentration'; }
+ function position() external pure returns (Applied) { return Applied.post; }
+ function identifier() external pure returns (string memory) { return 'Max concentration'; }
}
diff --git a/src/contracts/fund/policies/risk-management/MaxPositions.sol b/src/fund/policies/risk-management/MaxPositions.sol
similarity index 52%
rename from src/contracts/fund/policies/risk-management/MaxPositions.sol
rename to src/fund/policies/risk-management/MaxPositions.sol
index 4c4511b2..49873c5c 100644
--- a/src/contracts/fund/policies/risk-management/MaxPositions.sol
+++ b/src/fund/policies/risk-management/MaxPositions.sol
@@ -1,21 +1,21 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "PriceSource.i.sol";
-import "Accounting.sol";
-import "Policy.sol";
-import "Trading.sol";
-import "TradingSignatures.sol";
+import "../../../prices/IPriceSource.sol";
+import "../../accounting/Accounting.sol";
+import "../../trading/Trading.sol";
+import "../TradingSignatures.sol";
+
+contract MaxPositions is TradingSignatures {
+ enum Applied { pre, post }
-contract MaxPositions is TradingSignatures, Policy {
uint public maxPositions;
/// @dev _maxPositions = 10 means max 10 different asset tokens
/// @dev _maxPositions = 0 means no asset tokens are investable
- constructor(uint _maxPositions) { maxPositions = _maxPositions; }
+ constructor(uint _maxPositions) public { maxPositions = _maxPositions; }
- function rule(bytes4 sig, address[5] addresses, uint[3] values, bytes32 identifier)
+ function rule(bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier)
external
- view
returns (bool)
{
Accounting accounting = Accounting(Hub(Trading(msg.sender).hub()).accounting());
@@ -26,6 +26,6 @@ contract MaxPositions is TradingSignatures, Policy {
return accounting.getOwnedAssetsLength() <= maxPositions;
}
- function position() external view returns (Applied) { return Applied.post; }
- function identifier() external view returns (string) { return 'Max positions'; }
+ function position() external pure returns (Applied) { return Applied.post; }
+ function identifier() external pure returns (string memory) { return 'Max positions'; }
}
diff --git a/src/contracts/fund/policies/risk-management/PriceTolerance.sol b/src/fund/policies/risk-management/PriceTolerance.sol
similarity index 68%
rename from src/contracts/fund/policies/risk-management/PriceTolerance.sol
rename to src/fund/policies/risk-management/PriceTolerance.sol
index 948cc615..30bfa82b 100644
--- a/src/contracts/fund/policies/risk-management/PriceTolerance.sol
+++ b/src/fund/policies/risk-management/PriceTolerance.sol
@@ -1,20 +1,22 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "Hub.sol";
-import "Policy.sol";
-import "MatchingMarketAdapter.sol";
-import "PriceSource.i.sol";
-import "TradingSignatures.sol";
-import "math.sol";
+import "../../hub/Hub.sol";
+import "../../../prices/IPriceSource.sol";
+import "../TradingSignatures.sol";
+import "../../../dependencies/DSMath.sol";
+import "../../trading/Trading.sol";
+import "../../../exchanges/interfaces/IOasisDex.sol";
+
+contract PriceTolerance is TradingSignatures, DSMath {
+ enum Applied { pre, post }
-contract PriceTolerance is TradingSignatures, DSMath, Policy {
uint public tolerance;
uint constant MULTIPLIER = 10 ** 16; // to give effect of a percentage
uint constant DIVISOR = 10 ** 18;
// _tolerance: 10 equals to 10% of tolerance
- constructor(uint _tolerancePercent) {
+ constructor(uint _tolerancePercent) public {
require(_tolerancePercent <= 100, "Tolerance range is 0% - 100%");
tolerance = mul(_tolerancePercent, MULTIPLIER);
}
@@ -41,11 +43,11 @@ contract PriceTolerance is TradingSignatures, DSMath, Policy {
makerAsset,
maxTakerQuantity,
takerAsset
- ) = MatchingMarket(ofExchange).getOffer(uint(identifier));
+ ) = IOasisDex(ofExchange).getOffer(uint(identifier));
uint fillMakerQuantity = mul(fillTakerQuantity, maxMakerQuantity) / maxTakerQuantity;
- PriceSourceInterface pricefeed = PriceSourceInterface(Hub(Trading(address(msg.sender)).hub()).priceSource());
+ IPriceSource pricefeed = IPriceSource(Hub(Trading(address(msg.sender)).hub()).priceSource());
uint referencePrice;
(referencePrice,) = pricefeed.getReferencePriceInfo(takerAsset, makerAsset);
@@ -65,12 +67,12 @@ contract PriceTolerance is TradingSignatures, DSMath, Policy {
function takeGenericOrder(
address makerAsset,
address takerAsset,
- uint[3] values
+ uint[3] memory values
) public view returns (bool) {
uint fillTakerQuantity = values[2];
uint fillMakerQuantity = mul(fillTakerQuantity, values[0]) / values[1];
- PriceSourceInterface pricefeed = PriceSourceInterface(Hub(Trading(address(msg.sender)).hub()).priceSource());
+ IPriceSource pricefeed = IPriceSource(Hub(Trading(address(msg.sender)).hub()).priceSource());
uint referencePrice;
(referencePrice, ) = pricefeed.getReferencePriceInfo(takerAsset, makerAsset);
@@ -88,8 +90,8 @@ contract PriceTolerance is TradingSignatures, DSMath, Policy {
}
function takeOrder(
- address[5] addresses,
- uint[3] values,
+ address[5] memory addresses,
+ uint[3] memory values,
bytes32 identifier
) public view returns (bool) {
if (identifier == 0x0) {
@@ -100,15 +102,15 @@ contract PriceTolerance is TradingSignatures, DSMath, Policy {
}
function makeOrder(
- address[5] addresses,
- uint[3] values,
+ address[5] memory addresses,
+ uint[3] memory values,
bytes32 identifier
) public view returns (bool) {
- PriceSourceInterface pricefeed = PriceSourceInterface(Hub(Trading(address(msg.sender)).hub()).priceSource());
+ IPriceSource pricefeed = IPriceSource(Hub(Trading(address(msg.sender)).hub()).priceSource());
uint ratio;
- (ratio,) = PriceSourceInterface(pricefeed).getReferencePriceInfo(addresses[2], addresses[3]);
- uint _value = PriceSourceInterface(pricefeed).getOrderPriceInfo(addresses[2], addresses[3], values[0], values[1]);
+ (ratio,) = IPriceSource(pricefeed).getReferencePriceInfo(addresses[2], addresses[3]);
+ uint _value = IPriceSource(pricefeed).getOrderPriceInfo(addresses[2], addresses[3], values[0], values[1]);
int res = signedSafeSub(int(ratio), int(_value));
if (res < 0) {
@@ -120,10 +122,10 @@ contract PriceTolerance is TradingSignatures, DSMath, Policy {
function rule(
bytes4 sig,
- address[5] addresses,
- uint[3] values,
+ address[5] calldata addresses,
+ uint[3] calldata values,
bytes32 identifier
- ) external view returns (bool) {
+ ) external returns (bool) {
if (sig == MAKE_ORDER) {
return makeOrder(addresses, values, identifier);
} else if (sig == TAKE_ORDER) {
@@ -132,6 +134,6 @@ contract PriceTolerance is TradingSignatures, DSMath, Policy {
revert("Signature was neither MakeOrder nor TakeOrder");
}
- function position() external view returns (Applied) { return Applied.pre; }
- function identifier() external view returns (string) { return 'Price tolerance'; }
+ function position() external pure returns (Applied) { return Applied.pre; }
+ function identifier() external pure returns (string memory) { return 'Price tolerance'; }
}
diff --git a/src/fund/shares/IShares.sol b/src/fund/shares/IShares.sol
new file mode 100644
index 00000000..a5b06862
--- /dev/null
+++ b/src/fund/shares/IShares.sol
@@ -0,0 +1,12 @@
+pragma solidity 0.5.15;
+
+/// @notice Token representing ownership of the Fund
+interface IShares {
+ function createFor(address who, uint amount) external;
+ function destroyFor(address who, uint amount) external;
+}
+
+interface ISharesFactory {
+ function createInstance(address _hub) external returns (address);
+}
+
diff --git a/src/contracts/fund/shares/Shares.sol b/src/fund/shares/Shares.sol
similarity index 82%
rename from src/contracts/fund/shares/Shares.sol
rename to src/fund/shares/Shares.sol
index c4fa4108..9e712b57 100644
--- a/src/contracts/fund/shares/Shares.sol
+++ b/src/fund/shares/Shares.sol
@@ -1,16 +1,15 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "Shares.i.sol";
-import "Spoke.sol";
-import "StandardToken.sol";
-import "Factory.sol";
+import "../hub/Spoke.sol";
+import "../../dependencies/token/StandardToken.sol";
+import "../../factory/Factory.sol";
-contract Shares is Spoke, StandardToken, SharesInterface {
+contract Shares is Spoke, StandardToken {
string public symbol;
string public name;
uint8 public decimals;
- constructor(address _hub) Spoke(_hub) {
+ constructor(address _hub) public Spoke(_hub) {
name = hub.name();
symbol = "MLNF";
decimals = 18;
@@ -66,7 +65,7 @@ contract Shares is Spoke, StandardToken, SharesInterface {
contract SharesFactory is Factory {
function createInstance(address _hub) external returns (address) {
- address shares = new Shares(_hub);
+ address shares = address(new Shares(_hub));
childExists[shares] = true;
emit NewInstance(_hub, shares);
return shares;
diff --git a/src/fund/trading/ITrading.sol b/src/fund/trading/ITrading.sol
new file mode 100644
index 00000000..34e9808d
--- /dev/null
+++ b/src/fund/trading/ITrading.sol
@@ -0,0 +1,43 @@
+pragma solidity 0.5.15;
+
+pragma experimental ABIEncoderV2;
+
+// TODO: Restore indexed params
+
+/// @notice Mediation between a Fund and exchanges
+interface ITrading {
+ function callOnExchange(
+ uint exchangeIndex,
+ string calldata methodSignature,
+ address[8] calldata orderAddresses,
+ uint[8] calldata orderValues,
+ bytes[4] calldata orderData,
+ bytes32 identifier,
+ bytes calldata signature
+ ) external;
+
+ function addOpenMakeOrder(
+ address ofExchange,
+ address ofSellAsset,
+ address ofBuyAsset,
+ uint orderId,
+ uint expiryTime
+ ) external;
+
+ function removeOpenMakeOrder(
+ address ofExchange,
+ address ofSellAsset
+ ) external;
+
+ function updateAndGetQuantityBeingTraded(address _asset) external returns (uint256);
+ function getOpenMakeOrdersAgainstAsset(address _asset) external view returns (uint256);
+}
+
+interface ITradingFactory {
+ function createInstance(
+ address _hub,
+ address[] calldata _exchanges,
+ address[] calldata _adapters,
+ address _registry
+ ) external returns (address);
+}
diff --git a/src/contracts/fund/trading/Trading.sol b/src/fund/trading/Trading.sol
similarity index 71%
rename from src/contracts/fund/trading/Trading.sol
rename to src/fund/trading/Trading.sol
index 0e67aa0e..36793e4e 100644
--- a/src/contracts/fund/trading/Trading.sol
+++ b/src/fund/trading/Trading.sol
@@ -1,18 +1,28 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
pragma experimental ABIEncoderV2;
-import "Trading.i.sol";
-import "Spoke.sol";
-import "Vault.sol";
-import "PolicyManager.sol";
-import "Factory.sol";
-import "math.sol";
-import "ExchangeAdapter.sol";
-import "LibOrder.sol";
-import "Registry.sol";
-import "TokenUser.sol";
-
-contract Trading is DSMath, TokenUser, Spoke, TradingInterface {
+import "../hub/Spoke.sol";
+import "../vault/Vault.sol";
+import "../policies/PolicyManager.sol";
+import "../policies/TradingSignatures.sol";
+import "../../factory/Factory.sol";
+import "../../dependencies/DSMath.sol";
+import "../../exchanges/ExchangeAdapter.sol";
+import "../../exchanges/interfaces/IZeroExV2.sol";
+import "../../exchanges/interfaces/IZeroExV3.sol";
+import "../../version/Registry.sol";
+import "../../dependencies/TokenUser.sol";
+
+contract Trading is DSMath, TokenUser, Spoke, TradingSignatures {
+ event ExchangeMethodCall(
+ address indexed exchangeAddress,
+ string indexed methodSignature,
+ address[8] orderAddresses,
+ uint[8] orderValues,
+ bytes[4] orderData,
+ bytes32 identifier,
+ bytes signature
+ );
struct Exchange {
address exchange;
@@ -47,8 +57,9 @@ contract Trading is DSMath, TokenUser, Spoke, TradingInterface {
mapping (address => mapping(address => OpenMakeOrder)) public exchangesToOpenMakeOrders;
mapping (address => uint) public openMakeOrdersAgainstAsset;
mapping (address => bool) public isInOpenMakeOrder;
- mapping (address => uint) public makerAssetCooldown;
- mapping (bytes32 => LibOrder.Order) public orderIdToZeroExOrder;
+ mapping (address => uint) public makerAssetCooldown;
+ mapping (bytes32 => IZeroExV2.Order) internal orderIdToZeroExV2Order;
+ mapping (bytes32 => IZeroExV3.Order) internal orderIdToZeroExV3Order;
uint public constant ORDER_LIFESPAN = 1 days;
uint public constant MAKE_ORDER_COOLDOWN = 30 minutes;
@@ -60,10 +71,13 @@ contract Trading is DSMath, TokenUser, Spoke, TradingInterface {
constructor(
address _hub,
- address[] _exchanges,
- address[] _adapters,
+ address[] memory _exchanges,
+ address[] memory _adapters,
address _registry
- ) Spoke(_hub) {
+ )
+ public
+ Spoke(_hub)
+ {
routes.registry = _registry;
require(_exchanges.length == _adapters.length, "Array lengths unequal");
for (uint i = 0; i < _exchanges.length; i++) {
@@ -72,7 +86,11 @@ contract Trading is DSMath, TokenUser, Spoke, TradingInterface {
}
/// @notice Fallback function to receive ETH from WETH
- function() public payable {}
+ function() external payable {}
+
+ function addExchange(address _exchange, address _adapter) external auth {
+ _addExchange(_exchange, _adapter);
+ }
function _addExchange(
address _exchange,
@@ -106,6 +124,8 @@ contract Trading is DSMath, TokenUser, Spoke, TradingInterface {
/// @param orderAddresses [3] Order taker asset
/// @param orderAddresses [4] feeRecipientAddress
/// @param orderAddresses [5] senderAddress
+ /// @param orderAddresses [6] maker fee asset
+ /// @param orderAddresses [7] taker fee asset
/// @param orderValues [0] makerAssetAmount
/// @param orderValues [1] takerAssetAmount
/// @param orderValues [2] Maker fee
@@ -114,34 +134,36 @@ contract Trading is DSMath, TokenUser, Spoke, TradingInterface {
/// @param orderValues [5] Salt/nonce
/// @param orderValues [6] Fill amount: amount of taker token to be traded
/// @param orderValues [7] Dexy signature mode
+ /// @param orderData [0] Encoded data specific to maker asset
+ /// @param orderData [1] Encoded data specific to taker asset
+ /// @param orderData [2] Encoded data specific to maker asset fee
+ /// @param orderData [3] Encoded data specific to taker asset fee
/// @param identifier Order identifier
- /// @param makerAssetData Encoded data specific to makerAsset.
- /// @param takerAssetData Encoded data specific to takerAsset.
- /// @param signature Signature of order maker.
+ /// @param signature Signature of order maker
function callOnExchange(
uint exchangeIndex,
- string methodSignature,
- address[6] orderAddresses,
- uint[8] orderValues,
+ string memory methodSignature,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
)
public
onlyInitialized
{
- bytes4 methodSelector = bytes4(keccak256(methodSignature));
+ bytes4 methodSelector = bytes4(keccak256(bytes(methodSignature)));
require(
Registry(routes.registry).adapterMethodIsAllowed(
exchanges[exchangeIndex].adapter,
methodSelector
- )
+ ),
+ "Adapter method not allowed"
);
PolicyManager(routes.policyManager).preValidate(methodSelector, [orderAddresses[0], orderAddresses[1], orderAddresses[2], orderAddresses[3], exchanges[exchangeIndex].exchange], [orderValues[0], orderValues[1], orderValues[6]], identifier);
if (
- methodSelector == bytes4(hex'79705be7') || // make
- methodSelector == bytes4(hex'e51be6e8') // take
+ methodSelector == MAKE_ORDER ||
+ methodSelector == TAKE_ORDER
) {
require(Registry(routes.registry).assetIsRegistered(
orderAddresses[2]), 'Maker asset not registered'
@@ -149,31 +171,39 @@ contract Trading is DSMath, TokenUser, Spoke, TradingInterface {
require(Registry(routes.registry).assetIsRegistered(
orderAddresses[3]), 'Taker asset not registered'
);
+ if (orderAddresses[6] != address(0) && methodSelector == MAKE_ORDER) {
+ require(
+ Registry(routes.registry).assetIsRegistered(orderAddresses[6]),
+ 'Maker fee asset not registered'
+ );
+ }
+ if (orderAddresses[7] != address(0) && methodSelector == TAKE_ORDER) {
+ require(
+ Registry(routes.registry).assetIsRegistered(orderAddresses[7]),
+ 'Taker fee asset not registered'
+ );
+ }
}
- require(
- exchanges[exchangeIndex].adapter.delegatecall(
- abi.encodeWithSignature(
- methodSignature,
- exchanges[exchangeIndex].exchange,
- orderAddresses,
- orderValues,
- identifier,
- makerAssetData,
- takerAssetData,
- signature
- )
- ),
- "Delegated call to exchange failed"
+ (bool success, bytes memory returnData) = exchanges[exchangeIndex].adapter.delegatecall(
+ abi.encodeWithSignature(
+ methodSignature,
+ exchanges[exchangeIndex].exchange,
+ orderAddresses,
+ orderValues,
+ orderData,
+ identifier,
+ signature
+ )
);
+ require(success, string(returnData));
PolicyManager(routes.policyManager).postValidate(methodSelector, [orderAddresses[0], orderAddresses[1], orderAddresses[2], orderAddresses[3], exchanges[exchangeIndex].exchange], [orderValues[0], orderValues[1], orderValues[6]], identifier);
emit ExchangeMethodCall(
exchanges[exchangeIndex].exchange,
methodSignature,
orderAddresses,
orderValues,
+ orderData,
identifier,
- makerAssetData,
- takerAssetData,
signature
);
}
@@ -213,7 +243,7 @@ contract Trading is DSMath, TokenUser, Spoke, TradingInterface {
) internal {
if (isInOpenMakeOrder[sellAsset]) {
- makerAssetCooldown[sellAsset] = add(block.timestamp, MAKE_ORDER_COOLDOWN);
+ makerAssetCooldown[sellAsset] = add(block.timestamp, MAKE_ORDER_COOLDOWN);
address buyAsset = exchangesToOpenMakeOrders[exchange][sellAsset].buyAsset;
delete exchangesToOpenMakeOrders[exchange][sellAsset];
openMakeOrdersAgainstAsset[buyAsset] = sub(openMakeOrdersAgainstAsset[buyAsset], 1);
@@ -228,19 +258,25 @@ contract Trading is DSMath, TokenUser, Spoke, TradingInterface {
}
/// @dev Bit of Redundancy for now
- function addZeroExOrderData(
+ function addZeroExV2OrderData(
bytes32 orderId,
- LibOrder.Order zeroExOrderData
+ IZeroExV2.Order memory zeroExOrderData
) public delegateInternal {
- orderIdToZeroExOrder[orderId] = zeroExOrderData;
+ orderIdToZeroExV2Order[orderId] = zeroExOrderData;
+ }
+ function addZeroExV3OrderData(
+ bytes32 orderId,
+ IZeroExV3.Order memory zeroExOrderData
+ ) public delegateInternal {
+ orderIdToZeroExV3Order[orderId] = zeroExOrderData;
}
function orderUpdateHook(
address ofExchange,
bytes32 orderId,
UpdateType updateType,
- address[2] orderAddresses,
- uint[3] orderValues
+ address payable[2] memory orderAddresses,
+ uint[3] memory orderValues
) public delegateInternal {
// only save make/take
if (updateType == UpdateType.make || updateType == UpdateType.take) {
@@ -258,8 +294,8 @@ contract Trading is DSMath, TokenUser, Spoke, TradingInterface {
}
}
- function updateAndGetQuantityBeingTraded(address _asset) public returns (uint) {
- uint quantityHere = ERC20(_asset).balanceOf(this);
+ function updateAndGetQuantityBeingTraded(address _asset) external returns (uint) {
+ uint quantityHere = IERC20(_asset).balanceOf(address(this));
return add(updateAndGetQuantityHeldInExchange(_asset), quantityHere);
}
@@ -293,7 +329,7 @@ contract Trading is DSMath, TokenUser, Spoke, TradingInterface {
return sub(totalSellQuantity, totalSellQuantityInApprove); // Since quantity in approve is not actually in custody
}
- function returnBatchToVault(address[] _tokens) public {
+ function returnBatchToVault(address[] memory _tokens) public {
for (uint i = 0; i < _tokens.length; i++) {
returnAssetToVault(_tokens[i]);
}
@@ -304,10 +340,10 @@ contract Trading is DSMath, TokenUser, Spoke, TradingInterface {
msg.sender == address(this) || msg.sender == hub.manager() || hub.isShutDown(),
"Sender is not this contract or manager"
);
- safeTransfer(_token, routes.vault, ERC20(_token).balanceOf(this));
+ safeTransfer(_token, routes.vault, IERC20(_token).balanceOf(address(this)));
}
- function getExchangeInfo() public view returns (address[], address[], bool[]) {
+ function getExchangeInfo() public view returns (address[] memory, address[] memory, bool[] memory) {
address[] memory ofExchanges = new address[](exchanges.length);
address[] memory ofAdapters = new address[](exchanges.length);
bool[] memory takesCustody = new bool[](exchanges.length);
@@ -320,7 +356,7 @@ contract Trading is DSMath, TokenUser, Spoke, TradingInterface {
}
function getOpenOrderInfo(address ofExchange, address ofAsset) public view returns (uint, uint, uint) {
- OpenMakeOrder order = exchangesToOpenMakeOrders[ofExchange][ofAsset];
+ OpenMakeOrder memory order = exchangesToOpenMakeOrders[ofExchange][ofAsset];
return (order.id, order.expiresAt, order.orderIndex);
}
@@ -333,8 +369,16 @@ contract Trading is DSMath, TokenUser, Spoke, TradingInterface {
return (order.makerAsset, order.takerAsset, order.makerQuantity, order.takerQuantity);
}
- function getZeroExOrderDetails(bytes32 orderId) public view returns (LibOrder.Order) {
- return orderIdToZeroExOrder[orderId];
+ function getZeroExV2OrderDetails(bytes32 orderId) public view returns (IZeroExV2.Order memory) {
+ return orderIdToZeroExV2Order[orderId];
+ }
+
+ function getZeroExV3OrderDetails(bytes32 orderId) public view returns (IZeroExV3.Order memory) {
+ return orderIdToZeroExV3Order[orderId];
+ }
+
+ function getOpenMakeOrdersAgainstAsset(address _asset) external view returns (uint256) {
+ return openMakeOrdersAgainstAsset[_asset];
}
}
@@ -349,11 +393,11 @@ contract TradingFactory is Factory {
function createInstance(
address _hub,
- address[] _exchanges,
- address[] _adapters,
+ address[] memory _exchanges,
+ address[] memory _adapters,
address _registry
) public returns (address) {
- address trading = new Trading(_hub, _exchanges, _adapters, _registry);
+ address trading = address(new Trading(_hub, _exchanges, _adapters, _registry));
childExists[trading] = true;
emit NewInstance(
_hub,
diff --git a/src/fund/vault/IVault.sol b/src/fund/vault/IVault.sol
new file mode 100644
index 00000000..29d1fd4a
--- /dev/null
+++ b/src/fund/vault/IVault.sol
@@ -0,0 +1,10 @@
+pragma solidity 0.5.15;
+
+/// @notice Custody component
+interface IVault {
+ function withdraw(address token, uint amount) external;
+}
+
+interface IVaultFactory {
+ function createInstance(address _hub) external returns (address);
+}
diff --git a/src/contracts/fund/vault/Vault.sol b/src/fund/vault/Vault.sol
similarity index 52%
rename from src/contracts/fund/vault/Vault.sol
rename to src/fund/vault/Vault.sol
index 5090db64..2158e14b 100644
--- a/src/contracts/fund/vault/Vault.sol
+++ b/src/fund/vault/Vault.sol
@@ -1,14 +1,13 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "Vault.i.sol";
-import "Spoke.sol";
-import "Factory.sol";
-import "TokenUser.sol";
+import "../hub/Spoke.sol";
+import "../../factory/Factory.sol";
+import "../../dependencies/TokenUser.sol";
/// @notice Dumb custody component
-contract Vault is VaultInterface, TokenUser, Spoke {
+contract Vault is TokenUser, Spoke {
- constructor(address _hub) Spoke(_hub) {}
+ constructor(address _hub) public Spoke(_hub) {}
function withdraw(address token, uint amount) external auth {
safeTransfer(token, msg.sender, amount);
@@ -17,9 +16,9 @@ contract Vault is VaultInterface, TokenUser, Spoke {
contract VaultFactory is Factory {
function createInstance(address _hub) external returns (address) {
- address vault = new Vault(_hub);
+ address vault = address(new Vault(_hub));
childExists[vault] = true;
- NewInstance(_hub, vault);
+ emit NewInstance(_hub, vault);
return vault;
}
}
diff --git a/src/prices/IPriceSource.sol b/src/prices/IPriceSource.sol
new file mode 100644
index 00000000..9386a279
--- /dev/null
+++ b/src/prices/IPriceSource.sol
@@ -0,0 +1,28 @@
+pragma solidity 0.5.15;
+
+/// @notice Must return a value for an asset
+interface IPriceSource {
+ function getQuoteAsset() external view returns (address);
+ function getLastUpdate() external view returns (uint);
+
+ /// @notice Returns false if asset not applicable, or price not recent
+ function hasValidPrice(address) external view returns (bool);
+ function hasValidPrices(address[] calldata) external view returns (bool);
+
+ /// @notice Return the last known price, and when it was issued
+ function getPrice(address _asset) external view returns (uint price, uint timestamp);
+ function getPrices(address[] calldata _assets) external view returns (uint[] memory prices, uint[] memory timestamps);
+
+ /// @notice Get price info, and revert if not valid
+ function getPriceInfo(address _asset) external view returns (uint price, uint decimals);
+ function getInvertedPriceInfo(address ofAsset) external view returns (uint price, uint decimals);
+
+ function getReferencePriceInfo(address _base, address _quote) external view returns (uint referencePrice, uint decimal);
+ function getOrderPriceInfo(address sellAsset, address buyAsset, uint sellQuantity, uint buyQuantity) external view returns (uint orderPrice);
+ function existsPriceOnAssetPair(address sellAsset, address buyAsset) external view returns (bool isExistent);
+ function convertQuantity(
+ uint fromAssetQuantity,
+ address fromAsset,
+ address toAsset
+ ) external view returns (uint);
+}
diff --git a/src/contracts/prices/KyberPriceFeed.sol b/src/prices/KyberPriceFeed.sol
similarity index 78%
rename from src/contracts/prices/KyberPriceFeed.sol
rename to src/prices/KyberPriceFeed.sol
index 6d5ea322..6f13ab5a 100644
--- a/src/contracts/prices/KyberPriceFeed.sol
+++ b/src/prices/KyberPriceFeed.sol
@@ -1,24 +1,25 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "PriceSource.i.sol";
-import "ERC20.i.sol";
-import "thing.sol";
-import "KyberNetworkProxy.sol";
-import "Registry.sol";
+import "../dependencies/token/IERC20.sol";
+import "../dependencies/DSMath.sol";
+import "../dependencies/DSAuth.sol"; // TODO: remove? this may not be used at all
+import "../exchanges/interfaces/IKyberNetworkProxy.sol";
+import "../version/Registry.sol";
/// @title Price Feed Template
/// @author Melonport AG <team@melonport.com>
/// @notice Routes external data to smart contracts
/// @notice Where external data includes sharePrice of Melon funds
/// @notice PriceFeed operator could be staked and sharePrice input validated on chain
-contract KyberPriceFeed is PriceSourceInterface, DSThing {
+contract KyberPriceFeed is DSMath, DSAuth {
+ event PriceUpdate(address[] token, uint[] price);
address public KYBER_NETWORK_PROXY;
address public QUOTE_ASSET;
address public UPDATER;
Registry public REGISTRY;
uint public MAX_SPREAD;
- address public constant KYBER_ETH_TOKEN = 0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee;
+ address public constant KYBER_ETH_TOKEN = address(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee);
uint public constant KYBER_PRECISION = 18;
uint public constant VALIDITY_INTERVAL = 2 days;
uint public lastUpdate;
@@ -33,16 +34,19 @@ contract KyberPriceFeed is PriceSourceInterface, DSThing {
/// @dev Define and register a quote asset against which all prices are measured/based against
constructor(
- address ofRegistrar,
+ address ofRegistry,
address ofKyberNetworkProxy,
uint ofMaxSpread,
- address ofQuoteAsset
- ) {
+ address ofQuoteAsset,
+ address initialUpdater
+ )
+ public
+ {
KYBER_NETWORK_PROXY = ofKyberNetworkProxy;
MAX_SPREAD = ofMaxSpread;
QUOTE_ASSET = ofQuoteAsset;
- REGISTRY = Registry(ofRegistrar);
- UPDATER = REGISTRY.owner();
+ REGISTRY = Registry(ofRegistry);
+ UPDATER = initialUpdater;
}
/// @dev Stores zero as a convention for invalid price
@@ -56,12 +60,17 @@ contract KyberPriceFeed is PriceSourceInterface, DSThing {
for (uint i; i < assets.length; i++) {
bool isValid;
uint price;
- (isValid, price) = getKyberPrice(assets[i], QUOTE_ASSET);
+ if (assets[i] == QUOTE_ASSET) {
+ isValid = true;
+ price = 1 ether;
+ } else {
+ (isValid, price) = getKyberPrice(assets[i], QUOTE_ASSET);
+ }
newPrices[i] = isValid ? price : 0;
prices[assets[i]] = newPrices[i];
}
lastUpdate = block.timestamp;
- PriceUpdate(assets, newPrices);
+ emit PriceUpdate(assets, newPrices);
}
function setUpdater(address _updater) external {
@@ -102,17 +111,17 @@ contract KyberPriceFeed is PriceSourceInterface, DSThing {
timestamp = now;
}
- function getPrices(address[] _assets)
+ function getPrices(address[] memory _assets)
public
view
- returns (uint[], uint[])
+ returns (uint256[] memory, uint256[] memory)
{
- uint[] memory prices = new uint[](_assets.length);
+ uint[] memory newPrices = new uint[](_assets.length);
uint[] memory timestamps = new uint[](_assets.length);
for (uint i; i < _assets.length; i++) {
- (prices[i], timestamps[i]) = getPrice(_assets[i]);
+ (newPrices[i], timestamps[i]) = getPrice(_assets[i]);
}
- return (prices, timestamps);
+ return (newPrices, timestamps);
}
function hasValidPrice(address _asset)
@@ -125,7 +134,7 @@ contract KyberPriceFeed is PriceSourceInterface, DSThing {
return prices[_asset] != 0 && isRegistered && isFresh;
}
- function hasValidPrices(address[] _assets)
+ function hasValidPrices(address[] memory _assets)
public
view
returns (bool)
@@ -167,7 +176,7 @@ contract KyberPriceFeed is PriceSourceInterface, DSThing {
returns (bool isValid, uint referencePrice, uint decimals)
{
isValid = hasValidPrice(_baseAsset) && hasValidPrice(_quoteAsset);
- uint quoteDecimals = ERC20Clone(_quoteAsset).decimals();
+ uint256 quoteDecimals = ERC20WithFields(_quoteAsset).decimals();
if (prices[_quoteAsset] == 0) {
return (false, 0, 0); // return early and avoid revert
@@ -208,7 +217,7 @@ contract KyberPriceFeed is PriceSourceInterface, DSThing {
}
/// @dev Get Kyber representation of ETH if necessary
- function getKyberMaskAsset(address _asset) public returns (address) {
+ function getKyberMaskAsset(address _asset) public view returns (address) {
if (_asset == REGISTRY.nativeAsset()) {
return KYBER_ETH_TOKEN;
}
@@ -223,14 +232,14 @@ contract KyberPriceFeed is PriceSourceInterface, DSThing {
{
uint bidRate;
uint bidRateOfReversePair;
- (bidRate,) = KyberNetworkProxy(KYBER_NETWORK_PROXY).getExpectedRate(
- ERC20Clone(getKyberMaskAsset(_baseAsset)),
- ERC20Clone(getKyberMaskAsset(_quoteAsset)),
+ (bidRate,) = IKyberNetworkProxy(KYBER_NETWORK_PROXY).getExpectedRate(
+ getKyberMaskAsset(_baseAsset),
+ getKyberMaskAsset(_quoteAsset),
REGISTRY.getReserveMin(_baseAsset)
);
- (bidRateOfReversePair,) = KyberNetworkProxy(KYBER_NETWORK_PROXY).getExpectedRate(
- ERC20Clone(getKyberMaskAsset(_quoteAsset)),
- ERC20Clone(getKyberMaskAsset(_baseAsset)),
+ (bidRateOfReversePair,) = IKyberNetworkProxy(KYBER_NETWORK_PROXY).getExpectedRate(
+ getKyberMaskAsset(_quoteAsset),
+ getKyberMaskAsset(_baseAsset),
REGISTRY.getReserveMin(_quoteAsset)
);
@@ -239,22 +248,29 @@ contract KyberPriceFeed is PriceSourceInterface, DSThing {
}
uint askRate = 10 ** (KYBER_PRECISION * 2) / bidRateOfReversePair;
- // Check the the spread and average the price on both sides
- uint spreadFromKyber = mul(
- sub(askRate, bidRate),
- 10 ** uint(KYBER_PRECISION)
- ) / bidRate;
/**
- avgPriceFromKyber = (bidRate + astRate) / 2
+ Average the bid/ask prices:
+ avgPriceFromKyber = (bidRate + askRate) / 2
kyberPrice = (avgPriceFromKyber * 10^quoteDecimals) / 10^kyberPrecision
or, rearranged:
kyberPrice = ((bidRate + askRate) * 10^quoteDecimals) / 2 * 10^kyberPrecision
*/
uint kyberPrice = mul(
add(bidRate, askRate),
- 10 ** uint(ERC20Clone(_quoteAsset).decimals()) // use original quote decimals (not defined on mask)
+ 10 ** uint(ERC20WithFields(_quoteAsset).decimals()) // use original quote decimals (not defined on mask)
) / mul(2, 10 ** uint(KYBER_PRECISION));
+ // Find the "quoted spread", to inform caller whether it is below maximum
+ uint spreadFromKyber;
+ if (bidRate > askRate) {
+ spreadFromKyber = 0; // crossed market condition
+ } else {
+ spreadFromKyber = mul(
+ sub(askRate, bidRate),
+ 10 ** uint(KYBER_PRECISION)
+ ) / kyberPrice;
+ }
+
return (
spreadFromKyber <= MAX_SPREAD && bidRate != 0 && askRate != 0,
kyberPrice
@@ -278,7 +294,7 @@ contract KyberPriceFeed is PriceSourceInterface, DSThing {
returns (uint orderPrice)
{
// TODO: decimals
- return mul(buyQuantity, 10 ** uint(ERC20Clone(sellAsset).decimals())) / sellQuantity;
+ return mul(buyQuantity, 10 ** uint(ERC20WithFields(sellAsset).decimals())) / sellQuantity;
}
/// @notice Checks whether data exists for a given asset pair
diff --git a/src/version/IVersion.sol b/src/version/IVersion.sol
new file mode 100644
index 00000000..5f51a6b3
--- /dev/null
+++ b/src/version/IVersion.sol
@@ -0,0 +1,6 @@
+pragma solidity 0.5.15;
+
+interface IVersion {
+ function shutDownFund(address) external;
+}
+
diff --git a/src/contracts/version/Registry.sol b/src/version/Registry.sol
similarity index 89%
rename from src/contracts/version/Registry.sol
rename to src/version/Registry.sol
index a86309d1..c19f9c12 100644
--- a/src/contracts/version/Registry.sol
+++ b/src/version/Registry.sol
@@ -1,8 +1,8 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "auth.sol";
-import "Hub.sol";
-import "ERC20.i.sol";
+import "../dependencies/DSAuth.sol";
+import "../fund/hub/Hub.sol";
+import "../dependencies/token/IERC20.sol";
contract Registry is DSAuth {
@@ -100,14 +100,14 @@ contract Registry is DSAuth {
// METHODS
- constructor(address _postDeployOwner) {
+ constructor(address _postDeployOwner) public {
setOwner(_postDeployOwner);
}
// PUBLIC METHODS
/// @notice Whether _name has only valid characters
- function isValidFundName(string _name) public view returns (bool) {
+ function isValidFundName(string memory _name) public pure returns (bool) {
bytes memory b = bytes(_name);
if (b.length > MAX_FUND_NAME_BYTES) return false;
for (uint i; i < b.length; i++){
@@ -127,8 +127,8 @@ contract Registry is DSAuth {
}
/// @notice Whether _user can use _name for their fund
- function canUseFundName(address _user, string _name) public view returns (bool) {
- bytes32 nameHash = keccak256(_name);
+ function canUseFundName(address _user, string memory _name) public view returns (bool) {
+ bytes32 nameHash = keccak256(bytes(_name));
return (
isValidFundName(_name) &&
(
@@ -138,15 +138,15 @@ contract Registry is DSAuth {
);
}
- function reserveFundName(address _owner, string _name)
+ function reserveFundName(address _owner, string calldata _name)
external
onlyVersion
{
require(canUseFundName(_owner, _name), "Fund name cannot be used");
- fundNameHashToOwner[keccak256(_name)] = _owner;
+ fundNameHashToOwner[keccak256(bytes(_name))] = _owner;
}
- function registerFund(address _fund, address _owner, string _name)
+ function registerFund(address _fund, address _owner, string calldata _name)
external
onlyVersion
{
@@ -165,12 +165,12 @@ contract Registry is DSAuth {
/// @param _sigs Function signatures for whitelisted asset functions
function registerAsset(
address _asset,
- string _name,
- string _symbol,
- string _url,
+ string calldata _name,
+ string calldata _symbol,
+ string calldata _url,
uint _reserveMin,
- uint[] _standards,
- bytes4[] _sigs
+ uint[] calldata _standards,
+ bytes4[] calldata _sigs
) external auth {
require(registeredAssets.length < MAX_REGISTERED_ENTITIES);
require(!assetInformation[_asset].exists);
@@ -199,7 +199,7 @@ contract Registry is DSAuth {
address _exchange,
address _adapter,
bool _takesCustody,
- bytes4[] _sigs
+ bytes4[] calldata _sigs
) external auth {
require(!exchangeInformation[_adapter].exists, "Adapter already exists");
exchangeInformation[_adapter].exists = true;
@@ -273,15 +273,15 @@ contract Registry is DSAuth {
/// @param _url Url for extended information of the asset
function updateAsset(
address _asset,
- string _name,
- string _symbol,
- string _url,
+ string memory _name,
+ string memory _symbol,
+ string memory _url,
uint _reserveMin,
- uint[] _standards,
- bytes4[] _sigs
+ uint[] memory _standards,
+ bytes4[] memory _sigs
) public auth {
require(assetInformation[_asset].exists);
- Asset asset = assetInformation[_asset];
+ Asset storage asset = assetInformation[_asset];
asset.name = _name;
asset.symbol = _symbol;
asset.decimals = ERC20WithFields(_asset).decimals();
@@ -305,10 +305,10 @@ contract Registry is DSAuth {
address _exchange,
address _adapter,
bool _takesCustody,
- bytes4[] _sigs
+ bytes4[] memory _sigs
) public auth {
require(exchangeInformation[_adapter].exists, "Exchange with adapter doesn't exist");
- Exchange exchange = exchangeInformation[_adapter];
+ Exchange storage exchange = exchangeInformation[_adapter];
exchange.exchangeAddress = _exchange;
exchange.takesCustody = _takesCustody;
exchange.sigs = _sigs;
@@ -357,13 +357,13 @@ contract Registry is DSAuth {
emit ExchangeAdapterRemoval(_adapter);
}
- function registerFees(address[] _fees) external auth {
+ function registerFees(address[] calldata _fees) external auth {
for (uint i; i < _fees.length; i++) {
isFeeRegistered[_fees[i]] = true;
}
}
- function deregisterFees(address[] _fees) external auth {
+ function deregisterFees(address[] calldata _fees) external auth {
for (uint i; i < _fees.length; i++) {
delete isFeeRegistered[_fees[i]];
}
@@ -372,10 +372,10 @@ contract Registry is DSAuth {
// PUBLIC VIEW METHODS
// get asset specific information
- function getName(address _asset) external view returns (string) {
+ function getName(address _asset) external view returns (string memory) {
return assetInformation[_asset].name;
}
- function getSymbol(address _asset) external view returns (string) {
+ function getSymbol(address _asset) external view returns (string memory) {
return assetInformation[_asset].symbol;
}
function getDecimals(address _asset) external view returns (uint) {
@@ -387,7 +387,7 @@ contract Registry is DSAuth {
function assetIsRegistered(address _asset) external view returns (bool) {
return assetInformation[_asset].exists;
}
- function getRegisteredAssets() external view returns (address[]) {
+ function getRegisteredAssets() external view returns (address[] memory) {
return registeredAssets;
}
function assetMethodIsAllowed(address _asset, bytes4 _sig)
@@ -408,7 +408,7 @@ contract Registry is DSAuth {
function exchangeAdapterIsRegistered(address _adapter) external view returns (bool) {
return exchangeInformation[_adapter].exists;
}
- function getRegisteredExchangeAdapters() external view returns (address[]) {
+ function getRegisteredExchangeAdapters() external view returns (address[] memory) {
return registeredExchangeAdapters;
}
function getExchangeInformation(address _adapter)
@@ -416,20 +416,20 @@ contract Registry is DSAuth {
view
returns (address, bool)
{
- Exchange exchange = exchangeInformation[_adapter];
+ Exchange memory exchange = exchangeInformation[_adapter];
return (
exchange.exchangeAddress,
exchange.takesCustody
);
}
function exchangeForAdapter(address _adapter) external view returns (address) {
- Exchange exchange = exchangeInformation[_adapter];
+ Exchange memory exchange = exchangeInformation[_adapter];
return exchange.exchangeAddress;
}
function getAdapterFunctionSignatures(address _adapter)
public
view
- returns (bytes4[])
+ returns (bytes4[] memory)
{
return exchangeInformation[_adapter].sigs;
}
@@ -450,7 +450,7 @@ contract Registry is DSAuth {
}
// get version and fund information
- function getRegisteredVersions() external view returns (address[]) {
+ function getRegisteredVersions() external view returns (address[] memory) {
return registeredVersions;
}
@@ -458,12 +458,12 @@ contract Registry is DSAuth {
if (fundsToVersions[_who] != address(0)) {
return true; // directly from a hub
} else {
- address hub = Hub(Spoke(_who).hub());
+ Hub hub = Hub(Spoke(_who).hub());
require(
- Hub(hub).isSpoke(_who),
+ hub.isSpoke(_who),
"Call from either a spoke or hub"
);
- return fundsToVersions[hub] != address(0);
+ return fundsToVersions[address(hub)] != address(0);
}
}
diff --git a/src/contracts/version/Version.sol b/src/version/Version.sol
similarity index 82%
rename from src/contracts/version/Version.sol
rename to src/version/Version.sol
index 8736bb39..1ac03bed 100644
--- a/src/contracts/version/Version.sol
+++ b/src/version/Version.sol
@@ -1,12 +1,11 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
pragma experimental ABIEncoderV2;
-import "Version.i.sol";
-import "FundFactory.sol";
-import "Hub.sol";
+import "../factory/FundFactory.sol";
+import "../fund/hub/Hub.sol";
/// @notice Controlled by governance
-contract Version is FundFactory, DSAuth, VersionInterface {
+contract Version is FundFactory, DSAuth {
constructor(
address _accountingFactory,
@@ -19,6 +18,7 @@ contract Version is FundFactory, DSAuth, VersionInterface {
address _registry,
address _postDeployOwner
)
+ public
FundFactory(
_accountingFactory,
_feeManagerFactory,
@@ -30,7 +30,7 @@ contract Version is FundFactory, DSAuth, VersionInterface {
address(this)
)
{
- registry = _registry;
+ associatedRegistry = Registry(_registry);
setOwner(_postDeployOwner);
}
@@ -42,4 +42,3 @@ contract Version is FundFactory, DSAuth, VersionInterface {
Hub(_hub).shutDownFund();
}
}
-
diff --git a/tests/contracts/BooleanPolicy.sol b/tests/contracts/BooleanPolicy.sol
new file mode 100644
index 00000000..7e40258e
--- /dev/null
+++ b/tests/contracts/BooleanPolicy.sol
@@ -0,0 +1,23 @@
+pragma solidity 0.5.15;
+
+contract BooleanPolicy {
+ enum Applied { pre, post }
+
+ bool allowed;
+
+ function rule(bytes4 sig, address[5] calldata addresses, uint[3] calldata values, bytes32 identifier) external returns (bool) {
+ return allowed;
+ }
+
+ function position() external pure returns (Applied) { return Applied.pre; }
+}
+
+contract TruePolicy is BooleanPolicy {
+ constructor() public { allowed = true; }
+ function identifier() external pure returns (string memory) { return "TruePolicy"; }
+}
+
+contract FalsePolicy is BooleanPolicy {
+ constructor() public { allowed = false; }
+ function identifier() external pure returns (string memory) { return "FalsePolicy"; }
+}
diff --git a/src/contracts/dependencies/token/MaliciousToken.sol b/tests/contracts/MaliciousToken.sol
similarity index 81%
rename from src/contracts/dependencies/token/MaliciousToken.sol
rename to tests/contracts/MaliciousToken.sol
index baf9bb20..db531d9d 100644
--- a/src/contracts/dependencies/token/MaliciousToken.sol
+++ b/tests/contracts/MaliciousToken.sol
@@ -1,12 +1,12 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "PreminedToken.sol";
+import "main/dependencies/token/PreminedToken.sol";
contract MaliciousToken is PreminedToken {
bool public isReverting = false;
- constructor(string _symbol, uint8 _decimals, string _name)
+ constructor(string memory _symbol, uint8 _decimals, string memory _name)
public
PreminedToken(_symbol, _decimals, _name)
{}
diff --git a/src/contracts/fund/accounting/MockAccounting.sol b/tests/contracts/MockAccounting.sol
similarity index 71%
rename from src/contracts/fund/accounting/MockAccounting.sol
rename to tests/contracts/MockAccounting.sol
index 1eb13d2a..1c8e3b0b 100644
--- a/src/contracts/fund/accounting/MockAccounting.sol
+++ b/tests/contracts/MockAccounting.sol
@@ -1,6 +1,6 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "Spoke.sol";
+import "main/fund/hub/Spoke.sol";
/// @dev Balances are fake and can be set by anyone (testing)
contract MockAccounting is Spoke {
@@ -8,7 +8,7 @@ contract MockAccounting is Spoke {
uint public gav;
uint public nav;
uint public unclaimedFees;
- uint public valuePerShare;
+ uint public mockValuePerShare;
address[] public ownedAssets;
mapping (address => bool) public isInAssetList;
@@ -19,28 +19,28 @@ contract MockAccounting is Spoke {
uint public DEFAULT_SHARE_PRICE;
uint public SHARES_DECIMALS;
- constructor(address _hub, address _denominationAsset, address _nativeAsset, address[] _defaultAssets)
+ constructor(address _hub, address _denominationAsset, address _nativeAsset)
+ public
Spoke(_hub)
{
- setOwnedAssets(_defaultAssets);
DENOMINATION_ASSET = _denominationAsset;
NATIVE_ASSET = _nativeAsset;
SHARES_DECIMALS = 18;
DEFAULT_SHARE_PRICE = 10 ** uint(SHARES_DECIMALS);
}
- function setOwnedAssets(address[] _assets) public { ownedAssets = _assets; }
- function getOwnedAssetsLength() public returns (uint) { return ownedAssets.length; }
+ function setOwnedAssets(address[] memory _assets) public { ownedAssets = _assets; }
+ function getOwnedAssetsLength() public view returns (uint) { return ownedAssets.length; }
function setGav(uint _gav) public { gav = _gav; }
function setNav(uint _nav) public { nav = _nav; }
function setAssetGAV(address _asset, uint _amt) public { assetGav[_asset] = _amt; }
- function setFundHoldings(uint[] _amounts, address[] _assets) public {
+ function setFundHoldings(uint[] memory _amounts, address[] memory _assets) public {
for (uint i = 0; i < _assets.length; i++) {
held[_assets[i]] = _amounts[i];
}
}
- function getFundHoldings() public returns (uint[], address[]) {
+ function getFundHoldings() public view returns (uint[] memory, address[] memory) {
uint[] memory _quantities = new uint[](ownedAssets.length);
address[] memory _assets = new address[](ownedAssets.length);
for (uint i = 0; i < ownedAssets.length; i++) {
@@ -56,17 +56,17 @@ contract MockAccounting is Spoke {
return (_quantities, _assets);
}
- function calcGav() public returns (uint) { return gav; }
- function calcNav() public returns (uint) { return nav; }
+ function calcGav() public view returns (uint) { return gav; }
+ function calcNav() public view returns (uint) { return nav; }
- function calcAssetGAV(address _a) public returns (uint) { return assetGav[_a]; }
+ function calcAssetGAV(address _a) public view returns (uint) { return assetGav[_a]; }
function valuePerShare(uint totalValue, uint numShares) public view returns (uint) {
- return valuePerShare;
+ return mockValuePerShare;
}
function performCalculations() public view returns (uint, uint, uint, uint, uint) {
- return (gav, unclaimedFees, 0, nav, valuePerShare);
+ return (gav, unclaimedFees, 0, nav, mockValuePerShare);
}
function calcSharePrice() public view returns (uint sharePrice) {
diff --git a/src/contracts/exchanges/MockAdapter.sol b/tests/contracts/MockAdapter.sol
similarity index 65%
rename from src/contracts/exchanges/MockAdapter.sol
rename to tests/contracts/MockAdapter.sol
index ad41adab..3523c83d 100644
--- a/src/contracts/exchanges/MockAdapter.sol
+++ b/tests/contracts/MockAdapter.sol
@@ -1,9 +1,10 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
+pragma experimental ABIEncoderV2;
-import "Trading.sol";
-import "Hub.sol";
-import "Accounting.sol";
-import "ExchangeAdapter.sol";
+import "main/fund/trading/Trading.sol";
+import "main/fund/hub/Hub.sol";
+import "main/fund/accounting/Accounting.sol";
+import "main/exchanges/ExchangeAdapter.sol";
contract MockAdapter is ExchangeAdapter {
@@ -14,12 +15,11 @@ contract MockAdapter is ExchangeAdapter {
/// @notice Mock make order
function makeOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public {
Hub hub = getHub();
address makerAsset = orderAddresses[2];
@@ -31,21 +31,20 @@ contract MockAdapter is ExchangeAdapter {
targetExchange,
identifier,
Trading.UpdateType.make,
- [address(makerAsset), address(takerAsset)],
+ [address(uint160(makerAsset)), address(uint160(takerAsset))],
[makerQuantity, takerQuantity, uint(0)]
);
- Trading(address(this)).addOpenMakeOrder(targetExchange, makerAsset, takerAsset, uint(identifier), 0);
+ getTrading().addOpenMakeOrder(targetExchange, makerAsset, takerAsset, uint(identifier), 0);
}
/// @notice Mock take order
function takeOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public {
address makerAsset = orderAddresses[2];
address takerAsset = orderAddresses[3];
@@ -57,7 +56,7 @@ contract MockAdapter is ExchangeAdapter {
targetExchange,
bytes32(identifier),
Trading.UpdateType.take,
- [address(makerAsset), address(takerAsset)],
+ [address(uint160(makerAsset)), address(uint160(takerAsset))],
[makerQuantity, takerQuantity, fillTakerQuantity]
);
}
@@ -65,12 +64,11 @@ contract MockAdapter is ExchangeAdapter {
/// @notice Mock cancel order
function cancelOrder(
address targetExchange,
- address[6] orderAddresses,
- uint[8] orderValues,
+ address[8] memory orderAddresses,
+ uint[8] memory orderValues,
+ bytes[4] memory orderData,
bytes32 identifier,
- bytes makerAssetData,
- bytes takerAssetData,
- bytes signature
+ bytes memory signature
) public {
Hub hub = getHub();
address makerAsset = orderAddresses[2];
diff --git a/src/contracts/fund/fees/MockFee.sol b/tests/contracts/MockFee.sol
similarity index 77%
rename from src/contracts/fund/fees/MockFee.sol
rename to tests/contracts/MockFee.sol
index 4f071fe2..757b35a4 100644
--- a/src/contracts/fund/fees/MockFee.sol
+++ b/tests/contracts/MockFee.sol
@@ -1,15 +1,13 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "Fee.i.sol";
-
-contract MockFee is Fee {
+contract MockFee {
uint public fee;
uint public FEE_RATE;
uint public FEE_PERIOD;
uint public feeNumber;
- constructor(uint _feeNumber) {
+ constructor(uint _feeNumber) public {
feeNumber = _feeNumber;
}
@@ -17,7 +15,7 @@ contract MockFee is Fee {
fee = amount;
}
- function feeAmount() public view returns (uint feeInShares) {
+ function feeAmount() external returns (uint feeInShares) {
return fee;
}
diff --git a/src/contracts/fund/fees/MockFeeManager.sol b/tests/contracts/MockFeeManager.sol
similarity index 58%
rename from src/contracts/fund/fees/MockFeeManager.sol
rename to tests/contracts/MockFeeManager.sol
index 8c15c637..866cfe0f 100644
--- a/src/contracts/fund/fees/MockFeeManager.sol
+++ b/tests/contracts/MockFeeManager.sol
@@ -1,12 +1,11 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
pragma experimental ABIEncoderV2;
-import "Fee.i.sol";
-import "Spoke.sol";
-import "Shares.sol";
-import "Factory.sol";
-import "math.sol";
-import "AmguConsumer.sol";
+import "main/fund/hub/Spoke.sol";
+import "main/fund/shares/Shares.sol";
+import "main/factory/Factory.sol";
+import "main/dependencies/DSMath.sol";
+import "main/engine/AmguConsumer.sol";
contract MockFeeManager is DSMath, AmguConsumer, Spoke {
@@ -22,8 +21,8 @@ contract MockFeeManager is DSMath, AmguConsumer, Spoke {
constructor(
address _hub,
address _denominationAsset,
- address[] _fees,
- uint[] _periods,
+ address[] memory _fees,
+ uint[] memory _periods,
uint _rates,
address registry
) Spoke(_hub) public {}
@@ -32,6 +31,6 @@ contract MockFeeManager is DSMath, AmguConsumer, Spoke {
function setPerformanceFeeAmount(uint _amt) public { performanceFees = _amt; }
function rewardManagementFee() public { return; }
- function performanceFeeAmount() public view returns (uint) { return performanceFees; }
- function totalFeeAmount() public view returns (uint) { return totalFees; }
+ function performanceFeeAmount() external returns (uint) { return performanceFees; }
+ function totalFeeAmount() external returns (uint) { return totalFees; }
}
diff --git a/src/contracts/fund/hub/MockHub.sol b/tests/contracts/MockHub.sol
similarity index 95%
rename from src/contracts/fund/hub/MockHub.sol
rename to tests/contracts/MockHub.sol
index a3da104b..370f3566 100644
--- a/src/contracts/fund/hub/MockHub.sol
+++ b/tests/contracts/MockHub.sol
@@ -1,7 +1,7 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "guard.sol";
-import "Spoke.sol";
+import "main/dependencies/DSGuard.sol";
+import "main/fund/hub/Spoke.sol";
/// @notice Hub used for testing
contract MockHub is DSGuard {
@@ -27,13 +27,13 @@ contract MockHub is DSGuard {
function setManager(address _manager) public { manager = _manager; }
- function setName(string _name) public { name = _name; }
+ function setName(string memory _name) public { name = _name; }
function shutDownFund() public { isShutDown = true; }
function setShutDownState(bool _state) public { isShutDown = _state; }
- function setSpokes(address[12] _spokes) public {
+ function setSpokes(address[12] memory _spokes) public {
routes.accounting = _spokes[0];
routes.feeManager = _spokes[1];
routes.participation = _spokes[2];
diff --git a/src/contracts/version/MockRegistry.sol b/tests/contracts/MockRegistry.sol
similarity index 96%
rename from src/contracts/version/MockRegistry.sol
rename to tests/contracts/MockRegistry.sol
index f80a2a58..dda61c6b 100644
--- a/src/contracts/version/MockRegistry.sol
+++ b/tests/contracts/MockRegistry.sol
@@ -1,6 +1,6 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "auth.sol";
+import "main/dependencies/DSAuth.sol";
/// @dev Simplified for testing, and by default rigged to always return true
contract MockRegistry is DSAuth {
@@ -62,7 +62,7 @@ contract MockRegistry is DSAuth {
function isFundFactory(address _who) public view returns (bool) {
return _who == fundFactory;
}
- function getRegisteredAssets() public view returns (address[]) { return assets; }
+ function getRegisteredAssets() public view returns (address[] memory) { return assets; }
function getReserveMin(address _asset) public view returns (uint) { return 0; }
function isFeeRegistered(address _fee) public view returns (bool) {
return alwaysRegistered;
diff --git a/src/contracts/fund/shares/MockShares.sol b/tests/contracts/MockShares.sol
similarity index 78%
rename from src/contracts/fund/shares/MockShares.sol
rename to tests/contracts/MockShares.sol
index bfdb2a1b..37f5f8cf 100644
--- a/src/contracts/fund/shares/MockShares.sol
+++ b/tests/contracts/MockShares.sol
@@ -1,16 +1,15 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "Shares.i.sol";
-import "Spoke.sol";
-import "StandardToken.sol";
+import "main/fund/hub/Spoke.sol";
+import "main/dependencies/token/StandardToken.sol";
/// @dev Shares can be destroyed and created by anyone (testing)
-contract MockShares is Spoke, StandardToken, SharesInterface {
+contract MockShares is Spoke, StandardToken {
string public symbol;
string public name;
uint8 public decimals;
- constructor(address _hub) Spoke(_hub) {
+ constructor(address _hub) public Spoke(_hub) {
name = hub.name();
symbol = "MOCK";
decimals = 18;
diff --git a/src/contracts/version/MockVersion.sol b/tests/contracts/MockVersion.sol
similarity index 67%
rename from src/contracts/version/MockVersion.sol
rename to tests/contracts/MockVersion.sol
index e03918e0..591ea881 100644
--- a/src/contracts/version/MockVersion.sol
+++ b/tests/contracts/MockVersion.sol
@@ -1,16 +1,15 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "Version.i.sol";
-import "Hub.sol";
+import "main/fund/hub/Hub.sol";
/// @notice Version contract useful for testing
-contract MockVersion is VersionInterface {
+contract MockVersion {
uint public amguPrice;
bool public isShutDown;
function setAmguPrice(uint _price) public { amguPrice = _price; }
function securityShutDown() external { isShutDown = true; }
function shutDownFund(address _hub) external { Hub(_hub).shutDownFund(); }
- function getShutDownStatus() external returns (bool) {return isShutDown;}
+ function getShutDownStatus() external view returns (bool) {return isShutDown;}
function getAmguPrice() public view returns (uint) { return amguPrice; }
}
diff --git a/src/contracts/dependencies/PermissiveAuthority.sol b/tests/contracts/PermissiveAuthority.sol
similarity index 75%
rename from src/contracts/dependencies/PermissiveAuthority.sol
rename to tests/contracts/PermissiveAuthority.sol
index 2f33f6b5..8e5e2c60 100644
--- a/src/contracts/dependencies/PermissiveAuthority.sol
+++ b/tests/contracts/PermissiveAuthority.sol
@@ -1,6 +1,6 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "auth.sol";
+import "main/dependencies/DSAuth.sol";
contract PermissiveAuthority is DSAuthority {
function canCall(address src, address dst, bytes4 sig)
diff --git a/src/contracts/testing/SelfDestructing.sol b/tests/contracts/SelfDestructing.sol
similarity index 50%
rename from src/contracts/testing/SelfDestructing.sol
rename to tests/contracts/SelfDestructing.sol
index 22572ead..b1784888 100644
--- a/src/contracts/testing/SelfDestructing.sol
+++ b/tests/contracts/SelfDestructing.sol
@@ -1,10 +1,10 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
/// @dev Useful for testing force-sending of funds
contract SelfDestructing {
- function bequeath(address _heir) public {
+ function bequeath(address payable _heir) public {
selfdestruct(_heir);
}
- function () public payable {}
+ function () external payable {}
}
diff --git a/src/contracts/prices/TestingPriceFeed.sol b/tests/contracts/TestingPriceFeed.sol
similarity index 89%
rename from src/contracts/prices/TestingPriceFeed.sol
rename to tests/contracts/TestingPriceFeed.sol
index 7ab7ada5..b1296a70 100644
--- a/src/contracts/prices/TestingPriceFeed.sol
+++ b/tests/contracts/TestingPriceFeed.sol
@@ -1,13 +1,12 @@
-pragma solidity ^0.4.25;
+pragma solidity 0.5.15;
-import "ERC20.i.sol";
-import "PriceSource.i.sol";
-import "UpdatableFeed.i.sol";
-import "math.sol";
+import "main/dependencies/token/IERC20.sol";
+import "main/dependencies/DSMath.sol";
/// @notice Intended for testing purposes only
/// @notice Updates and exposes price information
-contract TestingPriceFeed is UpdatableFeedInterface, PriceSourceInterface, DSMath {
+contract TestingPriceFeed is DSMath {
+ event PriceUpdate(address[] token, uint[] price);
struct Data {
uint price;
@@ -22,7 +21,7 @@ contract TestingPriceFeed is UpdatableFeedInterface, PriceSourceInterface, DSMat
bool mockIsRecent = true;
bool neverValid = false;
- constructor(address _quoteAsset, uint _quoteDecimals) {
+ constructor(address _quoteAsset, uint _quoteDecimals) public {
QUOTE_ASSET = _quoteAsset;
setDecimals(_quoteAsset, _quoteDecimals);
}
@@ -31,7 +30,7 @@ contract TestingPriceFeed is UpdatableFeedInterface, PriceSourceInterface, DSMat
Input price is how much quote asset you would get
for one unit of _asset (10**assetDecimals)
*/
- function update(address[] _assets, uint[] _prices) external {
+ function update(address[] calldata _assets, uint[] calldata _prices) external {
require(_assets.length == _prices.length, "Array lengths unequal");
updateId++;
for (uint i = 0; i < _assets.length; ++i) {
@@ -41,7 +40,7 @@ contract TestingPriceFeed is UpdatableFeedInterface, PriceSourceInterface, DSMat
});
}
lastUpdate = block.timestamp;
- PriceUpdate(_assets, _prices);
+ emit PriceUpdate(_assets, _prices);
}
function getPrice(address ofAsset)
@@ -49,14 +48,14 @@ contract TestingPriceFeed is UpdatableFeedInterface, PriceSourceInterface, DSMat
view
returns (uint price, uint timestamp)
{
- Data data = assetsToPrices[ofAsset];
+ Data storage data = assetsToPrices[ofAsset];
return (data.price, data.timestamp);
}
- function getPrices(address[] ofAssets)
+ function getPrices(address[] memory ofAssets)
public
view
- returns (uint[], uint[])
+ returns (uint[] memory, uint[] memory)
{
uint[] memory prices = new uint[](ofAssets.length);
uint[] memory timestamps = new uint[](ofAssets.length);
@@ -114,7 +113,7 @@ contract TestingPriceFeed is UpdatableFeedInterface, PriceSourceInterface, DSMat
}
// needed just to get decimals for prices
- function batchSetDecimals(address[] _assets, uint[] _decimals) public {
+ function batchSetDecimals(address[] memory _assets, uint[] memory _decimals) public {
require(_assets.length == _decimals.length, "Array lengths unequal");
for (uint i = 0; i < _assets.length; i++) {
setDecimals(_assets[i], _decimals[i]);
@@ -168,7 +167,7 @@ contract TestingPriceFeed is UpdatableFeedInterface, PriceSourceInterface, DSMat
return !neverValid && price != 0;
}
- function hasValidPrices(address[] _assets)
+ function hasValidPrices(address[] memory _assets)
public
view
returns (bool)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment