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

Revert to old ReentrancyGuard implementation + random cleanup #2101

Merged
merged 6 commits into from
Aug 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 9 additions & 9 deletions contracts/asset-proxy/contracts/src/interfaces/IAssetData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,35 +43,35 @@ interface IAssetData {
/// @dev Function signature for encoding ERC1155 assetData.
/// @param tokenAddress Address of ERC1155 token contract.
/// @param tokenIds Array of ids of tokens to be transferred.
/// @param tokenValues Array of values that correspond to each token id to be transferred.
/// @param values Array of values that correspond to each token id to be transferred.
/// Note that each value will be multiplied by the amount being filled in the order before transferring.
/// @param callbackData Extra data to be passed to receiver's `onERC1155Received` callback function.
function ERC1155Assets(
address tokenAddress,
uint256[] calldata tokenIds,
uint256[] calldata tokenValues,
uint256[] calldata values,
bytes calldata callbackData
)
external;

/// @dev Function signature for encoding MultiAsset assetData.
/// @param amounts Array of amounts that correspond to each asset to be transferred.
/// @param values Array of amounts that correspond to each asset to be transferred.
/// Note that each value will be multiplied by the amount being filled in the order before transferring.
/// @param nestedAssetData Array of assetData fields that will be be dispatched to their correspnding AssetProxy contract.
function MultiAsset(
uint256[] calldata amounts,
uint256[] calldata values,
bytes[] calldata nestedAssetData
)
external;

/// @dev Function signature for encoding StaticCall assetData.
/// @param callTarget Contract that will execute the staticcall.
/// @param staticCallData Data that will be executed via staticcall on the callTarget contract.
/// @param callResultHash Keccak256 hash of the expected staticcall return data.
/// @param staticCallTargetAddress Address that will execute the staticcall.
/// @param staticCallData Data that will be executed via staticcall on the staticCallTargetAddress.
/// @param expectedReturnDataHash Keccak-256 hash of the expected staticcall return data.
function StaticCall(
address callTarget,
address staticCallTargetAddress,
bytes calldata staticCallData,
bytes32 callResultHash
bytes32 expectedReturnDataHash
)
external;
}
18 changes: 14 additions & 4 deletions contracts/exchange-libs/contracts/src/LibExchangeRichErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ library LibExchangeRichErrors {
bytes4 internal constant ORDER_EPOCH_ERROR_SELECTOR =
0x4ad31275;

// bytes4(keccak256("AssetProxyExistsError(address)"))
// bytes4(keccak256("AssetProxyExistsError(bytes4,address)"))
bytes4 internal constant ASSET_PROXY_EXISTS_ERROR_SELECTOR =
0xcc8b3b53;
0x11c7b720;

// bytes4(keccak256("AssetProxyDispatchError(uint8,bytes32,bytes)"))
bytes4 internal constant ASSET_PROXY_DISPATCH_ERROR_SELECTOR =
Expand Down Expand Up @@ -308,6 +308,14 @@ library LibExchangeRichErrors {
return TRANSACTION_GAS_PRICE_ERROR_SELECTOR;
}

function TransactionInvalidContextErrorSelector()
internal
pure
returns (bytes4)
{
return TRANSACTION_INVALID_CONTEXT_ERROR_SELECTOR;
}

function BatchMatchOrdersError(
BatchMatchOrdersErrorCodes errorCode
)
Expand Down Expand Up @@ -488,15 +496,17 @@ library LibExchangeRichErrors {
}

function AssetProxyExistsError(
address proxyAddress
bytes4 assetProxyId,
address assetProxyAddress
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
ASSET_PROXY_EXISTS_ERROR_SELECTOR,
proxyAddress
assetProxyId,
assetProxyAddress
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ contract MixinAssetProxyDispatcher is
bytes4 assetProxyId = IAssetProxy(assetProxy).getProxyId();
address currentAssetProxy = assetProxies[assetProxyId];
if (currentAssetProxy != address(0)) {
LibRichErrors.rrevert(LibExchangeRichErrors.AssetProxyExistsError(currentAssetProxy));
LibRichErrors.rrevert(LibExchangeRichErrors.AssetProxyExistsError(
assetProxyId,
currentAssetProxy
));
}

// Add asset proxy and log registration.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,16 +238,18 @@ contract LibExchangeRichErrorDecoder {

/// @dev Decompose an ABI-encoded AssetProxyExistsError.
/// @param encoded ABI-encoded revert error.
/// @return proxyAddress The address of the asset proxy.
/// @return assetProxyId Id of asset proxy.
/// @return assetProxyAddress The address of the asset proxy.
function decodeAssetProxyExistsError(bytes memory encoded)
public
pure
returns (address assetProxyAddress)
returns (
bytes4 assetProxyId, address assetProxyAddress)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.AssetProxyExistsErrorSelector());
(assetProxyAddress) = abi.decode(
(assetProxyId, assetProxyAddress) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(address)
(bytes4, address)
);
}

