Merge pull request #546 from 0xProject/feature/contracts/solidity-0.4.23

Use Solidity 0.4.23
This commit is contained in:
Amir Bandeali
2018-05-08 17:20:23 -07:00
committed by GitHub
53 changed files with 1145 additions and 699 deletions

View File

@@ -18,7 +18,7 @@
"compile:comment":
"Yarn workspaces do not link binaries correctly so we need to reference them directly https://github.com/yarnpkg/yarn/issues/3846",
"compile":
"node ../deployer/lib/src/cli.js compile --contracts ${npm_package_config_contracts} --contracts-dir src/contracts --artifacts-dir ../migrations/src/artifacts",
"node ../deployer/lib/src/cli.js compile --contracts ${npm_package_config_contracts} --should-optimize true --contracts-dir src/contracts --artifacts-dir ../migrations/src/artifacts",
"clean": "shx rm -rf ./lib ./src/contract_wrappers/generated",
"generate_contract_wrappers":
"node ../abi-gen/lib/index.js --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers && prettier --write 'src/contract_wrappers/generated/**.ts'",
@@ -30,9 +30,9 @@
},
"config": {
"abis":
"../migrations/src/artifacts/@(DummyERC20Token|Exchange|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|TestAssetProxyDispatcher|TestLibs|TestSignatureValidator|ERC20Proxy|ERC721Proxy|DummyERC721Token|LibBytes|Authorizable).json",
"../migrations/src/artifacts/@(DummyERC20Token|Exchange|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|TestAssetProxyDispatcher|TestLibs|TestSignatureValidator|ERC20Proxy|ERC721Proxy|DummyERC721Token|TestLibBytes|MixinAuthorizable).json",
"contracts":
"Exchange,DummyERC20Token,ZRXToken,WETH9,MultiSigWallet,MultiSigWalletWithTimeLock,MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,TokenRegistry,TestAssetProxyDispatcher,TestLibs,TestSignatureValidator,ERC20Proxy,ERC721Proxy,DummyERC721Token,LibBytes,Authorizable"
"Exchange,DummyERC20Token,ZRXToken,WETH9,MultiSigWallet,MultiSigWalletWithTimeLock,MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,TokenRegistry,TestAssetProxyDispatcher,TestLibs,TestSignatureValidator,ERC20Proxy,ERC721Proxy,DummyERC721Token,TestLibBytes,MixinAuthorizable"
},
"repository": {
"type": "git",

View File

@@ -16,21 +16,28 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "../../../utils/LibBytes/LibBytes.sol";
import "../../../tokens/ERC20Token/IERC20Token.sol";
import "../MixinAssetProxy.sol";
import "../../utils/LibBytes/LibBytes.sol";
import "../../tokens/ERC20Token/IERC20Token.sol";
import "./MixinAssetProxy.sol";
import "./MixinAuthorizable.sol";
contract ERC20Proxy is
LibBytes,
MixinAssetProxy
MixinAssetProxy,
MixinAuthorizable
{
// Id of this proxy.
uint8 constant PROXY_ID = 1;
// Revert reasons
string constant INVALID_METADATA_LENGTH = "Metadata must have a length of 21.";
string constant TRANSFER_FAILED = "Transfer failed.";
string constant PROXY_ID_MISMATCH = "Proxy id in metadata does not match this proxy id.";
/// @dev Internal version of `transferFrom`.
/// @param assetMetadata Encoded byte array.
/// @param from Address to transfer asset from.
@@ -44,15 +51,24 @@ contract ERC20Proxy is
internal
{
// Data must be intended for this proxy.
require(uint8(assetMetadata[0]) == PROXY_ID);
require(
uint8(assetMetadata[0]) == PROXY_ID,
PROXY_ID_MISMATCH
);
// Decode metadata.
require(assetMetadata.length == 21);
require(
assetMetadata.length == 21,
INVALID_METADATA_LENGTH
);
address token = readAddress(assetMetadata, 1);
// Transfer tokens.
bool success = IERC20Token(token).transferFrom(from, to, amount);
require(success == true);
require(
success == true,
TRANSFER_FAILED
);
}
/// @dev Gets the proxy id associated with the proxy address.

View File

@@ -16,20 +16,28 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "../../../utils/LibBytes/LibBytes.sol";
import "../../../tokens/ERC721Token/ERC721Token.sol";
import "../MixinAssetProxy.sol";
import "../../utils/LibBytes/LibBytes.sol";
import "../../tokens/ERC721Token/ERC721Token.sol";
import "./MixinAssetProxy.sol";
import "./MixinAuthorizable.sol";
contract ERC721Proxy is
LibBytes,
MixinAssetProxy
MixinAssetProxy,
MixinAuthorizable
{
// Id of this proxy.
uint8 constant PROXY_ID = 2;
// Revert reasons
string constant INVALID_TRANSFER_AMOUNT = "Transfer amount must equal 1.";
string constant INVALID_METADATA_LENGTH = "Metadata must have a length of 53.";
string constant PROXY_ID_MISMATCH = "Proxy id in metadata does not match this proxy id.";
/// @dev Internal version of `transferFrom`.
/// @param assetMetadata Encoded byte array.
/// @param from Address to transfer asset from.
@@ -43,13 +51,22 @@ contract ERC721Proxy is
internal
{
// Data must be intended for this proxy.
require(uint8(assetMetadata[0]) == PROXY_ID);
require(
uint8(assetMetadata[0]) == PROXY_ID,
PROXY_ID_MISMATCH
);
// There exists only 1 of each token.
require(amount == 1);
require(
amount == 1,
INVALID_TRANSFER_AMOUNT
);
// Decode metadata.
require(assetMetadata.length == 53);
// Decode metadata
require(
assetMetadata.length == 53,
INVALID_METADATA_LENGTH
);
address token = readAddress(assetMetadata, 1);
uint256 tokenId = readUint256(assetMetadata, 21);

View File

@@ -16,17 +16,15 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "./mixins/MAssetProxy.sol";
import "./IAssetProxy.sol";
import "../../utils/Authorizable/Authorizable.sol";
import "./mixins/MAuthorizable.sol";
contract MixinAssetProxy is
IAssetProxy,
MAssetProxy,
Authorizable
MAuthorizable,
MAssetProxy
{
/// @dev Transfers assets. Either succeeds or throws.

View File

@@ -16,46 +16,47 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "./IAuthorizable.sol";
import "../Ownable/Ownable.sol";
import "./mixins/MAuthorizable.sol";
import "../../utils/Ownable/Ownable.sol";
contract Authorizable is
contract MixinAuthorizable is
Ownable,
IAuthorizable
MAuthorizable
{
// Revert reasons
string constant SENDER_NOT_AUTHORIZED = "Sender not authorized to call this method.";
string constant TARGET_NOT_AUTHORIZED = "Target address must be authorized.";
string constant TARGET_ALREADY_AUTHORIZED = "Target must not already be authorized.";
string constant INDEX_OUT_OF_BOUNDS = "Specified array index is out of bounds.";
string constant INDEX_ADDRESS_MISMATCH = "Address found at index does not match target address.";
/// @dev Only authorized addresses can invoke functions with this modifier.
modifier onlyAuthorized {
require(authorized[msg.sender]);
_;
}
modifier targetAuthorized(address target) {
require(authorized[target]);
_;
}
modifier targetNotAuthorized(address target) {
require(!authorized[target]);
require(
authorized[msg.sender],
SENDER_NOT_AUTHORIZED
);
_;
}
mapping (address => bool) public authorized;
address[] public authorities;
/*
* Public functions
*/
/// @dev Authorizes an address.
/// @param target Address to authorize.
function addAuthorizedAddress(address target)
public
external
onlyOwner
targetNotAuthorized(target)
{
require(
!authorized[target],
TARGET_ALREADY_AUTHORIZED
);
authorized[target] = true;
authorities.push(target);
emit AuthorizedAddressAdded(target, msg.sender);
@@ -64,10 +65,14 @@ contract Authorizable is
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
function removeAuthorizedAddress(address target)
public
external
onlyOwner
targetAuthorized(target)
{
require(
authorized[target],
TARGET_NOT_AUTHORIZED
);
delete authorized[target];
for (uint i = 0; i < authorities.length; i++) {
if (authorities[i] == target) {
@@ -83,24 +88,28 @@ contract Authorizable is
/// @param target Address to remove authorization from.
/// @param index Index of target in authorities array.
function removeAuthorizedAddressAtIndex(address target, uint256 index)
public
external
{
require(index < authorities.length);
require(authorities[index] == target);
require(
index < authorities.length,
INDEX_OUT_OF_BOUNDS
);
require(
authorities[index] == target,
INDEX_ADDRESS_MISMATCH
);
delete authorized[target];
authorities[index] = authorities[authorities.length - 1];
authorities.length -= 1;
emit AuthorizedAddressRemoved(target, msg.sender);
}
/*
* Public constant functions
*/
/// @dev Gets all authorized addresses.
/// @return Array of authorized addresses.
function getAuthorizedAddresses()
public view
external
view
returns (address[] memory)
{
return authorities;

View File

@@ -16,12 +16,14 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "../../utils/Authorizable/IAuthorizable.sol";
import "./IAuthorizable.sol";
contract IAssetProxy is IAuthorizable {
contract IAssetProxy is
IAuthorizable
{
/// @dev Transfers assets. Either succeeds or throws.
/// @param assetMetadata Byte array encoded for the respective asset proxy.

View File

@@ -16,37 +16,35 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
contract IAuthorizable {
import "../../../utils/Ownable/IOwnable.sol";
contract IAuthorizable is
IOwnable
{
/// @dev Gets all authorized addresses.
/// @return Array of authorized addresses.
function getAuthorizedAddresses()
public view
external
view
returns (address[]);
/// @dev Authorizes an address.
/// @param target Address to authorize.
function addAuthorizedAddress(address target)
public;
external;
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
function removeAuthorizedAddress(address target)
public;
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)
public;
event AuthorizedAddressAdded(
address indexed target,
address indexed caller);
event AuthorizedAddressRemoved(
address indexed target,
address indexed caller);
external;
}

View File

@@ -16,10 +16,14 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
contract MAssetProxy {
import "../interfaces/IAssetProxy.sol";
contract MAssetProxy is
IAssetProxy
{
/// @dev Internal version of `transferFrom`.
/// @param assetMetadata Encoded byte array.

View File

@@ -16,20 +16,27 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
contract LibErrors {
import "../interfaces/IAuthorizable.sol";
// Error Codes
enum Errors {
ORDER_EXPIRED, // Order has already expired
ORDER_FULLY_FILLED, // Order has already been fully filled
ORDER_CANCELLED, // Order has already been cancelled
ROUNDING_ERROR_TOO_LARGE, // Rounding error too large
INSUFFICIENT_BALANCE_OR_ALLOWANCE // Insufficient balance or allowance for token transfer
}
contract MAuthorizable is
IAuthorizable
{
event ExchangeError(uint8 indexed errorId, bytes32 indexed orderHash);
// 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 { _; }
}

View File

@@ -16,7 +16,7 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "./MixinExchangeCore.sol";
@@ -36,7 +36,7 @@ contract Exchange is
{
string constant public VERSION = "2.0.1-alpha";
function Exchange(bytes memory _zrxProxyData)
constructor (bytes memory _zrxProxyData)
public
MixinExchangeCore()
MixinSignatureValidator()

View File

@@ -1,289 +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;
contract IExchange {
// Error Codes
enum Errors {
ORDER_EXPIRED, // Order has already expired
ORDER_FULLY_FILLED_OR_CANCELLED, // Order has already been fully filled or cancelled
ROUNDING_ERROR_TOO_LARGE, // Rounding error too large
INSUFFICIENT_BALANCE_OR_ALLOWANCE // Insufficient balance or allowance for token transfer
}
event LogError(uint8 indexed errorId, bytes32 indexed orderHash);
event LogFill(
address indexed maker,
address taker,
address indexed feeRecipient,
bytes makerAssetData,
bytes takerAssetData,
uint256 makerAssetFilledAmount,
uint256 takerAssetFilledAmount,
uint256 makerFeePaid,
uint256 takerFeePaid,
bytes32 indexed orderHash
);
event LogCancel(
address indexed maker,
address indexed feeRecipient,
bytes makerAssetData,
bytes takerAssetData,
uint256 makerAssetCancelledAmount,
uint256 takerAssetCancelledAmount,
bytes32 indexed orderHash
);
function ZRX_TOKEN_CONTRACT()
public view
returns (address);
function EXTERNAL_QUERY_GAS_LIMIT()
public view
returns (uint16);
function VERSION()
public view
returns (string);
function filled(bytes32)
public view
returns (uint256);
function cancelled(bytes32)
public view
returns (uint256);
/// @dev Calculates the sum of values already filled and cancelled for a given order.
/// @param orderHash The Keccak-256 hash of the given order.
/// @return Sum of values already filled and cancelled.
function getUnavailableTakerAssetAmount(bytes32 orderHash)
public view
returns (uint256 unavailableTakerAssetAmount);
/// @dev Calculates partial value given a numerator and denominator.
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to calculate partial of.
/// @return Partial value of target.
function getPartialAmount(uint256 numerator, uint256 denominator, uint256 target)
public pure
returns (uint256 partialAmount);
/// @dev Checks if rounding error > 0.1%.
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to multiply with numerator/denominator.
/// @return Rounding error is present.
function isRoundingError(uint256 numerator, uint256 denominator, uint256 target)
public pure
returns (bool isError);
/// @dev Calculates Keccak-256 hash of order with specified parameters.
/// @param orderAddresses Array of order's maker, taker, makerAsset, takerAsset, and feeRecipient.
/// @param orderValues Array of order's makerAssetAmount, takerAssetAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
/// @return Keccak-256 hash of order.
function getOrderHash(address[5] orderAddresses, uint256[6] orderValues)
public view
returns (bytes32 orderHash);
/// @dev Verifies that an order signature is valid.
/// @param signer address of signer.
/// @param hash Signed Keccak-256 hash.
/// @param v ECDSA signature parameter v.
/// @param r ECDSA signature parameters r.
/// @param s ECDSA signature parameters s.
/// @return Validity of order signature.
function isValidSignature(
address signer,
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s)
public pure
returns (bool isValid);
/// @dev Fills the input order.
/// @param orderAddresses Array of order's maker, taker, makerAsset, takerAsset, and feeRecipient.
/// @param orderValues Array of order's makerAssetAmount, takerAssetAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
/// @param takerAssetFillAmount Desired amount of takerAsset to fill.
/// @param v ECDSA signature parameter v.
/// @param r ECDSA signature parameters r.
/// @param s ECDSA signature parameters s.
/// @return Total amount of takerAsset filled in trade.
function fillOrder(
address[5] orderAddresses,
uint256[6] orderValues,
uint256 takerAssetFillAmount,
uint8 v,
bytes32 r,
bytes32 s)
public
returns (uint256 takerAssetFilledAmount);
/// @dev Cancels the input order.
/// @param orderAddresses Array of order's maker, taker, makerAsset, takerAsset, and feeRecipient.
/// @param orderValues Array of order's makerAssetAmount, takerAssetAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
/// @param takerAssetCancelAmount Desired amount of takerAsset to cancel in order.
/// @return Amount of takerAsset cancelled.
function cancelOrder(
address[5] orderAddresses,
uint256[6] orderValues,
uint256 takerAssetCancelAmount)
public
returns (uint256 takerAssetCancelledAmount);
/// @dev Cancels all orders for a specified maker up to a certain time.
/// @param salt Orders created with a salt less or equal to this value will be cancelled.
function cancelOrdersUpTo(uint256 salt)
external;
/// @dev Fills an order with specified parameters and ECDSA signature. Throws if specified amount not filled entirely.
/// @param orderAddresses Array of order's maker, taker, makerAsset, takerAsset, and feeRecipient.
/// @param orderValues Array of order's makerAssetAmount, takerAssetAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
/// @param takerAssetFillAmount Desired amount of takerAsset to fill.
/// @param v ECDSA signature parameter v.
/// @param r ECDSA signature parameters r.
/// @param s ECDSA signature parameters s.
function fillOrKillOrder(
address[5] orderAddresses,
uint256[6] orderValues,
uint256 takerAssetFillAmount,
uint8 v,
bytes32 r,
bytes32 s)
public;
/// @dev Fills an order with specified parameters and ECDSA signature. Returns false if the transaction would otherwise revert.
/// @param orderAddresses Array of order's maker, taker, makerAsset, takerAsset, and feeRecipient.
/// @param orderValues Array of order's makerAssetAmount, takerAssetAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
/// @param takerAssetFillAmount Desired amount of takerAsset to fill.
/// @param v ECDSA signature parameter v.
/// @param r ECDSA signature parameters r.
/// @param s ECDSA signature parameters s.
/// @return Success if the transaction did not revert.
/// @return Total amount of takerAsset filled in trade.
function fillOrderNoThrow(
address[5] orderAddresses,
uint256[6] orderValues,
uint256 takerAssetFillAmount,
uint8 v,
bytes32 r,
bytes32 s)
public
returns (bool success, uint256 takerAssetFilledAmount);
/// @dev Synchronously executes multiple calls of fillOrder in a single transaction.
/// @param orderAddresses Array of address arrays containing individual order addresses.
/// @param orderValues Array of uint256 arrays containing individual order values.
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to fill in orders.
/// @param v Array ECDSA signature v parameters.
/// @param r Array of ECDSA signature r parameters.
/// @param s Array of ECDSA signature s parameters.
function batchFillOrders(
address[5][] orderAddresses,
uint256[6][] orderValues,
uint256[] takerAssetFillAmounts,
uint8[] v,
bytes32[] r,
bytes32[] s)
external;
/// @dev Synchronously executes multiple calls of fillOrKill in a single transaction.
/// @param orderAddresses Array of address arrays containing individual order addresses.
/// @param orderValues Array of uint256 arrays containing individual order values.
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to fill in orders.
/// @param v Array ECDSA signature v parameters.
/// @param r Array of ECDSA signature r parameters.
/// @param s Array of ECDSA signature s parameters.
function batchFillOrKillOrders(
address[5][] orderAddresses,
uint256[6][] orderValues,
uint256[] takerAssetFillAmounts,
uint8[] v,
bytes32[] r,
bytes32[] s)
external;
/// @dev Synchronously executes multiple calls of fillOrderNoThrow in a single transaction.
/// @param orderAddresses Array of address arrays containing individual order addresses.
/// @param orderValues Array of uint256 arrays containing individual order values.
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to fill in orders.
/// @param v Array ECDSA signature v parameters.
/// @param r Array of ECDSA signature r parameters.
/// @param s Array of ECDSA signature s parameters.
function batchFillOrdersNoThrow(
address[5][] orderAddresses,
uint256[6][] orderValues,
uint256[] takerAssetFillAmounts,
uint8[] v,
bytes32[] r,
bytes32[] s)
external;
/// @dev Synchronously executes multiple fill orders in a single transaction until total takerAssetFillAmount filled.
/// @param orderAddresses Array of address arrays containing individual order addresses.
/// @param orderValues Array of uint256 arrays containing individual order values.
/// @param takerAssetFillAmount Desired total amount of takerAsset to fill in orders.
/// @param v Array ECDSA signature v parameters.
/// @param r Array of ECDSA signature r parameters.
/// @param s Array of ECDSA signature s parameters.
/// @return Total amount of takerAssetFillAmount filled in orders.
function marketFillOrders(
address[5][] orderAddresses,
uint256[6][] orderValues,
uint256 takerAssetFillAmount,
uint8[] v,
bytes32[] r,
bytes32[] s)
external
returns (uint256 totalTakerAssetFilledAmount);
/// @dev Synchronously executes multiple calls of fillOrderNoThrow in a single transaction until total takerAssetFillAmount filled.
/// @param orderAddresses Array of address arrays containing individual order addresses.
/// @param orderValues Array of uint256 arrays containing individual order values.
/// @param takerAssetFillAmount Desired total amount of takerAsset to fill in orders.
/// @param v Array ECDSA signature v parameters.
/// @param r Array of ECDSA signature r parameters.
/// @param s Array of ECDSA signature s parameters.
/// @return Total amount of takerAssetFillAmount filled in orders.
function marketFillOrdersNoThrow(
address[5][] orderAddresses,
uint256[6][] orderValues,
uint256 takerAssetFillAmount,
uint8[] v,
bytes32[] r,
bytes32[] s)
external
returns (uint256 totalTakerAssetFilledAmount);
/// @dev Synchronously cancels multiple orders in a single transaction.
/// @param orderAddresses Array of address arrays containing individual order addresses.
/// @param orderValues Array of uint256 arrays containing individual order values.
/// @param takerAssetCancelAmounts Array of desired amounts of takerAsset to cancel in orders.
function batchCancelOrders(
address[5][] orderAddresses,
uint256[6][] orderValues,
uint256[] takerAssetCancelAmounts)
external;
}

View File

@@ -16,43 +16,21 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
import "../../utils/Ownable/Ownable.sol";
import "../AssetProxy/IAssetProxy.sol";
import "../AssetProxy/interfaces/IAssetProxy.sol";
import "./libs/LibExchangeErrors.sol";
import "./mixins/MAssetProxyDispatcher.sol";
contract MixinAssetProxyDispatcher is
LibExchangeErrors,
Ownable,
MAssetProxyDispatcher
{
// Mapping from Asset Proxy Id's to their respective Asset Proxy
mapping (uint8 => IAssetProxy) public assetProxies;
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
/// @param assetMetadata Byte array encoded for the respective asset proxy.
/// @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 assetMetadata,
address from,
address to,
uint256 amount)
internal
{
// Do nothing if no amount should be transferred.
if (amount > 0) {
// Lookup asset proxy.
require(assetMetadata.length >= 1);
uint8 assetProxyId = uint8(assetMetadata[0]);
IAssetProxy assetProxy = assetProxies[assetProxyId];
// transferFrom will either succeed or throw.
assetProxy.transferFrom(assetMetadata, from, to, amount);
}
}
/// @dev Registers an asset proxy to an asset proxy id.
/// An id can only be assigned to a single proxy at a given time.
/// @param assetProxyId Id to register`newAssetProxy` under.
@@ -65,15 +43,21 @@ contract MixinAssetProxyDispatcher is
external
onlyOwner
{
// Ensure the existing asset proxy is not unintentionally overwritten.
require(oldAssetProxy == address(assetProxies[assetProxyId]));
// Ensure the existing asset proxy is not unintentionally overwritten
require(
oldAssetProxy == address(assetProxies[assetProxyId]),
OLD_ASSET_PROXY_MISMATCH
);
IAssetProxy assetProxy = IAssetProxy(newAssetProxy);
// Ensure that the id of newAssetProxy matches the passed in assetProxyId, unless it is being reset to 0.
if (newAssetProxy != address(0)) {
uint8 newAssetProxyId = assetProxy.getProxyId();
require(newAssetProxyId == assetProxyId);
require(
newAssetProxyId == assetProxyId,
NEW_ASSET_PROXY_MISMATCH
);
}
// Add asset proxy and log registration.
@@ -89,7 +73,34 @@ contract MixinAssetProxyDispatcher is
view
returns (address)
{
IAssetProxy assetProxy = assetProxies[assetProxyId];
return address(assetProxy);
address assetProxy = address(assetProxies[assetProxyId]);
return assetProxy;
}
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
/// @param assetMetadata Byte array encoded for the respective asset proxy.
/// @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 assetMetadata,
address from,
address to,
uint256 amount)
internal
{
// Do nothing if no amount should be transferred.
if (amount > 0) {
// Lookup asset proxy
require(
assetMetadata.length >= 1,
GT_ZERO_LENGTH_REQUIRED
);
uint8 assetProxyId = uint8(assetMetadata[0]);
IAssetProxy assetProxy = assetProxies[assetProxyId];
// transferFrom will either succeed or throw.
assetProxy.transferFrom(assetMetadata, from, to, amount);
}
}
}

View File

@@ -16,26 +16,23 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "./LibFillResults.sol";
import "./LibOrder.sol";
import "./LibErrors.sol";
import "./LibMath.sol";
import "./libs/LibFillResults.sol";
import "./libs/LibOrder.sol";
import "./libs/LibMath.sol";
import "./libs/LibExchangeErrors.sol";
import "./mixins/MExchangeCore.sol";
import "./mixins/MSettlement.sol";
import "./mixins/MSignatureValidator.sol";
import "./mixins/MTransactions.sol";
/// @dev Provides MExchangeCore
/// @dev Consumes MSettlement
/// @dev Consumes MSignatureValidator
contract MixinExchangeCore is
LibOrder,
LibFillResults,
LibErrors,
LibMath,
LibExchangeErrors,
MExchangeCore,
MSettlement,
MSignatureValidator,
@@ -51,35 +48,19 @@ contract MixinExchangeCore is
// Orders with a salt less than their maker's epoch are considered cancelled
mapping (address => uint256) public makerEpoch;
event Fill(
address indexed makerAddress,
address takerAddress,
address indexed feeRecipientAddress,
uint256 makerAssetFilledAmount,
uint256 takerAssetFilledAmount,
uint256 makerFeePaid,
uint256 takerFeePaid,
bytes32 indexed orderHash,
bytes makerAssetData,
bytes takerAssetData
);
event Cancel(
address indexed makerAddress,
address indexed feeRecipientAddress,
bytes32 indexed orderHash,
bytes makerAssetData,
bytes takerAssetData
);
event CancelUpTo(
address indexed makerAddress,
uint256 makerEpoch
);
/*
* Core exchange functions
*/
/// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value.
/// @param salt Orders created with a salt less or equal to this value will be cancelled.
function cancelOrdersUpTo(uint256 salt)
external
{
uint256 newMakerEpoch = salt + 1; // makerEpoch is initialized to 0, so to cancelUpTo we need salt + 1
require(
newMakerEpoch > makerEpoch[msg.sender], // epoch must be monotonically increasing
INVALID_NEW_MAKER_EPOCH
);
makerEpoch[msg.sender] = newMakerEpoch;
emit CancelUpTo(msg.sender, newMakerEpoch);
}
/// @dev Fills the input order.
/// @param order Order struct containing order specifications.
@@ -111,22 +92,40 @@ contract MixinExchangeCore is
// Validate order and maker only if first time seen
// TODO: Read filled and cancelled only once
if (filled[orderHash] == 0) {
require(order.makerAssetAmount > 0);
require(order.takerAssetAmount > 0);
require(isValidSignature(orderHash, order.makerAddress, signature));
require(
order.makerAssetAmount > 0,
GT_ZERO_AMOUNT_REQUIRED
);
require(
order.takerAssetAmount > 0,
GT_ZERO_AMOUNT_REQUIRED
);
require(
isValidSignature(orderHash, order.makerAddress, signature),
SIGNATURE_VALIDATION_FAILED
);
}
// Validate sender is allowed to fill this order
if (order.senderAddress != address(0)) {
require(order.senderAddress == msg.sender);
require(
order.senderAddress == msg.sender,
INVALID_SENDER
);
}
// Validate taker is allowed to fill this order
address takerAddress = getCurrentContextAddress();
if (order.takerAddress != address(0)) {
require(order.takerAddress == takerAddress);
require(
order.takerAddress == takerAddress,
INVALID_CONTEXT
);
}
require(takerAssetFillAmount > 0);
require(
takerAssetFillAmount > 0,
GT_ZERO_AMOUNT_REQUIRED
);
// Validate order expiration
if (block.timestamp >= order.expirationTimeSeconds) {
@@ -173,17 +172,29 @@ contract MixinExchangeCore is
bytes32 orderHash = getOrderHash(order);
// Validate the order
require(order.makerAssetAmount > 0);
require(order.takerAssetAmount > 0);
require(
order.makerAssetAmount > 0,
GT_ZERO_AMOUNT_REQUIRED
);
require(
order.takerAssetAmount > 0,
GT_ZERO_AMOUNT_REQUIRED
);
// Validate sender is allowed to cancel this order
if (order.senderAddress != address(0)) {
require(order.senderAddress == msg.sender);
require(
order.senderAddress == msg.sender,
INVALID_SENDER
);
}
// Validate transaction signed by maker
address makerAddress = getCurrentContextAddress();
require(order.makerAddress == makerAddress);
require(
order.makerAddress == makerAddress,
INVALID_CONTEXT
);
if (block.timestamp >= order.expirationTimeSeconds) {
emit ExchangeError(uint8(Errors.ORDER_EXPIRED), orderHash);
@@ -207,16 +218,6 @@ contract MixinExchangeCore is
return true;
}
/// @param salt Orders created with a salt less or equal to this value will be cancelled.
function cancelOrdersUpTo(uint256 salt)
external
{
uint256 newMakerEpoch = salt + 1; // makerEpoch is initialized to 0, so to cancelUpTo we need salt+1
require(newMakerEpoch > makerEpoch[msg.sender]); // epoch must be monotonically increasing
makerEpoch[msg.sender] = newMakerEpoch;
emit CancelUpTo(msg.sender, newMakerEpoch);
}
/// @dev Logs a Fill event with the given arguments.
/// The sole purpose of this function is to get around the stack variable limit.
function emitFillEvent(

View File

@@ -16,23 +16,24 @@
*/
pragma solidity ^0.4.21;
pragma experimental ABIEncoderV2;
pragma solidity ^0.4.23;
import "./mixins/MSettlement.sol";
import "./mixins/MAssetProxyDispatcher.sol";
import "./LibOrder.sol";
import "./LibMath.sol";
import "../AssetProxy/IAssetProxy.sol";
import "./libs/LibOrder.sol";
import "./libs/LibMath.sol";
/// @dev Provides MixinSettlement
contract MixinSettlement is
LibMath,
MSettlement,
MAssetProxyDispatcher
{
// ZRX metadata used for fee transfers.
// This will be constant throughout the life of the Exchange contract,
// since ZRX will always be transferred via the ERC20 AssetProxy.
bytes internal ZRX_PROXY_DATA;
/// @dev Gets the ZRX metadata used for fee transfers.
function zrxProxyData()
external
view
@@ -41,12 +42,20 @@ contract MixinSettlement is
return ZRX_PROXY_DATA;
}
function MixinSettlement(bytes memory _zrxProxyData)
/// TODO: _zrxProxyData should be a constant in production.
/// @dev Constructor sets the metadata that will be used for paying ZRX fees.
/// @param _zrxProxyData Byte array containing ERC20 proxy id concatenated with address of ZRX.
constructor (bytes memory _zrxProxyData)
public
{
ZRX_PROXY_DATA = _zrxProxyData;
}
/// @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 takerAssetFilledAmount The amount of takerAsset that will be transferred to the order's maker.
/// @return Amount filled by maker and fees paid by maker/taker.
function settleOrder(
LibOrder.Order memory order,
address takerAddress,

View File

@@ -16,29 +16,39 @@
*/
pragma solidity ^0.4.21;
pragma experimental ABIEncoderV2;
pragma solidity ^0.4.23;
import "./mixins/MSignatureValidator.sol";
import "./ISigner.sol";
import "./interfaces/ISigner.sol";
import "./libs/LibExchangeErrors.sol";
import "../../utils/LibBytes/LibBytes.sol";
/// @dev Provides MSignatureValidator
contract MixinSignatureValidator is MSignatureValidator {
enum SignatureType {
Illegal, // Default value
Invalid,
Caller,
Ecrecover,
EIP712,
Trezor,
Contract,
PreSigned
}
contract MixinSignatureValidator is
LibBytes,
LibExchangeErrors,
MSignatureValidator
{
// Mapping of hash => signer => signed
mapping(bytes32 => mapping(address => bool)) preSigned;
/// @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 signer Address that should have signed the given hash.
/// @param signature Proof that the hash has been signed by signer.
function preSign(
bytes32 hash,
address signer,
bytes signature)
external
{
require(
isValidSignature(hash, signer, signature),
SIGNATURE_VALIDATION_FAILED
);
preSigned[hash][signer] = true;
}
/// @dev Verifies that a hash has been signed by the given signer.
/// @param hash Any 32 byte hash.
/// @param signer Address that should have signed the given hash.
@@ -54,7 +64,10 @@ contract MixinSignatureValidator is MSignatureValidator {
{
// TODO: Domain separation: make hash depend on role. (Taker sig should not be valid as maker sig, etc.)
require(signature.length >= 1);
require(
signature.length >= 1,
INVALID_SIGNATURE_LENGTH
);
SignatureType signatureType = SignatureType(uint8(signature[0]));
// Variables are not scoped in Solidity
@@ -69,14 +82,18 @@ contract MixinSignatureValidator is MSignatureValidator {
// it an explicit option. This aids testing and analysis. It is
// also the initialization value for the enum type.
if (signatureType == SignatureType.Illegal) {
revert();
// NOTE: Reason cannot be assigned to a variable because of https://github.com/ethereum/solidity/issues/4051
revert("Illegal signature type.");
// 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 == 1);
require(
signature.length == 1,
INVALID_SIGNATURE_LENGTH
);
isValid = false;
return isValid;
@@ -89,16 +106,22 @@ contract MixinSignatureValidator is MSignatureValidator {
// `Caller` for his own signature. Or A and C can sign and B can
// submit using `Caller`. Having `Caller` allows this flexibility.
} else if (signatureType == SignatureType.Caller) {
require(signature.length == 1);
require(
signature.length == 1,
INVALID_SIGNATURE_LENGTH
);
isValid = signer == msg.sender;
return isValid;
// Signed using web3.eth_sign
} else if (signatureType == SignatureType.Ecrecover) {
require(signature.length == 66);
require(
signature.length == 66,
INVALID_SIGNATURE_LENGTH
);
v = uint8(signature[1]);
r = get32(signature, 2);
s = get32(signature, 34);
r = readBytes32(signature, 2);
s = readBytes32(signature, 34);
recovered = ecrecover(
keccak256("\x19Ethereum Signed Message:\n32", hash),
v,
@@ -110,10 +133,13 @@ contract MixinSignatureValidator is MSignatureValidator {
// Signature using EIP712
} else if (signatureType == SignatureType.EIP712) {
require(signature.length == 66);
require(
signature.length == 66,
INVALID_SIGNATURE_LENGTH
);
v = uint8(signature[1]);
r = get32(signature, 2);
s = get32(signature, 34);
r = readBytes32(signature, 2);
s = readBytes32(signature, 34);
recovered = ecrecover(hash, v, r, s);
isValid = signer == recovered;
return isValid;
@@ -127,10 +153,13 @@ contract MixinSignatureValidator is MSignatureValidator {
// https://github.com/trezor/trezor-mcu/blob/master/firmware/ethereum.c#L602
// https://github.com/trezor/trezor-mcu/blob/master/firmware/crypto.c#L36
} else if (signatureType == SignatureType.Trezor) {
require(signature.length == 66);
require(
signature.length == 66,
INVALID_SIGNATURE_LENGTH
);
v = uint8(signature[1]);
r = get32(signature, 2);
s = get32(signature, 34);
r = readBytes32(signature, 2);
s = readBytes32(signature, 34);
recovered = ecrecover(
keccak256("\x19Ethereum Signed Message:\n\x41", hash),
v,
@@ -156,37 +185,7 @@ contract MixinSignatureValidator is MSignatureValidator {
// that we currently support. In this case returning false
// may lead the caller to incorrectly believe that the
// signature was invalid.)
revert();
// NOTE: Reason cannot be assigned to a variable because of https://github.com/ethereum/solidity/issues/4051
revert("Unsupported signature type.");
}
/// @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 signer Address that should have signed the given hash.
/// @param signature Proof that the hash has been signed by signer.
function preSign(
bytes32 hash,
address signer,
bytes signature)
external
{
require(isValidSignature(hash, signer, signature));
preSigned[hash][signer] = true;
}
function get32(bytes memory b, uint256 index)
private pure
returns (bytes32 result)
{
require(b.length >= index + 32);
// 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;
}
}

View File

@@ -16,12 +16,13 @@
*/
pragma solidity ^0.4.21;
pragma experimental ABIEncoderV2;
import "./mixins/MSignatureValidator.sol";
import "./mixins/MTransactions.sol";
import "./libs/LibExchangeErrors.sol";
contract MixinTransactions is
LibExchangeErrors,
MSignatureValidator,
MTransactions
{
@@ -56,12 +57,18 @@ contract MixinTransactions is
);
// Validate transaction has not been executed
require(!transactions[transactionHash]);
require(
!transactions[transactionHash],
DUPLICATE_TRANSACTION_HASH
);
// TODO: is SignatureType.Caller necessary if we make this check?
if (signer != msg.sender) {
// Validate signature
require(isValidSignature(transactionHash, signer, signature));
require(
isValidSignature(transactionHash, signer, signature),
SIGNATURE_VALIDATION_FAILED
);
// Set the current transaction signer
currentContextAddress = signer;
@@ -69,7 +76,10 @@ contract MixinTransactions is
// Execute transaction
transactions[transactionHash] = true;
require(address(this).delegatecall(data));
require(
address(this).delegatecall(data),
TRANSACTION_EXECUTION_FAILED
);
// Reset current transaction signer
// TODO: Check if gas is paid when currentContextAddress is already 0.

View File

@@ -16,21 +16,22 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "../../utils/LibBytes/LibBytes.sol";
import "./mixins/MExchangeCore.sol";
import "./LibMath.sol";
import "./LibOrder.sol";
import "./LibFillResults.sol";
import "./libs/LibMath.sol";
import "./libs/LibOrder.sol";
import "./libs/LibFillResults.sol";
import "./libs/LibExchangeErrors.sol";
/// @dev Consumes MExchangeCore
contract MixinWrapperFunctions is
LibOrder,
LibFillResults,
LibMath,
LibBytes,
LibExchangeErrors,
MExchangeCore
{
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
@@ -49,7 +50,10 @@ contract MixinWrapperFunctions is
takerAssetFillAmount,
signature
);
require(fillResults.takerAssetFilledAmount == takerAssetFillAmount);
require(
fillResults.takerAssetFilledAmount == takerAssetFillAmount,
COMPLETE_FILL_FAILED
);
return fillResults;
}
@@ -327,7 +331,11 @@ contract MixinWrapperFunctions is
for (uint256 i = 0; i < orders.length; i++) {
// Token being sold by taker must be the same for each order
require(areBytesEqual(orders[i].takerAssetData, orders[0].takerAssetData));
// TODO: optimize by only using takerAssetData for first order.
require(
areBytesEqual(orders[i].takerAssetData, orders[0].takerAssetData),
ASSET_DATA_MISMATCH
);
// Calculate the remaining amount of takerAsset to sell
uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
@@ -366,7 +374,11 @@ contract MixinWrapperFunctions is
for (uint256 i = 0; i < orders.length; i++) {
// Token being sold by taker must be the same for each order
require(areBytesEqual(orders[i].takerAssetData, orders[0].takerAssetData));
// TODO: optimize by only using takerAssetData for first order.
require(
areBytesEqual(orders[i].takerAssetData, orders[0].takerAssetData),
ASSET_DATA_MISMATCH
);
// Calculate the remaining amount of takerAsset to sell
uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
@@ -404,7 +416,11 @@ contract MixinWrapperFunctions is
for (uint256 i = 0; i < orders.length; i++) {
// Token being bought by taker must be the same for each order
require(areBytesEqual(orders[i].makerAssetData, orders[0].makerAssetData));
// TODO: optimize by only using makerAssetData for first order.
require(
areBytesEqual(orders[i].makerAssetData, orders[0].makerAssetData),
ASSET_DATA_MISMATCH
);
// Calculate the remaining amount of makerAsset to buy
uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
@@ -451,7 +467,11 @@ contract MixinWrapperFunctions is
for (uint256 i = 0; i < orders.length; i++) {
// Token being bought by taker must be the same for each order
require(areBytesEqual(orders[i].makerAssetData, orders[0].makerAssetData));
// TODO: optimize by only using makerAssetData for first order.
require(
areBytesEqual(orders[i].makerAssetData, orders[0].makerAssetData),
ASSET_DATA_MISMATCH
);
// Calculate the remaining amount of makerAsset to buy
uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);

View File

@@ -0,0 +1,41 @@
/*
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.23;
contract IAssetProxyDispatcher {
/// @dev Registers an asset proxy to an asset proxy id.
/// An id can only be assigned to a single proxy at a given time.
/// @param assetProxyId Id to register`newAssetProxy` under.
/// @param newAssetProxy Address of new asset proxy to register, or 0x0 to unset assetProxyId.
/// @param oldAssetProxy Existing asset proxy to overwrite, or 0x0 if assetProxyId is currently unused.
function registerAssetProxy(
uint8 assetProxyId,
address newAssetProxy,
address oldAssetProxy)
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(uint8 assetProxyId)
external
view
returns (address);
}

View File

@@ -0,0 +1,34 @@
/*
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.23;
pragma experimental ABIEncoderV2;
import "./IExchangeCore.sol";
import "./ISignatureValidator.sol";
import "./IAssetProxyDispatcher.sol";
import "./ITransactions.sol";
import "./IWrapperFunctions.sol";
contract IExchange is
IWrapperFunctions,
IExchangeCore,
ISignatureValidator,
ITransactions,
IAssetProxyDispatcher
{}

View File

@@ -0,0 +1,51 @@
/*
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.23;
pragma experimental ABIEncoderV2;
import "../libs/LibOrder.sol";
import "../libs/LibFillResults.sol";
contract IExchangeCore {
/// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value.
/// @param salt Orders created with a salt less or equal to this value will be cancelled.
function cancelOrdersUpTo(uint256 salt)
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.
/// @return True if the order state changed to cancelled.
/// False if the transaction was already cancelled or expired.
function cancelOrder(LibOrder.Order memory order)
public
returns (bool);
}

View File

@@ -0,0 +1,32 @@
/*
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.23;
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 signer Address that should have signed the given hash.
/// @param signature Proof that the hash has been signed by signer.
function preSign(
bytes32 hash,
address signer,
bytes signature)
external;
}

View File

@@ -16,11 +16,14 @@
*/
pragma solidity ^0.4.21;
pragma experimental ABIEncoderV2;
pragma solidity ^0.4.23;
contract ISigner {
/// @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)

View File

@@ -0,0 +1,33 @@
/*
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.23;
contract ITransactions {
/// @dev Executes an exchange method call in the context of signer.
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
/// @param signer Address of transaction signer.
/// @param data AbiV2 encoded calldata.
/// @param signature Proof of signer transaction by signer.
function executeTransaction(
uint256 salt,
address signer,
bytes data,
bytes signature)
external;
}

View File

@@ -0,0 +1,142 @@
/*
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.23;
pragma experimental ABIEncoderV2;
import "./libs/LibOrder.sol";
import "./libs/LibFillResults.sol";
contract IWrapperFunctions is
LibOrder,
LibFillResults,
LibMath,
LibBytes,
LibExchangeErrors,
MExchangeCore
{
/// @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.LibOrder.Order memory order,
uint256 takerAssetFillAmount,
bytes memory signature)
public
returns (LibFillResults.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.
function batchFillOrders(
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
bytes[] memory signatures)
public;
/// @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.
function batchFillOrKillOrders(
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
bytes[] memory signatures)
public;
/// @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.
function batchFillOrdersNoThrow(
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
bytes[] memory signatures)
public;
/// @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;
}

View File

@@ -0,0 +1,58 @@
/*
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.23;
contract LibExchangeErrors {
// Error Codes
enum Errors {
ORDER_EXPIRED, // Order has already expired
ORDER_FULLY_FILLED, // Order has already been fully filled
ORDER_CANCELLED, // Order has already been cancelled
ROUNDING_ERROR_TOO_LARGE, // Rounding error too large
INSUFFICIENT_BALANCE_OR_ALLOWANCE // Insufficient balance or allowance for token transfer
}
event ExchangeError(uint8 indexed errorId, bytes32 indexed orderHash);
// Core revert reasons
string constant GT_ZERO_AMOUNT_REQUIRED = "Amount must be greater than 0.";
string constant SIGNATURE_VALIDATION_FAILED = "Signature validation failed.";
string constant INVALID_SENDER = "Invalid `msg.sender`.";
string constant INVALID_CONTEXT = "Function called in an invalid context.";
string constant INVALID_NEW_MAKER_EPOCH = "Specified salt must be greater than or equal to existing makerEpoch.";
// Transaction revert reasons
string constant DUPLICATE_TRANSACTION_HASH = "Transaction has already been executed.";
string constant TRANSACTION_EXECUTION_FAILED = "Transaction execution failed.";
// Wrapper revert reasons
string constant COMPLETE_FILL_FAILED = "Desired fill amount could not be completely filled.";
string constant ASSET_DATA_MISMATCH = "Asset data must be the same for each order.";
// Asset proxy dispatcher revert reasons
string constant GT_ZERO_LENGTH_REQUIRED = "Length must be greater than 0.";
string constant OLD_ASSET_PROXY_MISMATCH = "Old asset proxy does not match asset proxy at given id.";
string constant NEW_ASSET_PROXY_MISMATCH = "New asset proxy id does not match given id.";
// Signature validator revert reasons
string constant INVALID_SIGNATURE_LENGTH = "Invalid signature length.";
string constant ILLEGAL_SIGNATURE_TYPE = "Illegal signature type.";
string constant UNSUPPORTED_SIGNATURE_TYPE = "Unsupported signature type.";
}

View File

@@ -16,12 +16,13 @@
*/
pragma solidity ^0.4.21;
pragma experimental ABIEncoderV2;
pragma solidity ^0.4.23;
import "../../utils/SafeMath/SafeMath.sol";
import "../../../utils/SafeMath/SafeMath.sol";
contract LibFillResults is SafeMath {
contract LibFillResults is
SafeMath
{
struct FillResults {
uint256 makerAssetFilledAmount;

View File

@@ -16,12 +16,13 @@
*/
pragma solidity ^0.4.21;
pragma experimental ABIEncoderV2;
pragma solidity ^0.4.23;
import "../../utils/SafeMath/SafeMath.sol";
import "../../../utils/SafeMath/SafeMath.sol";
contract LibMath is SafeMath {
contract LibMath is
SafeMath
{
/// @dev Calculates partial value given a numerator and denominator.
/// @param numerator Numerator.

View File

@@ -16,8 +16,7 @@
*/
pragma solidity ^0.4.21;
pragma experimental ABIEncoderV2;
pragma solidity ^0.4.23;
contract LibOrder {

View File

@@ -16,9 +16,13 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
contract MAssetProxyDispatcher {
import "../interfaces/IAssetProxyDispatcher.sol";
contract MAssetProxyDispatcher is
IAssetProxyDispatcher
{
// Logs registration of new asset proxy
event AssetProxySet(
@@ -38,23 +42,4 @@ contract MAssetProxyDispatcher {
address to,
uint256 amount)
internal;
/// @dev Registers an asset proxy to an asset proxy id.
/// An id can only be assigned to a single proxy at a given time.
/// @param assetProxyId Id to register`newAssetProxy` under.
/// @param newAssetProxy Address of new asset proxy to register, or 0x0 to unset assetProxyId.
/// @param oldAssetProxy Existing asset proxy to overwrite, or 0x0 if assetProxyId is currently unused.
function registerAssetProxy(
uint8 assetProxyId,
address newAssetProxy,
address oldAssetProxy)
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(uint8 assetProxyId)
external
view
returns (address);
}

View File

@@ -16,25 +16,51 @@
*/
pragma solidity ^0.4.21;
pragma experimental ABIEncoderV2;
pragma solidity ^0.4.23;
import "../LibOrder.sol";
import "../LibFillResults.sol";
import "../libs/LibOrder.sol";
import "../libs/LibFillResults.sol";
import "../interfaces/IExchangeCore.sol";
contract MExchangeCore {
contract MExchangeCore is
IExchangeCore
{
function fillOrder(
// Fill event is emitted whenever an order is filled.
event Fill(
address indexed makerAddress,
address takerAddress,
address indexed feeRecipientAddress,
uint256 makerAssetFilledAmount,
uint256 takerAssetFilledAmount,
uint256 makerFeePaid,
uint256 takerFeePaid,
bytes32 indexed orderHash,
bytes makerAssetData,
bytes takerAssetData
);
// Cancel event is emitted whenever an individual order is cancelled.
event Cancel(
address indexed makerAddress,
address indexed feeRecipientAddress,
bytes32 indexed orderHash,
bytes makerAssetData,
bytes takerAssetData
);
// CancelUpTo event is emitted whenever `cancelOrdersUpTo` is executed succesfully.
event CancelUpTo(
address indexed makerAddress,
uint256 makerEpoch
);
/// @dev Logs a Fill event with the given arguments.
/// The sole purpose of this function is to get around the stack variable limit.
function emitFillEvent(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
bytes memory signature)
public
returns (LibFillResults.FillResults memory fillResults);
function cancelOrder(LibOrder.Order memory order)
public
returns (bool);
function cancelOrdersUpTo(uint256 salt)
external;
address takerAddress,
bytes32 orderHash,
LibFillResults.FillResults memory fillResults)
internal;
}

View File

@@ -16,13 +16,17 @@
*/
pragma solidity ^0.4.21;
pragma experimental ABIEncoderV2;
pragma solidity ^0.4.23;
import "../LibOrder.sol";
import "../libs/LibOrder.sol";
contract MSettlement {
/// @dev Settles an order by transfering assets between counterparties.
/// @param order Order struct containing order specifications.
/// @param takerAddress Address selling takerAsset and buying makerAsset.
/// @param takerAssetFilledAmount The amount of takerAsset that will be transfered to the order's maker.
/// @return Amount filled by maker and fees paid by maker/taker.
function settleOrder(
LibOrder.Order memory order,
address takerAddress,
@@ -33,5 +37,5 @@ contract MSettlement {
uint256 makerFeePaid,
uint256 takerFeePaid
);
}

View File

@@ -16,10 +16,24 @@
*/
pragma solidity ^0.4.21;
pragma experimental ABIEncoderV2;
pragma solidity ^0.4.23;
contract MSignatureValidator {
import "../interfaces/ISignatureValidator.sol";
contract MSignatureValidator is
ISignatureValidator
{
// Allowed signature types.
enum SignatureType {
Illegal, // Default value
Invalid,
Caller,
Ecrecover,
EIP712,
Trezor,
Contract,
PreSigned
}
/// @dev Verifies that a signature is valid.
/// @param hash Message hash that is signed.

View File

@@ -15,24 +15,13 @@
limitations under the License.
*/
pragma solidity ^0.4.21;
pragma experimental ABIEncoderV2;
pragma solidity ^0.4.23;
import "./MSignatureValidator.sol";
import "../interfaces/ITransactions.sol";
contract MTransactions is MSignatureValidator {
/// @dev Executes an exchange method call in the context of signer.
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
/// @param signer Address of transaction signer.
/// @param data AbiV2 encoded calldata.
/// @param signature Proof of signer transaction by signer.
function executeTransaction(
uint256 salt,
address signer,
bytes data,
bytes signature)
external;
contract MTransactions is
ITransactions
{
/// @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.

View File

@@ -16,7 +16,8 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "../Mintable/Mintable.sol";
import "../../utils/Ownable/Ownable.sol";
@@ -26,7 +27,7 @@ contract DummyERC20Token is Mintable, Ownable {
string public symbol;
uint256 public decimals;
function DummyERC20Token(
constructor (
string _name,
string _symbol,
uint256 _decimals,

View File

@@ -16,7 +16,9 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "../../tokens/ERC721Token/ERC721Token.sol";
import "../../utils/Ownable/Ownable.sol";
@@ -30,7 +32,7 @@ contract DummyERC721Token is
* @param name of token
* @param symbol of token
*/
function DummyERC721Token(
constructor (
string name,
string symbol)
public
@@ -47,7 +49,10 @@ contract DummyERC721Token is
public
onlyOwner
{
require(!exists(tokenId));
require(
!exists(tokenId),
"Token with tokenId already exists."
);
_mint(to, tokenId);
}
}

View File

@@ -16,7 +16,8 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "../../tokens/UnlimitedAllowanceToken/UnlimitedAllowanceToken.sol";
import "../../utils/SafeMath/SafeMath.sol";
@@ -29,7 +30,10 @@ contract Mintable is UnlimitedAllowanceToken, SafeMath {
function mint(uint256 _value)
public
{
require(_value <= 100000000000000000000);
require(
_value <= 100000000000000000000,
"Minting more than 100000000000000000000 is not allowed."
);
balances[msg.sender] = safeAdd(_value, balances[msg.sender]);
totalSupply = safeAdd(totalSupply, _value);
}

View File

@@ -16,7 +16,8 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "../../protocol/Exchange/MixinAssetProxyDispatcher.sol";

View File

@@ -0,0 +1,133 @@
/*
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.23;
pragma experimental ABIEncoderV2;
import "../../utils/LibBytes/LibBytes.sol";
contract TestLibBytes is
LibBytes
{
/// @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 publicAreBytesEqual(bytes memory lhs, bytes memory rhs)
public
pure
returns (bool equal)
{
equal = areBytesEqual(lhs, rhs);
return equal;
}
/// @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 publicReadAddress(
bytes memory b,
uint256 index)
public
pure
returns (address result)
{
result = readAddress(b, index);
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 publicWriteAddress(
bytes memory b,
uint256 index,
address input)
public
pure
returns (bytes memory)
{
writeAddress(b, index, input);
return b;
}
/// @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 publicReadBytes32(
bytes memory b,
uint256 index)
public
pure
returns (bytes32 result)
{
result = readBytes32(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 publicWriteBytes32(
bytes memory b,
uint256 index,
bytes32 input)
public
pure
returns (bytes memory)
{
writeBytes32(b, index, input);
return b;
}
/// @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 publicReadUint256(
bytes memory b,
uint256 index)
public
pure
returns (uint256 result)
{
result = readUint256(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 publicWriteUint256(
bytes memory b,
uint256 index,
uint256 input)
public
pure
returns (bytes memory)
{
writeUint256(b, index, input);
return b;
}
}

View File

@@ -16,12 +16,12 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "../../protocol/Exchange/LibMath.sol";
import "../../protocol/Exchange/LibOrder.sol";
import "../../protocol/Exchange/LibFillResults.sol";
import "../../protocol/Exchange/libs/LibMath.sol";
import "../../protocol/Exchange/libs/LibOrder.sol";
import "../../protocol/Exchange/libs/LibFillResults.sol";
contract TestLibs is
LibMath,

View File

@@ -16,7 +16,7 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "../../protocol/Exchange/MixinSignatureValidator.sol";

View File

@@ -16,17 +16,34 @@
*/
pragma solidity ^0.4.18;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import "./IERC20Token.sol";
contract ERC20Token is IERC20Token {
string constant INSUFFICIENT_BALANCE = "Insufficient balance to complete transfer.";
string constant INSUFFICIENT_ALLOWANCE = "Insufficient allowance to complete transfer.";
string constant OVERFLOW = "Transfer would result in an overflow.";
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
uint256 public totalSupply;
function transfer(address _to, uint256 _value)
public
returns (bool)
{
require(balances[msg.sender] >= _value && balances[_to] + _value >= balances[_to]);
require(
balances[msg.sender] >= _value,
INSUFFICIENT_BALANCE
);
require(
balances[_to] + _value >= balances[_to],
OVERFLOW
);
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value);
@@ -37,7 +54,18 @@ contract ERC20Token is IERC20Token {
public
returns (bool)
{
require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value >= balances[_to]);
require(
balances[_from] >= _value,
INSUFFICIENT_BALANCE
);
require(
allowed[_from][msg.sender] >= _value,
INSUFFICIENT_ALLOWANCE
);
require(
balances[_to] + _value >= balances[_to],
OVERFLOW
);
balances[_to] += _value;
balances[_from] -= _value;
allowed[_from][msg.sender] -= _value;
@@ -68,8 +96,5 @@ contract ERC20Token is IERC20Token {
{
return allowed[_owner][_spender];
}
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
uint256 public totalSupply;
}

View File

@@ -16,11 +16,12 @@
*/
pragma solidity ^0.4.18;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
contract IERC20Token {
/// @notice send `_value` token to `_to` from `msg.sender`
/// @notice send `value` token to `to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
@@ -28,7 +29,7 @@ contract IERC20Token {
public
returns (bool);
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
/// @notice send `value` token to `to` from `from` on the condition it is approved by `from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
@@ -61,10 +62,12 @@ contract IERC20Token {
event Transfer(
address indexed _from,
address indexed _to,
uint256 _value);
uint256 _value
);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _value);
uint256 _value
);
}

View File

@@ -23,7 +23,7 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
import "./IERC721Token.sol";
import "./IERC721Receiver.sol";

View File

@@ -23,7 +23,7 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
/**
* @title ERC721 token receiver interface

View File

@@ -23,7 +23,7 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
/**
* @title ERC721 Non-Fungible Token Standard basic interface

View File

@@ -16,9 +16,10 @@
*/
pragma solidity ^0.4.18;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
import { ERC20Token } from "../ERC20Token/ERC20Token.sol";
import "../ERC20Token/ERC20Token.sol";
contract UnlimitedAllowanceToken is ERC20Token {
@@ -34,7 +35,18 @@ contract UnlimitedAllowanceToken is ERC20Token {
returns (bool)
{
uint256 allowance = allowed[_from][msg.sender];
require(balances[_from] >= _value && allowance >= _value && balances[_to] + _value >= balances[_to]);
require(
balances[_from] >= _value,
INSUFFICIENT_BALANCE
);
require(
allowance >= _value,
INSUFFICIENT_ALLOWANCE
);
require(
balances[_to] + _value >= balances[_to],
OVERFLOW
);
balances[_to] += _value;
balances[_from] -= _value;
if (allowance < MAX_UINT) {

View File

@@ -16,16 +16,21 @@
*/
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
contract LibBytes {
// Revert reasons
string constant GTE_20_LENGTH_REQUIRED = "Length must be greater than or equal to 20.";
string constant GTE_32_LENGTH_REQUIRED = "Length must be greater than or equal to 32.";
/// @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 areBytesEqual(bytes memory lhs, bytes memory rhs)
public pure
internal
pure
returns (bool equal)
{
assembly {
@@ -58,10 +63,14 @@ contract LibBytes {
function readAddress(
bytes memory b,
uint256 index)
public pure
internal
pure
returns (address result)
{
require(b.length >= index + 20); // 20 is length of address
require(
b.length >= index + 20, // 20 is length of address
GTE_20_LENGTH_REQUIRED
);
// Add offset to index:
// 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
@@ -86,9 +95,13 @@ contract LibBytes {
bytes memory b,
uint256 index,
address input)
public pure
internal
pure
{
require(b.length >= index + 20); // 20 is length of address
require(
b.length >= index + 20, // 20 is length of address
GTE_20_LENGTH_REQUIRED
);
// Add offset to index:
// 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
@@ -119,10 +132,14 @@ contract LibBytes {
function readBytes32(
bytes memory b,
uint256 index)
public pure
internal
pure
returns (bytes32 result)
{
require(b.length >= index + 32);
require(
b.length >= index + 32,
GTE_32_LENGTH_REQUIRED
);
// Arrays are prefixed by a 256 bit length parameter
index += 32;
@@ -142,9 +159,13 @@ contract LibBytes {
bytes memory b,
uint256 index,
bytes32 input)
public pure
internal
pure
{
require(b.length >= index + 32);
require(
b.length >= index + 32,
GTE_32_LENGTH_REQUIRED
);
// Arrays are prefixed by a 256 bit length parameter
index += 32;
@@ -162,7 +183,8 @@ contract LibBytes {
function readUint256(
bytes memory b,
uint256 index)
public pure
internal
pure
returns (uint256 result)
{
return uint256(readBytes32(b, index));
@@ -176,7 +198,8 @@ contract LibBytes {
bytes memory b,
uint256 index,
uint256 input)
public pure
internal
pure
{
writeBytes32(b, index, bytes32(input));
}

View File

@@ -1,4 +1,5 @@
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
/*
* Ownable

View File

@@ -1,4 +1,5 @@
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
/*
* Ownable
@@ -7,19 +8,22 @@ pragma solidity ^0.4.21;
* Provides onlyOwner modifier, which prevents function from running if it is called by anyone other than the owner.
*/
import "../Ownable/IOwnable.sol";
import "./IOwnable.sol";
contract Ownable is IOwnable {
address public owner;
function Ownable()
constructor ()
public
{
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
require(
msg.sender == owner,
"Only contract owner is allowed to call this method."
);
_;
}

View File

@@ -1,4 +1,5 @@
pragma solidity ^0.4.21;
pragma solidity ^0.4.23;
pragma experimental ABIEncoderV2;
contract SafeMath {
function safeMul(uint a, uint b)

View File

@@ -99,7 +99,7 @@ export enum ContractName {
ERC20Proxy = 'ERC20Proxy',
ERC721Proxy = 'ERC721Proxy',
DummyERC721Token = 'DummyERC721Token',
LibBytes = 'LibBytes',
TestLibBytes = 'TestLibBytes',
Authorizable = 'Authorizable',
}

View File

@@ -3,7 +3,7 @@ import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as chai from 'chai';
import * as Web3 from 'web3';
import { AuthorizableContract } from '../../src/contract_wrappers/generated/authorizable';
import { MixinAuthorizableContract } from '../../src/contract_wrappers/generated/mixin_authorizable';
import { constants } from '../../src/utils/constants';
import { ContractName } from '../../src/utils/types';
import { chaiSetup } from '../utils/chai_setup';
@@ -18,13 +18,13 @@ describe('Authorizable', () => {
let owner: string;
let notOwner: string;
let address: string;
let authorizable: AuthorizableContract;
let authorizable: MixinAuthorizableContract;
before(async () => {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
owner = address = accounts[0];
notOwner = accounts[1];
const authorizableInstance = await deployer.deployAsync(ContractName.Authorizable);
authorizable = new AuthorizableContract(authorizableInstance.abi, authorizableInstance.address, provider);
authorizable = new MixinAuthorizableContract(authorizableInstance.abi, authorizableInstance.address, provider);
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();

View File

@@ -7,7 +7,7 @@ import * as chai from 'chai';
import ethUtil = require('ethereumjs-util');
import * as Web3 from 'web3';
import { LibBytesContract } from '../../src/contract_wrappers/generated/lib_bytes';
import { TestLibBytesContract } from '../../src/contract_wrappers/generated/test_lib_bytes';
import { constants } from '../../src/utils/constants';
import { AssetProxyId, ContractName } from '../../src/utils/types';
import { chaiSetup } from '../utils/chai_setup';
@@ -20,7 +20,7 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('LibBytes', () => {
let owner: string;
let libBytes: LibBytesContract;
let libBytes: TestLibBytesContract;
const byteArrayShorterThan32Bytes = '0x012345';
const byteArrayLongerThan32Bytes =
'0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
@@ -38,8 +38,8 @@ describe('LibBytes', () => {
owner = accounts[0];
testAddress = accounts[1];
// Deploy LibBytes
const libBytesInstance = await deployer.deployAsync(ContractName.LibBytes);
libBytes = new LibBytesContract(libBytesInstance.abi, libBytesInstance.address, provider);
const libBytesInstance = await deployer.deployAsync(ContractName.TestLibBytes);
libBytes = new TestLibBytesContract(libBytesInstance.abi, libBytesInstance.address, provider);
// Verify lengths of test data
const byteArrayShorterThan32BytesLength = ethUtil.toBuffer(byteArrayShorterThan32Bytes).byteLength;
expect(byteArrayShorterThan32BytesLength).to.be.lessThan(32);
@@ -57,7 +57,7 @@ describe('LibBytes', () => {
describe('areBytesEqual', () => {
it('should return true if byte arrays are equal (both arrays < 32 bytes)', async () => {
const areBytesEqual = await libBytes.areBytesEqual.callAsync(
const areBytesEqual = await libBytes.publicAreBytesEqual.callAsync(
byteArrayShorterThan32Bytes,
byteArrayShorterThan32Bytes,
);
@@ -65,7 +65,7 @@ describe('LibBytes', () => {
});
it('should return true if byte arrays are equal (both arrays > 32 bytes)', async () => {
const areBytesEqual = await libBytes.areBytesEqual.callAsync(
const areBytesEqual = await libBytes.publicAreBytesEqual.callAsync(
byteArrayLongerThan32Bytes,
byteArrayLongerThan32Bytes,
);
@@ -73,7 +73,7 @@ describe('LibBytes', () => {
});
it('should return false if byte arrays are not equal (first array < 32 bytes, second array > 32 bytes)', async () => {
const areBytesEqual = await libBytes.areBytesEqual.callAsync(
const areBytesEqual = await libBytes.publicAreBytesEqual.callAsync(
byteArrayShorterThan32Bytes,
byteArrayLongerThan32Bytes,
);
@@ -81,7 +81,7 @@ describe('LibBytes', () => {
});
it('should return false if byte arrays are not equal (first array > 32 bytes, second array < 32 bytes)', async () => {
const areBytesEqual = await libBytes.areBytesEqual.callAsync(
const areBytesEqual = await libBytes.publicAreBytesEqual.callAsync(
byteArrayLongerThan32Bytes,
byteArrayShorterThan32Bytes,
);
@@ -89,7 +89,7 @@ describe('LibBytes', () => {
});
it('should return false if byte arrays are not equal (same length, but a byte in first word differs)', async () => {
const areBytesEqual = await libBytes.areBytesEqual.callAsync(
const areBytesEqual = await libBytes.publicAreBytesEqual.callAsync(
byteArrayLongerThan32BytesFirstBytesSwapped,
byteArrayLongerThan32Bytes,
);
@@ -97,7 +97,7 @@ describe('LibBytes', () => {
});
it('should return false if byte arrays are not equal (same length, but a byte in last word differs)', async () => {
const areBytesEqual = await libBytes.areBytesEqual.callAsync(
const areBytesEqual = await libBytes.publicAreBytesEqual.callAsync(
byteArrayLongerThan32BytesLastBytesSwapped,
byteArrayLongerThan32Bytes,
);
@@ -109,7 +109,7 @@ describe('LibBytes', () => {
it('should successfully read address when the address takes up the whole array)', async () => {
const byteArray = ethUtil.addHexPrefix(testAddress);
const testAddressOffset = new BigNumber(0);
const address = await libBytes.readAddress.callAsync(byteArray, testAddressOffset);
const address = await libBytes.publicReadAddress.callAsync(byteArray, testAddressOffset);
return expect(address).to.be.equal(testAddress);
});
@@ -119,20 +119,24 @@ describe('LibBytes', () => {
const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, addressByteArrayBuffer]);
const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
const testAddressOffset = new BigNumber(prefixByteArrayBuffer.byteLength);
const address = await libBytes.readAddress.callAsync(combinedByteArray, testAddressOffset);
const address = await libBytes.publicReadAddress.callAsync(combinedByteArray, testAddressOffset);
return expect(address).to.be.equal(testAddress);
});
it('should fail if the byte array is too short to hold an address)', async () => {
const shortByteArray = '0xabcdef';
const offset = new BigNumber(0);
return expect(libBytes.readAddress.callAsync(shortByteArray, offset)).to.be.rejectedWith(constants.REVERT);
return expect(libBytes.publicReadAddress.callAsync(shortByteArray, offset)).to.be.rejectedWith(
constants.REVERT,
);
});
it('should fail if the length between the offset and end of the byte array is too short to hold an address)', async () => {
const byteArray = ethUtil.addHexPrefix(testAddress);
const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
return expect(libBytes.readAddress.callAsync(byteArray, badOffset)).to.be.rejectedWith(constants.REVERT);
return expect(libBytes.publicReadAddress.callAsync(byteArray, badOffset)).to.be.rejectedWith(
constants.REVERT,
);
});
});
@@ -150,7 +154,7 @@ describe('LibBytes', () => {
describe('readBytes32', () => {
it('should successfully read bytes32 when the bytes32 takes up the whole array)', async () => {
const testBytes32Offset = new BigNumber(0);
const bytes32 = await libBytes.readBytes32.callAsync(testBytes32, testBytes32Offset);
const bytes32 = await libBytes.publicReadBytes32.callAsync(testBytes32, testBytes32Offset);
return expect(bytes32).to.be.equal(testBytes32);
});
@@ -160,20 +164,22 @@ describe('LibBytes', () => {
const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes32ByteArrayBuffer]);
const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
const testAddressOffset = new BigNumber(prefixByteArrayBuffer.byteLength);
const bytes32 = await libBytes.readBytes32.callAsync(combinedByteArray, testAddressOffset);
const bytes32 = await libBytes.publicReadBytes32.callAsync(combinedByteArray, testAddressOffset);
return expect(bytes32).to.be.equal(testBytes32);
});
it('should fail if the byte array is too short to hold a bytes32)', async () => {
const offset = new BigNumber(0);
return expect(libBytes.readBytes32.callAsync(byteArrayShorterThan32Bytes, offset)).to.be.rejectedWith(
return expect(libBytes.publicReadBytes32.callAsync(byteArrayShorterThan32Bytes, offset)).to.be.rejectedWith(
constants.REVERT,
);
});
it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32)', async () => {
const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength);
return expect(libBytes.readBytes32.callAsync(testBytes32, badOffset)).to.be.rejectedWith(constants.REVERT);
return expect(libBytes.publicReadBytes32.callAsync(testBytes32, badOffset)).to.be.rejectedWith(
constants.REVERT,
);
});
});
@@ -194,7 +200,7 @@ describe('LibBytes', () => {
const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256);
const byteArray = ethUtil.bufferToHex(testUint256AsBuffer);
const testUint256Offset = new BigNumber(0);
const uint256 = await libBytes.readUint256.callAsync(byteArray, testUint256Offset);
const uint256 = await libBytes.publicReadUint256.callAsync(byteArray, testUint256Offset);
return expect(uint256).to.bignumber.equal(testUint256);
});
@@ -205,13 +211,13 @@ describe('LibBytes', () => {
const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, testUint256AsBuffer]);
const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
const uint256 = await libBytes.readUint256.callAsync(combinedByteArray, testUint256Offset);
const uint256 = await libBytes.publicReadUint256.callAsync(combinedByteArray, testUint256Offset);
return expect(uint256).to.bignumber.equal(testUint256);
});
it('should fail if the byte array is too short to hold a uint256)', async () => {
const offset = new BigNumber(0);
return expect(libBytes.readUint256.callAsync(byteArrayShorterThan32Bytes, offset)).to.be.rejectedWith(
return expect(libBytes.publicReadUint256.callAsync(byteArrayShorterThan32Bytes, offset)).to.be.rejectedWith(
constants.REVERT,
);
});
@@ -221,7 +227,9 @@ describe('LibBytes', () => {
const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256);
const byteArray = ethUtil.bufferToHex(testUint256AsBuffer);
const badOffset = new BigNumber(testUint256AsBuffer.byteLength);
return expect(libBytes.readUint256.callAsync(byteArray, badOffset)).to.be.rejectedWith(constants.REVERT);
return expect(libBytes.publicReadUint256.callAsync(byteArray, badOffset)).to.be.rejectedWith(
constants.REVERT,
);
});
});