Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

[3.0] Exchange Rich Reverts (once more, with feeling!) #1761

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
96af267
Reimplementing rich reverts in the contracts.
dorothy-zbornak Mar 29, 2019
a1fded8
Convert to use rich reverts
dorothy-zbornak Mar 30, 2019
14ccab1
Change `LibRichErrors` to just `RichErrors`.
dorothy-zbornak Apr 1, 2019
12b36b7
Convert `MixinExchangeCore` to use rich errors.
dorothy-zbornak Apr 2, 2019
f7aa989
Convert `MixinMatchOrders` to use rich reverts
dorothy-zbornak Apr 2, 2019
fa2b673
Convert `MixinSignatureValidator` to use rich reverts
dorothy-zbornak Apr 2, 2019
acc1968
Convert `MixinTransactions` to use rich reverts
dorothy-zbornak Apr 2, 2019
b1c0151
Convert `exchange` `MixinWrapperFunctions` to use rich reverts
dorothy-zbornak Apr 2, 2019
d50d1ad
Add `OrderStatus` to `@0x/types`
dorothy-zbornak Apr 2, 2019
ee2387a
Add `chaiSetup` function wtih rich revert support to `@0x/dev-utils`
dorothy-zbornak Apr 2, 2019
ea1544d
Add `RichRevertAbi` to `etherem-types`
dorothy-zbornak Apr 2, 2019
ca602f5
Inherit `chaiSetup` from `@0x/dev-utils`
dorothy-zbornak Apr 2, 2019
00f04ac
In `contract-wrappers`, inherit `chaiSetup` from `@0x/dev-utils`
dorothy-zbornak Apr 2, 2019
e538540
In `order-utils`, inherit `chaiSetup` from `@0x/dev-utils`
dorothy-zbornak Apr 2, 2019
068338f
Add `RichRevertReason` type and utilities to `@0x/utils`
dorothy-zbornak Apr 2, 2019
7f0cb06
Add Exchange rich revert types to `@0x/order-utils`
dorothy-zbornak Apr 2, 2019
93251b2
Make the chai helper for rich reverts in `dev-utils` more robust.
dorothy-zbornak Apr 3, 2019
6f9b049
Remove chai plugin dependencies from `@0x/contract-test-utils` and `@…
dorothy-zbornak Apr 3, 2019
7ab831a
Export `StandardError` from `@0x/utils`
dorothy-zbornak Apr 3, 2019
b4188fe
Ran prettier
dorothy-zbornak Apr 3, 2019
a5f98f7
Fix linter errors.
dorothy-zbornak Apr 4, 2019
c1b9b99
Rename `RichRevertReason` to `RevertError`.
dorothy-zbornak Apr 4, 2019
c61b598
Use new `RevertError` nomenclature.
dorothy-zbornak Apr 4, 2019
688cca6
Make `@0x/base-contract` `_throwIfRevertWithReasonCallResult` decode …
dorothy-zbornak Apr 4, 2019
d7b4407
In `@0x/dev-utils` fix the `RevertError` chai helper's `equal` overri…
dorothy-zbornak Apr 4, 2019
cead5f6
In `@0x/contracts-exchange`: fix contract bugs introduced by changes
dorothy-zbornak Apr 4, 2019
1ec678e
In `@0x/contracts-test-utils` add `generatePseudoRandomOrderHash()` t…
dorothy-zbornak Apr 4, 2019
912c910
In `@0x/order-utils`: Rename `ExchangeErrors` to `ExchangeRevertErrors`.
dorothy-zbornak Apr 4, 2019
b9b0e77
In `@0x/utils`: Add `AnyRevertError` type that matches with any rever…
dorothy-zbornak Apr 4, 2019
ed16086
In `@0x/dev-utils`: Break out `RevertError` helper code into a separa…
dorothy-zbornak Apr 4, 2019
0cca10c
In `@0x/contracts-test-utils`: Inherit `OrderStatus` from `@0x/types`
dorothy-zbornak Apr 4, 2019
9cdcfab
In `@0x/typescript-typings`: Add types for `@0x/dev-utils` chai helpe…
dorothy-zbornak Apr 4, 2019
0c97b3b
In `@0x/dev-utils`: Tweak equality assertion failure `actual` and `ex…
dorothy-zbornak Apr 4, 2019
99103a5
In `@0x/contracts-exchange`: Fix `dispatchTransferFrom` so it preserv…
dorothy-zbornak Apr 4, 2019
f52cbd7
In `@0x/order-utils`: add `AssetProxyTransferError` Exchange `RevertE…
dorothy-zbornak Apr 4, 2019
a422ec2
In `@0x/contracts-exchange`: Fix busted `TestAssetProxyDispatcher.sol`
dorothy-zbornak Apr 4, 2019
4e1da8d
In `@0x/contracts-exchange`: upgrading tests...
dorothy-zbornak Apr 4, 2019
719d557
In `@0x/dev-utils`: swap order of equality check in `RevertError` cha…
dorothy-zbornak Apr 5, 2019
61e1f93
In `@0x/utils` add `encode()` method to `RevertError`
dorothy-zbornak Apr 5, 2019
1867af0
In `@0x/order-utils`: Rename Exchange `RevertError` error codes.
dorothy-zbornak Apr 5, 2019
0ec8026
In `@0x/contract-wrappers`: Update tests
dorothy-zbornak Apr 5, 2019
6132759
In `@0x/contracts-exchange`: Update tests for rich reverts
dorothy-zbornak Apr 5, 2019
eca0618
In `@0x/contract-wrappers`: Update CHANGELOG
dorothy-zbornak Apr 5, 2019
1d7d5c8
Ran prettier and linter
dorothy-zbornak Apr 5, 2019
ac2032d
In `@0x/contracts-extensions`: Upgrade tests for rich reverts
dorothy-zbornak Apr 5, 2019
d8944d5
Fix linter errors
dorothy-zbornak Apr 5, 2019
54b59aa
In `@0x/contracts-test-utils`: Update CHANGELOG
dorothy-zbornak Apr 5, 2019
d3a06ca
Add PRs to changelogs
dorothy-zbornak Apr 5, 2019
e01f8ee
In `@0x/contracts-utils` add natspec comments `RichErrors.StandardError`
dorothy-zbornak Apr 11, 2019
ecd60e1
In `@0x/contracts-utils` switch from `encodePacked` to `encodeWithSel…
dorothy-zbornak Apr 11, 2019
ad5792a
In `@0x/contracts-exchange`: More efficient revert string extraction …
dorothy-zbornak Apr 11, 2019
e172a87
Switch order of parameters in some rich reverts for easier dirty pars…
dorothy-zbornak Apr 11, 2019
c18c975
In `@0x/order-utils`: Add `signerAddress` and `signature` to `Exchang…
dorothy-zbornak Apr 11, 2019
9c104f4
In `@0x/order-utils`: Add `TransactionSignatureError` to `ExchangeRev…
dorothy-zbornak Apr 11, 2019
db1e0e0
In `@0x/contracts-exchange`: Fix line count linter error.
dorothy-zbornak Apr 11, 2019
cb010eb
In `@0x/contracts-exchange`: Fix comments in `MixinSignatureValidator…
dorothy-zbornak Apr 12, 2019
4511d08
Update contracts/exchange/contracts/src/MixinSignatureValidator.sol
abandeali1 Apr 12, 2019
7a19280
In `@0x/order-utils`: Add `SignatureWalletError`, `SignatureValidator…
dorothy-zbornak Apr 12, 2019
fc2a26a
In `@0x/contracts-exchange`: Add `SignatureWalletError` and `Signatur…
dorothy-zbornak Apr 12, 2019
dfb43dd
Ran prettier/linter
dorothy-zbornak Apr 12, 2019
bb15955
In `@0x/contracts-exchange`: Change validator/wallet return value tes…
dorothy-zbornak Apr 12, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions contracts/exchange/CHANGELOG.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
{
"note": "Refactor example contracts that use `executeTransaction`",
"pr": 1753
},
{
"note": "Upgrade all string reverts to rich reverts",
"pr": 1761
}
]
},
Expand Down
1 change: 1 addition & 0 deletions contracts/exchange/compiler.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"test/ReentrantERC20Token.sol",
"test/TestAssetProxyDispatcher.sol",
"test/TestExchangeInternals.sol",
"test/TestRevertReceiver.sol",
"test/TestSignatureValidator.sol",
"test/TestStaticCallReceiver.sol"
]
Expand Down
4 changes: 3 additions & 1 deletion contracts/exchange/contracts/src/Exchange.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import "./MixinWrapperFunctions.sol";
import "./MixinAssetProxyDispatcher.sol";
import "./MixinTransactions.sol";
import "./MixinMatchOrders.sol";
import "./MixinExchangeRichErrors.sol";


// solhint-disable no-empty-blocks
Expand All @@ -35,7 +36,8 @@ contract Exchange is
MixinSignatureValidator,
MixinTransactions,
MixinAssetProxyDispatcher,
MixinWrapperFunctions
MixinWrapperFunctions,
MixinExchangeRichErrors
{
string constant public VERSION = "3.0.0";

Expand Down
87 changes: 60 additions & 27 deletions contracts/exchange/contracts/src/MixinAssetProxyDispatcher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ pragma solidity ^0.5.5;

import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "./mixins/MAssetProxyDispatcher.sol";
import "./mixins/MExchangeRichErrors.sol";
import "./interfaces/IAssetProxy.sol";


contract MixinAssetProxyDispatcher is
Ownable,
MAssetProxyDispatcher
MAssetProxyDispatcher,
MExchangeRichErrors
{
// Mapping from Asset Proxy Id's to their respective Asset Proxy
mapping (bytes4 => address) public assetProxies;
Expand All @@ -40,10 +42,9 @@ contract MixinAssetProxyDispatcher is
// Ensure that no asset proxy exists with current id.
bytes4 assetProxyId = IAssetProxy(assetProxy).getProxyId();
address currentAssetProxy = assetProxies[assetProxyId];
require(
currentAssetProxy == address(0),
"ASSET_PROXY_ALREADY_EXISTS"
);
if (currentAssetProxy != address(0)) {
rrevert(AssetProxyExistsError(currentAssetProxy));
}

// Add asset proxy and log registration.
assetProxies[assetProxyId] = assetProxy;
Expand All @@ -65,11 +66,13 @@ contract MixinAssetProxyDispatcher is
}

/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
/// @param orderHash Hash of the order associated with this transfer.
/// @param assetData Byte array encoded for the asset.
/// @param from Address to transfer token from.
/// @param to Address to transfer token to.
/// @param amount Amount of token to transfer.
function dispatchTransferFrom(
bytes32 orderHash,
bytes memory assetData,
address from,
address to,
Expand All @@ -80,11 +83,14 @@ contract MixinAssetProxyDispatcher is
// Do nothing if no amount should be transferred.
if (amount > 0 && from != to) {
// Ensure assetData length is valid
require(
assetData.length > 3,
"LENGTH_GREATER_THAN_3_REQUIRED"
);

if (assetData.length <= 3) {
rrevert(AssetProxyDispatchError(
AssetProxyDispatchErrorCodes.INVALID_ASSET_DATA_LENGTH,
orderHash,
assetData
));
}

// Lookup assetProxy. We do not use `LibBytes.readBytes4` for gas efficiency reasons.
bytes4 assetProxyId;
assembly {
Expand All @@ -96,14 +102,22 @@ contract MixinAssetProxyDispatcher is
address assetProxy = assetProxies[assetProxyId];

// Ensure that assetProxy exists
require(
assetProxy != address(0),
"ASSET_PROXY_DOES_NOT_EXIST"
);

if (assetProxy == address(0)) {
rrevert(AssetProxyDispatchError(
AssetProxyDispatchErrorCodes.UNKNOWN_ASSET_PROXY,
orderHash,
assetData
));
}

// Whether the AssetProxy transfer succeeded.
bool didSucceed;
// On failure, the revert data thrown by the asset proxy.
bytes memory revertData;

// We construct calldata for the `assetProxy.transferFrom` ABI.
// The layout of this calldata is in the table below.
//
//
// | Area | Offset | Length | Contents |
// | -------- |--------|---------|-------------------------------------------- |
// | Header | 0 | 4 | function selector |
Expand All @@ -127,12 +141,11 @@ contract MixinAssetProxyDispatcher is
// `cdEnd` is the end of the calldata for `assetProxy.transferFrom`.
let cdEnd := add(cdStart, add(132, dataAreaLength))


/////// Setup Header Area ///////
// This area holds the 4-byte `transferFromSelector`.
// bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
mstore(cdStart, 0xa85e59e400000000000000000000000000000000000000000000000000000000)

/////// Setup Params Area ///////
// Each parameter is padded to 32-bytes. The entire Params Area is 128 bytes.
// Notes:
Expand All @@ -142,31 +155,51 @@ contract MixinAssetProxyDispatcher is
mstore(add(cdStart, 36), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(cdStart, 68), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(cdStart, 100), amount)

/////// Setup Data Area ///////
// This area holds `assetData`.
let dataArea := add(cdStart, 132)
let assetDataArea := assetData
// solhint-disable-next-line no-empty-blocks
for {} lt(dataArea, cdEnd) {} {
mstore(dataArea, mload(assetData))
mstore(dataArea, mload(assetDataArea))
dataArea := add(dataArea, 32)
assetData := add(assetData, 32)
assetDataArea := add(assetDataArea, 32)
}

/////// Call `assetProxy.transferFrom` using the constructed calldata ///////
let success := call(
didSucceed := call(
gas, // forward all gas
assetProxy, // call address of asset proxy
0, // don't send any ETH
cdStart, // pointer to start of input
sub(cdEnd, cdStart), // length of input
cdStart, // write output over input
512 // reserve 512 bytes for output
sub(cdEnd, cdStart), // length of input
0, // don't store the returndata
0 // don't store the returndata
)
if iszero(success) {
revert(cdStart, returndatasize())

if iszero(didSucceed) { // Call reverted.
dorothy-zbornak marked this conversation as resolved.
Show resolved Hide resolved
let revertDataSize := returndatasize()
// Construct a `bytes memory` type to hold the revert data
// at `cdStart`.
// The first 32 bytes are the length of the data.
mstore(cdStart, revertDataSize)
// Copy the revert data immediately after the length.
returndatacopy(add(cdStart, 32), 0, revertDataSize)
// We need to move the free memory pointer because we
// still have solidity logic that executes after this assembly.
mstore(64, add(cdStart, add(revertDataSize, 32)))
revertData := cdStart
}
}

if (!didSucceed) {
rrevert(AssetProxyTransferError(
orderHash,
assetData,
revertData
));
}
}
}
}
Loading