Expand Down
4 changes: 2 additions & 2 deletions contracts/exchange/contracts/test/IsolatedExchange.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ contract IsolatedExchange is
Exchange(1337)
{}

/// @dev Overriden to only log arguments and revert on certain assetDatas.
/// @dev Overridden to only log arguments and revert on certain assetDatas.
function _dispatchTransferFrom(
bytes32 orderHash,
bytes memory assetData,
Expand All @@ -69,7 +69,7 @@ contract IsolatedExchange is
}
}

/// @dev Overriden to simplify signature validation.
/// @dev Overridden to simplify signature validation.
/// Unfortunately, this is `view`, so it can't log arguments.
function _isValidOrderWithHashSignature(
LibOrder.Order memory order,
Expand Down
51 changes: 36 additions & 15 deletions contracts/exchange/contracts/test/ReentrancyTester.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,15 @@ contract ReentrancyTester is
{}

/// @dev Calls a public function to check if it is reentrant.
/// Because this function uses the `nonReentrant` modifier, if
/// the function being called is also guarded by the `nonReentrant` modifier,
/// it will revert when it returns.
function isReentrant(bytes calldata fnCallData)
external
nonReentrant
returns (bool isReentrant)
{
bytes memory callData = abi.encodeWithSelector(this.testReentrantFunction.selector, fnCallData);
(bool didSucceed, bytes memory resultData) = address(this).delegatecall(callData);
(bool didSucceed, bytes memory resultData) = address(this).delegatecall(fnCallData);
if (didSucceed) {
isReentrant = true;
} else {
Expand All @@ -61,18 +64,36 @@ contract ReentrancyTester is
}
}

/// @dev Calls a public function to check if it is reentrant.
/// Because this function uses the `nonReentrant` modifier, if
/// the function being called is also guarded by the `nonReentrant` modifier,
/// it will revert when it returns.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this comment up to isReentrant now that it has the nonReentrant modifier

function testReentrantFunction(bytes calldata fnCallData)
external
nonReentrant
/// @dev Overridden to revert on unsuccessful fillOrder call.
function fillOrderNoThrow(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This almost feels not worth testing since it's bascially rewriting fillOrderNoThrow. I guess it's fine for now until we can come up with some clever way of getting around it.

LibOrder.Order memory order,
uint256 takerAssetFillAmount,
bytes memory signature
)
public
returns (LibFillResults.FillResults memory fillResults)
{
address(this).delegatecall(fnCallData);
// ABI encode calldata for `fillOrder`
bytes memory fillOrderCalldata = abi.encodeWithSelector(
IExchangeCore(address(0)).fillOrder.selector,
order,
takerAssetFillAmount,
signature
);

(bool didSucceed, bytes memory returnData) = address(this).delegatecall(fillOrderCalldata);
if (didSucceed) {
assert(returnData.length == 128);
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
return fillResults;
}
// Revert and rethrow error if unsuccessful
assembly {
revert(add(returnData, 32), mload(returnData))
}
}

/// @dev Overriden to always succeed.
/// @dev Overridden to always succeed.
function _fillOrder(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
Expand All @@ -87,7 +108,7 @@ contract ReentrancyTester is
fillResults.takerFeePaid = order.takerFee;
}

/// @dev Overriden to always succeed.
/// @dev Overridden to always succeed.
function _fillOrKillOrder(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
Expand All @@ -114,7 +135,7 @@ contract ReentrancyTester is
return resultData;
}

/// @dev Overriden to always succeed.
/// @dev Overridden to always succeed.
function _batchMatchOrders(
LibOrder.Order[] memory leftOrders,
LibOrder.Order[] memory rightOrders,
Expand Down Expand Up @@ -144,7 +165,7 @@ contract ReentrancyTester is
}
}

