Add ChaiBridge balance checks to DevUtils

This commit is contained in:
Amir 2020-01-06 21:37:31 -08:00
parent 969b9814d5
commit 410a3fef18
4 changed files with 76 additions and 11 deletions

View File

@ -30,4 +30,11 @@ contract IChai {
uint256 wad uint256 wad
) )
external; external;
/// @dev Queries Dai balance of Chai holder.
/// @param usr Address of Chai holder.
/// @return Dai balance.
function dai(address usr)
external
returns (uint256);
} }

View File

@ -37,9 +37,15 @@ contract DevUtils is
LibEIP712ExchangeDomain, LibEIP712ExchangeDomain,
EthBalanceChecker EthBalanceChecker
{ {
constructor (address _exchange) constructor (
address _exchange,
address _chaiBridge
)
public public
OrderValidationUtils(_exchange) OrderValidationUtils(
_exchange,
_chaiBridge
)
OrderTransferSimulationUtils(_exchange) OrderTransferSimulationUtils(_exchange)
LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants
{} {}

View File

@ -26,9 +26,13 @@ import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.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 "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol"; import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IChai.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
contract LibAssetData { contract LibAssetData is
DeploymentConstants
{
// 2^256 - 1 // 2^256 - 1
uint256 constant internal _MAX_UINT256 = uint256(-1); uint256 constant internal _MAX_UINT256 = uint256(-1);
@ -41,9 +45,13 @@ contract LibAssetData {
address internal _ERC721_PROXY_ADDRESS; address internal _ERC721_PROXY_ADDRESS;
address internal _ERC1155_PROXY_ADDRESS; address internal _ERC1155_PROXY_ADDRESS;
address internal _STATIC_CALL_PROXY_ADDRESS; address internal _STATIC_CALL_PROXY_ADDRESS;
address internal _CHAI_BRIDGE_ADDRESS;
// solhint-enable var-name-mixedcase // solhint-enable var-name-mixedcase
constructor (address _exchange) constructor (
address _exchange,
address _chaiBridge
)
public public
{ {
_EXCHANGE = IExchange(_exchange); _EXCHANGE = IExchange(_exchange);
@ -51,6 +59,7 @@ contract LibAssetData {
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector); _ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector);
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector); _ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
_STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).StaticCall.selector); _STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).StaticCall.selector);
_CHAI_BRIDGE_ADDRESS = _chaiBridge;
} }
/// @dev Returns the owner's balance of the assets(s) specified in /// @dev Returns the owner's balance of the assets(s) specified in
@ -62,7 +71,6 @@ contract LibAssetData {
/// @return Number of assets (or asset baskets) held by owner. /// @return Number of assets (or asset baskets) held by owner.
function getBalance(address ownerAddress, bytes memory assetData) function getBalance(address ownerAddress, bytes memory assetData)
public public
view
returns (uint256 balance) returns (uint256 balance)
{ {
// Get id of AssetProxy contract // Get id of AssetProxy contract
@ -140,6 +148,19 @@ contract LibAssetData {
// Success means that the staticcall can be made an unlimited amount of times // Success means that the staticcall can be made an unlimited amount of times
balance = success ? _MAX_UINT256 : 0; balance = success ? _MAX_UINT256 : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
// Get address of ERC20 token and bridge contract
(, address tokenAddress, address bridgeAddress,) = decodeERC20BridgeAssetData(assetData);
if (tokenAddress == _getDaiAddress() && bridgeAddress == _CHAI_BRIDGE_ADDRESS) {
bytes memory chaiDaiCalldata = abi.encodeWithSelector(
IChai(address(0)).dai.selector,
ownerAddress
);
// We do not make a STATICCALL because this function can potentially alter state
(bool success, bytes memory returnData) = _getChaiAddress().call(chaiDaiCalldata);
uint256 chaiBalance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
}
// Balance will be 0 if bridge is not supported
} else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) { } else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
// Get array of values and array of assetDatas // Get array of values and array of assetDatas
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData); (, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
@ -176,7 +197,6 @@ contract LibAssetData {
/// corresponding to the same-indexed element in the assetData input. /// corresponding to the same-indexed element in the assetData input.
function getBatchBalances(address ownerAddress, bytes[] memory assetData) function getBatchBalances(address ownerAddress, bytes[] memory assetData)
public public
view
returns (uint256[] memory balances) returns (uint256[] memory balances)
{ {
uint256 length = assetData.length; uint256 length = assetData.length;
@ -316,7 +336,6 @@ contract LibAssetData {
/// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend. /// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData) function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData)
public public
view
returns (uint256 balance, uint256 allowance) returns (uint256 balance, uint256 allowance)
{ {
balance = getBalance(ownerAddress, assetData); balance = getBalance(ownerAddress, assetData);
@ -332,7 +351,6 @@ contract LibAssetData {
/// corresponding to the same-indexed element in the assetData input. /// corresponding to the same-indexed element in the assetData input.
function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData) function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
public public
view
returns (uint256[] memory balances, uint256[] memory allowances) returns (uint256[] memory balances, uint256[] memory allowances)
{ {
balances = getBatchBalances(ownerAddress, assetData); balances = getBatchBalances(ownerAddress, assetData);
@ -613,6 +631,33 @@ contract LibAssetData {
); );
} }
/// @dev Decode ERC20Bridge asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing an ERC20Bridge asset
/// @return The ERC20BridgeProxy identifier, the address of the ERC20 token to transfer, the address
/// of the bridge contract, and extra data to be passed to the bridge contract.
function decodeERC20BridgeAssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
address tokenAddress,
address bridgeAddress,
bytes memory bridgeData
)
{
assetProxyId = assetData.readBytes4(0);
require(
assetProxyId == IAssetData(address(0)).ERC20Bridge.selector,
"WRONG_PROXY_ID"
);
(tokenAddress, bridgeAddress, bridgeData) = abi.decode(
assetData.slice(4, assetData.length),
(address, address, bytes)
);
}
function revertIfInvalidAssetData(bytes memory assetData) function revertIfInvalidAssetData(bytes memory assetData)
public public
pure pure
@ -629,6 +674,8 @@ contract LibAssetData {
decodeMultiAssetData(assetData); decodeMultiAssetData(assetData);
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
decodeStaticCallAssetData(assetData); decodeStaticCallAssetData(assetData);
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
decodeERC20BridgeAssetData(assetData);
} else { } else {
revert("WRONG_PROXY_ID"); revert("WRONG_PROXY_ID");
} }

View File

@ -35,9 +35,15 @@ contract OrderValidationUtils is
using LibBytes for bytes; using LibBytes for bytes;
using LibSafeMath for uint256; using LibSafeMath for uint256;
constructor (address _exchange) constructor (
address _exchange,
address _chaiBridge
)
public public
LibAssetData(_exchange) LibAssetData(
_exchange,
_chaiBridge
)
{} {}
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable. /// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
@ -173,7 +179,6 @@ contract OrderValidationUtils is
/// the individual asset amounts located within the `assetData`. /// the individual asset amounts located within the `assetData`.
function getTransferableAssetAmount(address ownerAddress, bytes memory assetData) function getTransferableAssetAmount(address ownerAddress, bytes memory assetData)
public public
view
returns (uint256 transferableAssetAmount) returns (uint256 transferableAssetAmount)
{ {
(uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData); (uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData);