chore: [asset swapper] sampler Solidity 0.6 + Bridge addresses in AS (#4)

* Refactor excess interfaces

* Compiles on 0.6

* Refactored into try/catch

* Rebase and Refactored to v06

* Handle invalid registry in LP

* Update packages/asset-swapper/contracts/src/LiquidityProviderSampler.sol

Co-authored-by: Lawrence Forman <lawrence@0xproject.com>

* chore: [asset-swapper] Move Bridge Addresses and Gas schedule

* curve->pool

* lint

* Refactor to fix module load order

* Move FEE Schedule

* rollup: Swerve/Sushi/SnowSwap/DODO (#7)

* rollup: Swerve/Sushi

* DODO Rollup + Snowswap Swerve

* hardcode addresses temporarily

* rebase

* rename to SUSHISWAP_ROUTER

* CHANGELOGs

* CHANGELOGs

Co-authored-by: Lawrence Forman <lawrence@0xproject.com>
This commit is contained in:
Jacob Evans
2020-10-27 15:16:09 +10:00
committed by GitHub
parent 8de0282d92
commit 99f5be8378
73 changed files with 1663 additions and 612 deletions

View File

@@ -1,4 +1,13 @@
[
{
"version": "0.5.0",
"changes": [
{
"note": "Add `Swerve`, `SnowSwap`, `DODO` and `SushiSwap` into FQT",
"pr": 7
}
]
},
{
"version": "0.4.0",
"changes": [

View File

@@ -22,11 +22,13 @@ pragma experimental ABIEncoderV2;
import "./mixins/MixinAdapterAddresses.sol";
import "./mixins/MixinBalancer.sol";
import "./mixins/MixinCurve.sol";
import "./mixins/MixinDodo.sol";
import "./mixins/MixinKyber.sol";
import "./mixins/MixinMooniswap.sol";
import "./mixins/MixinMStable.sol";
import "./mixins/MixinOasis.sol";
import "./mixins/MixinShell.sol";
import "./mixins/MixinSushiswap.sol";
import "./mixins/MixinUniswap.sol";
import "./mixins/MixinUniswapV2.sol";
import "./mixins/MixinZeroExBridge.sol";
@@ -35,11 +37,13 @@ contract BridgeAdapter is
MixinAdapterAddresses,
MixinBalancer,
MixinCurve,
MixinDodo,
MixinKyber,
MixinMooniswap,
MixinMStable,
MixinOasis,
MixinShell,
MixinSushiswap,
MixinUniswap,
MixinUniswapV2,
MixinZeroExBridge
@@ -48,11 +52,15 @@ contract BridgeAdapter is
address private immutable BALANCER_BRIDGE_ADDRESS;
address private immutable CREAM_BRIDGE_ADDRESS;
address private immutable CURVE_BRIDGE_ADDRESS;
address private immutable DODO_BRIDGE_ADDRESS;
address private immutable KYBER_BRIDGE_ADDRESS;
address private immutable MOONISWAP_BRIDGE_ADDRESS;
address private immutable MSTABLE_BRIDGE_ADDRESS;
address private immutable OASIS_BRIDGE_ADDRESS;
address private immutable SHELL_BRIDGE_ADDRESS;
address private immutable SNOW_SWAP_BRIDGE_ADDRESS;
address private immutable SUSHISWAP_BRIDGE_ADDRESS;
address private immutable SWERVE_BRIDGE_ADDRESS;
address private immutable UNISWAP_BRIDGE_ADDRESS;
address private immutable UNISWAP_V2_BRIDGE_ADDRESS;
@@ -76,11 +84,13 @@ contract BridgeAdapter is
public
MixinBalancer()
MixinCurve()
MixinDodo(addresses)
MixinKyber(addresses)
MixinMooniswap(addresses)
MixinMStable(addresses)
MixinOasis(addresses)
MixinShell(addresses)
MixinSushiswap(addresses)
MixinUniswap(addresses)
MixinUniswapV2(addresses)
MixinZeroExBridge()
@@ -92,9 +102,13 @@ contract BridgeAdapter is
MSTABLE_BRIDGE_ADDRESS = addresses.mStableBridge;
OASIS_BRIDGE_ADDRESS = addresses.oasisBridge;
SHELL_BRIDGE_ADDRESS = addresses.shellBridge;
SUSHISWAP_BRIDGE_ADDRESS = addresses.sushiswapBridge;
SWERVE_BRIDGE_ADDRESS = addresses.swerveBridge;
UNISWAP_BRIDGE_ADDRESS = addresses.uniswapBridge;
UNISWAP_V2_BRIDGE_ADDRESS = addresses.uniswapV2Bridge;
CREAM_BRIDGE_ADDRESS = addresses.creamBridge;
SNOW_SWAP_BRIDGE_ADDRESS = addresses.snowSwapBridge;
DODO_BRIDGE_ADDRESS = addresses.dodoBridge;
}
function trade(
@@ -118,12 +132,20 @@ contract BridgeAdapter is
"BridgeAdapter/INVALID_BRIDGE_ADDRESS"
);
if (bridgeAddress == CURVE_BRIDGE_ADDRESS) {
if (bridgeAddress == CURVE_BRIDGE_ADDRESS ||
bridgeAddress == SWERVE_BRIDGE_ADDRESS ||
bridgeAddress == SNOW_SWAP_BRIDGE_ADDRESS) {
boughtAmount = _tradeCurve(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == SUSHISWAP_BRIDGE_ADDRESS) {
boughtAmount = _tradeSushiswap(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == UNISWAP_V2_BRIDGE_ADDRESS) {
boughtAmount = _tradeUniswapV2(
buyToken,
@@ -136,7 +158,8 @@ contract BridgeAdapter is
sellAmount,
bridgeData
);
} else if (bridgeAddress == BALANCER_BRIDGE_ADDRESS || bridgeAddress == CREAM_BRIDGE_ADDRESS) {
} else if (bridgeAddress == BALANCER_BRIDGE_ADDRESS ||
bridgeAddress == CREAM_BRIDGE_ADDRESS) {
boughtAmount = _tradeBalancer(
buyToken,
sellAmount,
@@ -172,6 +195,12 @@ contract BridgeAdapter is
sellAmount,
bridgeData
);
} else if (bridgeAddress == DODO_BRIDGE_ADDRESS) {
boughtAmount = _tradeDodo(
buyToken,
sellAmount,
bridgeData
);
} else {
boughtAmount = _tradeZeroExBridge(
bridgeAddress,

View File

@@ -26,20 +26,26 @@ contract MixinAdapterAddresses
address balancerBridge;
address creamBridge;
address curveBridge;
address dodoBridge;
address kyberBridge;
address mooniswapBridge;
address mStableBridge;
address oasisBridge;
address shellBridge;
address snowSwapBridge;
address swerveBridge;
address sushiswapBridge;
address uniswapBridge;
address uniswapV2Bridge;
// Exchanges
address kyberNetworkProxy;
address oasis;
address sushiswapRouter;
address uniswapV2Router;
address uniswapExchangeFactory;
address mStable;
address shell;
address dodoHelper;
// Other
address weth;
}

View File

@@ -0,0 +1,97 @@
/*
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 "./MixinAdapterAddresses.sol";
interface IDODOHelper {
function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256);
}
interface IDODO {
function sellBaseToken(uint256 amount, uint256 minReceiveQuote, bytes calldata data) external returns (uint256);
function buyBaseToken(uint256 amount, uint256 maxPayQuote, bytes calldata data) external returns (uint256);
}
contract MixinDodo is
MixinAdapterAddresses
{
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Mainnet address of the `DOODO Helper` contract.
IDODOHelper private immutable DODO_HELPER;
constructor(AdapterAddresses memory addresses)
public
{
DODO_HELPER = IDODOHelper(addresses.dodoHelper);
}
function _tradeDodo(
IERC20TokenV06 /* buyToken */,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256 boughtAmount)
{
(address fromTokenAddress,
address pool,
bool isSellBase) = abi.decode(bridgeData, (address, address, bool));
// Grant the Dodo pool contract an allowance to sell the first token.
IERC20TokenV06(fromTokenAddress).approveIfBelow(pool, sellAmount);
if (isSellBase) {
// Sell the Base token directly against the contract
boughtAmount = IDODO(pool).sellBaseToken(
// amount to sell
sellAmount,
// min receive amount
1,
new bytes(0)
);
} else {
// Need to re-calculate the sell quote amount into buyBase
boughtAmount = DODO_HELPER.querySellQuoteToken(
pool,
sellAmount
);
IDODO(pool).buyBaseToken(
// amount to buy
boughtAmount,
// max pay amount
sellAmount,
new bytes(0)
);
}
return boughtAmount;
}
}

View File

@@ -69,7 +69,7 @@ contract MixinShell is
sellAmount
);
uint256 buyAmount = SHELL.originSwap(
boughtAmount = SHELL.originSwap(
fromTokenAddress,
address(buyToken),
// Sell all tokens we hold.
@@ -79,6 +79,6 @@ contract MixinShell is
// deadline
block.timestamp + 1
);
return buyAmount;
return boughtAmount;
}
}

View File

@@ -0,0 +1,79 @@
/*
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 "./MixinAdapterAddresses.sol";
import "./MixinUniswapV2.sol";
contract MixinSushiswap is
MixinAdapterAddresses
{
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Mainnet address of the `SushiswapRouter` contract.
IUniswapV2Router02 private immutable SUSHISWAP_ROUTER;
constructor(AdapterAddresses memory addresses)
public
{
SUSHISWAP_ROUTER = IUniswapV2Router02(addresses.sushiswapRouter);
}
function _tradeSushiswap(
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256 boughtAmount)
{
// solhint-disable indent
address[] memory path = abi.decode(bridgeData, (address[]));
// solhint-enable indent
require(path.length >= 2, "SushiswapBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(
path[path.length - 1] == address(buyToken),
"SushiswapBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
);
// Grant the Uniswap router an allowance to sell the first token.
IERC20TokenV06(path[0]).approveIfBelow(
address(SUSHISWAP_ROUTER),
sellAmount
);
uint[] memory amounts = SUSHISWAP_ROUTER.swapExactTokensForTokens(
// Sell all tokens we hold.
sellAmount,
// Minimum buy amount.
1,
// Convert to `buyToken` along this path.
path,
// Recipient is `this`.
address(this),
// Expires after this block.
block.timestamp
);
return amounts[amounts.length-1];
}
}

View File

@@ -65,11 +65,13 @@ import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransa
import * as MixinAdapterAddresses from '../test/generated-artifacts/MixinAdapterAddresses.json';
import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json';
import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json';
import * as MixinDodo from '../test/generated-artifacts/MixinDodo.json';
import * as MixinKyber from '../test/generated-artifacts/MixinKyber.json';
import * as MixinMooniswap from '../test/generated-artifacts/MixinMooniswap.json';
import * as MixinMStable from '../test/generated-artifacts/MixinMStable.json';
import * as MixinOasis from '../test/generated-artifacts/MixinOasis.json';
import * as MixinShell from '../test/generated-artifacts/MixinShell.json';
import * as MixinSushiswap from '../test/generated-artifacts/MixinSushiswap.json';
import * as MixinUniswap from '../test/generated-artifacts/MixinUniswap.json';
import * as MixinUniswapV2 from '../test/generated-artifacts/MixinUniswapV2.json';
import * as MixinZeroExBridge from '../test/generated-artifacts/MixinZeroExBridge.json';
@@ -176,11 +178,13 @@ export const artifacts = {
MixinAdapterAddresses: MixinAdapterAddresses as ContractArtifact,
MixinBalancer: MixinBalancer as ContractArtifact,
MixinCurve: MixinCurve as ContractArtifact,
MixinDodo: MixinDodo as ContractArtifact,
MixinKyber: MixinKyber as ContractArtifact,
MixinMStable: MixinMStable as ContractArtifact,
MixinMooniswap: MixinMooniswap as ContractArtifact,
MixinOasis: MixinOasis as ContractArtifact,
MixinShell: MixinShell as ContractArtifact,
MixinSushiswap: MixinSushiswap as ContractArtifact,
MixinUniswap: MixinUniswap as ContractArtifact,
MixinUniswapV2: MixinUniswapV2 as ContractArtifact,
MixinZeroExBridge: MixinZeroExBridge as ContractArtifact,

View File

@@ -65,10 +65,13 @@ blockchainTests.resets('FillQuoteTransformer', env => {
mooniswapBridge: NULL_ADDRESS,
mStableBridge: NULL_ADDRESS,
oasisBridge: NULL_ADDRESS,
sushiswapBridge: NULL_ADDRESS,
swerveBridge: NULL_ADDRESS,
uniswapBridge: NULL_ADDRESS,
uniswapV2Bridge: NULL_ADDRESS,
kyberNetworkProxy: NULL_ADDRESS,
oasis: NULL_ADDRESS,
sushiswapRouter: NULL_ADDRESS,
uniswapV2Router: NULL_ADDRESS,
uniswapExchangeFactory: NULL_ADDRESS,
mStable: NULL_ADDRESS,
@@ -76,6 +79,9 @@ blockchainTests.resets('FillQuoteTransformer', env => {
shellBridge: NULL_ADDRESS,
shell: NULL_ADDRESS,
creamBridge: NULL_ADDRESS,
dodoBridge: NULL_ADDRESS,
dodoHelper: NULL_ADDRESS,
snowSwapBridge: NULL_ADDRESS,
},
);
transformer = await FillQuoteTransformerContract.deployFrom0xArtifactAsync(

View File

@@ -63,11 +63,13 @@ export * from '../test/generated-wrappers/meta_transactions_feature';
export * from '../test/generated-wrappers/mixin_adapter_addresses';
export * from '../test/generated-wrappers/mixin_balancer';
export * from '../test/generated-wrappers/mixin_curve';
export * from '../test/generated-wrappers/mixin_dodo';
export * from '../test/generated-wrappers/mixin_kyber';
export * from '../test/generated-wrappers/mixin_m_stable';
export * from '../test/generated-wrappers/mixin_mooniswap';
export * from '../test/generated-wrappers/mixin_oasis';
export * from '../test/generated-wrappers/mixin_shell';
export * from '../test/generated-wrappers/mixin_sushiswap';
export * from '../test/generated-wrappers/mixin_uniswap';
export * from '../test/generated-wrappers/mixin_uniswap_v2';
export * from '../test/generated-wrappers/mixin_zero_ex_bridge';

View File

@@ -87,11 +87,13 @@
"test/generated-artifacts/MixinAdapterAddresses.json",
"test/generated-artifacts/MixinBalancer.json",
"test/generated-artifacts/MixinCurve.json",
"test/generated-artifacts/MixinDodo.json",
"test/generated-artifacts/MixinKyber.json",
"test/generated-artifacts/MixinMStable.json",
"test/generated-artifacts/MixinMooniswap.json",
"test/generated-artifacts/MixinOasis.json",
"test/generated-artifacts/MixinShell.json",
"test/generated-artifacts/MixinSushiswap.json",
"test/generated-artifacts/MixinUniswap.json",
"test/generated-artifacts/MixinUniswapV2.json",
"test/generated-artifacts/MixinZeroExBridge.json",