This repository has been archived by the owner on Jul 9, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 465
Add transfer simulator and reorder Exchange transfers #1868
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
0cc7348
Add MixinTransferSimulator
abandeali1 8d19ba9
Add tests for simulateTransferFromCalls
abandeali1 63a233d
Swap ordering of transfers in fills and remove redundant checks
abandeali1 bac7004
Add OrderTransferSimulationUtils
abandeali1 cc1d687
Add tests for OrderTransferSimulationUtils
abandeali1 92540a8
Reorder matchOrder transfers and remove redundant checks
abandeali1 c6a063f
Add fillOrder transfer ordering tests
abandeali1 e959dd1
Update CHANGELOGs
abandeali1 b59145e
Update comments and add a catch-all else in getSimulatedOrderTransfer…
abandeali1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
154 changes: 154 additions & 0 deletions
154
contracts/dev-utils/contracts/src/OrderTransferSimulationUtils.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
/* | ||
|
||
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.5.5; | ||
pragma experimental ABIEncoderV2; | ||
|
||
|
||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; | ||
import "@0x/contracts-exchange/contracts/src/libs/LibExchangeRichErrorDecoder.sol"; | ||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; | ||
import "@0x/contracts-utils/contracts/src/LibBytes.sol"; | ||
|
||
|
||
contract OrderTransferSimulationUtils is | ||
LibExchangeRichErrorDecoder | ||
{ | ||
using LibBytes for bytes; | ||
|
||
enum OrderTransferResults { | ||
TakerAssetDataFailed, // Transfer of takerAsset failed | ||
MakerAssetDataFailed, // Transfer of makerAsset failed | ||
TakerFeeAssetDataFailed, // Transfer of takerFeeAsset failed | ||
MakerFeeAssetDataFailed, // Transfer of makerFeeAsset failed | ||
TransfersSuccessful // All transfers in the order were successful | ||
} | ||
|
||
// simulateDispatchTransferFromCalls(bytes[],address[],address[],uint256[]) | ||
bytes4 constant internal _SIMULATE_DISPATCH_TRANSFER_FROM_CALLS_SELECTOR = 0xb04fbddd; | ||
|
||
// keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL")); | ||
bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0; | ||
|
||
// solhint-disable var-name-mixedcase | ||
IExchange internal _EXCHANGE; | ||
// solhint-enable var-name-mixedcase | ||
|
||
constructor (address _exchange) | ||
public | ||
{ | ||
_EXCHANGE = IExchange(_exchange); | ||
} | ||
|
||
/// @dev Simulates all of the transfers within an order and returns the index of the first failed transfer. | ||
/// @param order The order to simulate transfers for. | ||
/// @param takerAddress The address of the taker that will fill the order. | ||
/// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill. | ||
/// @return The index of the first failed transfer (or 4 if all transfers are successful). | ||
function getSimulatedOrderTransferResults( | ||
LibOrder.Order memory order, | ||
address takerAddress, | ||
uint256 takerAssetFillAmount | ||
) | ||
public | ||
returns (OrderTransferResults orderTransferResults) | ||
{ | ||
// Create input arrays | ||
bytes[] memory assetData = new bytes[](4); | ||
address[] memory fromAddresses = new address[](4); | ||
address[] memory toAddresses = new address[](4); | ||
uint256[] memory amounts = new uint256[](4); | ||
|
||
// Transfer `takerAsset` from taker to maker | ||
assetData[0] = order.takerAssetData; | ||
fromAddresses[0] = takerAddress; | ||
toAddresses[0] = order.makerAddress; | ||
amounts[0] = order.takerAssetAmount; | ||
|
||
// Transfer `makerAsset` from maker to taker | ||
assetData[1] = order.makerAssetData; | ||
fromAddresses[1] = order.makerAddress; | ||
toAddresses[1] = takerAddress; | ||
amounts[1] = order.makerAssetAmount; | ||
|
||
// Transfer `takerFeeAsset` from taker to feeRecipient | ||
assetData[2] = order.takerFeeAssetData; | ||
fromAddresses[2] = takerAddress; | ||
toAddresses[2] = order.feeRecipientAddress; | ||
amounts[2] = order.takerFee; | ||
|
||
// Transfer `makerFeeAsset` from maker to feeRecipient | ||
assetData[3] = order.makerFeeAssetData; | ||
fromAddresses[3] = order.makerAddress; | ||
toAddresses[3] = order.feeRecipientAddress; | ||
amounts[3] = order.makerFee; | ||
|
||
// Encode data for `simulateDispatchTransferFromCalls(assetData, fromAddresses, toAddresses, amounts)` | ||
bytes memory simulateDispatchTransferFromCallsData = abi.encodeWithSelector( | ||
_SIMULATE_DISPATCH_TRANSFER_FROM_CALLS_SELECTOR, | ||
assetData, | ||
fromAddresses, | ||
toAddresses, | ||
amounts | ||
); | ||
|
||
// Perform call and catch revert | ||
(, bytes memory returnData) = address(_EXCHANGE).call(simulateDispatchTransferFromCallsData); | ||
|
||
bytes4 selector = returnData.readBytes4(0); | ||
if (selector == ASSET_PROXY_DISPATCH_ERROR_SELECTOR) { | ||
// Decode AssetProxyDispatchError and return index of failed transfer | ||
(, bytes32 failedTransferIndex,) = decodeAssetProxyDispatchError(returnData); | ||
return OrderTransferResults(uint8(uint256(failedTransferIndex))); | ||
} else if (selector == ASSET_PROXY_TRANSFER_ERROR_SELECTOR) { | ||
// Decode AssetProxyTransferError and return index of failed transfer | ||
(bytes32 failedTransferIndex, ,) = decodeAssetProxyTransferError(returnData); | ||
return OrderTransferResults(uint8(uint256(failedTransferIndex))); | ||
} else if (keccak256(returnData) == _TRANSFERS_SUCCESSFUL_RESULT_HASH) { | ||
// All transfers were successful | ||
return OrderTransferResults.TransfersSuccessful; | ||
} else { | ||
revert("UNKNOWN_RETURN_DATA"); | ||
} | ||
} | ||
|
||
/// @dev Simulates all of the transfers for each given order and returns the indices of each first failed transfer. | ||
/// @param orders Array of orders to individually simulate transfers for. | ||
/// @param takerAddresses Array of addresses of takers that will fill each order. | ||
/// @param takerAssetFillAmounts Array of amounts of takerAsset that will be filled for each order. | ||
/// @return The indices of the first failed transfer (or 4 if all transfers are successful) for each order. | ||
function getSimulatedOrdersTransferResults( | ||
LibOrder.Order[] memory orders, | ||
address[] memory takerAddresses, | ||
uint256[] memory takerAssetFillAmounts | ||
) | ||
public | ||
returns (OrderTransferResults[] memory orderTransferResults) | ||
{ | ||
uint256 length = orders.length; | ||
orderTransferResults = new OrderTransferResults[](length); | ||
for (uint256 i = 0; i != length; i++) { | ||
orderTransferResults[i] = getSimulatedOrderTransferResults( | ||
orders[i], | ||
takerAddresses[i], | ||
takerAssetFillAmounts[i] | ||
); | ||
} | ||
return orderTransferResults; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit - it could be good to add a catch-all
else
here to show that we've considered all cases + for future-proofing.