forwarder rich errors second pass

This commit is contained in:
Michael Zhu 2019-08-07 17:06:19 -07:00
parent 5879aeac52
commit c9f0c46017
6 changed files with 98 additions and 72 deletions

View File

@ -19,10 +19,12 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/LibBytes.sol"; import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/Ownable.sol"; import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol"; import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
import "./libs/LibConstants.sol"; import "./libs/LibConstants.sol";
import "./libs/LibForwarderRichErrors.sol";
import "./interfaces/IAssets.sol"; import "./interfaces/IAssets.sol";
@ -63,10 +65,9 @@ contract MixinAssets is
// For now we only care about ERC20, since percentage fees on ERC721 tokens are invalid. // For now we only care about ERC20, since percentage fees on ERC721 tokens are invalid.
if (proxyId == ERC20_DATA_ID) { if (proxyId == ERC20_DATA_ID) {
address proxyAddress = EXCHANGE.getAssetProxy(ERC20_DATA_ID); address proxyAddress = EXCHANGE.getAssetProxy(ERC20_DATA_ID);
require( if (proxyAddress == address(0)) {
proxyAddress != address(0), LibRichErrors._rrevert(LibForwarderRichErrors.UnregisteredAssetProxyError());
"UNREGISTERED_ASSET_PROXY" }
);
IERC20Token assetToken = IERC20Token(assetData.readAddress(16)); IERC20Token assetToken = IERC20Token(assetData.readAddress(16));
if (assetToken.allowance(address(this), proxyAddress) != MAX_UINT) { if (assetToken.allowance(address(this), proxyAddress) != MAX_UINT) {
assetToken.approve(proxyAddress, MAX_UINT); assetToken.approve(proxyAddress, MAX_UINT);
@ -90,7 +91,9 @@ contract MixinAssets is
} else if (proxyId == ERC721_DATA_ID) { } else if (proxyId == ERC721_DATA_ID) {
_transferERC721Token(assetData, amount); _transferERC721Token(assetData, amount);
} else { } else {
revert("UNSUPPORTED_ASSET_PROXY"); LibRichErrors._rrevert(LibForwarderRichErrors.UnsupportedAssetProxyError(
proxyId
));
} }
} }
@ -113,10 +116,9 @@ contract MixinAssets is
msg.sender, msg.sender,
amount amount
)); ));
require( if (!success) {
success, LibRichErrors._rrevert(LibForwarderRichErrors.TransferFailedError());
"TRANSFER_FAILED" }
);
// Check return data. // Check return data.
// If there is no return data, we assume the token incorrectly // If there is no return data, we assume the token incorrectly
@ -134,10 +136,9 @@ contract MixinAssets is
} }
} }
} }
require( if (!success) {
success, LibRichErrors._rrevert(LibForwarderRichErrors.TransferFailedError());
"TRANSFER_FAILED" }
);
} }
/// @dev Decodes ERC721 assetData and transfers given amount to sender. /// @dev Decodes ERC721 assetData and transfers given amount to sender.
@ -149,10 +150,11 @@ contract MixinAssets is
) )
internal internal
{ {
require( if (amount != 1) {
amount == 1, LibRichErrors._rrevert(LibForwarderRichErrors.InvalidErc721AmountError(
"INVALID_AMOUNT" amount
); ));
}
// Decode asset data. // Decode asset data.
address token = assetData.readAddress(16); address token = assetData.readAddress(16);
uint256 tokenId = assetData.readUint256(36); uint256 tokenId = assetData.readUint256(36);

View File

@ -19,11 +19,12 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "./libs/LibConstants.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/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/contracts/src/interfaces/IExchange.sol"; import "@0x/contracts/exchange/contracts/src/interfaces/IExchange.sol";
import "./libs/LibForwarderRichErrors.sol";
contract MixinExchangeWrapper is contract MixinExchangeWrapper is
@ -98,10 +99,12 @@ contract MixinExchangeWrapper is
uint256 ordersLength = orders.length; uint256 ordersLength = orders.length;
for (uint256 i = 0; i != ordersLength; i++) { for (uint256 i = 0; i != ordersLength; i++) {
require( if (!orders[i].makerAssetData.equals(orders[0].makerAssetData)) {
orders[i].makerAssetData.equals(orders[0].makerAssetData), LibRichErrors._rrevert(LibForwarderRichErrors.MakerAssetMismatchError(
"MAKER_ASSET_MISMATCH" orders[0].makerAssetData,
); orders[i].makerAssetData
));
}
// The remaining amount of WETH to sell // The remaining amount of WETH to sell
uint256 remainingTakerAssetFillAmount = _safeSub( uint256 remainingTakerAssetFillAmount = _safeSub(
@ -189,10 +192,12 @@ contract MixinExchangeWrapper is
{ {
uint256 ordersLength = orders.length; uint256 ordersLength = orders.length;
for (uint256 i = 0; i != ordersLength; i++) { for (uint256 i = 0; i != ordersLength; i++) {
require( if (!orders[i].makerAssetData.equals(orders[0].makerAssetData)) {
orders[i].makerAssetData.equals(orders[0].makerAssetData), LibRichErrors._rrevert(LibForwarderRichErrors.MakerAssetMismatchError(
"MAKER_ASSET_MISMATCH" orders[0].makerAssetData,
); orders[i].makerAssetData
));
}
// Calculate the remaining amount of takerAsset to sell // Calculate the remaining amount of takerAsset to sell
uint256 remainingTakerAssetFillAmount = _getPartialAmountCeil( uint256 remainingTakerAssetFillAmount = _getPartialAmountCeil(

View File

@ -20,10 +20,12 @@ pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibBytes.sol"; import "@0x/contracts-utils/contracts/src/LibBytes.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/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 "./libs/LibConstants.sol"; import "./libs/LibConstants.sol";
import "./libs/LibForwarderRichErrors.sol";
import "./interfaces/IAssets.sol"; import "./interfaces/IAssets.sol";
import "./interfaces/IForwarderCore.sol"; import "./interfaces/IForwarderCore.sol";
import "./MixinAssets.sol"; import "./MixinAssets.sol";
@ -48,10 +50,9 @@ contract MixinForwarderCore is
public public
{ {
address proxyAddress = EXCHANGE.getAssetProxy(ERC20_DATA_ID); address proxyAddress = EXCHANGE.getAssetProxy(ERC20_DATA_ID);
require( if (proxyAddress == address(0)) {
proxyAddress != address(0), LibRichErrors._rrevert(LibForwarderRichErrors.UnregisteredAssetProxyError());
"UNREGISTERED_ASSET_PROXY" }
);
ETHER_TOKEN.approve(proxyAddress, MAX_UINT); ETHER_TOKEN.approve(proxyAddress, MAX_UINT);
} }

View File

@ -18,8 +18,10 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
import "./libs/LibConstants.sol"; import "./libs/LibConstants.sol";
import "./libs/LibForwarderRichErrors.sol";
contract MixinWeth is contract MixinWeth is
@ -31,20 +33,20 @@ contract MixinWeth is
external external
payable payable
{ {
require( if (msg.sender != address(ETHER_TOKEN)) {
msg.sender == address(ETHER_TOKEN), LibRichErrors._rrevert(LibForwarderRichErrors.DefaultFunctionWethContractOnlyError(
"DEFAULT_FUNCTION_WETH_CONTRACT_ONLY" msg.sender
); ));
}
} }
/// @dev Converts message call's ETH value into WETH. /// @dev Converts message call's ETH value into WETH.
function _convertEthToWeth() function _convertEthToWeth()
internal internal
{ {
require( if (msg.value <= 0) {
msg.value > 0, LibRichErrors._rrevert(LibForwarderRichErrors.InvalidMsgValueError());
"INVALID_MSG_VALUE" }
);
ETHER_TOKEN.deposit.value(msg.value)(); ETHER_TOKEN.deposit.value(msg.value)();
} }
@ -61,16 +63,19 @@ contract MixinWeth is
internal internal
{ {
// Ensure feePercentage is less than 5%. // Ensure feePercentage is less than 5%.
require( if (feePercentage > MAX_FEE_PERCENTAGE) {
feePercentage <= MAX_FEE_PERCENTAGE, LibRichErrors._rrevert(LibForwarderRichErrors.FeePercentageTooLargeError(
"FEE_PERCENTAGE_TOO_LARGE" feePercentage
); ));
}
// Ensure that no extra WETH owned by this contract has been sold. // Ensure that no extra WETH owned by this contract has been sold.
require( if (wethSold > msg.value) {
wethSold <= msg.value, LibRichErrors._rrevert(LibForwarderRichErrors.OversoldWethError(
"OVERSOLD_WETH" wethSold,
); msg.value
));
}
// Calculate amount of WETH that hasn't been sold. // Calculate amount of WETH that hasn't been sold.
uint256 wethRemaining = _safeSub(msg.value, wethSold); uint256 wethRemaining = _safeSub(msg.value, wethSold);
@ -83,10 +88,12 @@ contract MixinWeth is
); );
// Ensure fee is less than amount of WETH remaining. // Ensure fee is less than amount of WETH remaining.
require( if (ethFee > wethRemaining) {
ethFee <= wethRemaining, LibRichErrors._rrevert(LibForwarderRichErrors.InsufficientEthRemainingError(
"INSUFFICIENT_ETH_REMAINING" ethFee,
); wethRemaining
));
}
// Do nothing if no WETH remaining // Do nothing if no WETH remaining
if (wethRemaining > 0) { if (wethRemaining > 0) {

View File

@ -1,10 +0,0 @@
pragma solidity ^0.5.9;
contract IForwarderRichErrors {
enum AssetProxyErrorCodes {
UNREGISTERED_ASSET_PROXY,
UNSUPPORTED_ASSET_PROXY
}
}

View File

@ -19,15 +19,21 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
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 "./interfaces/IExchangeRichErrors.sol";
library LibExchangeRichErrors { library LibForwarderRichErrors {
// bytes4(keccak256("AssetProxyError(bytes4)")) // bytes4(keccak256("UnregisteredAssetProxyError()"))
bytes4 internal constant ASEST_PROXY_ERROR_SELECTOR = bytes4 internal constant UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR =
0xaa3ff166; 0xf3b96b8d;
// bytes4(keccak256("UnregisteredAssetProxyError()"))
bytes internal constant UNREGISTERED_ASSET_PROXY_ERROR =
hex"f3b96b8d";
// bytes4(keccak256("UnsupportedAssetProxyError(bytes4)"))
bytes4 internal constant UNSUPPORTED_ASSET_PROXY_ERROR_SELECTOR =
0x7996a271;
// bytes4(keccak256("CompleteFillFailedError(uint256,uint256)")) // bytes4(keccak256("CompleteFillFailedError(uint256,uint256)"))
bytes4 internal constant COMPLETE_FILL_FAILED_ERROR_SELECTOR = bytes4 internal constant COMPLETE_FILL_FAILED_ERROR_SELECTOR =
@ -53,6 +59,10 @@ library LibExchangeRichErrors {
bytes4 internal constant TRANSFER_FAILED_ERROR_SELECTOR = bytes4 internal constant TRANSFER_FAILED_ERROR_SELECTOR =
0x570f1df4; 0x570f1df4;
// bytes4(keccak256("TransferFailedError()"))
bytes internal constant TRANSFER_FAILED_ERROR =
hex"570f1df4";
// bytes4(keccak256("DefaultFunctionWethContractOnlyError(address)")) // bytes4(keccak256("DefaultFunctionWethContractOnlyError(address)"))
bytes4 internal constant DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR = bytes4 internal constant DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR =
0x08b18698; 0x08b18698;
@ -61,13 +71,24 @@ library LibExchangeRichErrors {
bytes4 internal constant INVALID_MSG_VALUE_ERROR_SELECTOR = bytes4 internal constant INVALID_MSG_VALUE_ERROR_SELECTOR =
0xb0658a43; 0xb0658a43;
// bytes4(keccak256("InvalidMsgValueError()"))
bytes internal constant INVALID_MSG_VALUE_ERROR =
hex"b0658a43";
// bytes4(keccak256("InvalidErc721AmountError(uint256)")) // bytes4(keccak256("InvalidErc721AmountError(uint256)"))
bytes4 internal constant INVALID_ERC721_AMOUNT_ERROR_SELECTOR = bytes4 internal constant INVALID_ERC721_AMOUNT_ERROR_SELECTOR =
0x27ed87bf; 0x27ed87bf;
// solhint-disable func-name-mixedcase // solhint-disable func-name-mixedcase
function AssetProxyError( function UnregisteredAssetProxyError()
IForwarderRichErrors.AssetProxyErrorCodes errorCode, internal
pure
returns (bytes memory)
{
return UNREGISTERED_ASSET_PROXY_ERROR;
}
function UnsupportedAssetProxyError(
bytes4 proxyId bytes4 proxyId
) )
internal internal
@ -75,7 +96,7 @@ library LibExchangeRichErrors {
returns (bytes memory) returns (bytes memory)
{ {
return abi.encodeWithSelector( return abi.encodeWithSelector(
ASSET_PROXY_ERROR_SELECTOR, UNSUPPORTED_ASSET_PROXY_ERROR_SELECTOR,
proxyId proxyId
); );
} }
@ -158,7 +179,7 @@ library LibExchangeRichErrors {
pure pure
returns (bytes memory) returns (bytes memory)
{ {
return TRANSFER_FAILED_ERROR_SELECTOR; return TRANSFER_FAILED_ERROR;
} }
function DefaultFunctionWethContractOnlyError( function DefaultFunctionWethContractOnlyError(
@ -179,7 +200,7 @@ library LibExchangeRichErrors {
pure pure
returns (bytes memory) returns (bytes memory)
{ {
return INVALID_MSG_VALUE_ERROR_SELECTOR; return INVALID_MSG_VALUE_ERROR;
} }
function InvalidErc721AmountError( function InvalidErc721AmountError(