Merge pull request #2352 from 0xProject/feat/asset-proxy/KyberBridge
KyberBridge
This commit is contained in:
		@@ -1,4 +1,13 @@
 | 
				
			|||||||
[
 | 
					[
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        "version": "2.3.0-beta.4",
 | 
				
			||||||
 | 
					        "changes": [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "note": "Implement `KyberBridge`.",
 | 
				
			||||||
 | 
					                "pr": 2352
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        "version": "2.3.0-beta.3",
 | 
					        "version": "2.3.0-beta.3",
 | 
				
			||||||
        "changes": [
 | 
					        "changes": [
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
 | 
				
			|||||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
					import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
				
			||||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
					import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
				
			||||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
					import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
				
			||||||
 | 
					import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
				
			||||||
import "../interfaces/IERC20Bridge.sol";
 | 
					import "../interfaces/IERC20Bridge.sol";
 | 
				
			||||||
import "../interfaces/IEth2Dai.sol";
 | 
					import "../interfaces/IEth2Dai.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,11 +30,9 @@ import "../interfaces/IEth2Dai.sol";
 | 
				
			|||||||
// solhint-disable space-after-comma
 | 
					// solhint-disable space-after-comma
 | 
				
			||||||
contract Eth2DaiBridge is
 | 
					contract Eth2DaiBridge is
 | 
				
			||||||
    IERC20Bridge,
 | 
					    IERC20Bridge,
 | 
				
			||||||
    IWallet
 | 
					    IWallet,
 | 
				
			||||||
 | 
					    DeploymentConstants
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /* Mainnet addresses */
 | 
					 | 
				
			||||||
    address constant public ETH2DAI_ADDRESS = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
 | 
					    /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
 | 
				
			||||||
    ///      `toTokenAddress` tokens by selling the entirety of the opposing asset
 | 
					    ///      `toTokenAddress` tokens by selling the entirety of the opposing asset
 | 
				
			||||||
    ///      (DAI or WETH) to the Eth2Dai contract, then transfers the bought
 | 
					    ///      (DAI or WETH) to the Eth2Dai contract, then transfers the bought
 | 
				
			||||||
@@ -61,8 +60,8 @@ contract Eth2DaiBridge is
 | 
				
			|||||||
        LibERC20Token.approve(fromTokenAddress, address(exchange), uint256(-1));
 | 
					        LibERC20Token.approve(fromTokenAddress, address(exchange), uint256(-1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Try to sell all of this contract's `fromTokenAddress` token balance.
 | 
					        // Try to sell all of this contract's `fromTokenAddress` token balance.
 | 
				
			||||||
        uint256 boughtAmount = _getEth2DaiContract().sellAllAmount(
 | 
					        uint256 boughtAmount = exchange.sellAllAmount(
 | 
				
			||||||
            address(fromTokenAddress),
 | 
					            fromTokenAddress,
 | 
				
			||||||
            IERC20Token(fromTokenAddress).balanceOf(address(this)),
 | 
					            IERC20Token(fromTokenAddress).balanceOf(address(this)),
 | 
				
			||||||
            toTokenAddress,
 | 
					            toTokenAddress,
 | 
				
			||||||
            amount
 | 
					            amount
 | 
				
			||||||
@@ -93,6 +92,6 @@ contract Eth2DaiBridge is
 | 
				
			|||||||
        view
 | 
					        view
 | 
				
			||||||
        returns (IEth2Dai exchange)
 | 
					        returns (IEth2Dai exchange)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return IEth2Dai(ETH2DAI_ADDRESS);
 | 
					        return IEth2Dai(_getEth2DaiAddress());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										166
									
								
								contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,166 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Copyright 2019 ZeroEx Intl.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					  you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					  You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					  distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					  See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					  limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pragma solidity ^0.5.9;
 | 
				
			||||||
 | 
					pragma experimental ABIEncoderV2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
				
			||||||
 | 
					import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
 | 
				
			||||||
 | 
					import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
				
			||||||
 | 
					import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
				
			||||||
 | 
					import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
				
			||||||
 | 
					import "../interfaces/IERC20Bridge.sol";
 | 
				
			||||||
 | 
					import "../interfaces/IKyberNetworkProxy.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// solhint-disable space-after-comma
 | 
				
			||||||
 | 
					contract KyberBridge is
 | 
				
			||||||
 | 
					    IERC20Bridge,
 | 
				
			||||||
 | 
					    IWallet,
 | 
				
			||||||
 | 
					    DeploymentConstants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // @dev Structure used internally to get around stack limits.
 | 
				
			||||||
 | 
					    struct TradeState {
 | 
				
			||||||
 | 
					        IKyberNetworkProxy kyber;
 | 
				
			||||||
 | 
					        IEtherToken weth;
 | 
				
			||||||
 | 
					        address fromTokenAddress;
 | 
				
			||||||
 | 
					        uint256 fromTokenBalance;
 | 
				
			||||||
 | 
					        uint256 payableAmount;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Kyber ETH pseudo-address.
 | 
				
			||||||
 | 
					    address constant public KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
 | 
				
			||||||
 | 
					    /// @dev `bridgeTransferFrom()` failure result.
 | 
				
			||||||
 | 
					    bytes4 constant private BRIDGE_FAILED = 0x0;
 | 
				
			||||||
 | 
					    /// @dev Precision of Kyber rates.
 | 
				
			||||||
 | 
					    uint256 constant private KYBER_RATE_BASE = 10 ** 18;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // solhint-disable no-empty-blocks
 | 
				
			||||||
 | 
					    /// @dev Payable fallback to receive ETH from Kyber.
 | 
				
			||||||
 | 
					    function ()
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        payable
 | 
				
			||||||
 | 
					    {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Callback for `IKyberBridge`. Tries to buy `amount` of
 | 
				
			||||||
 | 
					    ///      `toTokenAddress` tokens by selling the entirety of the opposing asset
 | 
				
			||||||
 | 
					    ///      to the `KyberNetworkProxy` contract, then transfers the bought
 | 
				
			||||||
 | 
					    ///      tokens to `to`.
 | 
				
			||||||
 | 
					    /// @param toTokenAddress The token to give to `to`.
 | 
				
			||||||
 | 
					    /// @param to The recipient of the bought tokens.
 | 
				
			||||||
 | 
					    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
				
			||||||
 | 
					    /// @param bridgeData The abi-encoeded "from" token address.
 | 
				
			||||||
 | 
					    /// @return success The magic bytes if successful.
 | 
				
			||||||
 | 
					    function bridgeTransferFrom(
 | 
				
			||||||
 | 
					        address toTokenAddress,
 | 
				
			||||||
 | 
					        address /* from */,
 | 
				
			||||||
 | 
					        address to,
 | 
				
			||||||
 | 
					        uint256 amount,
 | 
				
			||||||
 | 
					        bytes calldata bridgeData
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        returns (bytes4 success)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        TradeState memory state;
 | 
				
			||||||
 | 
					        state.kyber = _getKyberContract();
 | 
				
			||||||
 | 
					        state.weth = _getWETHContract();
 | 
				
			||||||
 | 
					        // Decode the bridge data to get the `fromTokenAddress`.
 | 
				
			||||||
 | 
					        (state.fromTokenAddress) = abi.decode(bridgeData, (address));
 | 
				
			||||||
 | 
					        state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));
 | 
				
			||||||
 | 
					        if (state.fromTokenBalance == 0) {
 | 
				
			||||||
 | 
					            // Return failure if no input tokens.
 | 
				
			||||||
 | 
					            return BRIDGE_FAILED;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (state.fromTokenAddress == toTokenAddress) {
 | 
				
			||||||
 | 
					            // Just transfer the tokens if they're the same.
 | 
				
			||||||
 | 
					            LibERC20Token.transfer(state.fromTokenAddress, to, state.fromTokenBalance);
 | 
				
			||||||
 | 
					            return BRIDGE_SUCCESS;
 | 
				
			||||||
 | 
					        } else if (state.fromTokenAddress != address(state.weth)) {
 | 
				
			||||||
 | 
					            // If the input token is not WETH, grant an allowance to the exchange
 | 
				
			||||||
 | 
					            // to spend them.
 | 
				
			||||||
 | 
					            LibERC20Token.approve(state.fromTokenAddress, address(state.kyber), uint256(-1));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // If the input token is WETH, unwrap it and attach it to the call.
 | 
				
			||||||
 | 
					            state.fromTokenAddress = KYBER_ETH_ADDRESS;
 | 
				
			||||||
 | 
					            state.payableAmount = state.fromTokenBalance;
 | 
				
			||||||
 | 
					            state.weth.withdraw(state.fromTokenBalance);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        bool isToTokenWeth = toTokenAddress == address(state.weth);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Try to sell all of this contract's input token balance through
 | 
				
			||||||
 | 
					        // `KyberNetworkProxy.trade()`.
 | 
				
			||||||
 | 
					        uint256 boughtAmount = state.kyber.trade.value(state.payableAmount)(
 | 
				
			||||||
 | 
					            // Input token.
 | 
				
			||||||
 | 
					            state.fromTokenAddress,
 | 
				
			||||||
 | 
					            // Sell amount.
 | 
				
			||||||
 | 
					            state.fromTokenBalance,
 | 
				
			||||||
 | 
					            // Output token.
 | 
				
			||||||
 | 
					            isToTokenWeth ? KYBER_ETH_ADDRESS : toTokenAddress,
 | 
				
			||||||
 | 
					            // Transfer to this contract if converting to ETH, otherwise
 | 
				
			||||||
 | 
					            // transfer directly to the recipient.
 | 
				
			||||||
 | 
					            isToTokenWeth ? address(uint160(address(this))) : address(uint160(to)),
 | 
				
			||||||
 | 
					            // Buy as much as possible.
 | 
				
			||||||
 | 
					            uint256(-1),
 | 
				
			||||||
 | 
					            // Compute the minimum conversion rate, which is expressed in units with
 | 
				
			||||||
 | 
					            // 18 decimal places.
 | 
				
			||||||
 | 
					            (KYBER_RATE_BASE * amount) / state.fromTokenBalance,
 | 
				
			||||||
 | 
					            // No affiliate address.
 | 
				
			||||||
 | 
					            address(0)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        // Wrap ETH output and transfer to recipient.
 | 
				
			||||||
 | 
					        if (isToTokenWeth) {
 | 
				
			||||||
 | 
					            state.weth.deposit.value(boughtAmount)();
 | 
				
			||||||
 | 
					            state.weth.transfer(to, boughtAmount);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return BRIDGE_SUCCESS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
				
			||||||
 | 
					    ///      and sign for itself in orders. Always succeeds.
 | 
				
			||||||
 | 
					    /// @return magicValue Magic success bytes, always.
 | 
				
			||||||
 | 
					    function isValidSignature(
 | 
				
			||||||
 | 
					        bytes32,
 | 
				
			||||||
 | 
					        bytes calldata
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (bytes4 magicValue)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return LEGACY_WALLET_MAGIC_VALUE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Overridable way to get the `KyberNetworkProxy` contract.
 | 
				
			||||||
 | 
					    /// @return kyber The `IKyberNetworkProxy` contract.
 | 
				
			||||||
 | 
					    function _getKyberContract()
 | 
				
			||||||
 | 
					        internal
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (IKyberNetworkProxy kyber)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return IKyberNetworkProxy(_getKyberNetworkProxyAddress());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Overridable way to get the WETH contract.
 | 
				
			||||||
 | 
					    /// @return weth The WETH contract.
 | 
				
			||||||
 | 
					    function _getWETHContract()
 | 
				
			||||||
 | 
					        internal
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (IEtherToken weth)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return IEtherToken(_getWETHAddress());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -23,6 +23,7 @@ import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
				
			|||||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
 | 
					import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
 | 
				
			||||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
					import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
				
			||||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
					import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
				
			||||||
 | 
					import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
				
			||||||
import "../interfaces/IUniswapExchangeFactory.sol";
 | 
					import "../interfaces/IUniswapExchangeFactory.sol";
 | 
				
			||||||
import "../interfaces/IUniswapExchange.sol";
 | 
					import "../interfaces/IUniswapExchange.sol";
 | 
				
			||||||
import "../interfaces/IERC20Bridge.sol";
 | 
					import "../interfaces/IERC20Bridge.sol";
 | 
				
			||||||
@@ -32,12 +33,9 @@ import "../interfaces/IERC20Bridge.sol";
 | 
				
			|||||||
// solhint-disable not-rely-on-time
 | 
					// solhint-disable not-rely-on-time
 | 
				
			||||||
contract UniswapBridge is
 | 
					contract UniswapBridge is
 | 
				
			||||||
    IERC20Bridge,
 | 
					    IERC20Bridge,
 | 
				
			||||||
    IWallet
 | 
					    IWallet,
 | 
				
			||||||
 | 
					    DeploymentConstants
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /* Mainnet addresses */
 | 
					 | 
				
			||||||
    address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
 | 
					 | 
				
			||||||
    address constant private WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Struct to hold `bridgeTransferFrom()` local variables in memory and to avoid
 | 
					    // Struct to hold `bridgeTransferFrom()` local variables in memory and to avoid
 | 
				
			||||||
    // stack overflows.
 | 
					    // stack overflows.
 | 
				
			||||||
    struct WithdrawToState {
 | 
					    struct WithdrawToState {
 | 
				
			||||||
@@ -170,7 +168,7 @@ contract UniswapBridge is
 | 
				
			|||||||
        view
 | 
					        view
 | 
				
			||||||
        returns (IEtherToken token)
 | 
					        returns (IEtherToken token)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return IEtherToken(WETH_ADDRESS);
 | 
					        return IEtherToken(_getWETHAddress());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// @dev Overridable way to get the uniswap exchange factory contract.
 | 
					    /// @dev Overridable way to get the uniswap exchange factory contract.
 | 
				
			||||||
@@ -180,7 +178,7 @@ contract UniswapBridge is
 | 
				
			|||||||
        view
 | 
					        view
 | 
				
			||||||
        returns (IUniswapExchangeFactory factory)
 | 
					        returns (IUniswapExchangeFactory factory)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return IUniswapExchangeFactory(UNISWAP_EXCHANGE_FACTORY_ADDRESS);
 | 
					        return IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// @dev Grants an unlimited allowance to the exchange for its token
 | 
					    /// @dev Grants an unlimited allowance to the exchange for its token
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Copyright 2019 ZeroEx Intl.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					  you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					  You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					  distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					  See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					  limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pragma solidity ^0.5.9;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IKyberNetworkProxy {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens.
 | 
				
			||||||
 | 
					    /// @param sellTokenAddress Token to sell.
 | 
				
			||||||
 | 
					    /// @param sellAmount Amount of tokens to sell.
 | 
				
			||||||
 | 
					    /// @param buyTokenAddress Token to buy.
 | 
				
			||||||
 | 
					    /// @param recipientAddress Address to send bought tokens to.
 | 
				
			||||||
 | 
					    /// @param maxBuyTokenAmount A limit on the amount of tokens to buy.
 | 
				
			||||||
 | 
					    /// @param minConversionRate The minimal conversion rate. If actual rate
 | 
				
			||||||
 | 
					    ///        is lower, trade is canceled.
 | 
				
			||||||
 | 
					    /// @param walletId The wallet ID to send part of the fees
 | 
				
			||||||
 | 
					    /// @return boughtAmount Amount of tokens bought.
 | 
				
			||||||
 | 
					    function trade(
 | 
				
			||||||
 | 
					        address sellTokenAddress,
 | 
				
			||||||
 | 
					        uint256 sellAmount,
 | 
				
			||||||
 | 
					        address buyTokenAddress,
 | 
				
			||||||
 | 
					        address payable recipientAddress,
 | 
				
			||||||
 | 
					        uint256 maxBuyTokenAmount,
 | 
				
			||||||
 | 
					        uint256 minConversionRate,
 | 
				
			||||||
 | 
					        address walletId
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        payable
 | 
				
			||||||
 | 
					        returns(uint256 boughtAmount);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										322
									
								
								contracts/asset-proxy/contracts/test/TestKyberBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								contracts/asset-proxy/contracts/test/TestKyberBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,322 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Copyright 2019 ZeroEx Intl.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					  you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					  You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					  distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					  See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					  limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pragma solidity ^0.5.9;
 | 
				
			||||||
 | 
					pragma experimental ABIEncoderV2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
				
			||||||
 | 
					import "../src/bridges/KyberBridge.sol";
 | 
				
			||||||
 | 
					import "../src/interfaces/IKyberNetworkProxy.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// solhint-disable no-simple-event-func-name
 | 
				
			||||||
 | 
					interface ITestContract {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function wethWithdraw(
 | 
				
			||||||
 | 
					        address payable ownerAddress,
 | 
				
			||||||
 | 
					        uint256 amount
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function wethDeposit(
 | 
				
			||||||
 | 
					        address ownerAddress
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        payable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function tokenTransfer(
 | 
				
			||||||
 | 
					        address ownerAddress,
 | 
				
			||||||
 | 
					        address recipientAddress,
 | 
				
			||||||
 | 
					        uint256 amount
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        returns (bool success);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function tokenApprove(
 | 
				
			||||||
 | 
					        address ownerAddress,
 | 
				
			||||||
 | 
					        address spenderAddress,
 | 
				
			||||||
 | 
					        uint256 allowance
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        returns (bool success);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function tokenBalanceOf(
 | 
				
			||||||
 | 
					        address ownerAddress
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (uint256 balance);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// @dev A minimalist ERC20/WETH token.
 | 
				
			||||||
 | 
					contract TestToken {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ITestContract private _testContract;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor() public {
 | 
				
			||||||
 | 
					        _testContract = ITestContract(msg.sender);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function approve(address spender, uint256 allowance)
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        returns (bool)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return _testContract.tokenApprove(
 | 
				
			||||||
 | 
					            msg.sender,
 | 
				
			||||||
 | 
					            spender,
 | 
				
			||||||
 | 
					            allowance
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function transfer(address recipient, uint256 amount)
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        returns (bool)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return _testContract.tokenTransfer(
 | 
				
			||||||
 | 
					            msg.sender,
 | 
				
			||||||
 | 
					            recipient,
 | 
				
			||||||
 | 
					            amount
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function withdraw(uint256 amount)
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return _testContract.wethWithdraw(msg.sender, amount);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function deposit()
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        payable
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return _testContract.wethDeposit.value(msg.value)(msg.sender);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function balanceOf(address owner)
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (uint256)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return _testContract.tokenBalanceOf(owner);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// @dev KyberBridge overridden to mock tokens and implement IKyberBridge.
 | 
				
			||||||
 | 
					contract TestKyberBridge is
 | 
				
			||||||
 | 
					    KyberBridge,
 | 
				
			||||||
 | 
					    ITestContract,
 | 
				
			||||||
 | 
					    IKyberNetworkProxy
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    event KyberBridgeTrade(
 | 
				
			||||||
 | 
					        uint256 msgValue,
 | 
				
			||||||
 | 
					        address sellTokenAddress,
 | 
				
			||||||
 | 
					        uint256 sellAmount,
 | 
				
			||||||
 | 
					        address buyTokenAddress,
 | 
				
			||||||
 | 
					        address payable recipientAddress,
 | 
				
			||||||
 | 
					        uint256 maxBuyTokenAmount,
 | 
				
			||||||
 | 
					        uint256 minConversionRate,
 | 
				
			||||||
 | 
					        address walletId
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    event KyberBridgeWethWithdraw(
 | 
				
			||||||
 | 
					        address ownerAddress,
 | 
				
			||||||
 | 
					        uint256 amount
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    event KyberBridgeWethDeposit(
 | 
				
			||||||
 | 
					        uint256 msgValue,
 | 
				
			||||||
 | 
					        address ownerAddress,
 | 
				
			||||||
 | 
					        uint256 amount
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    event KyberBridgeTokenApprove(
 | 
				
			||||||
 | 
					        address tokenAddress,
 | 
				
			||||||
 | 
					        address ownerAddress,
 | 
				
			||||||
 | 
					        address spenderAddress,
 | 
				
			||||||
 | 
					        uint256 allowance
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    event KyberBridgeTokenTransfer(
 | 
				
			||||||
 | 
					        address tokenAddress,
 | 
				
			||||||
 | 
					        address ownerAddress,
 | 
				
			||||||
 | 
					        address recipientAddress,
 | 
				
			||||||
 | 
					        uint256 amount
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    IEtherToken public weth;
 | 
				
			||||||
 | 
					    mapping (address => mapping (address => uint256)) private _tokenBalances;
 | 
				
			||||||
 | 
					    uint256 private _nextFillAmount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor() public {
 | 
				
			||||||
 | 
					        weth = IEtherToken(address(new TestToken()));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Implementation of `IKyberNetworkProxy.trade()`
 | 
				
			||||||
 | 
					    function trade(
 | 
				
			||||||
 | 
					        address sellTokenAddress,
 | 
				
			||||||
 | 
					        uint256 sellAmount,
 | 
				
			||||||
 | 
					        address buyTokenAddress,
 | 
				
			||||||
 | 
					        address payable recipientAddress,
 | 
				
			||||||
 | 
					        uint256 maxBuyTokenAmount,
 | 
				
			||||||
 | 
					        uint256 minConversionRate,
 | 
				
			||||||
 | 
					        address walletId
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        payable
 | 
				
			||||||
 | 
					        returns(uint256 boughtAmount)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        emit KyberBridgeTrade(
 | 
				
			||||||
 | 
					            msg.value,
 | 
				
			||||||
 | 
					            sellTokenAddress,
 | 
				
			||||||
 | 
					            sellAmount,
 | 
				
			||||||
 | 
					            buyTokenAddress,
 | 
				
			||||||
 | 
					            recipientAddress,
 | 
				
			||||||
 | 
					            maxBuyTokenAmount,
 | 
				
			||||||
 | 
					            minConversionRate,
 | 
				
			||||||
 | 
					            walletId
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        return _nextFillAmount;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function createToken()
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        returns (address tokenAddress)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return address(new TestToken());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function setNextFillAmount(uint256 amount)
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        payable
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (msg.value != 0) {
 | 
				
			||||||
 | 
					            require(amount == msg.value, "VALUE_AMOUNT_MISMATCH");
 | 
				
			||||||
 | 
					            grantTokensTo(address(weth), address(this), msg.value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        _nextFillAmount = amount;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function wethDeposit(
 | 
				
			||||||
 | 
					        address ownerAddress
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        payable
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        require(msg.sender == address(weth), "ONLY_WETH");
 | 
				
			||||||
 | 
					        grantTokensTo(address(weth), ownerAddress, msg.value);
 | 
				
			||||||
 | 
					        emit KyberBridgeWethDeposit(
 | 
				
			||||||
 | 
					            msg.value,
 | 
				
			||||||
 | 
					            ownerAddress,
 | 
				
			||||||
 | 
					            msg.value
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function wethWithdraw(
 | 
				
			||||||
 | 
					        address payable ownerAddress,
 | 
				
			||||||
 | 
					        uint256 amount
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        require(msg.sender == address(weth), "ONLY_WETH");
 | 
				
			||||||
 | 
					        _tokenBalances[address(weth)][ownerAddress] -= amount;
 | 
				
			||||||
 | 
					        ownerAddress.transfer(amount);
 | 
				
			||||||
 | 
					        emit KyberBridgeWethWithdraw(
 | 
				
			||||||
 | 
					            ownerAddress,
 | 
				
			||||||
 | 
					            amount
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function tokenApprove(
 | 
				
			||||||
 | 
					        address ownerAddress,
 | 
				
			||||||
 | 
					        address spenderAddress,
 | 
				
			||||||
 | 
					        uint256 allowance
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        returns (bool success)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        emit KyberBridgeTokenApprove(
 | 
				
			||||||
 | 
					            msg.sender,
 | 
				
			||||||
 | 
					            ownerAddress,
 | 
				
			||||||
 | 
					            spenderAddress,
 | 
				
			||||||
 | 
					            allowance
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function tokenTransfer(
 | 
				
			||||||
 | 
					        address ownerAddress,
 | 
				
			||||||
 | 
					        address recipientAddress,
 | 
				
			||||||
 | 
					        uint256 amount
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        returns (bool success)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _tokenBalances[msg.sender][ownerAddress] -= amount;
 | 
				
			||||||
 | 
					        _tokenBalances[msg.sender][recipientAddress] += amount;
 | 
				
			||||||
 | 
					        emit KyberBridgeTokenTransfer(
 | 
				
			||||||
 | 
					            msg.sender,
 | 
				
			||||||
 | 
					            ownerAddress,
 | 
				
			||||||
 | 
					            recipientAddress,
 | 
				
			||||||
 | 
					            amount
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function tokenBalanceOf(
 | 
				
			||||||
 | 
					        address ownerAddress
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (uint256 balance)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return _tokenBalances[msg.sender][ownerAddress];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function grantTokensTo(address tokenAddress, address ownerAddress, uint256 amount)
 | 
				
			||||||
 | 
					        public
 | 
				
			||||||
 | 
					        payable
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _tokenBalances[tokenAddress][ownerAddress] += amount;
 | 
				
			||||||
 | 
					        if (tokenAddress != address(weth)) {
 | 
				
			||||||
 | 
					            // Send back ether if not WETH.
 | 
				
			||||||
 | 
					            msg.sender.transfer(msg.value);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            require(msg.value == amount, "VALUE_AMOUNT_MISMATCH");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // @dev overridden to point to this contract.
 | 
				
			||||||
 | 
					    function _getKyberContract()
 | 
				
			||||||
 | 
					        internal
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (IKyberNetworkProxy kyber)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return IKyberNetworkProxy(address(this));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // @dev overridden to point to test WETH.
 | 
				
			||||||
 | 
					    function _getWETHContract()
 | 
				
			||||||
 | 
					        internal
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (IEtherToken weth_)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return weth;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -38,8 +38,8 @@
 | 
				
			|||||||
        "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
 | 
					        "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "config": {
 | 
					    "config": {
 | 
				
			||||||
        "publicInterfaceContracts": "ERC1155Proxy,ERC20Proxy,ERC721Proxy,MultiAssetProxy,StaticCallProxy,ERC20BridgeProxy,Eth2DaiBridge,IAssetData,IAssetProxy,UniswapBridge,TestStaticCallTarget",
 | 
					        "publicInterfaceContracts": "ERC1155Proxy,ERC20Proxy,ERC721Proxy,MultiAssetProxy,StaticCallProxy,ERC20BridgeProxy,Eth2DaiBridge,IAssetData,IAssetProxy,UniswapBridge,KyberBridge,TestStaticCallTarget",
 | 
				
			||||||
        "abis": "./test/generated-artifacts/@(ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IERC20Bridge|IEth2Dai|IUniswapExchange|IUniswapExchangeFactory|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestERC20Bridge|TestEth2DaiBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
 | 
					        "abis": "./test/generated-artifacts/@(ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
 | 
				
			||||||
        "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
 | 
					        "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "repository": {
 | 
					    "repository": {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json';
 | 
				
			|||||||
import * as Eth2DaiBridge from '../generated-artifacts/Eth2DaiBridge.json';
 | 
					import * as Eth2DaiBridge from '../generated-artifacts/Eth2DaiBridge.json';
 | 
				
			||||||
import * as IAssetData from '../generated-artifacts/IAssetData.json';
 | 
					import * as IAssetData from '../generated-artifacts/IAssetData.json';
 | 
				
			||||||
import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
 | 
					import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
 | 
				
			||||||
 | 
					import * as KyberBridge from '../generated-artifacts/KyberBridge.json';
 | 
				
			||||||
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
 | 
					import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
 | 
				
			||||||
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
 | 
					import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
 | 
				
			||||||
import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json';
 | 
					import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json';
 | 
				
			||||||
@@ -27,5 +28,6 @@ export const artifacts = {
 | 
				
			|||||||
    IAssetData: IAssetData as ContractArtifact,
 | 
					    IAssetData: IAssetData as ContractArtifact,
 | 
				
			||||||
    IAssetProxy: IAssetProxy as ContractArtifact,
 | 
					    IAssetProxy: IAssetProxy as ContractArtifact,
 | 
				
			||||||
    UniswapBridge: UniswapBridge as ContractArtifact,
 | 
					    UniswapBridge: UniswapBridge as ContractArtifact,
 | 
				
			||||||
 | 
					    KyberBridge: KyberBridge as ContractArtifact,
 | 
				
			||||||
    TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
 | 
					    TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@ export * from '../generated-wrappers/erc721_proxy';
 | 
				
			|||||||
export * from '../generated-wrappers/eth2_dai_bridge';
 | 
					export * from '../generated-wrappers/eth2_dai_bridge';
 | 
				
			||||||
export * from '../generated-wrappers/i_asset_data';
 | 
					export * from '../generated-wrappers/i_asset_data';
 | 
				
			||||||
export * from '../generated-wrappers/i_asset_proxy';
 | 
					export * from '../generated-wrappers/i_asset_proxy';
 | 
				
			||||||
 | 
					export * from '../generated-wrappers/kyber_bridge';
 | 
				
			||||||
export * from '../generated-wrappers/multi_asset_proxy';
 | 
					export * from '../generated-wrappers/multi_asset_proxy';
 | 
				
			||||||
export * from '../generated-wrappers/static_call_proxy';
 | 
					export * from '../generated-wrappers/static_call_proxy';
 | 
				
			||||||
export * from '../generated-wrappers/test_static_call_target';
 | 
					export * from '../generated-wrappers/test_static_call_target';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,8 +16,10 @@ import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyD
 | 
				
			|||||||
import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json';
 | 
					import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json';
 | 
				
			||||||
import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
 | 
					import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
 | 
				
			||||||
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
 | 
					import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
 | 
				
			||||||
 | 
					import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json';
 | 
				
			||||||
import * as IUniswapExchange from '../test/generated-artifacts/IUniswapExchange.json';
 | 
					import * as IUniswapExchange from '../test/generated-artifacts/IUniswapExchange.json';
 | 
				
			||||||
import * as IUniswapExchangeFactory from '../test/generated-artifacts/IUniswapExchangeFactory.json';
 | 
					import * as IUniswapExchangeFactory from '../test/generated-artifacts/IUniswapExchangeFactory.json';
 | 
				
			||||||
 | 
					import * as KyberBridge from '../test/generated-artifacts/KyberBridge.json';
 | 
				
			||||||
import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json';
 | 
					import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json';
 | 
				
			||||||
import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizable.json';
 | 
					import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizable.json';
 | 
				
			||||||
import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json';
 | 
					import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json';
 | 
				
			||||||
@@ -25,6 +27,7 @@ import * as Ownable from '../test/generated-artifacts/Ownable.json';
 | 
				
			|||||||
import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json';
 | 
					import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json';
 | 
				
			||||||
import * as TestERC20Bridge from '../test/generated-artifacts/TestERC20Bridge.json';
 | 
					import * as TestERC20Bridge from '../test/generated-artifacts/TestERC20Bridge.json';
 | 
				
			||||||
import * as TestEth2DaiBridge from '../test/generated-artifacts/TestEth2DaiBridge.json';
 | 
					import * as TestEth2DaiBridge from '../test/generated-artifacts/TestEth2DaiBridge.json';
 | 
				
			||||||
 | 
					import * as TestKyberBridge from '../test/generated-artifacts/TestKyberBridge.json';
 | 
				
			||||||
import * as TestStaticCallTarget from '../test/generated-artifacts/TestStaticCallTarget.json';
 | 
					import * as TestStaticCallTarget from '../test/generated-artifacts/TestStaticCallTarget.json';
 | 
				
			||||||
import * as TestUniswapBridge from '../test/generated-artifacts/TestUniswapBridge.json';
 | 
					import * as TestUniswapBridge from '../test/generated-artifacts/TestUniswapBridge.json';
 | 
				
			||||||
import * as UniswapBridge from '../test/generated-artifacts/UniswapBridge.json';
 | 
					import * as UniswapBridge from '../test/generated-artifacts/UniswapBridge.json';
 | 
				
			||||||
@@ -39,6 +42,7 @@ export const artifacts = {
 | 
				
			|||||||
    MultiAssetProxy: MultiAssetProxy as ContractArtifact,
 | 
					    MultiAssetProxy: MultiAssetProxy as ContractArtifact,
 | 
				
			||||||
    StaticCallProxy: StaticCallProxy as ContractArtifact,
 | 
					    StaticCallProxy: StaticCallProxy as ContractArtifact,
 | 
				
			||||||
    Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
 | 
					    Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
 | 
				
			||||||
 | 
					    KyberBridge: KyberBridge as ContractArtifact,
 | 
				
			||||||
    UniswapBridge: UniswapBridge as ContractArtifact,
 | 
					    UniswapBridge: UniswapBridge as ContractArtifact,
 | 
				
			||||||
    IAssetData: IAssetData as ContractArtifact,
 | 
					    IAssetData: IAssetData as ContractArtifact,
 | 
				
			||||||
    IAssetProxy: IAssetProxy as ContractArtifact,
 | 
					    IAssetProxy: IAssetProxy as ContractArtifact,
 | 
				
			||||||
@@ -46,10 +50,12 @@ export const artifacts = {
 | 
				
			|||||||
    IAuthorizable: IAuthorizable as ContractArtifact,
 | 
					    IAuthorizable: IAuthorizable as ContractArtifact,
 | 
				
			||||||
    IERC20Bridge: IERC20Bridge as ContractArtifact,
 | 
					    IERC20Bridge: IERC20Bridge as ContractArtifact,
 | 
				
			||||||
    IEth2Dai: IEth2Dai as ContractArtifact,
 | 
					    IEth2Dai: IEth2Dai as ContractArtifact,
 | 
				
			||||||
 | 
					    IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
 | 
				
			||||||
    IUniswapExchange: IUniswapExchange as ContractArtifact,
 | 
					    IUniswapExchange: IUniswapExchange as ContractArtifact,
 | 
				
			||||||
    IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
 | 
					    IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
 | 
				
			||||||
    TestERC20Bridge: TestERC20Bridge as ContractArtifact,
 | 
					    TestERC20Bridge: TestERC20Bridge as ContractArtifact,
 | 
				
			||||||
    TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact,
 | 
					    TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact,
 | 
				
			||||||
 | 
					    TestKyberBridge: TestKyberBridge as ContractArtifact,
 | 
				
			||||||
    TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
 | 
					    TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
 | 
				
			||||||
    TestUniswapBridge: TestUniswapBridge as ContractArtifact,
 | 
					    TestUniswapBridge: TestUniswapBridge as ContractArtifact,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										272
									
								
								contracts/asset-proxy/test/kyber_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								contracts/asset-proxy/test/kyber_bridge.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,272 @@
 | 
				
			|||||||
 | 
					import {
 | 
				
			||||||
 | 
					    blockchainTests,
 | 
				
			||||||
 | 
					    constants,
 | 
				
			||||||
 | 
					    expect,
 | 
				
			||||||
 | 
					    getRandomInteger,
 | 
				
			||||||
 | 
					    hexLeftPad,
 | 
				
			||||||
 | 
					    hexRandom,
 | 
				
			||||||
 | 
					    randomAddress,
 | 
				
			||||||
 | 
					    verifyEventsFromLogs,
 | 
				
			||||||
 | 
					} from '@0x/contracts-test-utils';
 | 
				
			||||||
 | 
					import { AssetProxyId } from '@0x/types';
 | 
				
			||||||
 | 
					import { BigNumber } from '@0x/utils';
 | 
				
			||||||
 | 
					import { DecodedLogs } from 'ethereum-types';
 | 
				
			||||||
 | 
					import * as _ from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { artifacts } from './artifacts';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { TestKyberBridgeContract, TestKyberBridgeEvents } from './wrappers';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					blockchainTests.resets('KyberBridge unit tests', env => {
 | 
				
			||||||
 | 
					    const KYBER_ETH_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
 | 
				
			||||||
 | 
					    let testContract: TestKyberBridgeContract;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    before(async () => {
 | 
				
			||||||
 | 
					        testContract = await TestKyberBridgeContract.deployFrom0xArtifactAsync(
 | 
				
			||||||
 | 
					            artifacts.TestKyberBridge,
 | 
				
			||||||
 | 
					            env.provider,
 | 
				
			||||||
 | 
					            env.txDefaults,
 | 
				
			||||||
 | 
					            artifacts,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe('isValidSignature()', () => {
 | 
				
			||||||
 | 
					        it('returns success bytes', async () => {
 | 
				
			||||||
 | 
					            const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
 | 
				
			||||||
 | 
					            const result = await testContract.isValidSignature(hexRandom(), hexRandom(_.random(0, 32))).callAsync();
 | 
				
			||||||
 | 
					            expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe('bridgeTransferFrom()', () => {
 | 
				
			||||||
 | 
					        let fromTokenAddress: string;
 | 
				
			||||||
 | 
					        let toTokenAddress: string;
 | 
				
			||||||
 | 
					        let wethAddress: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        before(async () => {
 | 
				
			||||||
 | 
					            wethAddress = await testContract.weth().callAsync();
 | 
				
			||||||
 | 
					            fromTokenAddress = await testContract.createToken().callAsync();
 | 
				
			||||||
 | 
					            await testContract.createToken().awaitTransactionSuccessAsync();
 | 
				
			||||||
 | 
					            toTokenAddress = await testContract.createToken().callAsync();
 | 
				
			||||||
 | 
					            await testContract.createToken().awaitTransactionSuccessAsync();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const STATIC_KYBER_TRADE_ARGS = {
 | 
				
			||||||
 | 
					            maxBuyTokenAmount: constants.MAX_UINT256,
 | 
				
			||||||
 | 
					            walletId: constants.NULL_ADDRESS,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        interface TransferFromOpts {
 | 
				
			||||||
 | 
					            toTokenAddress: string;
 | 
				
			||||||
 | 
					            fromTokenAddress: string;
 | 
				
			||||||
 | 
					            toAddress: string;
 | 
				
			||||||
 | 
					            // Amount to pass into `bridgeTransferFrom()`
 | 
				
			||||||
 | 
					            amount: BigNumber;
 | 
				
			||||||
 | 
					            // Amount to convert in `trade()`.
 | 
				
			||||||
 | 
					            fillAmount: BigNumber;
 | 
				
			||||||
 | 
					            // Token balance of the bridge.
 | 
				
			||||||
 | 
					            fromTokenBalance: BigNumber;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        interface TransferFromResult {
 | 
				
			||||||
 | 
					            opts: TransferFromOpts;
 | 
				
			||||||
 | 
					            result: string;
 | 
				
			||||||
 | 
					            logs: DecodedLogs;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                fromTokenAddress,
 | 
				
			||||||
 | 
					                toTokenAddress,
 | 
				
			||||||
 | 
					                toAddress: randomAddress(),
 | 
				
			||||||
 | 
					                amount: getRandomInteger(1, 10e18),
 | 
				
			||||||
 | 
					                fillAmount: getRandomInteger(1, 10e18),
 | 
				
			||||||
 | 
					                fromTokenBalance: getRandomInteger(1, 10e18),
 | 
				
			||||||
 | 
					                ...opts,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async function withdrawToAsync(opts?: Partial<TransferFromOpts>): Promise<TransferFromResult> {
 | 
				
			||||||
 | 
					            const _opts = createTransferFromOpts(opts);
 | 
				
			||||||
 | 
					            // Fund the contract with input tokens.
 | 
				
			||||||
 | 
					            await testContract
 | 
				
			||||||
 | 
					                .grantTokensTo(_opts.fromTokenAddress, testContract.address, _opts.fromTokenBalance)
 | 
				
			||||||
 | 
					                .awaitTransactionSuccessAsync({ value: _opts.fromTokenBalance });
 | 
				
			||||||
 | 
					            // Fund the contract with output tokens.
 | 
				
			||||||
 | 
					            await testContract.setNextFillAmount(_opts.fillAmount).awaitTransactionSuccessAsync({
 | 
				
			||||||
 | 
					                value: _opts.toTokenAddress === wethAddress ? _opts.fillAmount : constants.ZERO_AMOUNT,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            // Call bridgeTransferFrom().
 | 
				
			||||||
 | 
					            const bridgeTransferFromFn = testContract.bridgeTransferFrom(
 | 
				
			||||||
 | 
					                // Output token
 | 
				
			||||||
 | 
					                _opts.toTokenAddress,
 | 
				
			||||||
 | 
					                // Random maker address.
 | 
				
			||||||
 | 
					                randomAddress(),
 | 
				
			||||||
 | 
					                // Recipient address.
 | 
				
			||||||
 | 
					                _opts.toAddress,
 | 
				
			||||||
 | 
					                // Transfer amount.
 | 
				
			||||||
 | 
					                _opts.amount,
 | 
				
			||||||
 | 
					                // ABI-encode the input token address as the bridge data.
 | 
				
			||||||
 | 
					                hexLeftPad(_opts.fromTokenAddress),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            const result = await bridgeTransferFromFn.callAsync();
 | 
				
			||||||
 | 
					            const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                opts: _opts,
 | 
				
			||||||
 | 
					                result,
 | 
				
			||||||
 | 
					                logs: (logs as any) as DecodedLogs,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function getMinimumConversionRate(opts: TransferFromOpts): BigNumber {
 | 
				
			||||||
 | 
					            return opts.amount
 | 
				
			||||||
 | 
					                .times(constants.ONE_ETHER)
 | 
				
			||||||
 | 
					                .div(opts.fromTokenBalance)
 | 
				
			||||||
 | 
					                .integerValue(BigNumber.ROUND_DOWN);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('returns magic bytes on success', async () => {
 | 
				
			||||||
 | 
					            const BRIDGE_SUCCESS_RETURN_DATA = AssetProxyId.ERC20Bridge;
 | 
				
			||||||
 | 
					            const { result } = await withdrawToAsync();
 | 
				
			||||||
 | 
					            expect(result).to.eq(BRIDGE_SUCCESS_RETURN_DATA);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('can trade token -> token', async () => {
 | 
				
			||||||
 | 
					            const { opts, logs } = await withdrawToAsync();
 | 
				
			||||||
 | 
					            verifyEventsFromLogs(
 | 
				
			||||||
 | 
					                logs,
 | 
				
			||||||
 | 
					                [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        sellTokenAddress: opts.fromTokenAddress,
 | 
				
			||||||
 | 
					                        buyTokenAddress: opts.toTokenAddress,
 | 
				
			||||||
 | 
					                        sellAmount: opts.fromTokenBalance,
 | 
				
			||||||
 | 
					                        recipientAddress: opts.toAddress,
 | 
				
			||||||
 | 
					                        minConversionRate: getMinimumConversionRate(opts),
 | 
				
			||||||
 | 
					                        msgValue: constants.ZERO_AMOUNT,
 | 
				
			||||||
 | 
					                        ...STATIC_KYBER_TRADE_ARGS,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                TestKyberBridgeEvents.KyberBridgeTrade,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('can trade token -> ETH', async () => {
 | 
				
			||||||
 | 
					            const { opts, logs } = await withdrawToAsync({
 | 
				
			||||||
 | 
					                toTokenAddress: wethAddress,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            verifyEventsFromLogs(
 | 
				
			||||||
 | 
					                logs,
 | 
				
			||||||
 | 
					                [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        sellTokenAddress: opts.fromTokenAddress,
 | 
				
			||||||
 | 
					                        buyTokenAddress: KYBER_ETH_ADDRESS,
 | 
				
			||||||
 | 
					                        sellAmount: opts.fromTokenBalance,
 | 
				
			||||||
 | 
					                        recipientAddress: testContract.address,
 | 
				
			||||||
 | 
					                        minConversionRate: getMinimumConversionRate(opts),
 | 
				
			||||||
 | 
					                        msgValue: constants.ZERO_AMOUNT,
 | 
				
			||||||
 | 
					                        ...STATIC_KYBER_TRADE_ARGS,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                TestKyberBridgeEvents.KyberBridgeTrade,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('can trade ETH -> token', async () => {
 | 
				
			||||||
 | 
					            const { opts, logs } = await withdrawToAsync({
 | 
				
			||||||
 | 
					                fromTokenAddress: wethAddress,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            verifyEventsFromLogs(
 | 
				
			||||||
 | 
					                logs,
 | 
				
			||||||
 | 
					                [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        sellTokenAddress: KYBER_ETH_ADDRESS,
 | 
				
			||||||
 | 
					                        buyTokenAddress: opts.toTokenAddress,
 | 
				
			||||||
 | 
					                        sellAmount: opts.fromTokenBalance,
 | 
				
			||||||
 | 
					                        recipientAddress: opts.toAddress,
 | 
				
			||||||
 | 
					                        minConversionRate: getMinimumConversionRate(opts),
 | 
				
			||||||
 | 
					                        msgValue: opts.fromTokenBalance,
 | 
				
			||||||
 | 
					                        ...STATIC_KYBER_TRADE_ARGS,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                TestKyberBridgeEvents.KyberBridgeTrade,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('does nothing if bridge has no token balance', async () => {
 | 
				
			||||||
 | 
					            const { logs } = await withdrawToAsync({
 | 
				
			||||||
 | 
					                fromTokenBalance: constants.ZERO_AMOUNT,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            expect(logs).to.be.length(0);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('only transfers the token if trading the same token', async () => {
 | 
				
			||||||
 | 
					            const { opts, logs } = await withdrawToAsync({
 | 
				
			||||||
 | 
					                toTokenAddress: fromTokenAddress,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            verifyEventsFromLogs(
 | 
				
			||||||
 | 
					                logs,
 | 
				
			||||||
 | 
					                [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        tokenAddress: fromTokenAddress,
 | 
				
			||||||
 | 
					                        ownerAddress: testContract.address,
 | 
				
			||||||
 | 
					                        recipientAddress: opts.toAddress,
 | 
				
			||||||
 | 
					                        amount: opts.fromTokenBalance,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                TestKyberBridgeEvents.KyberBridgeTokenTransfer,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('grants Kyber an allowance when selling non-WETH', async () => {
 | 
				
			||||||
 | 
					            const { opts, logs } = await withdrawToAsync();
 | 
				
			||||||
 | 
					            verifyEventsFromLogs(
 | 
				
			||||||
 | 
					                logs,
 | 
				
			||||||
 | 
					                [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        tokenAddress: opts.fromTokenAddress,
 | 
				
			||||||
 | 
					                        ownerAddress: testContract.address,
 | 
				
			||||||
 | 
					                        spenderAddress: testContract.address,
 | 
				
			||||||
 | 
					                        allowance: constants.MAX_UINT256,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                TestKyberBridgeEvents.KyberBridgeTokenApprove,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('does not grant Kyber an allowance when selling WETH', async () => {
 | 
				
			||||||
 | 
					            const { logs } = await withdrawToAsync({
 | 
				
			||||||
 | 
					                fromTokenAddress: wethAddress,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            verifyEventsFromLogs(logs, [], TestKyberBridgeEvents.KyberBridgeTokenApprove);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('withdraws WETH and passes it to Kyber when selling WETH', async () => {
 | 
				
			||||||
 | 
					            const { opts, logs } = await withdrawToAsync({
 | 
				
			||||||
 | 
					                fromTokenAddress: wethAddress,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            expect(logs[0].event).to.eq(TestKyberBridgeEvents.KyberBridgeWethWithdraw);
 | 
				
			||||||
 | 
					            expect(logs[0].args).to.deep.eq({
 | 
				
			||||||
 | 
					                ownerAddress: testContract.address,
 | 
				
			||||||
 | 
					                amount: opts.fromTokenBalance,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            expect(logs[1].event).to.eq(TestKyberBridgeEvents.KyberBridgeTrade);
 | 
				
			||||||
 | 
					            expect(logs[1].args.msgValue).to.bignumber.eq(opts.fromTokenBalance);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('wraps WETH and transfers it to the recipient when buyng WETH', async () => {
 | 
				
			||||||
 | 
					            const { opts, logs } = await withdrawToAsync({
 | 
				
			||||||
 | 
					                toTokenAddress: wethAddress,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            expect(logs[0].event).to.eq(TestKyberBridgeEvents.KyberBridgeTokenApprove);
 | 
				
			||||||
 | 
					            expect(logs[0].args.tokenAddress).to.eq(opts.fromTokenAddress);
 | 
				
			||||||
 | 
					            expect(logs[1].event).to.eq(TestKyberBridgeEvents.KyberBridgeTrade);
 | 
				
			||||||
 | 
					            expect(logs[1].args.recipientAddress).to.eq(testContract.address);
 | 
				
			||||||
 | 
					            expect(logs[2].event).to.eq(TestKyberBridgeEvents.KyberBridgeWethDeposit);
 | 
				
			||||||
 | 
					            expect(logs[2].args).to.deep.eq({
 | 
				
			||||||
 | 
					                msgValue: opts.fillAmount,
 | 
				
			||||||
 | 
					                ownerAddress: testContract.address,
 | 
				
			||||||
 | 
					                amount: opts.fillAmount,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@@ -14,8 +14,10 @@ export * from '../test/generated-wrappers/i_asset_proxy_dispatcher';
 | 
				
			|||||||
export * from '../test/generated-wrappers/i_authorizable';
 | 
					export * from '../test/generated-wrappers/i_authorizable';
 | 
				
			||||||
export * from '../test/generated-wrappers/i_erc20_bridge';
 | 
					export * from '../test/generated-wrappers/i_erc20_bridge';
 | 
				
			||||||
export * from '../test/generated-wrappers/i_eth2_dai';
 | 
					export * from '../test/generated-wrappers/i_eth2_dai';
 | 
				
			||||||
 | 
					export * from '../test/generated-wrappers/i_kyber_network_proxy';
 | 
				
			||||||
export * from '../test/generated-wrappers/i_uniswap_exchange';
 | 
					export * from '../test/generated-wrappers/i_uniswap_exchange';
 | 
				
			||||||
export * from '../test/generated-wrappers/i_uniswap_exchange_factory';
 | 
					export * from '../test/generated-wrappers/i_uniswap_exchange_factory';
 | 
				
			||||||
 | 
					export * from '../test/generated-wrappers/kyber_bridge';
 | 
				
			||||||
export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher';
 | 
					export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher';
 | 
				
			||||||
export * from '../test/generated-wrappers/mixin_authorizable';
 | 
					export * from '../test/generated-wrappers/mixin_authorizable';
 | 
				
			||||||
export * from '../test/generated-wrappers/multi_asset_proxy';
 | 
					export * from '../test/generated-wrappers/multi_asset_proxy';
 | 
				
			||||||
@@ -23,6 +25,7 @@ export * from '../test/generated-wrappers/ownable';
 | 
				
			|||||||
export * from '../test/generated-wrappers/static_call_proxy';
 | 
					export * from '../test/generated-wrappers/static_call_proxy';
 | 
				
			||||||
export * from '../test/generated-wrappers/test_erc20_bridge';
 | 
					export * from '../test/generated-wrappers/test_erc20_bridge';
 | 
				
			||||||
export * from '../test/generated-wrappers/test_eth2_dai_bridge';
 | 
					export * from '../test/generated-wrappers/test_eth2_dai_bridge';
 | 
				
			||||||
 | 
					export * from '../test/generated-wrappers/test_kyber_bridge';
 | 
				
			||||||
export * from '../test/generated-wrappers/test_static_call_target';
 | 
					export * from '../test/generated-wrappers/test_static_call_target';
 | 
				
			||||||
export * from '../test/generated-wrappers/test_uniswap_bridge';
 | 
					export * from '../test/generated-wrappers/test_uniswap_bridge';
 | 
				
			||||||
export * from '../test/generated-wrappers/uniswap_bridge';
 | 
					export * from '../test/generated-wrappers/uniswap_bridge';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@
 | 
				
			|||||||
        "generated-artifacts/Eth2DaiBridge.json",
 | 
					        "generated-artifacts/Eth2DaiBridge.json",
 | 
				
			||||||
        "generated-artifacts/IAssetData.json",
 | 
					        "generated-artifacts/IAssetData.json",
 | 
				
			||||||
        "generated-artifacts/IAssetProxy.json",
 | 
					        "generated-artifacts/IAssetProxy.json",
 | 
				
			||||||
 | 
					        "generated-artifacts/KyberBridge.json",
 | 
				
			||||||
        "generated-artifacts/MultiAssetProxy.json",
 | 
					        "generated-artifacts/MultiAssetProxy.json",
 | 
				
			||||||
        "generated-artifacts/StaticCallProxy.json",
 | 
					        "generated-artifacts/StaticCallProxy.json",
 | 
				
			||||||
        "generated-artifacts/TestStaticCallTarget.json",
 | 
					        "generated-artifacts/TestStaticCallTarget.json",
 | 
				
			||||||
@@ -25,8 +26,10 @@
 | 
				
			|||||||
        "test/generated-artifacts/IAuthorizable.json",
 | 
					        "test/generated-artifacts/IAuthorizable.json",
 | 
				
			||||||
        "test/generated-artifacts/IERC20Bridge.json",
 | 
					        "test/generated-artifacts/IERC20Bridge.json",
 | 
				
			||||||
        "test/generated-artifacts/IEth2Dai.json",
 | 
					        "test/generated-artifacts/IEth2Dai.json",
 | 
				
			||||||
 | 
					        "test/generated-artifacts/IKyberNetworkProxy.json",
 | 
				
			||||||
        "test/generated-artifacts/IUniswapExchange.json",
 | 
					        "test/generated-artifacts/IUniswapExchange.json",
 | 
				
			||||||
        "test/generated-artifacts/IUniswapExchangeFactory.json",
 | 
					        "test/generated-artifacts/IUniswapExchangeFactory.json",
 | 
				
			||||||
 | 
					        "test/generated-artifacts/KyberBridge.json",
 | 
				
			||||||
        "test/generated-artifacts/MixinAssetProxyDispatcher.json",
 | 
					        "test/generated-artifacts/MixinAssetProxyDispatcher.json",
 | 
				
			||||||
        "test/generated-artifacts/MixinAuthorizable.json",
 | 
					        "test/generated-artifacts/MixinAuthorizable.json",
 | 
				
			||||||
        "test/generated-artifacts/MultiAssetProxy.json",
 | 
					        "test/generated-artifacts/MultiAssetProxy.json",
 | 
				
			||||||
@@ -34,6 +37,7 @@
 | 
				
			|||||||
        "test/generated-artifacts/StaticCallProxy.json",
 | 
					        "test/generated-artifacts/StaticCallProxy.json",
 | 
				
			||||||
        "test/generated-artifacts/TestERC20Bridge.json",
 | 
					        "test/generated-artifacts/TestERC20Bridge.json",
 | 
				
			||||||
        "test/generated-artifacts/TestEth2DaiBridge.json",
 | 
					        "test/generated-artifacts/TestEth2DaiBridge.json",
 | 
				
			||||||
 | 
					        "test/generated-artifacts/TestKyberBridge.json",
 | 
				
			||||||
        "test/generated-artifacts/TestStaticCallTarget.json",
 | 
					        "test/generated-artifacts/TestStaticCallTarget.json",
 | 
				
			||||||
        "test/generated-artifacts/TestUniswapBridge.json",
 | 
					        "test/generated-artifacts/TestUniswapBridge.json",
 | 
				
			||||||
        "test/generated-artifacts/UniswapBridge.json"
 | 
					        "test/generated-artifacts/UniswapBridge.json"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										75
									
								
								contracts/utils/contracts/src/DeploymentConstants.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								contracts/utils/contracts/src/DeploymentConstants.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Copyright 2019 ZeroEx Intl.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					  you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					  You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					  distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					  See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					  limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pragma solidity ^0.5.9;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "./interfaces/IOwnable.sol";
 | 
				
			||||||
 | 
					import "./LibOwnableRichErrors.sol";
 | 
				
			||||||
 | 
					import "./LibRichErrors.sol";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					contract DeploymentConstants {
 | 
				
			||||||
 | 
					    /// @dev Mainnet address of the WETH contract.
 | 
				
			||||||
 | 
					    address constant private WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
 | 
				
			||||||
 | 
					    /// @dev Mainnet address of the KyberNeworkProxy contract.
 | 
				
			||||||
 | 
					    address constant private KYBER_NETWORK_PROXY_ADDRESS = 0x818E6FECD516Ecc3849DAf6845e3EC868087B755;
 | 
				
			||||||
 | 
					    /// @dev Mainnet address of the `UniswapExchangeFactory` contract.
 | 
				
			||||||
 | 
					    address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
 | 
				
			||||||
 | 
					    /// @dev Mainnet address of the Eth2Dai `MatchingMarket` contract.
 | 
				
			||||||
 | 
					    address constant private ETH2DAI_ADDRESS = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Overridable way to get the `KyberNetworkProxy` address.
 | 
				
			||||||
 | 
					    /// @return kyberAddress The `IKyberNetworkProxy` address.
 | 
				
			||||||
 | 
					    function _getKyberNetworkProxyAddress()
 | 
				
			||||||
 | 
					        internal
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (address kyberAddress)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return KYBER_NETWORK_PROXY_ADDRESS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Overridable way to get the WETH address.
 | 
				
			||||||
 | 
					    /// @return wethAddress The WETH address.
 | 
				
			||||||
 | 
					    function _getWETHAddress()
 | 
				
			||||||
 | 
					        internal
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (address wethAddress)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return WETH_ADDRESS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Overridable way to get the `UniswapExchangeFactory` address.
 | 
				
			||||||
 | 
					    /// @return uniswapAddress The `UniswapExchangeFactory` address.
 | 
				
			||||||
 | 
					    function _getUniswapExchangeFactoryAddress()
 | 
				
			||||||
 | 
					        internal
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (address uniswapAddress)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return UNISWAP_EXCHANGE_FACTORY_ADDRESS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev An overridable way to retrieve the Eth2Dai `MatchingMarket` contract.
 | 
				
			||||||
 | 
					    /// @return eth2daiAddress The Eth2Dai `MatchingMarket` contract.
 | 
				
			||||||
 | 
					    function _getEth2DaiAddress()
 | 
				
			||||||
 | 
					        internal
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (address eth2daiAddress)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return ETH2DAI_ADDRESS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -38,7 +38,7 @@
 | 
				
			|||||||
    "config": {
 | 
					    "config": {
 | 
				
			||||||
        "publicInterfaceContracts": "Authorizable,IAuthorizable,IOwnable,LibAddress,LibAddressArray,LibAddressArrayRichErrors,LibAuthorizableRichErrors,LibBytes,LibBytesRichErrors,LibEIP1271,LibEIP712,LibFractions,LibOwnableRichErrors,LibReentrancyGuardRichErrors,LibRichErrors,LibSafeMath,LibSafeMathRichErrors,Ownable,ReentrancyGuard,Refundable",
 | 
					        "publicInterfaceContracts": "Authorizable,IAuthorizable,IOwnable,LibAddress,LibAddressArray,LibAddressArrayRichErrors,LibAuthorizableRichErrors,LibBytes,LibBytesRichErrors,LibEIP1271,LibEIP712,LibFractions,LibOwnableRichErrors,LibReentrancyGuardRichErrors,LibRichErrors,LibSafeMath,LibSafeMathRichErrors,Ownable,ReentrancyGuard,Refundable",
 | 
				
			||||||
        "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
 | 
					        "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
 | 
				
			||||||
        "abis": "./test/generated-artifacts/@(Authorizable|IAuthorizable|IOwnable|LibAddress|LibAddressArray|LibAddressArrayRichErrors|LibAuthorizableRichErrors|LibBytes|LibBytesRichErrors|LibEIP1271|LibEIP712|LibFractions|LibOwnableRichErrors|LibReentrancyGuardRichErrors|LibRichErrors|LibSafeMath|LibSafeMathRichErrors|Ownable|ReentrancyGuard|Refundable|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibRichErrors|TestLibSafeMath|TestLogDecoding|TestLogDecodingDownstream|TestOwnable|TestReentrancyGuard|TestRefundable|TestRefundableReceiver).json"
 | 
					        "abis": "./test/generated-artifacts/@(Authorizable|DeploymentConstants|IAuthorizable|IOwnable|LibAddress|LibAddressArray|LibAddressArrayRichErrors|LibAuthorizableRichErrors|LibBytes|LibBytesRichErrors|LibEIP1271|LibEIP712|LibFractions|LibOwnableRichErrors|LibReentrancyGuardRichErrors|LibRichErrors|LibSafeMath|LibSafeMathRichErrors|Ownable|ReentrancyGuard|Refundable|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibRichErrors|TestLibSafeMath|TestLogDecoding|TestLogDecodingDownstream|TestOwnable|TestReentrancyGuard|TestRefundable|TestRefundableReceiver).json"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "repository": {
 | 
					    "repository": {
 | 
				
			||||||
        "type": "git",
 | 
					        "type": "git",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@
 | 
				
			|||||||
import { ContractArtifact } from 'ethereum-types';
 | 
					import { ContractArtifact } from 'ethereum-types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import * as Authorizable from '../test/generated-artifacts/Authorizable.json';
 | 
					import * as Authorizable from '../test/generated-artifacts/Authorizable.json';
 | 
				
			||||||
 | 
					import * as DeploymentConstants from '../test/generated-artifacts/DeploymentConstants.json';
 | 
				
			||||||
import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json';
 | 
					import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json';
 | 
				
			||||||
import * as IOwnable from '../test/generated-artifacts/IOwnable.json';
 | 
					import * as IOwnable from '../test/generated-artifacts/IOwnable.json';
 | 
				
			||||||
import * as LibAddress from '../test/generated-artifacts/LibAddress.json';
 | 
					import * as LibAddress from '../test/generated-artifacts/LibAddress.json';
 | 
				
			||||||
@@ -39,6 +40,7 @@ import * as TestRefundable from '../test/generated-artifacts/TestRefundable.json
 | 
				
			|||||||
import * as TestRefundableReceiver from '../test/generated-artifacts/TestRefundableReceiver.json';
 | 
					import * as TestRefundableReceiver from '../test/generated-artifacts/TestRefundableReceiver.json';
 | 
				
			||||||
export const artifacts = {
 | 
					export const artifacts = {
 | 
				
			||||||
    Authorizable: Authorizable as ContractArtifact,
 | 
					    Authorizable: Authorizable as ContractArtifact,
 | 
				
			||||||
 | 
					    DeploymentConstants: DeploymentConstants as ContractArtifact,
 | 
				
			||||||
    LibAddress: LibAddress as ContractArtifact,
 | 
					    LibAddress: LibAddress as ContractArtifact,
 | 
				
			||||||
    LibAddressArray: LibAddressArray as ContractArtifact,
 | 
					    LibAddressArray: LibAddressArray as ContractArtifact,
 | 
				
			||||||
    LibAddressArrayRichErrors: LibAddressArrayRichErrors as ContractArtifact,
 | 
					    LibAddressArrayRichErrors: LibAddressArrayRichErrors as ContractArtifact,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@
 | 
				
			|||||||
 * -----------------------------------------------------------------------------
 | 
					 * -----------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export * from '../test/generated-wrappers/authorizable';
 | 
					export * from '../test/generated-wrappers/authorizable';
 | 
				
			||||||
 | 
					export * from '../test/generated-wrappers/deployment_constants';
 | 
				
			||||||
export * from '../test/generated-wrappers/i_authorizable';
 | 
					export * from '../test/generated-wrappers/i_authorizable';
 | 
				
			||||||
export * from '../test/generated-wrappers/i_ownable';
 | 
					export * from '../test/generated-wrappers/i_ownable';
 | 
				
			||||||
export * from '../test/generated-wrappers/lib_address';
 | 
					export * from '../test/generated-wrappers/lib_address';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@
 | 
				
			|||||||
        "generated-artifacts/ReentrancyGuard.json",
 | 
					        "generated-artifacts/ReentrancyGuard.json",
 | 
				
			||||||
        "generated-artifacts/Refundable.json",
 | 
					        "generated-artifacts/Refundable.json",
 | 
				
			||||||
        "test/generated-artifacts/Authorizable.json",
 | 
					        "test/generated-artifacts/Authorizable.json",
 | 
				
			||||||
 | 
					        "test/generated-artifacts/DeploymentConstants.json",
 | 
				
			||||||
        "test/generated-artifacts/IAuthorizable.json",
 | 
					        "test/generated-artifacts/IAuthorizable.json",
 | 
				
			||||||
        "test/generated-artifacts/IOwnable.json",
 | 
					        "test/generated-artifacts/IOwnable.json",
 | 
				
			||||||
        "test/generated-artifacts/LibAddress.json",
 | 
					        "test/generated-artifacts/LibAddress.json",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user