/// @dev Overriden to always succeed.
/// @dev Overridden to always succeed.
function _matchOrders(
LibOrder.Order memory leftOrder,
LibOrder.Order memory rightOrder,
Expand All @@ -169,7 +190,7 @@ contract ReentrancyTester is
});
}

/// @dev Overriden to do nothing.
/// @dev Overridden to do nothing.
function _cancelOrder(LibOrder.Order memory order)
internal
{}
Expand Down
7 changes: 1 addition & 6 deletions contracts/exchange/test/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -618,12 +618,7 @@ blockchainTests.resets('Exchange core', () => {
salt: new BigNumber(3),
}),
];
await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 600000,
});
await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress);

const newBalances = await erc20Wrapper.getBalancesAsync();
const fillMakerAssetAmount = signedOrders[2].makerAssetAmount.plus(signedOrders[3].makerAssetAmount);
Expand Down
2 changes: 1 addition & 1 deletion contracts/exchange/test/dispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ describe('AssetProxyDispatcher', () => {
txDefaults,
dependencyArtifacts,
);
const expectedError = new ExchangeRevertErrors.AssetProxyExistsError(proxyAddress);
const expectedError = new ExchangeRevertErrors.AssetProxyExistsError(AssetProxyId.ERC20, proxyAddress);
const tx = assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(newErc20TransferProxy.address, {
from: owner,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import * as _ from 'lodash';
import { artifacts, TestLibExchangeRichErrorDecoderContract } from '../src';

blockchainTests.resets('LibExchangeRichErrorDecoder', ({ provider, txDefaults }) => {
const ASSET_PROXY_ID_LENGTH = 4;
const SIGNATURE_LENGTH = 66;
const ASSET_DATA_LENGTH = 36;
const ERROR_DATA_LENGTH = 100;
Expand Down Expand Up @@ -103,7 +104,10 @@ blockchainTests.resets('LibExchangeRichErrorDecoder', ({ provider, txDefaults })

(() => {
const assetProxyAddress = addressUtils.generatePseudoRandomAddress();
createDecodeTest(ExchangeRevertErrors.AssetProxyExistsError, [assetProxyAddress]);
createDecodeTest(ExchangeRevertErrors.AssetProxyExistsError, [
hexRandom(ASSET_PROXY_ID_LENGTH),
assetProxyAddress,
]);
})();

(() => {
Expand Down
40 changes: 0 additions & 40 deletions contracts/exchange/test/wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,6 @@ blockchainTests.resets('Exchange wrappers', env => {
);
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress, {
takerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 250000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();

Expand Down Expand Up @@ -450,10 +446,6 @@ blockchainTests.resets('Exchange wrappers', env => {
);
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress, {
takerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 280000,
});

// Verify post-conditions
Expand Down Expand Up @@ -688,10 +680,6 @@ blockchainTests.resets('Exchange wrappers', env => {
);
await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
takerAssetFillAmounts,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 600000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();

Expand Down Expand Up @@ -763,10 +751,6 @@ blockchainTests.resets('Exchange wrappers', env => {
);
await exchangeWrapper.batchFillOrdersNoThrowAsync(newOrders, takerAddress, {
takerAssetFillAmounts,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 450000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();

Expand All @@ -789,10 +773,6 @@ blockchainTests.resets('Exchange wrappers', env => {
);
await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
takerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 6000000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();

Expand Down Expand Up @@ -864,10 +844,6 @@ blockchainTests.resets('Exchange wrappers', env => {
);
await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
takerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 600000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();

Expand Down Expand Up @@ -938,10 +914,6 @@ blockchainTests.resets('Exchange wrappers', env => {
);
await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
takerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 600000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();

Expand Down Expand Up @@ -985,10 +957,6 @@ blockchainTests.resets('Exchange wrappers', env => {
);
await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
makerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 600000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();

Expand Down Expand Up @@ -1060,10 +1028,6 @@ blockchainTests.resets('Exchange wrappers', env => {
);
await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
makerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 600000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();

Expand Down Expand Up @@ -1135,10 +1099,6 @@ blockchainTests.resets('Exchange wrappers', env => {
);
await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
makerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 600000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();

Expand Down
Loading