Update Exchange contract to use libraries

This commit is contained in:
Amir Bandeali 2019-07-29 21:58:24 -05:00
parent 7eb64eb3dc
commit ae859fa01e
5 changed files with 46 additions and 30 deletions

View File

@ -19,9 +19,11 @@ pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol";
import "./interfaces/IExchangeCore.sol"; import "./interfaces/IExchangeCore.sol";
import "./interfaces/IExchangeRichErrors.sol"; import "./interfaces/IExchangeRichErrors.sol";
import "./LibExchangeRichErrors.sol"; import "./LibExchangeRichErrors.sol";
@ -30,11 +32,14 @@ import "./MixinSignatureValidator.sol";
contract MixinExchangeCore is contract MixinExchangeCore is
LibEIP712ExchangeDomain,
IExchangeCore, IExchangeCore,
LibMath,
MixinAssetProxyDispatcher, MixinAssetProxyDispatcher,
MixinSignatureValidator MixinSignatureValidator
{ {
using LibOrder for LibOrder.Order;
using LibSafeMath for uint256;
// Mapping of orderHash => amount of takerAsset already bought by maker // Mapping of orderHash => amount of takerAsset already bought by maker
mapping (bytes32 => uint256) public filled; mapping (bytes32 => uint256) public filled;
@ -121,7 +126,7 @@ contract MixinExchangeCore is
returns (LibOrder.OrderInfo memory orderInfo) returns (LibOrder.OrderInfo memory orderInfo)
{ {
// Compute the order hash // Compute the order hash
orderInfo.orderHash = LibOrder.getOrderHash(order); orderInfo.orderHash = order.getOrderHash(EIP712_EXCHANGE_DOMAIN_HASH);
// Fetch filled amount // Fetch filled amount
orderInfo.orderTakerAssetFilledAmount = filled[orderInfo.orderHash]; orderInfo.orderTakerAssetFilledAmount = filled[orderInfo.orderHash];
@ -200,8 +205,8 @@ contract MixinExchangeCore is
); );
// Get amount of takerAsset to fill // Get amount of takerAsset to fill
uint256 remainingTakerAssetAmount = _safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount); uint256 remainingTakerAssetAmount = order.takerAssetAmount.safeSub(orderInfo.orderTakerAssetFilledAmount);
uint256 takerAssetFilledAmount = _min256(takerAssetFillAmount, remainingTakerAssetAmount); uint256 takerAssetFilledAmount = LibSafeMath.min256(takerAssetFillAmount, remainingTakerAssetAmount);
// Compute proportional fill amounts // Compute proportional fill amounts
fillResults = LibFillResults.calculateFillResults(order, takerAssetFilledAmount); fillResults = LibFillResults.calculateFillResults(order, takerAssetFilledAmount);
@ -263,7 +268,7 @@ contract MixinExchangeCore is
internal internal
{ {
// Update state // Update state
filled[orderHash] = _safeAdd(orderTakerAssetFilledAmount, fillResults.takerAssetFilledAmount); filled[orderHash] = orderTakerAssetFilledAmount.safeAdd(fillResults.takerAssetFilledAmount);
// Emit a Fill() event THE HARD WAY to avoid a stack overflow. // Emit a Fill() event THE HARD WAY to avoid a stack overflow.
// All this logic is equivalent to: // All this logic is equivalent to:

View File

@ -29,6 +29,7 @@ contract MixinMatchOrders is
IMatchOrders IMatchOrders
{ {
using LibBytes for bytes; using LibBytes for bytes;
using LibSafeMath for uint256;
/// @dev Match complementary orders that have a profitable spread. /// @dev Match complementary orders that have a profitable spread.
/// Each order is filled at their respective price point, and /// Each order is filled at their respective price point, and
@ -163,8 +164,8 @@ contract MixinMatchOrders is
// AND // AND
// <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount> >= <leftOrder.takerAssetAmount> / <leftOrder.makerAssetAmount> // <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount> >= <leftOrder.takerAssetAmount> / <leftOrder.makerAssetAmount>
// These equations can be combined to get the following: // These equations can be combined to get the following:
if (_safeMul(leftOrder.makerAssetAmount, rightOrder.makerAssetAmount) < if (leftOrder.makerAssetAmount.safeMul(rightOrder.makerAssetAmount) <
_safeMul(leftOrder.takerAssetAmount, rightOrder.takerAssetAmount)) { leftOrder.takerAssetAmount.safeMul(rightOrder.takerAssetAmount)) {
LibRichErrors._rrevert(LibExchangeRichErrors.NegativeSpreadError( LibRichErrors._rrevert(LibExchangeRichErrors.NegativeSpreadError(
leftOrderInfo.orderHash, leftOrderInfo.orderHash,
rightOrderInfo.orderHash rightOrderInfo.orderHash
@ -245,33 +246,29 @@ contract MixinMatchOrders is
); );
// Update the orderInfo structs with the updated takerAssetFilledAmount // Update the orderInfo structs with the updated takerAssetFilledAmount
leftOrderInfo.orderTakerAssetFilledAmount = _safeAdd( leftOrderInfo.orderTakerAssetFilledAmount = leftOrderInfo.orderTakerAssetFilledAmount.safeAdd(
leftOrderInfo.orderTakerAssetFilledAmount,
matchResults.left.takerAssetFilledAmount matchResults.left.takerAssetFilledAmount
); );
rightOrderInfo.orderTakerAssetFilledAmount = _safeAdd( rightOrderInfo.orderTakerAssetFilledAmount = rightOrderInfo.orderTakerAssetFilledAmount.safeAdd(
rightOrderInfo.orderTakerAssetFilledAmount,
matchResults.right.takerAssetFilledAmount matchResults.right.takerAssetFilledAmount
); );
// Aggregate the new fill results with the previous fill results for the current orders. // Aggregate the new fill results with the previous fill results for the current orders.
leftFillResults = LibFillResults._addFillResults( leftFillResults = LibFillResults.addFillResults(
leftFillResults, leftFillResults,
matchResults.left matchResults.left
); );
rightFillResults = LibFillResults._addFillResults( rightFillResults = LibFillResults.addFillResults(
rightFillResults, rightFillResults,
matchResults.right matchResults.right
); );
// Update the profit in the left and right maker assets using the profits from // Update the profit in the left and right maker assets using the profits from
// the match. // the match.
batchMatchedFillResults.profitInLeftMakerAsset = _safeAdd( batchMatchedFillResults.profitInLeftMakerAsset = batchMatchedFillResults.profitInLeftMakerAsset.safeAdd(
batchMatchedFillResults.profitInLeftMakerAsset,
matchResults.profitInLeftMakerAsset matchResults.profitInLeftMakerAsset
); );
batchMatchedFillResults.profitInRightMakerAsset = _safeAdd( batchMatchedFillResults.profitInRightMakerAsset = batchMatchedFillResults.profitInRightMakerAsset.safeAdd(
batchMatchedFillResults.profitInRightMakerAsset,
matchResults.profitInRightMakerAsset matchResults.profitInRightMakerAsset
); );
@ -368,7 +365,12 @@ contract MixinMatchOrders is
takerAddress, takerAddress,
rightSignature rightSignature
); );
_assertValidMatch(leftOrder, rightOrder); _assertValidMatch(
leftOrder,
rightOrder,
leftOrderInfo,
rightOrderInfo
);
// Compute proportional fill amounts // Compute proportional fill amounts
matchedFillResults = LibFillResults.calculateMatchedFillResults( matchedFillResults = LibFillResults.calculateMatchedFillResults(
@ -493,10 +495,7 @@ contract MixinMatchOrders is
leftOrder.takerFeeAssetData, leftOrder.takerFeeAssetData,
takerAddress, takerAddress,
leftFeeRecipientAddress, leftFeeRecipientAddress,
_safeAdd( matchedFillResults.left.takerFeePaid.safeAdd(matchedFillResults.right.takerFeePaid)
matchedFillResults.left.takerFeePaid,
matchedFillResults.right.takerFeePaid
)
); );
} else { } else {
// Right taker fee -> right fee recipient // Right taker fee -> right fee recipient

View File

@ -25,6 +25,7 @@ import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/ReentrancyGuard.sol"; import "@0x/contracts-utils/contracts/src/ReentrancyGuard.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol";
import "./interfaces/IWallet.sol"; import "./interfaces/IWallet.sol";
import "./interfaces/IEIP1271Wallet.sol"; import "./interfaces/IEIP1271Wallet.sol";
import "./interfaces/IExchangeRichErrors.sol"; import "./interfaces/IExchangeRichErrors.sol";
@ -35,11 +36,14 @@ import "./MixinTransactions.sol";
contract MixinSignatureValidator is contract MixinSignatureValidator is
ReentrancyGuard, ReentrancyGuard,
LibEIP712ExchangeDomain,
LibEIP1271, LibEIP1271,
ISignatureValidator, ISignatureValidator,
MixinTransactions MixinTransactions
{ {
using LibBytes for bytes; using LibBytes for bytes;
using LibOrder for LibOrder.Order;
using LibZeroExTransaction for LibZeroExTransaction.ZeroExTransaction;
// Magic bytes to be returned by `Wallet` signature type validators. // Magic bytes to be returned by `Wallet` signature type validators.
// bytes4(keccak256("isValidWalletSignature(bytes32,address,bytes)")) // bytes4(keccak256("isValidWalletSignature(bytes32,address,bytes)"))
@ -134,7 +138,7 @@ contract MixinSignatureValidator is
view view
returns (bool isValid) returns (bool isValid)
{ {
bytes32 orderHash = LibOrder.getOrderHash(order); bytes32 orderHash = order.getOrderHash(EIP712_EXCHANGE_DOMAIN_HASH);
return _isValidOrderWithHashSignature( return _isValidOrderWithHashSignature(
order, order,
orderHash, orderHash,
@ -154,7 +158,7 @@ contract MixinSignatureValidator is
view view
returns (bool isValid) returns (bool isValid)
{ {
bytes32 transactionHash = LibZeroExTransaction.getTransactionHash(transaction); bytes32 transactionHash = transaction.getTransactionHash(EIP712_EXCHANGE_DOMAIN_HASH);
isValid = _isValidTransactionWithHashSignature( isValid = _isValidTransactionWithHashSignature(
transaction, transaction,
transactionHash, transactionHash,

View File

@ -20,6 +20,7 @@ pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol";
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "./interfaces/IExchangeRichErrors.sol"; import "./interfaces/IExchangeRichErrors.sol";
import "./interfaces/ITransactions.sol"; import "./interfaces/ITransactions.sol";
@ -28,9 +29,12 @@ import "./LibExchangeRichErrors.sol";
contract MixinTransactions is contract MixinTransactions is
LibEIP712ExchangeDomain,
ISignatureValidator, ISignatureValidator,
ITransactions ITransactions
{ {
using LibZeroExTransaction for LibZeroExTransaction.ZeroExTransaction;
// Mapping of transaction hash => executed // Mapping of transaction hash => executed
// This prevents transactions from being executed more than once. // This prevents transactions from being executed more than once.
mapping (bytes32 => bool) public transactionsExecuted; mapping (bytes32 => bool) public transactionsExecuted;
@ -82,7 +86,7 @@ contract MixinTransactions is
internal internal
returns (bytes memory) returns (bytes memory)
{ {
bytes32 transactionHash = LibZeroExTransaction.getTransactionHash(transaction); bytes32 transactionHash = transaction.getTransactionHash(EIP712_EXCHANGE_DOMAIN_HASH);
// Check transaction is not expired // Check transaction is not expired
// solhint-disable-next-line not-rely-on-time // solhint-disable-next-line not-rely-on-time

View File

@ -19,8 +19,10 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
import "./interfaces/IExchangeCore.sol"; import "./interfaces/IExchangeCore.sol";
import "./interfaces/IExchangeRichErrors.sol"; import "./interfaces/IExchangeRichErrors.sol";
@ -33,6 +35,8 @@ contract MixinWrapperFunctions is
IWrapperFunctions, IWrapperFunctions,
MixinExchangeCore MixinExchangeCore
{ {
using LibSafeMath for uint256;
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled. /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
/// @param order Order struct containing order specifications. /// @param order Order struct containing order specifications.
/// @param takerAssetFillAmount Desired amount of takerAsset to sell. /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
@ -186,7 +190,7 @@ contract MixinWrapperFunctions is
orders[i].takerAssetData = takerAssetData; orders[i].takerAssetData = takerAssetData;
// Calculate the remaining amount of takerAsset to sell // Calculate the remaining amount of takerAsset to sell
uint256 remainingTakerAssetFillAmount = _safeSub(takerAssetFillAmount, fillResults.takerAssetFilledAmount); uint256 remainingTakerAssetFillAmount = takerAssetFillAmount.safeSub(fillResults.takerAssetFilledAmount);
// Attempt to sell the remaining amount of takerAsset // Attempt to sell the remaining amount of takerAsset
LibFillResults.FillResults memory singleFillResults = fillOrderNoThrow( LibFillResults.FillResults memory singleFillResults = fillOrderNoThrow(
@ -196,7 +200,7 @@ contract MixinWrapperFunctions is
); );
// Update amounts filled and fees paid by maker and taker // Update amounts filled and fees paid by maker and taker
fillResults = LibFillResults._addFillResults(fillResults, singleFillResults); fillResults = LibFillResults.addFillResults(fillResults, singleFillResults);
// Stop execution if the entire amount of takerAsset has been sold // Stop execution if the entire amount of takerAsset has been sold
if (fillResults.takerAssetFilledAmount >= takerAssetFillAmount) { if (fillResults.takerAssetFilledAmount >= takerAssetFillAmount) {
@ -230,11 +234,11 @@ contract MixinWrapperFunctions is
orders[i].makerAssetData = makerAssetData; orders[i].makerAssetData = makerAssetData;
// Calculate the remaining amount of makerAsset to buy // Calculate the remaining amount of makerAsset to buy
uint256 remainingMakerAssetFillAmount = _safeSub(makerAssetFillAmount, fillResults.makerAssetFilledAmount); uint256 remainingMakerAssetFillAmount = makerAssetFillAmount.safeSub(fillResults.makerAssetFilledAmount);
// Convert the remaining amount of makerAsset to buy into remaining amount // 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 // of takerAsset to sell, assuming entire amount can be sold in the current order
uint256 remainingTakerAssetFillAmount = _getPartialAmountFloor( uint256 remainingTakerAssetFillAmount = LibMath.getPartialAmountFloor(
orders[i].takerAssetAmount, orders[i].takerAssetAmount,
orders[i].makerAssetAmount, orders[i].makerAssetAmount,
remainingMakerAssetFillAmount remainingMakerAssetFillAmount
@ -248,7 +252,7 @@ contract MixinWrapperFunctions is
); );
// Update amounts filled and fees paid by maker and taker // Update amounts filled and fees paid by maker and taker
fillResults = LibFillResults._addFillResults(fillResults, singleFillResults); fillResults = LibFillResults.addFillResults(fillResults, singleFillResults);
// Stop execution if the entire amount of makerAsset has been bought // Stop execution if the entire amount of makerAsset has been bought
if (fillResults.makerAssetFilledAmount >= makerAssetFillAmount) { if (fillResults.makerAssetFilledAmount >= makerAssetFillAmount) {