diff --git a/contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol b/contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol new file mode 100644 index 0000000000..93ff9f9ec8 --- /dev/null +++ b/contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol @@ -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; +pragma experimental ABIEncoderV2; + +import "../interfaces/IERC20Bridge.sol"; +import "../interfaces/IChai.sol"; +import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; +import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; + + +// solhint-disable space-after-comma +contract ChaiBridge is + IERC20Bridge, + DeploymentConstants +{ + /// @dev Withdraws `amount` of `from` address's Dai from the Chai contract. + /// Transfers `amount` of Dai to `to` address. + /// @param from Address to transfer asset from. + /// @param to Address to transfer asset to. + /// @param amount Amount of asset to transfer. + /// @return success The magic bytes `0x37708e9b` if successful. + function bridgeTransferFrom( + address /* tokenAddress */, + address from, + address to, + uint256 amount, + bytes calldata /* bridgeData */ + ) + external + returns (bytes4 success) + { + // Ensure that only the `ERC20BridgeProxy` can call this function. + require( + msg.sender == _getERC20BridgeProxyAddress(), + "ChaiBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY" + ); + + // Withdraw `from` address's Dai. + // NOTE: This contract must be approved to spend Chai on behalf of `from`. + bytes memory drawCalldata = abi.encodeWithSelector( + IChai(address(0)).draw.selector, + from, + amount + ); + + (bool success,) = _getChaiAddress().call(drawCalldata); + require( + success, + "ChaiBridge/DRAW_DAI_FAILED" + ); + + // Transfer Dai to `to` + // This will never fail if the `draw` call was successful + IERC20Token(_getDaiAddress()).transfer(to, amount); + + return BRIDGE_SUCCESS; + } +} diff --git a/contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol b/contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol index f08b83b4b3..b3b84d8d96 100644 --- a/contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol +++ b/contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol @@ -55,7 +55,7 @@ contract Eth2DaiBridge is // Decode the bridge data to get the `fromTokenAddress`. (address fromTokenAddress) = abi.decode(bridgeData, (address)); - IEth2Dai exchange = _getEth2DaiContract(); + IEth2Dai exchange = IEth2Dai(_getEth2DaiAddress()); // Grant an allowance to the exchange to spend `fromTokenAddress` token. LibERC20Token.approve(fromTokenAddress, address(exchange), uint256(-1)); @@ -84,14 +84,4 @@ contract Eth2DaiBridge is { return LEGACY_WALLET_MAGIC_VALUE; } - - /// @dev Overridable way to get the eth2dai contract. - /// @return exchange The Eth2Dai exchange contract. - function _getEth2DaiContract() - internal - view - returns (IEth2Dai exchange) - { - return IEth2Dai(_getEth2DaiAddress()); - } } diff --git a/contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol b/contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol index 818f80e697..f1b6d8263c 100644 --- a/contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol +++ b/contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol @@ -77,8 +77,8 @@ contract KyberBridge is returns (bytes4 success) { TradeState memory state; - state.kyber = _getKyberContract(); - state.weth = _getWETHContract(); + state.kyber = IKyberNetworkProxy(_getKyberNetworkProxyAddress()); + state.weth = IEtherToken(_getWethAddress()); // Decode the bridge data to get the `fromTokenAddress`. (state.fromTokenAddress) = abi.decode(bridgeData, (address)); state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this)); @@ -143,24 +143,4 @@ contract KyberBridge is { 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()); - } } diff --git a/contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol b/contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol index 23fb69c47c..872d858333 100644 --- a/contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol +++ b/contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol @@ -88,7 +88,7 @@ contract UniswapBridge is // Get our balance of `fromTokenAddress` token. state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this)); // Get the weth contract. - state.weth = getWethContract(); + state.weth = IEtherToken(_getWethAddress()); // Convert from WETH to a token. if (fromTokenAddress == address(state.weth)) { @@ -161,26 +161,6 @@ contract UniswapBridge is return LEGACY_WALLET_MAGIC_VALUE; } - /// @dev Overridable way to get the weth contract. - /// @return token The WETH contract. - function getWethContract() - public - view - returns (IEtherToken token) - { - return IEtherToken(_getWETHAddress()); - } - - /// @dev Overridable way to get the uniswap exchange factory contract. - /// @return factory The exchange factory contract. - function getUniswapExchangeFactoryContract() - public - view - returns (IUniswapExchangeFactory factory) - { - return IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress()); - } - /// @dev Grants an unlimited allowance to the exchange for its token /// on behalf of this contract. /// @param exchange The Uniswap token exchange. @@ -207,11 +187,12 @@ contract UniswapBridge is { address exchangeTokenAddress = fromTokenAddress; // Whichever isn't WETH is the exchange token. - if (fromTokenAddress == address(getWethContract())) { + if (fromTokenAddress == _getWethAddress()) { exchangeTokenAddress = toTokenAddress; } exchange = IUniswapExchange( - getUniswapExchangeFactoryContract().getExchange(exchangeTokenAddress) + IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress()) + .getExchange(exchangeTokenAddress) ); require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN"); return exchange; diff --git a/contracts/asset-proxy/contracts/src/interfaces/IChai.sol b/contracts/asset-proxy/contracts/src/interfaces/IChai.sol new file mode 100644 index 0000000000..2074eece31 --- /dev/null +++ b/contracts/asset-proxy/contracts/src/interfaces/IChai.sol @@ -0,0 +1,33 @@ +/* + + 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; + + +// The actual Chai contract can be found here: https://github.com/dapphub/chai +contract IChai { + + /// @dev Withdraws Dai owned by `src` + /// @param src Address that owns Dai. + /// @param wad Amount of Dai to withdraw. + function draw( + address src, + uint256 wad + ) + external; +} diff --git a/contracts/asset-proxy/contracts/test/TestChaiBridge.sol b/contracts/asset-proxy/contracts/test/TestChaiBridge.sol new file mode 100644 index 0000000000..3b2dc7f1bf --- /dev/null +++ b/contracts/asset-proxy/contracts/test/TestChaiBridge.sol @@ -0,0 +1,80 @@ +/* + + 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 "../src/bridges/ChaiBridge.sol"; +import "@0x/contracts-erc20/contracts/src/ERC20Token.sol"; + + +contract TestChaiDai is + ERC20Token +{ + address private constant ALWAYS_REVERT_ADDRESS = address(1); + + function draw( + address from, + uint256 amount + ) + external + { + if (from == ALWAYS_REVERT_ADDRESS) { + revert(); + } + balances[msg.sender] += amount; + } +} + + +contract TestChaiBridge is + ChaiBridge +{ + address public testChaiDai; + address private constant ALWAYS_REVERT_ADDRESS = address(1); + + constructor() + public + { + testChaiDai = address(new TestChaiDai()); + } + + function _getDaiAddress() + internal + view + returns (address) + { + return testChaiDai; + } + + function _getChaiAddress() + internal + view + returns (address) + { + return testChaiDai; + } + + function _getERC20BridgeProxyAddress() + internal + view + returns (address) + { + return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender; + } +} diff --git a/contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol b/contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol index 2f1b07703e..859af2c1af 100644 --- a/contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol +++ b/contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol @@ -192,11 +192,11 @@ contract TestEth2DaiBridge is } // @dev This contract will double as the Eth2Dai contract. - function _getEth2DaiContract() + function _getEth2DaiAddress() internal view - returns (IEth2Dai) + returns (address) { - return IEth2Dai(address(this)); + return address(this); } } diff --git a/contracts/asset-proxy/contracts/test/TestKyberBridge.sol b/contracts/asset-proxy/contracts/test/TestKyberBridge.sol index 81ff12b885..9a54bc16b8 100644 --- a/contracts/asset-proxy/contracts/test/TestKyberBridge.sol +++ b/contracts/asset-proxy/contracts/test/TestKyberBridge.sol @@ -303,20 +303,20 @@ contract TestKyberBridge is } // @dev overridden to point to this contract. - function _getKyberContract() + function _getKyberNetworkProxyAddress() internal view - returns (IKyberNetworkProxy kyber) + returns (address) { - return IKyberNetworkProxy(address(this)); + return address(this); } // @dev overridden to point to test WETH. - function _getWETHContract() + function _getWethAddress() internal view - returns (IEtherToken weth_) + returns (address) { - return weth; + return address(weth); } } diff --git a/contracts/asset-proxy/contracts/test/TestUniswapBridge.sol b/contracts/asset-proxy/contracts/test/TestUniswapBridge.sol index db3a14a254..f295a939f7 100644 --- a/contracts/asset-proxy/contracts/test/TestUniswapBridge.sol +++ b/contracts/asset-proxy/contracts/test/TestUniswapBridge.sol @@ -413,20 +413,20 @@ contract TestUniswapBridge is } // @dev Use `wethToken`. - function getWethContract() - public + function _getWethAddress() + internal view - returns (IEtherToken) + returns (address) { - return IEtherToken(address(wethToken)); + return address(wethToken); } // @dev This contract will double as the Uniswap contract. - function getUniswapExchangeFactoryContract() - public + function _getUniswapExchangeFactoryAddress() + internal view - returns (IUniswapExchangeFactory) + returns (address) { - return IUniswapExchangeFactory(address(this)); + return address(this); } } diff --git a/contracts/asset-proxy/package.json b/contracts/asset-proxy/package.json index f23ffa2673..9b5a0eed76 100644 --- a/contracts/asset-proxy/package.json +++ b/contracts/asset-proxy/package.json @@ -38,8 +38,8 @@ "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" }, "config": { - "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|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json", + "publicInterfaceContracts": "ERC1155Proxy,ERC20Proxy,ERC721Proxy,MultiAssetProxy,StaticCallProxy,ERC20BridgeProxy,Eth2DaiBridge,IAssetData,IAssetProxy,UniswapBridge,KyberBridge,ChaiBridge,TestStaticCallTarget", + "abis": "./test/generated-artifacts/@(ChaiBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." }, "repository": { diff --git a/contracts/asset-proxy/src/artifacts.ts b/contracts/asset-proxy/src/artifacts.ts index 14ed1ee378..a9559e4bba 100644 --- a/contracts/asset-proxy/src/artifacts.ts +++ b/contracts/asset-proxy/src/artifacts.ts @@ -5,6 +5,7 @@ */ import { ContractArtifact } from 'ethereum-types'; +import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json'; import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json'; import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json'; import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json'; @@ -29,5 +30,6 @@ export const artifacts = { IAssetProxy: IAssetProxy as ContractArtifact, UniswapBridge: UniswapBridge as ContractArtifact, KyberBridge: KyberBridge as ContractArtifact, + ChaiBridge: ChaiBridge as ContractArtifact, TestStaticCallTarget: TestStaticCallTarget as ContractArtifact, }; diff --git a/contracts/asset-proxy/src/wrappers.ts b/contracts/asset-proxy/src/wrappers.ts index 7b01c84334..b335aa2f5b 100644 --- a/contracts/asset-proxy/src/wrappers.ts +++ b/contracts/asset-proxy/src/wrappers.ts @@ -3,6 +3,7 @@ * Warning: This file is auto-generated by contracts-gen. Don't edit manually. * ----------------------------------------------------------------------------- */ +export * from '../generated-wrappers/chai_bridge'; export * from '../generated-wrappers/erc1155_proxy'; export * from '../generated-wrappers/erc20_bridge_proxy'; export * from '../generated-wrappers/erc20_proxy'; diff --git a/contracts/asset-proxy/test/artifacts.ts b/contracts/asset-proxy/test/artifacts.ts index 54d46b2ee1..1e9b719310 100644 --- a/contracts/asset-proxy/test/artifacts.ts +++ b/contracts/asset-proxy/test/artifacts.ts @@ -5,6 +5,7 @@ */ import { ContractArtifact } from 'ethereum-types'; +import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json'; import * as ERC1155Proxy from '../test/generated-artifacts/ERC1155Proxy.json'; import * as ERC20BridgeProxy from '../test/generated-artifacts/ERC20BridgeProxy.json'; import * as ERC20Proxy from '../test/generated-artifacts/ERC20Proxy.json'; @@ -14,6 +15,7 @@ import * as IAssetData from '../test/generated-artifacts/IAssetData.json'; import * as IAssetProxy from '../test/generated-artifacts/IAssetProxy.json'; import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyDispatcher.json'; import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json'; +import * as IChai from '../test/generated-artifacts/IChai.json'; import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json'; import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json'; import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json'; @@ -25,6 +27,7 @@ import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizabl import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json'; import * as Ownable from '../test/generated-artifacts/Ownable.json'; import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json'; +import * as TestChaiBridge from '../test/generated-artifacts/TestChaiBridge.json'; import * as TestERC20Bridge from '../test/generated-artifacts/TestERC20Bridge.json'; import * as TestEth2DaiBridge from '../test/generated-artifacts/TestEth2DaiBridge.json'; import * as TestKyberBridge from '../test/generated-artifacts/TestKyberBridge.json'; @@ -41,6 +44,7 @@ export const artifacts = { ERC721Proxy: ERC721Proxy as ContractArtifact, MultiAssetProxy: MultiAssetProxy as ContractArtifact, StaticCallProxy: StaticCallProxy as ContractArtifact, + ChaiBridge: ChaiBridge as ContractArtifact, Eth2DaiBridge: Eth2DaiBridge as ContractArtifact, KyberBridge: KyberBridge as ContractArtifact, UniswapBridge: UniswapBridge as ContractArtifact, @@ -48,11 +52,13 @@ export const artifacts = { IAssetProxy: IAssetProxy as ContractArtifact, IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, IAuthorizable: IAuthorizable as ContractArtifact, + IChai: IChai as ContractArtifact, IERC20Bridge: IERC20Bridge as ContractArtifact, IEth2Dai: IEth2Dai as ContractArtifact, IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact, IUniswapExchange: IUniswapExchange as ContractArtifact, IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact, + TestChaiBridge: TestChaiBridge as ContractArtifact, TestERC20Bridge: TestERC20Bridge as ContractArtifact, TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact, TestKyberBridge: TestKyberBridge as ContractArtifact, diff --git a/contracts/asset-proxy/test/chai_bridge.ts b/contracts/asset-proxy/test/chai_bridge.ts new file mode 100644 index 0000000000..9bed1f9864 --- /dev/null +++ b/contracts/asset-proxy/test/chai_bridge.ts @@ -0,0 +1,60 @@ +import { ERC20TokenContract } from '@0x/contracts-erc20'; +import { blockchainTests, constants, expect, randomAddress } from '@0x/contracts-test-utils'; +import { AssetProxyId, RevertReason } from '@0x/types'; +import { BigNumber } from '@0x/utils'; + +import { artifacts } from './artifacts'; +import { TestChaiBridgeContract } from './wrappers'; + +blockchainTests.resets('ChaiBridge unit tests', env => { + let chaiBridgeContract: TestChaiBridgeContract; + let testDaiContract: ERC20TokenContract; + let fromAddress: string; + let toAddress: string; + + const alwaysRevertAddress = '0x0000000000000000000000000000000000000001'; + const amount = new BigNumber(1); + + before(async () => { + [fromAddress, toAddress] = await env.getAccountAddressesAsync(); + chaiBridgeContract = await TestChaiBridgeContract.deployFrom0xArtifactAsync( + artifacts.TestChaiBridge, + env.provider, + env.txDefaults, + artifacts, + ); + const testChaiDaiAddress = await chaiBridgeContract.testChaiDai().callAsync(); + testDaiContract = new ERC20TokenContract(testChaiDaiAddress, env.provider, env.txDefaults); + }); + + describe('bridgeTransferFrom()', () => { + it('fails if not called by ERC20BridgeProxy', async () => { + return expect( + chaiBridgeContract + .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES) + .awaitTransactionSuccessAsync({ from: alwaysRevertAddress }), + ).to.revertWith(RevertReason.ChaiBridgeOnlyCallableByErc20BridgeProxy); + }); + it('returns magic bytes upon success', async () => { + const magicBytes = await chaiBridgeContract + .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES) + .callAsync(); + expect(magicBytes).to.eq(AssetProxyId.ERC20Bridge); + }); + it('should increase the Dai balance of `toAddress` by `amount` if successful', async () => { + const initialBalance = await testDaiContract.balanceOf(toAddress).callAsync(); + await chaiBridgeContract + .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES) + .awaitTransactionSuccessAsync(); + const endBalance = await testDaiContract.balanceOf(toAddress).callAsync(); + expect(endBalance).to.bignumber.eq(initialBalance.plus(amount)); + }); + it('fails if the `chai.draw` call fails', async () => { + return expect( + chaiBridgeContract + .bridgeTransferFrom(randomAddress(), alwaysRevertAddress, toAddress, amount, constants.NULL_BYTES) + .awaitTransactionSuccessAsync(), + ).to.revertWith(RevertReason.ChaiBridgeDrawDaiFailed); + }); + }); +}); diff --git a/contracts/asset-proxy/test/wrappers.ts b/contracts/asset-proxy/test/wrappers.ts index 3ae5cf51d8..18085e0d6d 100644 --- a/contracts/asset-proxy/test/wrappers.ts +++ b/contracts/asset-proxy/test/wrappers.ts @@ -3,6 +3,7 @@ * Warning: This file is auto-generated by contracts-gen. Don't edit manually. * ----------------------------------------------------------------------------- */ +export * from '../test/generated-wrappers/chai_bridge'; export * from '../test/generated-wrappers/erc1155_proxy'; export * from '../test/generated-wrappers/erc20_bridge_proxy'; export * from '../test/generated-wrappers/erc20_proxy'; @@ -12,6 +13,7 @@ export * from '../test/generated-wrappers/i_asset_data'; export * from '../test/generated-wrappers/i_asset_proxy'; export * from '../test/generated-wrappers/i_asset_proxy_dispatcher'; export * from '../test/generated-wrappers/i_authorizable'; +export * from '../test/generated-wrappers/i_chai'; export * from '../test/generated-wrappers/i_erc20_bridge'; export * from '../test/generated-wrappers/i_eth2_dai'; export * from '../test/generated-wrappers/i_kyber_network_proxy'; @@ -23,6 +25,7 @@ export * from '../test/generated-wrappers/mixin_authorizable'; export * from '../test/generated-wrappers/multi_asset_proxy'; export * from '../test/generated-wrappers/ownable'; export * from '../test/generated-wrappers/static_call_proxy'; +export * from '../test/generated-wrappers/test_chai_bridge'; export * from '../test/generated-wrappers/test_erc20_bridge'; export * from '../test/generated-wrappers/test_eth2_dai_bridge'; export * from '../test/generated-wrappers/test_kyber_bridge'; diff --git a/contracts/asset-proxy/tsconfig.json b/contracts/asset-proxy/tsconfig.json index d75379ddcf..b7dfad1922 100644 --- a/contracts/asset-proxy/tsconfig.json +++ b/contracts/asset-proxy/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], "files": [ + "generated-artifacts/ChaiBridge.json", "generated-artifacts/ERC1155Proxy.json", "generated-artifacts/ERC20BridgeProxy.json", "generated-artifacts/ERC20Proxy.json", @@ -15,6 +16,7 @@ "generated-artifacts/StaticCallProxy.json", "generated-artifacts/TestStaticCallTarget.json", "generated-artifacts/UniswapBridge.json", + "test/generated-artifacts/ChaiBridge.json", "test/generated-artifacts/ERC1155Proxy.json", "test/generated-artifacts/ERC20BridgeProxy.json", "test/generated-artifacts/ERC20Proxy.json", @@ -24,6 +26,7 @@ "test/generated-artifacts/IAssetProxy.json", "test/generated-artifacts/IAssetProxyDispatcher.json", "test/generated-artifacts/IAuthorizable.json", + "test/generated-artifacts/IChai.json", "test/generated-artifacts/IERC20Bridge.json", "test/generated-artifacts/IEth2Dai.json", "test/generated-artifacts/IKyberNetworkProxy.json", @@ -35,6 +38,7 @@ "test/generated-artifacts/MultiAssetProxy.json", "test/generated-artifacts/Ownable.json", "test/generated-artifacts/StaticCallProxy.json", + "test/generated-artifacts/TestChaiBridge.json", "test/generated-artifacts/TestERC20Bridge.json", "test/generated-artifacts/TestEth2DaiBridge.json", "test/generated-artifacts/TestKyberBridge.json", diff --git a/contracts/integrations/contracts/test/TestEth2DaiBridge.sol b/contracts/integrations/contracts/test/TestEth2DaiBridge.sol index 4029e9f110..80c0536762 100644 --- a/contracts/integrations/contracts/test/TestEth2DaiBridge.sol +++ b/contracts/integrations/contracts/test/TestEth2DaiBridge.sol @@ -20,7 +20,6 @@ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol"; -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IEth2Dai.sol"; contract TestEth2DaiBridge is @@ -35,11 +34,11 @@ contract TestEth2DaiBridge is TEST_ETH2DAI_ADDRESS = testEth2Dai; } - function _getEth2DaiContract() + function _getEth2DaiAddress() internal view - returns (IEth2Dai exchange) + returns (address exchange) { - return IEth2Dai(TEST_ETH2DAI_ADDRESS); + return TEST_ETH2DAI_ADDRESS; } } diff --git a/contracts/integrations/contracts/test/TestUniswapBridge.sol b/contracts/integrations/contracts/test/TestUniswapBridge.sol index 1154218d78..0686a2e6f8 100644 --- a/contracts/integrations/contracts/test/TestUniswapBridge.sol +++ b/contracts/integrations/contracts/test/TestUniswapBridge.sol @@ -20,8 +20,6 @@ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-asset-proxy/contracts/src/bridges/UniswapBridge.sol"; -import "@0x/contracts-asset-proxy/contracts/src/interfaces/IUniswapExchangeFactory.sol"; -import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; contract TestUniswapBridge is @@ -41,19 +39,19 @@ contract TestUniswapBridge is TEST_UNISWAP_EXCHANGE_FACTORY_ADDRESS = testUniswapExchangeFactory; } - function getWethContract() - public + function _getWethAddress() + internal view - returns (IEtherToken token) + returns (address token) { - return IEtherToken(TEST_WETH_ADDRESS); + return TEST_WETH_ADDRESS; } - function getUniswapExchangeFactoryContract() - public + function _getUniswapExchangeFactoryAddress() + internal view - returns (IUniswapExchangeFactory factory) + returns (address factory) { - return IUniswapExchangeFactory(TEST_UNISWAP_EXCHANGE_FACTORY_ADDRESS); + return TEST_UNISWAP_EXCHANGE_FACTORY_ADDRESS; } } diff --git a/contracts/utils/contracts/src/DeploymentConstants.sol b/contracts/utils/contracts/src/DeploymentConstants.sol index d218b80eae..ba7bdc8caf 100644 --- a/contracts/utils/contracts/src/DeploymentConstants.sol +++ b/contracts/utils/contracts/src/DeploymentConstants.sol @@ -32,6 +32,12 @@ contract DeploymentConstants { address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95; /// @dev Mainnet address of the Eth2Dai `MatchingMarket` contract. address constant private ETH2DAI_ADDRESS = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e; + /// @dev Mainnet address of the `ERC20BridgeProxy` contract + address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0x8ED95d1746bf1E4dAb58d8ED4724f1Ef95B20Db0; + ///@dev Mainnet address of the `Dai` (multi-collateral) contract + address constant private DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F; + /// @dev Mainnet address of the `Chai` contract + address constant private CHAI_ADDRESS = 0x06AF07097C9Eeb7fD685c692751D5C66dB49c215; /// @dev Overridable way to get the `KyberNetworkProxy` address. /// @return kyberAddress The `IKyberNetworkProxy` address. @@ -45,7 +51,7 @@ contract DeploymentConstants { /// @dev Overridable way to get the WETH address. /// @return wethAddress The WETH address. - function _getWETHAddress() + function _getWethAddress() internal view returns (address wethAddress) @@ -72,4 +78,34 @@ contract DeploymentConstants { { return ETH2DAI_ADDRESS; } + + /// @dev An overridable way to retrieve the `ERC20BridgeProxy` contract. + /// @return erc20BridgeProxyAddress The `ERC20BridgeProxy` contract. + function _getERC20BridgeProxyAddress() + internal + view + returns (address erc20BridgeProxyAddress) + { + return ERC20_BRIDGE_PROXY_ADDRESS; + } + + /// @dev An overridable way to retrieve the `Dai` contract. + /// @return daiAddress The `Dai` contract. + function _getDaiAddress() + internal + view + returns (address daiAddress) + { + return DAI_ADDRESS; + } + + /// @dev An overridable way to retrieve the `Chai` contract. + /// @return chaiAddress The `Chai` contract. + function _getChaiAddress() + internal + view + returns (address chaiAddress) + { + return CHAI_ADDRESS; + } } diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 82dbc94c78..f0cc329b16 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -350,6 +350,8 @@ export enum RevertReason { CustomTimeLockIncomplete = 'CUSTOM_TIME_LOCK_INCOMPLETE', EqualLengthsRequired = 'EQUAL_LENGTHS_REQUIRED', OnlyCallableByWallet = 'ONLY_CALLABLE_BY_WALLET', + ChaiBridgeOnlyCallableByErc20BridgeProxy = 'ChaiBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY', + ChaiBridgeDrawDaiFailed = 'ChaiBridge/DRAW_DAI_FAILED', } export enum StatusCodes {