Bancor FQT rollup (#91)
* Add MixinBancor for BridgeAdapter * Update changelog * Use 0.6 call value syntax * `@0x/contract-addresses`: Deploy new FQT * feat: Rollup CoFiX (#92) * `@0x/contract-addreses`: update FQT addresses Co-authored-by: Lawrence Forman <me@merklejerk.com> Co-authored-by: Jacob Evans <jacob@dekz.net>
This commit is contained in:
@@ -21,6 +21,8 @@ pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./mixins/MixinAdapterAddresses.sol";
|
||||
import "./mixins/MixinBalancer.sol";
|
||||
import "./mixins/MixinBancor.sol";
|
||||
import "./mixins/MixinCoFiX.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinCryptoCom.sol";
|
||||
import "./mixins/MixinDodo.sol";
|
||||
@@ -37,6 +39,8 @@ import "./mixins/MixinZeroExBridge.sol";
|
||||
contract BridgeAdapter is
|
||||
MixinAdapterAddresses,
|
||||
MixinBalancer,
|
||||
MixinBancor,
|
||||
MixinCoFiX,
|
||||
MixinCurve,
|
||||
MixinCryptoCom,
|
||||
MixinDodo,
|
||||
@@ -51,7 +55,25 @@ contract BridgeAdapter is
|
||||
MixinZeroExBridge
|
||||
{
|
||||
|
||||
/// @dev Emitted when a trade occurs.
|
||||
/// @param inputToken The token the bridge is converting from.
|
||||
/// @param outputToken The token the bridge is converting to.
|
||||
/// @param inputTokenAmount Amount of input token.
|
||||
/// @param outputTokenAmount Amount of output token.
|
||||
/// @param from The bridge address, indicating the underlying source of the fill.
|
||||
/// @param to The `to` address, currrently `address(this)`
|
||||
event ERC20BridgeTransfer(
|
||||
IERC20TokenV06 inputToken,
|
||||
IERC20TokenV06 outputToken,
|
||||
uint256 inputTokenAmount,
|
||||
uint256 outputTokenAmount,
|
||||
address from,
|
||||
address to
|
||||
);
|
||||
|
||||
address private immutable BALANCER_BRIDGE_ADDRESS;
|
||||
address private immutable BANCOR_BRIDGE_ADDRESS;
|
||||
address private immutable COFIX_BRIDGE_ADDRESS;
|
||||
address private immutable CREAM_BRIDGE_ADDRESS;
|
||||
address private immutable CURVE_BRIDGE_ADDRESS;
|
||||
address private immutable CRYPTO_COM_BRIDGE_ADDRESS;
|
||||
@@ -70,6 +92,8 @@ contract BridgeAdapter is
|
||||
constructor(AdapterAddresses memory addresses)
|
||||
public
|
||||
MixinBalancer()
|
||||
MixinBancor(addresses)
|
||||
MixinCoFiX()
|
||||
MixinCurve()
|
||||
MixinCryptoCom(addresses)
|
||||
MixinDodo(addresses)
|
||||
@@ -84,6 +108,8 @@ contract BridgeAdapter is
|
||||
MixinZeroExBridge()
|
||||
{
|
||||
BALANCER_BRIDGE_ADDRESS = addresses.balancerBridge;
|
||||
BANCOR_BRIDGE_ADDRESS = addresses.bancorBridge;
|
||||
COFIX_BRIDGE_ADDRESS = addresses.cofixBridge;
|
||||
CURVE_BRIDGE_ADDRESS = addresses.curveBridge;
|
||||
CRYPTO_COM_BRIDGE_ADDRESS = addresses.cryptoComBridge;
|
||||
KYBER_BRIDGE_ADDRESS = addresses.kyberBridge;
|
||||
@@ -196,6 +222,18 @@ contract BridgeAdapter is
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
} else if (bridgeAddress == BANCOR_BRIDGE_ADDRESS) {
|
||||
boughtAmount = _tradeBancor(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
} else if (bridgeAddress == COFIX_BRIDGE_ADDRESS) {
|
||||
boughtAmount = _tradeCoFiX(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
} else {
|
||||
boughtAmount = _tradeZeroExBridge(
|
||||
bridgeAddress,
|
||||
@@ -204,9 +242,6 @@ contract BridgeAdapter is
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
// Old bridge contracts should emit an `ERC20BridgeTransfer` themselves,
|
||||
// otherwise an event will be emitted from `_tradeZeroExBridge`.
|
||||
return boughtAmount;
|
||||
}
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
|
@@ -24,6 +24,8 @@ contract MixinAdapterAddresses
|
||||
struct AdapterAddresses {
|
||||
// Bridges
|
||||
address balancerBridge;
|
||||
address bancorBridge;
|
||||
address cofixBridge;
|
||||
address creamBridge;
|
||||
address curveBridge;
|
||||
address cryptoComBridge;
|
||||
|
@@ -0,0 +1,111 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2020 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.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
import "./MixinAdapterAddresses.sol";
|
||||
|
||||
|
||||
interface IBancorNetwork {
|
||||
function convertByPath(
|
||||
address[] calldata _path,
|
||||
uint256 _amount,
|
||||
uint256 _minReturn,
|
||||
address _beneficiary,
|
||||
address _affiliateAccount,
|
||||
uint256 _affiliateFee
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (uint256);
|
||||
}
|
||||
|
||||
|
||||
contract MixinBancor is
|
||||
MixinAdapterAddresses
|
||||
{
|
||||
/// @dev Bancor ETH pseudo-address.
|
||||
address constant public BANCOR_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
IEtherTokenV06 private immutable WETH;
|
||||
|
||||
constructor(AdapterAddresses memory addresses)
|
||||
public
|
||||
{
|
||||
WETH = IEtherTokenV06(addresses.weth);
|
||||
}
|
||||
|
||||
function _tradeBancor(
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Decode the bridge data.
|
||||
(
|
||||
address[] memory path,
|
||||
address bancorNetworkAddress
|
||||
// solhint-disable indent
|
||||
) = abi.decode(bridgeData, (address[], address));
|
||||
// solhint-enable indent
|
||||
|
||||
require(path.length >= 2, "MixinBancor/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
|
||||
require(
|
||||
path[path.length - 1] == address(buyToken) ||
|
||||
(path[path.length - 1] == BANCOR_ETH_ADDRESS && address(buyToken) == address(WETH)),
|
||||
"MixinBancor/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
|
||||
);
|
||||
|
||||
uint256 payableAmount = 0;
|
||||
// If it's ETH in the path then withdraw from WETH
|
||||
// The Bancor path will have ETH as the 0xeee address
|
||||
// Bancor expects to be paid in ETH not WETH
|
||||
if (path[0] == BANCOR_ETH_ADDRESS) {
|
||||
WETH.withdraw(sellAmount);
|
||||
payableAmount = sellAmount;
|
||||
} else {
|
||||
// Grant an allowance to the Bancor Network.
|
||||
LibERC20TokenV06.approveIfBelow(
|
||||
IERC20TokenV06(path[0]),
|
||||
bancorNetworkAddress,
|
||||
sellAmount
|
||||
);
|
||||
}
|
||||
|
||||
// Convert the tokens
|
||||
boughtAmount = IBancorNetwork(bancorNetworkAddress).convertByPath{value: payableAmount}(
|
||||
path, // path originating with source token and terminating in destination token
|
||||
sellAmount, // amount of source token to trade
|
||||
1, // minimum amount of destination token expected to receive
|
||||
address(this), // beneficiary
|
||||
address(0), // affiliateAccount; no fee paid
|
||||
0 // affiliateFee; no fee paid
|
||||
);
|
||||
if (path[path.length - 1] == BANCOR_ETH_ADDRESS) {
|
||||
WETH.deposit{value: boughtAmount}();
|
||||
}
|
||||
|
||||
return boughtAmount;
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 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.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
import "./MixinAdapterAddresses.sol";
|
||||
|
||||
|
||||
interface ICoFiXRouter {
|
||||
// msg.value = fee
|
||||
function swapExactTokensForETH(
|
||||
address token,
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address to,
|
||||
address rewardTo,
|
||||
uint deadline
|
||||
) external payable returns (uint _amountIn, uint _amountOut);
|
||||
|
||||
// msg.value = amountIn + fee
|
||||
function swapExactETHForTokens(
|
||||
address token,
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address to,
|
||||
address rewardTo,
|
||||
uint deadline
|
||||
) external payable returns (uint _amountIn, uint _amountOut);
|
||||
}
|
||||
|
||||
interface ICoFiXPair {
|
||||
|
||||
function swapWithExact(address outToken, address to)
|
||||
external
|
||||
payable
|
||||
returns (uint amountIn, uint amountOut, uint oracleFeeChange, uint256[4] memory tradeInfo);
|
||||
}
|
||||
|
||||
contract MixinCoFiX is
|
||||
MixinAdapterAddresses
|
||||
{
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
function _tradeCoFiX(
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
(address fromTokenAddress, uint256 fee, address pool) = abi.decode(bridgeData, (address, uint256, address));
|
||||
// Transfer tokens into the pool
|
||||
LibERC20TokenV06.compatTransfer(
|
||||
IERC20TokenV06(fromTokenAddress),
|
||||
pool,
|
||||
sellAmount);
|
||||
// Call the swap exact with the tokens now in the pool
|
||||
// pay the NEST Oracle fee with ETH
|
||||
(/* In */, boughtAmount, , ) = ICoFiXPair(pool).swapWithExact{value: fee}(
|
||||
address(buyToken),
|
||||
address(this)
|
||||
);
|
||||
|
||||
return boughtAmount;
|
||||
}
|
||||
}
|
@@ -29,22 +29,6 @@ contract MixinZeroExBridge {
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
using LibSafeMathV06 for uint256;
|
||||
|
||||
/// @dev Emitted when a trade occurs.
|
||||
/// @param inputToken The token the bridge is converting from.
|
||||
/// @param outputToken The token the bridge is converting to.
|
||||
/// @param inputTokenAmount Amount of input token.
|
||||
/// @param outputTokenAmount Amount of output token.
|
||||
/// @param from The bridge address, indicating the underlying source of the fill.
|
||||
/// @param to The `to` address, currrently `address(this)`
|
||||
event ERC20BridgeTransfer(
|
||||
IERC20TokenV06 inputToken,
|
||||
IERC20TokenV06 outputToken,
|
||||
uint256 inputTokenAmount,
|
||||
uint256 outputTokenAmount,
|
||||
address from,
|
||||
address to
|
||||
);
|
||||
|
||||
function _tradeZeroExBridge(
|
||||
address bridgeAddress,
|
||||
IERC20TokenV06 sellToken,
|
||||
@@ -67,13 +51,5 @@ contract MixinZeroExBridge {
|
||||
1, // minBuyAmount
|
||||
bridgeData
|
||||
);
|
||||
emit ERC20BridgeTransfer(
|
||||
sellToken,
|
||||
buyToken,
|
||||
sellAmount,
|
||||
boughtAmount,
|
||||
bridgeAddress,
|
||||
address(this)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user