Merge pull request #2440 from 0xProject/feat/dev-utils/chai-bridge-validation
Add ChaiBridge order balance/allowance checks to DevUtils
This commit is contained in:
		@@ -18,10 +18,22 @@
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.9;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract PotLike {
 | 
			
		||||
    function chi() external returns (uint256);
 | 
			
		||||
    function rho() external returns (uint256);
 | 
			
		||||
    function drip() external returns (uint256);
 | 
			
		||||
    function join(uint256) external;
 | 
			
		||||
    function exit(uint256) external;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// The actual Chai contract can be found here: https://github.com/dapphub/chai
 | 
			
		||||
contract IChai {
 | 
			
		||||
 | 
			
		||||
contract IChai is
 | 
			
		||||
    IERC20Token
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Withdraws Dai owned by `src`
 | 
			
		||||
    /// @param src Address that owns Dai.
 | 
			
		||||
    /// @param wad Amount of Dai to withdraw.
 | 
			
		||||
@@ -30,4 +42,25 @@ contract IChai {
 | 
			
		||||
        uint256 wad
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Queries Dai balance of Chai holder.
 | 
			
		||||
    /// @param usr Address of Chai holder.
 | 
			
		||||
    /// @return Dai balance.
 | 
			
		||||
    function dai(address usr)
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /// @dev Queries the Pot contract used by the Chai contract.
 | 
			
		||||
    function pot()
 | 
			
		||||
        external
 | 
			
		||||
        returns (PotLike);
 | 
			
		||||
 | 
			
		||||
    /// @dev Deposits Dai in exchange for Chai
 | 
			
		||||
    /// @param dst Address to receive Chai.
 | 
			
		||||
    /// @param wad Amount of Dai to deposit.
 | 
			
		||||
    function join(
 | 
			
		||||
        address dst,
 | 
			
		||||
        uint256 wad
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ export {
 | 
			
		||||
    UniswapBridgeContract,
 | 
			
		||||
    KyberBridgeContract,
 | 
			
		||||
    ChaiBridgeContract,
 | 
			
		||||
    IChaiContract,
 | 
			
		||||
} from './wrappers';
 | 
			
		||||
 | 
			
		||||
export { ERC20Wrapper } from './erc20_wrapper';
 | 
			
		||||
 
 | 
			
		||||
@@ -37,14 +37,24 @@ contract DevUtils is
 | 
			
		||||
    LibEIP712ExchangeDomain,
 | 
			
		||||
    EthBalanceChecker
 | 
			
		||||
{
 | 
			
		||||
    constructor (address _exchange)
 | 
			
		||||
    constructor (
 | 
			
		||||
        address _exchange,
 | 
			
		||||
        address _chaiBridge
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        OrderValidationUtils(_exchange)
 | 
			
		||||
        OrderValidationUtils(
 | 
			
		||||
            _exchange,
 | 
			
		||||
            _chaiBridge
 | 
			
		||||
        )
 | 
			
		||||
        OrderTransferSimulationUtils(_exchange)
 | 
			
		||||
        LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    function getOrderHash(LibOrder.Order memory order, uint256 chainId, address exchange)
 | 
			
		||||
    function getOrderHash(
 | 
			
		||||
        LibOrder.Order memory order,
 | 
			
		||||
        uint256 chainId,
 | 
			
		||||
        address exchange
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes32 orderHash)
 | 
			
		||||
 
 | 
			
		||||
@@ -26,10 +26,14 @@ import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.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";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract LibAssetData {
 | 
			
		||||
 | 
			
		||||
contract LibAssetData is
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    // 2^256 - 1
 | 
			
		||||
    uint256 constant internal _MAX_UINT256 = uint256(-1);
 | 
			
		||||
 | 
			
		||||
@@ -41,9 +45,13 @@ contract LibAssetData {
 | 
			
		||||
    address internal _ERC721_PROXY_ADDRESS;
 | 
			
		||||
    address internal _ERC1155_PROXY_ADDRESS;
 | 
			
		||||
    address internal _STATIC_CALL_PROXY_ADDRESS;
 | 
			
		||||
    address internal _CHAI_BRIDGE_ADDRESS;
 | 
			
		||||
    // solhint-enable var-name-mixedcase
 | 
			
		||||
 | 
			
		||||
    constructor (address _exchange)
 | 
			
		||||
    constructor (
 | 
			
		||||
        address _exchange,
 | 
			
		||||
        address _chaiBridge
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        _EXCHANGE = IExchange(_exchange);
 | 
			
		||||
@@ -51,6 +59,7 @@ contract LibAssetData {
 | 
			
		||||
        _ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector);
 | 
			
		||||
        _ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.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
 | 
			
		||||
@@ -62,7 +71,6 @@ contract LibAssetData {
 | 
			
		||||
    /// @return Number of assets (or asset baskets) held by owner.
 | 
			
		||||
    function getBalance(address ownerAddress, bytes memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 balance)
 | 
			
		||||
    {
 | 
			
		||||
        // Get id of AssetProxy contract
 | 
			
		||||
@@ -71,16 +79,8 @@ contract LibAssetData {
 | 
			
		||||
        if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
 | 
			
		||||
            // Get ERC20 token address
 | 
			
		||||
            address tokenAddress = assetData.readAddress(16);
 | 
			
		||||
            balance = _erc20BalanceOf(tokenAddress, ownerAddress);
 | 
			
		||||
 | 
			
		||||
            // Encode data for `balanceOf(ownerAddress)`
 | 
			
		||||
            bytes memory balanceOfData = abi.encodeWithSelector(
 | 
			
		||||
                IERC20Token(address(0)).balanceOf.selector,
 | 
			
		||||
                ownerAddress
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Query balance
 | 
			
		||||
            (bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
 | 
			
		||||
            balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
 | 
			
		||||
        } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
 | 
			
		||||
            // Get ERC721 token address and id
 | 
			
		||||
            (, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
 | 
			
		||||
@@ -94,6 +94,7 @@ contract LibAssetData {
 | 
			
		||||
            (bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
 | 
			
		||||
            address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
 | 
			
		||||
            balance = currentOwnerAddress == ownerAddress ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
        } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
 | 
			
		||||
            // Get ERC1155 token address, array of ids, and array of values
 | 
			
		||||
            (, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData);
 | 
			
		||||
@@ -125,6 +126,7 @@ contract LibAssetData {
 | 
			
		||||
                    balance = scaledBalance;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
 | 
			
		||||
            // Encode data for `staticCallProxy.transferFrom(assetData,...)`
 | 
			
		||||
            bytes memory transferFromData = abi.encodeWithSelector(
 | 
			
		||||
@@ -140,6 +142,17 @@ contract LibAssetData {
 | 
			
		||||
 | 
			
		||||
            // Success means that the staticcall can be made an unlimited amount of times
 | 
			
		||||
            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) {
 | 
			
		||||
                uint256 chaiBalance = _erc20BalanceOf(_getChaiAddress(), ownerAddress);
 | 
			
		||||
                // Calculate Dai balance
 | 
			
		||||
                balance = _convertChaiToDaiAmount(chaiBalance);
 | 
			
		||||
            }
 | 
			
		||||
            // Balance will be 0 if bridge is not supported
 | 
			
		||||
 | 
			
		||||
        } else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
 | 
			
		||||
            // Get array of values and array of assetDatas
 | 
			
		||||
            (, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
 | 
			
		||||
@@ -176,7 +189,6 @@ contract LibAssetData {
 | 
			
		||||
    /// corresponding to the same-indexed element in the assetData input.
 | 
			
		||||
    function getBatchBalances(address ownerAddress, bytes[] memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory balances)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 length = assetData.length;
 | 
			
		||||
@@ -197,7 +209,6 @@ contract LibAssetData {
 | 
			
		||||
    /// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
 | 
			
		||||
    function getAssetProxyAllowance(address ownerAddress, bytes memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 allowance)
 | 
			
		||||
    {
 | 
			
		||||
        // Get id of AssetProxy contract
 | 
			
		||||
@@ -243,6 +254,7 @@ contract LibAssetData {
 | 
			
		||||
            // Query allowance
 | 
			
		||||
            (bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData);
 | 
			
		||||
            allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
 | 
			
		||||
 | 
			
		||||
        } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
 | 
			
		||||
            // Get ERC721 token address and id
 | 
			
		||||
            (, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
 | 
			
		||||
@@ -268,6 +280,7 @@ contract LibAssetData {
 | 
			
		||||
                // Allowance is 2^256 - 1 if `isApprovedForAll` returned true
 | 
			
		||||
                allowance = _MAX_UINT256;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
 | 
			
		||||
            // Get ERC1155 token address
 | 
			
		||||
            (, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
 | 
			
		||||
@@ -282,9 +295,26 @@ contract LibAssetData {
 | 
			
		||||
            // Query allowance
 | 
			
		||||
            (bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
 | 
			
		||||
            allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
 | 
			
		||||
 | 
			
		||||
        } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
 | 
			
		||||
            // The StaticCallProxy does not require any approvals
 | 
			
		||||
            allowance = _MAX_UINT256;
 | 
			
		||||
 | 
			
		||||
        } 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 allowanceData = abi.encodeWithSelector(
 | 
			
		||||
                    IERC20Token(address(0)).allowance.selector,
 | 
			
		||||
                    ownerAddress,
 | 
			
		||||
                    _CHAI_BRIDGE_ADDRESS
 | 
			
		||||
                );
 | 
			
		||||
                (bool success, bytes memory returnData) = _getChaiAddress().staticcall(allowanceData);
 | 
			
		||||
                uint256 chaiAllowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
 | 
			
		||||
                // Dai allowance is unlimited if Chai allowance is unlimited
 | 
			
		||||
                allowance = chaiAllowance == _MAX_UINT256 ? _MAX_UINT256 : _convertChaiToDaiAmount(chaiAllowance);
 | 
			
		||||
            }
 | 
			
		||||
            // Allowance will be 0 if bridge is not supported
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Allowance will be 0 if the assetProxyId is unknown
 | 
			
		||||
@@ -298,7 +328,6 @@ contract LibAssetData {
 | 
			
		||||
    /// element corresponding to the same-indexed element in the assetData input.
 | 
			
		||||
    function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory allowances)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 length = assetData.length;
 | 
			
		||||
@@ -316,7 +345,6 @@ contract LibAssetData {
 | 
			
		||||
    /// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
 | 
			
		||||
    function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 balance, uint256 allowance)
 | 
			
		||||
    {
 | 
			
		||||
        balance = getBalance(ownerAddress, assetData);
 | 
			
		||||
@@ -332,7 +360,6 @@ contract LibAssetData {
 | 
			
		||||
    /// corresponding to the same-indexed element in the assetData input.
 | 
			
		||||
    function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory balances, uint256[] memory allowances)
 | 
			
		||||
    {
 | 
			
		||||
        balances = getBatchBalances(ownerAddress, assetData);
 | 
			
		||||
@@ -613,6 +640,35 @@ 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)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Reverts if assetData is not of a valid format for its given proxy id.
 | 
			
		||||
    /// @param assetData AssetProxy compliant asset data.
 | 
			
		||||
    function revertIfInvalidAssetData(bytes memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
@@ -629,8 +685,50 @@ contract LibAssetData {
 | 
			
		||||
            decodeMultiAssetData(assetData);
 | 
			
		||||
        } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
 | 
			
		||||
            decodeStaticCallAssetData(assetData);
 | 
			
		||||
        } else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
 | 
			
		||||
            decodeERC20BridgeAssetData(assetData);
 | 
			
		||||
        } else {
 | 
			
		||||
            revert("WRONG_PROXY_ID");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Queries balance of an ERC20 token. Returns 0 if call was unsuccessful.
 | 
			
		||||
    /// @param tokenAddress Address of ERC20 token.
 | 
			
		||||
    /// @param ownerAddress Address of owner of ERC20 token.
 | 
			
		||||
    /// @return balance ERC20 token balance of owner.
 | 
			
		||||
    function _erc20BalanceOf(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        address ownerAddress
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 balance)
 | 
			
		||||
    {
 | 
			
		||||
        // Encode data for `balanceOf(ownerAddress)`
 | 
			
		||||
        bytes memory balanceOfData = abi.encodeWithSelector(
 | 
			
		||||
            IERC20Token(address(0)).balanceOf.selector,
 | 
			
		||||
            ownerAddress
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Query balance
 | 
			
		||||
        (bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
 | 
			
		||||
        balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
 | 
			
		||||
        return balance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Converts an amount of Chai into its equivalent Dai amount.
 | 
			
		||||
    ///      Also accumulates Dai from DSR if called after the last time it was collected.
 | 
			
		||||
    /// @param chaiAmount Amount of Chai to converts.
 | 
			
		||||
    function _convertChaiToDaiAmount(uint256 chaiAmount)
 | 
			
		||||
        internal
 | 
			
		||||
        returns (uint256 daiAmount)
 | 
			
		||||
    {
 | 
			
		||||
        PotLike pot = IChai(_getChaiAddress()).pot();
 | 
			
		||||
        // Accumulate savings if called after last time savings were collected
 | 
			
		||||
        uint256 chiMultiplier = (now > pot.rho())
 | 
			
		||||
            ? pot.drip()
 | 
			
		||||
            : pot.chi();
 | 
			
		||||
        daiAmount = LibMath.getPartialAmountFloor(chiMultiplier, 10**27, chaiAmount);
 | 
			
		||||
        return daiAmount;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -35,9 +35,15 @@ contract OrderValidationUtils is
 | 
			
		||||
    using LibBytes for bytes;
 | 
			
		||||
    using LibSafeMath for uint256;
 | 
			
		||||
 | 
			
		||||
    constructor (address _exchange)
 | 
			
		||||
    constructor (
 | 
			
		||||
        address _exchange,
 | 
			
		||||
        address _chaiBridge
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        LibAssetData(_exchange)
 | 
			
		||||
        LibAssetData(
 | 
			
		||||
            _exchange,
 | 
			
		||||
            _chaiBridge
 | 
			
		||||
        )
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /// @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`.
 | 
			
		||||
    function getTransferableAssetAmount(address ownerAddress, bytes memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 transferableAssetAmount)
 | 
			
		||||
    {
 | 
			
		||||
        (uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData);
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ import { contractAddresses, dydxAccountOwner } from '../mainnet_fork_utils';
 | 
			
		||||
 | 
			
		||||
import { dydxEvents } from './abi/dydxEvents';
 | 
			
		||||
 | 
			
		||||
blockchainTests.fork.resets('Mainnet dydx bridge tests', env => {
 | 
			
		||||
blockchainTests.fork.skip('Mainnet dydx bridge tests', env => {
 | 
			
		||||
    let testContract: DydxBridgeContract;
 | 
			
		||||
    // random account to receive tokens from dydx
 | 
			
		||||
    const receiver = '0x986ccf5234d9cfbb25246f1a5bfa51f4ccfcb308';
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,76 @@
 | 
			
		||||
import { IChaiContract } from '@0x/contracts-asset-proxy';
 | 
			
		||||
import { artifacts as devUtilsArtifacts, DevUtilsContract } from '@0x/contracts-dev-utils';
 | 
			
		||||
import { ERC20TokenContract } from '@0x/contracts-erc20';
 | 
			
		||||
import { blockchainTests, constants, expect } from '@0x/contracts-test-utils';
 | 
			
		||||
import { assetDataUtils } from '@0x/order-utils';
 | 
			
		||||
import { Web3Wrapper } from '@0x/web3-wrapper';
 | 
			
		||||
 | 
			
		||||
import { contractAddresses } from '../mainnet_fork_utils';
 | 
			
		||||
 | 
			
		||||
blockchainTests.fork.resets('DevUtils mainnet tests', env => {
 | 
			
		||||
    const daiAddress = '0x6b175474e89094c44da98b954eedeac495271d0f';
 | 
			
		||||
    const chaiAddress = '0x06af07097c9eeb7fd685c692751d5c66db49c215';
 | 
			
		||||
    const daiHolder = '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b';
 | 
			
		||||
    let noDaiAddress: string;
 | 
			
		||||
 | 
			
		||||
    const assetData = assetDataUtils.encodeERC20BridgeAssetData(
 | 
			
		||||
        daiAddress,
 | 
			
		||||
        contractAddresses.chaiBridge,
 | 
			
		||||
        constants.NULL_BYTES,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const dai = new ERC20TokenContract(daiAddress, env.provider, env.txDefaults);
 | 
			
		||||
    const chai = new IChaiContract(chaiAddress, env.provider, env.txDefaults);
 | 
			
		||||
    let devUtils: DevUtilsContract;
 | 
			
		||||
    const daiDepositAmount = Web3Wrapper.toBaseUnitAmount(1000, 18);
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        [noDaiAddress] = await env.getAccountAddressesAsync();
 | 
			
		||||
        devUtils = await DevUtilsContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            devUtilsArtifacts.DevUtils,
 | 
			
		||||
            env.provider,
 | 
			
		||||
            env.txDefaults,
 | 
			
		||||
            devUtilsArtifacts,
 | 
			
		||||
            contractAddresses.exchange,
 | 
			
		||||
            contractAddresses.chaiBridge,
 | 
			
		||||
        );
 | 
			
		||||
        await dai.approve(chai.address, constants.MAX_UINT256).awaitTransactionSuccessAsync({ from: daiHolder });
 | 
			
		||||
        await chai.join(daiHolder, daiDepositAmount).awaitTransactionSuccessAsync({ from: daiHolder });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('LibAssetData', () => {
 | 
			
		||||
        describe('ChaiBridge getBalance', () => {
 | 
			
		||||
            it('should return the correct non-zero Dai balance for a Chai holder', async () => {
 | 
			
		||||
                const expectedDaiBalance = await chai.dai(daiHolder).callAsync();
 | 
			
		||||
                const daiBalance = await devUtils.getBalance(daiHolder, assetData).callAsync();
 | 
			
		||||
                expect(daiBalance).bignumber.eq(expectedDaiBalance);
 | 
			
		||||
            });
 | 
			
		||||
            it('should return a balance of 0 when Chai balance is 0', async () => {
 | 
			
		||||
                const daiBalance = await devUtils.getBalance(noDaiAddress, assetData).callAsync();
 | 
			
		||||
                expect(daiBalance).bignumber.eq(constants.ZERO_AMOUNT);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
        describe('ChaiBridge getProxyAllowance', () => {
 | 
			
		||||
            it('should return the correct non-zero non-unlimited allowance', async () => {
 | 
			
		||||
                const chaiBalance = await chai.balanceOf(daiHolder).callAsync();
 | 
			
		||||
                await chai
 | 
			
		||||
                    .approve(contractAddresses.chaiBridge, chaiBalance)
 | 
			
		||||
                    .awaitTransactionSuccessAsync({ from: daiHolder });
 | 
			
		||||
                const daiBalance = await chai.dai(daiHolder).callAsync();
 | 
			
		||||
                const allowance = await devUtils.getAssetProxyAllowance(daiHolder, assetData).callAsync();
 | 
			
		||||
                expect(allowance).to.bignumber.eq(daiBalance);
 | 
			
		||||
            });
 | 
			
		||||
            it('should return an unlimited allowance of Dai when Chai allowance is also unlimited', async () => {
 | 
			
		||||
                await chai
 | 
			
		||||
                    .approve(contractAddresses.chaiBridge, constants.MAX_UINT256)
 | 
			
		||||
                    .awaitTransactionSuccessAsync({ from: daiHolder });
 | 
			
		||||
                const allowance = await devUtils.getAssetProxyAllowance(daiHolder, assetData).callAsync();
 | 
			
		||||
                expect(allowance).to.bignumber.eq(constants.MAX_UINT256);
 | 
			
		||||
            });
 | 
			
		||||
            it('should return an allowance of 0 when Chai allowance is 0', async () => {
 | 
			
		||||
                const allowance = await devUtils.getAssetProxyAllowance(noDaiAddress, assetData).callAsync();
 | 
			
		||||
                expect(allowance).to.bignumber.eq(constants.ZERO_AMOUNT);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@@ -25,6 +25,7 @@ blockchainTests('DevUtils.getOrderHash', env => {
 | 
			
		||||
            env.txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
            exchange.address,
 | 
			
		||||
            constants.NULL_ADDRESS,
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -79,6 +79,7 @@ blockchainTests.resets('LibAssetData', env => {
 | 
			
		||||
            env.txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
            deployment.exchange.address,
 | 
			
		||||
            constants.NULL_ADDRESS,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync(
 | 
			
		||||
 
 | 
			
		||||
@@ -203,6 +203,7 @@ export class DeploymentManager {
 | 
			
		||||
            environment.txDefaults,
 | 
			
		||||
            devUtilsArtifacts,
 | 
			
		||||
            exchange.address,
 | 
			
		||||
            constants.NULL_ADDRESS,
 | 
			
		||||
        );
 | 
			
		||||
        const assetDataEncoder = new IAssetDataContract(constants.NULL_ADDRESS, environment.provider);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ import { BigNumber } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { contractAddresses, getContractwrappers } from './mainnet_fork_utils';
 | 
			
		||||
 | 
			
		||||
blockchainTests.fork.resets('Mainnet configs tests', env => {
 | 
			
		||||
blockchainTests.live('Mainnet configs tests', env => {
 | 
			
		||||
    let contractWrappers: ContractWrappers;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ export let providerConfigs: Web3Config = {
 | 
			
		||||
    shouldUseInProcessGanache: true,
 | 
			
		||||
    shouldAllowUnlimitedContractSize: true,
 | 
			
		||||
    hardfork: 'istanbul',
 | 
			
		||||
    unlocked_accounts: ['0x6cc5f688a315f3dc28a7781717a9a798a59fda7b', '0x55dc8f21d20d4c6ed3c82916a438a413ca68e335'],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const provider: Web3ProviderEngine = web3Factory.getRpcProvider(providerConfigs);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										60
									
								
								packages/contract-artifacts/artifacts/DevUtils.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										60
									
								
								packages/contract-artifacts/artifacts/DevUtils.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -175,6 +175,7 @@ export async function runMigrationsAsync(
 | 
			
		||||
        txDefaults,
 | 
			
		||||
        artifacts,
 | 
			
		||||
        exchange.address,
 | 
			
		||||
        constants.NULL_ADDRESS,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // tslint:disable-next-line:no-unused-variable
 | 
			
		||||
 
 | 
			
		||||
@@ -113,7 +113,7 @@ export async function runMigrationsAsync(supportedProvider: SupportedProvider, t
 | 
			
		||||
        assetProxyArtifacts,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await ChaiBridgeContract.deployFrom0xArtifactAsync(
 | 
			
		||||
    const chaiBridge = await ChaiBridgeContract.deployFrom0xArtifactAsync(
 | 
			
		||||
        assetProxyArtifacts.ChaiBridge,
 | 
			
		||||
        provider,
 | 
			
		||||
        txDefaults,
 | 
			
		||||
@@ -251,6 +251,7 @@ export async function runMigrationsAsync(supportedProvider: SupportedProvider, t
 | 
			
		||||
        txDefaults,
 | 
			
		||||
        devUtilsArtifacts,
 | 
			
		||||
        exchange.address,
 | 
			
		||||
        chaiBridge.address,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await CoordinatorContract.deployFrom0xArtifactAsync(
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user