feat: Swerve Finance and SushiSwap (#2698)
* feat: Swerve Finance * export SwerveFillData * test and CHANGELOG * feat: Sushiswap (#2700) * feat: SushiSwap * Changelog * fix tests * Deployed SushiSwap bridge * Fix test * IGNORED_EXCESSIVE_TYPES
This commit is contained in:
		
							
								
								
									
										136
									
								
								contracts/asset-proxy/contracts/src/bridges/SushiSwapBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								contracts/asset-proxy/contracts/src/bridges/SushiSwapBridge.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,136 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   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.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/LibAddressArray.sol"; | ||||||
|  | import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "../interfaces/IUniswapV2Router01.sol"; | ||||||
|  | import "../interfaces/IERC20Bridge.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // solhint-disable space-after-comma | ||||||
|  | // solhint-disable not-rely-on-time | ||||||
|  | contract SushiSwapBridge is | ||||||
|  |     IERC20Bridge, | ||||||
|  |     IWallet, | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |     struct TransferState { | ||||||
|  |         address[] path; | ||||||
|  |         address router; | ||||||
|  |         uint256 fromTokenBalance; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of | ||||||
|  |     ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` | ||||||
|  |     ///      token encoded in the bridge data. | ||||||
|  |     /// @param toTokenAddress The token to buy and transfer to `to`. | ||||||
|  |     /// @param from The maker (this contract). | ||||||
|  |     /// @param to The recipient of the bought tokens. | ||||||
|  |     /// @param amount Minimum amount of `toTokenAddress` tokens to buy. | ||||||
|  |     /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress | ||||||
|  |     /// @return success The magic bytes if successful. | ||||||
|  |     function bridgeTransferFrom( | ||||||
|  |         address toTokenAddress, | ||||||
|  |         address from, | ||||||
|  |         address to, | ||||||
|  |         uint256 amount, | ||||||
|  |         bytes calldata bridgeData | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         returns (bytes4 success) | ||||||
|  |     { | ||||||
|  |         // hold variables to get around stack depth limitations | ||||||
|  |         TransferState memory state; | ||||||
|  |  | ||||||
|  |         // Decode the bridge data to get the `fromTokenAddress`. | ||||||
|  |         // solhint-disable indent | ||||||
|  |         (state.path, state.router) = abi.decode(bridgeData, (address[], address)); | ||||||
|  |         // solhint-enable indent | ||||||
|  |  | ||||||
|  |         require(state.path.length >= 2, "SushiSwapBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO"); | ||||||
|  |         require(state.path[state.path.length - 1] == toTokenAddress, "SushiSwapBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"); | ||||||
|  |  | ||||||
|  |         // Just transfer the tokens if they're the same. | ||||||
|  |         if (state.path[0] == toTokenAddress) { | ||||||
|  |             LibERC20Token.transfer(state.path[0], to, amount); | ||||||
|  |             return BRIDGE_SUCCESS; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Get our balance of `fromTokenAddress` token. | ||||||
|  |         state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this)); | ||||||
|  |  | ||||||
|  |         // Grant the SushiSwap router an allowance. | ||||||
|  |         LibERC20Token.approveIfBelow( | ||||||
|  |             state.path[0], | ||||||
|  |             state.router, | ||||||
|  |             state.fromTokenBalance | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // Buy as much `toTokenAddress` token with `fromTokenAddress` token | ||||||
|  |         // and transfer it to `to`. | ||||||
|  |         IUniswapV2Router01 router = IUniswapV2Router01(state.router); | ||||||
|  |         uint[] memory amounts = router.swapExactTokensForTokens( | ||||||
|  |              // Sell all tokens we hold. | ||||||
|  |             state.fromTokenBalance, | ||||||
|  |              // Minimum buy amount. | ||||||
|  |             amount, | ||||||
|  |             // Convert `fromTokenAddress` to `toTokenAddress`. | ||||||
|  |             state.path, | ||||||
|  |             // Recipient is `to`. | ||||||
|  |             to, | ||||||
|  |             // Expires after this block. | ||||||
|  |             block.timestamp | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         emit ERC20BridgeTransfer( | ||||||
|  |             // input token | ||||||
|  |             state.path[0], | ||||||
|  |             // output token | ||||||
|  |             toTokenAddress, | ||||||
|  |             // input token amount | ||||||
|  |             state.fromTokenBalance, | ||||||
|  |             // output token amount | ||||||
|  |             amounts[amounts.length - 1], | ||||||
|  |             from, | ||||||
|  |             to | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         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 Success bytes, always. | ||||||
|  |     function isValidSignature( | ||||||
|  |         bytes32, | ||||||
|  |         bytes calldata | ||||||
|  |     ) | ||||||
|  |         external | ||||||
|  |         view | ||||||
|  |         returns (bytes4 magicValue) | ||||||
|  |     { | ||||||
|  |         return LEGACY_WALLET_MAGIC_VALUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -38,7 +38,7 @@ | |||||||
|         "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": { | ||||||
|         "abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CurveBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|StaticCallProxy|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json", |         "abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CurveBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|StaticCallProxy|SushiSwapBridge|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).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": { | ||||||
|   | |||||||
| @@ -44,6 +44,7 @@ import * as MStableBridge from '../generated-artifacts/MStableBridge.json'; | |||||||
| import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json'; | import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json'; | ||||||
| import * as Ownable from '../generated-artifacts/Ownable.json'; | import * as Ownable from '../generated-artifacts/Ownable.json'; | ||||||
| import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json'; | import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json'; | ||||||
|  | import * as SushiSwapBridge from '../generated-artifacts/SushiSwapBridge.json'; | ||||||
| import * as TestBancorBridge from '../generated-artifacts/TestBancorBridge.json'; | import * as TestBancorBridge from '../generated-artifacts/TestBancorBridge.json'; | ||||||
| import * as TestChaiBridge from '../generated-artifacts/TestChaiBridge.json'; | import * as TestChaiBridge from '../generated-artifacts/TestChaiBridge.json'; | ||||||
| import * as TestDexForwarderBridge from '../generated-artifacts/TestDexForwarderBridge.json'; | import * as TestDexForwarderBridge from '../generated-artifacts/TestDexForwarderBridge.json'; | ||||||
| @@ -77,6 +78,7 @@ export const artifacts = { | |||||||
|     MStableBridge: MStableBridge as ContractArtifact, |     MStableBridge: MStableBridge as ContractArtifact, | ||||||
|     MixinGasToken: MixinGasToken as ContractArtifact, |     MixinGasToken: MixinGasToken as ContractArtifact, | ||||||
|     MooniswapBridge: MooniswapBridge as ContractArtifact, |     MooniswapBridge: MooniswapBridge as ContractArtifact, | ||||||
|  |     SushiSwapBridge: SushiSwapBridge as ContractArtifact, | ||||||
|     UniswapBridge: UniswapBridge as ContractArtifact, |     UniswapBridge: UniswapBridge as ContractArtifact, | ||||||
|     UniswapV2Bridge: UniswapV2Bridge as ContractArtifact, |     UniswapV2Bridge: UniswapV2Bridge as ContractArtifact, | ||||||
|     IAssetData: IAssetData as ContractArtifact, |     IAssetData: IAssetData as ContractArtifact, | ||||||
|   | |||||||
| @@ -42,6 +42,7 @@ export * from '../generated-wrappers/mooniswap_bridge'; | |||||||
| export * from '../generated-wrappers/multi_asset_proxy'; | export * from '../generated-wrappers/multi_asset_proxy'; | ||||||
| export * from '../generated-wrappers/ownable'; | export * from '../generated-wrappers/ownable'; | ||||||
| export * from '../generated-wrappers/static_call_proxy'; | export * from '../generated-wrappers/static_call_proxy'; | ||||||
|  | export * from '../generated-wrappers/sushi_swap_bridge'; | ||||||
| export * from '../generated-wrappers/test_bancor_bridge'; | export * from '../generated-wrappers/test_bancor_bridge'; | ||||||
| export * from '../generated-wrappers/test_chai_bridge'; | export * from '../generated-wrappers/test_chai_bridge'; | ||||||
| export * from '../generated-wrappers/test_dex_forwarder_bridge'; | export * from '../generated-wrappers/test_dex_forwarder_bridge'; | ||||||
|   | |||||||
| @@ -44,6 +44,7 @@ import * as MStableBridge from '../test/generated-artifacts/MStableBridge.json'; | |||||||
| import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json'; | import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json'; | ||||||
| import * as Ownable from '../test/generated-artifacts/Ownable.json'; | 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 SushiSwapBridge from '../test/generated-artifacts/SushiSwapBridge.json'; | ||||||
| import * as TestBancorBridge from '../test/generated-artifacts/TestBancorBridge.json'; | import * as TestBancorBridge from '../test/generated-artifacts/TestBancorBridge.json'; | ||||||
| import * as TestChaiBridge from '../test/generated-artifacts/TestChaiBridge.json'; | import * as TestChaiBridge from '../test/generated-artifacts/TestChaiBridge.json'; | ||||||
| import * as TestDexForwarderBridge from '../test/generated-artifacts/TestDexForwarderBridge.json'; | import * as TestDexForwarderBridge from '../test/generated-artifacts/TestDexForwarderBridge.json'; | ||||||
| @@ -77,6 +78,7 @@ export const artifacts = { | |||||||
|     MStableBridge: MStableBridge as ContractArtifact, |     MStableBridge: MStableBridge as ContractArtifact, | ||||||
|     MixinGasToken: MixinGasToken as ContractArtifact, |     MixinGasToken: MixinGasToken as ContractArtifact, | ||||||
|     MooniswapBridge: MooniswapBridge as ContractArtifact, |     MooniswapBridge: MooniswapBridge as ContractArtifact, | ||||||
|  |     SushiSwapBridge: SushiSwapBridge as ContractArtifact, | ||||||
|     UniswapBridge: UniswapBridge as ContractArtifact, |     UniswapBridge: UniswapBridge as ContractArtifact, | ||||||
|     UniswapV2Bridge: UniswapV2Bridge as ContractArtifact, |     UniswapV2Bridge: UniswapV2Bridge as ContractArtifact, | ||||||
|     IAssetData: IAssetData as ContractArtifact, |     IAssetData: IAssetData as ContractArtifact, | ||||||
|   | |||||||
| @@ -42,6 +42,7 @@ export * from '../test/generated-wrappers/mooniswap_bridge'; | |||||||
| export * from '../test/generated-wrappers/multi_asset_proxy'; | export * from '../test/generated-wrappers/multi_asset_proxy'; | ||||||
| export * from '../test/generated-wrappers/ownable'; | 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/sushi_swap_bridge'; | ||||||
| export * from '../test/generated-wrappers/test_bancor_bridge'; | export * from '../test/generated-wrappers/test_bancor_bridge'; | ||||||
| export * from '../test/generated-wrappers/test_chai_bridge'; | export * from '../test/generated-wrappers/test_chai_bridge'; | ||||||
| export * from '../test/generated-wrappers/test_dex_forwarder_bridge'; | export * from '../test/generated-wrappers/test_dex_forwarder_bridge'; | ||||||
|   | |||||||
| @@ -42,6 +42,7 @@ | |||||||
|         "generated-artifacts/MultiAssetProxy.json", |         "generated-artifacts/MultiAssetProxy.json", | ||||||
|         "generated-artifacts/Ownable.json", |         "generated-artifacts/Ownable.json", | ||||||
|         "generated-artifacts/StaticCallProxy.json", |         "generated-artifacts/StaticCallProxy.json", | ||||||
|  |         "generated-artifacts/SushiSwapBridge.json", | ||||||
|         "generated-artifacts/TestBancorBridge.json", |         "generated-artifacts/TestBancorBridge.json", | ||||||
|         "generated-artifacts/TestChaiBridge.json", |         "generated-artifacts/TestChaiBridge.json", | ||||||
|         "generated-artifacts/TestDexForwarderBridge.json", |         "generated-artifacts/TestDexForwarderBridge.json", | ||||||
| @@ -93,6 +94,7 @@ | |||||||
|         "test/generated-artifacts/MultiAssetProxy.json", |         "test/generated-artifacts/MultiAssetProxy.json", | ||||||
|         "test/generated-artifacts/Ownable.json", |         "test/generated-artifacts/Ownable.json", | ||||||
|         "test/generated-artifacts/StaticCallProxy.json", |         "test/generated-artifacts/StaticCallProxy.json", | ||||||
|  |         "test/generated-artifacts/SushiSwapBridge.json", | ||||||
|         "test/generated-artifacts/TestBancorBridge.json", |         "test/generated-artifacts/TestBancorBridge.json", | ||||||
|         "test/generated-artifacts/TestChaiBridge.json", |         "test/generated-artifacts/TestChaiBridge.json", | ||||||
|         "test/generated-artifacts/TestDexForwarderBridge.json", |         "test/generated-artifacts/TestDexForwarderBridge.json", | ||||||
|   | |||||||
| @@ -288,11 +288,11 @@ contract DeploymentConstants { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// @dev An overridable way to retrieve the Mooniswap registry address. |     /// @dev An overridable way to retrieve the Mooniswap registry address. | ||||||
|     /// @return musd The Mooniswap registry address. |     /// @return registry The Mooniswap registry address. | ||||||
|     function _getMooniswapAddress() |     function _getMooniswapAddress() | ||||||
|         internal |         internal | ||||||
|         view |         view | ||||||
|         returns (address registry) |         returns (address) | ||||||
|     { |     { | ||||||
|         return MOONISWAP_REGISTRY; |         return MOONISWAP_REGISTRY; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -101,6 +101,14 @@ | |||||||
|             { |             { | ||||||
|                 "note": "Return Mooniswap pool in sampler and encode it in bridge data", |                 "note": "Return Mooniswap pool in sampler and encode it in bridge data", | ||||||
|                 "pr": 2692 |                 "pr": 2692 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Added `Swerve`", | ||||||
|  |                 "pr": 2698 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Added `SushiSwap`", | ||||||
|  |                 "pr": 2698 | ||||||
|             } |             } | ||||||
|         ] |         ] | ||||||
|     }, |     }, | ||||||
|   | |||||||
| @@ -28,9 +28,10 @@ import "./MultiBridgeSampler.sol"; | |||||||
| import "./MStableSampler.sol"; | import "./MStableSampler.sol"; | ||||||
| import "./MooniswapSampler.sol"; | import "./MooniswapSampler.sol"; | ||||||
| import "./NativeOrderSampler.sol"; | import "./NativeOrderSampler.sol"; | ||||||
|  | import "./SushiSwapSampler.sol"; | ||||||
|  | import "./TwoHopSampler.sol"; | ||||||
| import "./UniswapSampler.sol"; | import "./UniswapSampler.sol"; | ||||||
| import "./UniswapV2Sampler.sol"; | import "./UniswapV2Sampler.sol"; | ||||||
| import "./TwoHopSampler.sol"; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| contract ERC20BridgeSampler is | contract ERC20BridgeSampler is | ||||||
| @@ -43,6 +44,7 @@ contract ERC20BridgeSampler is | |||||||
|     MooniswapSampler, |     MooniswapSampler, | ||||||
|     MultiBridgeSampler, |     MultiBridgeSampler, | ||||||
|     NativeOrderSampler, |     NativeOrderSampler, | ||||||
|  |     SushiSwapSampler, | ||||||
|     TwoHopSampler, |     TwoHopSampler, | ||||||
|     UniswapSampler, |     UniswapSampler, | ||||||
|     UniswapV2Sampler |     UniswapV2Sampler | ||||||
|   | |||||||
							
								
								
									
										103
									
								
								packages/asset-swapper/contracts/src/SushiSwapSampler.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								packages/asset-swapper/contracts/src/SushiSwapSampler.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | |||||||
|  | /* | ||||||
|  |  | ||||||
|  |   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-utils/contracts/src/DeploymentConstants.sol"; | ||||||
|  | import "./interfaces/IUniswapV2Router01.sol"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | contract SushiSwapSampler is | ||||||
|  |     DeploymentConstants | ||||||
|  | { | ||||||
|  |     /// @dev Gas limit for SushiSwap calls. | ||||||
|  |     uint256 constant private SUSHISWAP_CALL_GAS = 150e3; // 150k | ||||||
|  |  | ||||||
|  |     /// @dev Sample sell quotes from SushiSwap. | ||||||
|  |     /// @param router Router to look up tokens and amounts | ||||||
|  |     /// @param path Token route. Should be takerToken -> makerToken | ||||||
|  |     /// @param takerTokenAmounts Taker token sell amount for each sample. | ||||||
|  |     /// @return makerTokenAmounts Maker amounts bought at each taker token | ||||||
|  |     ///         amount. | ||||||
|  |     function sampleSellsFromSushiSwap( | ||||||
|  |         address router, | ||||||
|  |         address[] memory path, | ||||||
|  |         uint256[] memory takerTokenAmounts | ||||||
|  |     ) | ||||||
|  |         public | ||||||
|  |         view | ||||||
|  |         returns (uint256[] memory makerTokenAmounts) | ||||||
|  |     { | ||||||
|  |         uint256 numSamples = takerTokenAmounts.length; | ||||||
|  |         makerTokenAmounts = new uint256[](numSamples); | ||||||
|  |         for (uint256 i = 0; i < numSamples; i++) { | ||||||
|  |             (bool didSucceed, bytes memory resultData) = | ||||||
|  |                 router.staticcall.gas(SUSHISWAP_CALL_GAS)( | ||||||
|  |                     abi.encodeWithSelector( | ||||||
|  |                         IUniswapV2Router01(0).getAmountsOut.selector, | ||||||
|  |                         takerTokenAmounts[i], | ||||||
|  |                         path | ||||||
|  |                     )); | ||||||
|  |             uint256 buyAmount = 0; | ||||||
|  |             if (didSucceed) { | ||||||
|  |                 // solhint-disable-next-line indent | ||||||
|  |                 buyAmount = abi.decode(resultData, (uint256[]))[path.length - 1]; | ||||||
|  |             } else { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             makerTokenAmounts[i] = buyAmount; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// @dev Sample buy quotes from SushiSwap | ||||||
|  |     /// @param router Router to look up tokens and amounts | ||||||
|  |     /// @param path Token route. Should be takerToken -> makerToken. | ||||||
|  |     /// @param makerTokenAmounts Maker token buy amount for each sample. | ||||||
|  |     /// @return takerTokenAmounts Taker amounts sold at each maker token | ||||||
|  |     ///         amount. | ||||||
|  |     function sampleBuysFromSushiSwap( | ||||||
|  |         address router, | ||||||
|  |         address[] memory path, | ||||||
|  |         uint256[] memory makerTokenAmounts | ||||||
|  |     ) | ||||||
|  |         public | ||||||
|  |         view | ||||||
|  |         returns (uint256[] memory takerTokenAmounts) | ||||||
|  |     { | ||||||
|  |         uint256 numSamples = makerTokenAmounts.length; | ||||||
|  |         takerTokenAmounts = new uint256[](numSamples); | ||||||
|  |         for (uint256 i = 0; i < numSamples; i++) { | ||||||
|  |             (bool didSucceed, bytes memory resultData) = | ||||||
|  |                 router.staticcall.gas(SUSHISWAP_CALL_GAS)( | ||||||
|  |                     abi.encodeWithSelector( | ||||||
|  |                         IUniswapV2Router01(0).getAmountsIn.selector, | ||||||
|  |                         makerTokenAmounts[i], | ||||||
|  |                         path | ||||||
|  |                     )); | ||||||
|  |             uint256 sellAmount = 0; | ||||||
|  |             if (didSucceed) { | ||||||
|  |                 // solhint-disable-next-line indent | ||||||
|  |                 sellAmount = abi.decode(resultData, (uint256[]))[0]; | ||||||
|  |             } else { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             takerTokenAmounts[i] = sellAmount; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -38,7 +38,7 @@ | |||||||
|     "config": { |     "config": { | ||||||
|         "publicInterfaceContracts": "ERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider", |         "publicInterfaceContracts": "ERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider", | ||||||
|         "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/@(ApproximateBuys|BalancerSampler|CurveSampler|DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|ILiquidityProvider|ILiquidityProviderRegistry|IMStable|IMooniswap|IMultiBridge|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json", |         "abis": "./test/generated-artifacts/@(ApproximateBuys|BalancerSampler|CurveSampler|DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|ILiquidityProvider|ILiquidityProviderRegistry|IMStable|IMooniswap|IMultiBridge|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json", | ||||||
|         "postpublish": { |         "postpublish": { | ||||||
|             "assets": [] |             "assets": [] | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -99,6 +99,7 @@ export { | |||||||
|     MarketOperation, |     MarketOperation, | ||||||
|     MarketSellSwapQuote, |     MarketSellSwapQuote, | ||||||
|     MockedRfqtFirmQuoteResponse, |     MockedRfqtFirmQuoteResponse, | ||||||
|  |     OrderPrunerPermittedFeeTypes, | ||||||
|     RfqtMakerAssetOfferings, |     RfqtMakerAssetOfferings, | ||||||
|     RfqtRequestOpts, |     RfqtRequestOpts, | ||||||
|     SamplerOverrides, |     SamplerOverrides, | ||||||
| @@ -148,6 +149,9 @@ export { | |||||||
|     OptimizedMarketOrder, |     OptimizedMarketOrder, | ||||||
|     SourceInfo, |     SourceInfo, | ||||||
|     SourceQuoteOperation, |     SourceQuoteOperation, | ||||||
|  |     SushiSwapFillData, | ||||||
|  |     SwerveFillData, | ||||||
|  |     SwerveInfo, | ||||||
|     TokenAdjacencyGraph, |     TokenAdjacencyGraph, | ||||||
|     UniswapV2FillData, |     UniswapV2FillData, | ||||||
| } from './utils/market_operation_utils/types'; | } from './utils/market_operation_utils/types'; | ||||||
|   | |||||||
| @@ -17,6 +17,8 @@ export const SELL_SOURCES = [ | |||||||
|     // ERC20BridgeSource.Bancor, // FIXME: Disabled until Bancor SDK supports batch requests |     // ERC20BridgeSource.Bancor, // FIXME: Disabled until Bancor SDK supports batch requests | ||||||
|     ERC20BridgeSource.MStable, |     ERC20BridgeSource.MStable, | ||||||
|     ERC20BridgeSource.Mooniswap, |     ERC20BridgeSource.Mooniswap, | ||||||
|  |     ERC20BridgeSource.Swerve, | ||||||
|  |     ERC20BridgeSource.SushiSwap, | ||||||
| ]; | ]; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -32,6 +34,8 @@ export const BUY_SOURCES = [ | |||||||
|     // ERC20BridgeSource.Bancor, // FIXME: Disabled until Bancor SDK supports buy quotes |     // ERC20BridgeSource.Bancor, // FIXME: Disabled until Bancor SDK supports buy quotes | ||||||
|     ERC20BridgeSource.MStable, |     ERC20BridgeSource.MStable, | ||||||
|     ERC20BridgeSource.Mooniswap, |     ERC20BridgeSource.Mooniswap, | ||||||
|  |     ERC20BridgeSource.Swerve, | ||||||
|  |     ERC20BridgeSource.SushiSwap, | ||||||
| ]; | ]; | ||||||
|  |  | ||||||
| export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = { | export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = { | ||||||
| @@ -132,6 +136,20 @@ export const MAINNET_CURVE_INFOS: { [name: string]: CurveInfo } = { | |||||||
|         ], |         ], | ||||||
|     }, |     }, | ||||||
| }; | }; | ||||||
|  | export const MAINNET_SWERVE_INFOS: { [name: string]: CurveInfo } = { | ||||||
|  |     swUSD: { | ||||||
|  |         exchangeFunctionSelector: CurveFunctionSelectors.exchange, | ||||||
|  |         sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, | ||||||
|  |         buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx_underlying, | ||||||
|  |         poolAddress: '0x329239599afB305DA0A2eC69c58F8a6697F9F88d', | ||||||
|  |         tokens: [ | ||||||
|  |             '0x6b175474e89094c44da98b954eedeac495271d0f', | ||||||
|  |             '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', | ||||||
|  |             '0xdac17f958d2ee523a2206206994597c13d831ec7', | ||||||
|  |             '0x0000000000085d4780b73119b644ae5ecd22b376', | ||||||
|  |         ], | ||||||
|  |     }, | ||||||
|  | }; | ||||||
|  |  | ||||||
| export const MAINNET_KYBER_RESERVE_IDS: { [name: string]: string } = { | export const MAINNET_KYBER_RESERVE_IDS: { [name: string]: string } = { | ||||||
|     Reserve1: '0xff4b796265722046707200000000000000000000000000000000000000000000', |     Reserve1: '0xff4b796265722046707200000000000000000000000000000000000000000000', | ||||||
| @@ -169,6 +187,8 @@ export const MAINNET_KYBER_TOKEN_RESERVE_IDS: { [token: string]: string } = { | |||||||
|         '0xaa42414e44000000000000000000000000000000000000000000000000000000', |         '0xaa42414e44000000000000000000000000000000000000000000000000000000', | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | export const MAINNET_SUSHI_SWAP_ROUTER = '0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F'; | ||||||
|  |  | ||||||
| export const ERC20_PROXY_ID = '0xf47261b0'; | export const ERC20_PROXY_ID = '0xf47261b0'; | ||||||
| export const WALLET_SIGNATURE = '0x04'; | export const WALLET_SIGNATURE = '0x04'; | ||||||
| export const ONE_ETHER = new BigNumber(1e18); | export const ONE_ETHER = new BigNumber(1e18); | ||||||
|   | |||||||
| @@ -1,7 +1,11 @@ | |||||||
| import { MAINNET_CURVE_INFOS } from './constants'; | import { MAINNET_CURVE_INFOS, MAINNET_SWERVE_INFOS } from './constants'; | ||||||
| import { CurveInfo } from './types'; | import { CurveInfo, SwerveInfo } from './types'; | ||||||
|  |  | ||||||
| // tslint:disable completed-docs | // tslint:disable completed-docs | ||||||
| export function getCurveInfosForPair(takerToken: string, makerToken: string): CurveInfo[] { | export function getCurveInfosForPair(takerToken: string, makerToken: string): CurveInfo[] { | ||||||
|     return Object.values(MAINNET_CURVE_INFOS).filter(c => [makerToken, takerToken].every(t => c.tokens.includes(t))); |     return Object.values(MAINNET_CURVE_INFOS).filter(c => [makerToken, takerToken].every(t => c.tokens.includes(t))); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export function getSwerveInfosForPair(takerToken: string, makerToken: string): SwerveInfo[] { | ||||||
|  |     return Object.values(MAINNET_SWERVE_INFOS).filter(c => [makerToken, takerToken].every(t => c.tokens.includes(t))); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -35,6 +35,8 @@ import { | |||||||
|     NativeCollapsedFill, |     NativeCollapsedFill, | ||||||
|     OptimizedMarketOrder, |     OptimizedMarketOrder, | ||||||
|     OrderDomain, |     OrderDomain, | ||||||
|  |     SushiSwapFillData, | ||||||
|  |     SwerveFillData, | ||||||
|     UniswapV2FillData, |     UniswapV2FillData, | ||||||
| } from './types'; | } from './types'; | ||||||
|  |  | ||||||
| @@ -222,8 +224,12 @@ function getBridgeAddressFromFill(fill: CollapsedFill, opts: CreateOrderFromPath | |||||||
|             return opts.contractAddresses.uniswapBridge; |             return opts.contractAddresses.uniswapBridge; | ||||||
|         case ERC20BridgeSource.UniswapV2: |         case ERC20BridgeSource.UniswapV2: | ||||||
|             return opts.contractAddresses.uniswapV2Bridge; |             return opts.contractAddresses.uniswapV2Bridge; | ||||||
|  |         case ERC20BridgeSource.SushiSwap: | ||||||
|  |             return opts.contractAddresses.sushiswapBridge; | ||||||
|         case ERC20BridgeSource.Curve: |         case ERC20BridgeSource.Curve: | ||||||
|             return opts.contractAddresses.curveBridge; |             return opts.contractAddresses.curveBridge; | ||||||
|  |         case ERC20BridgeSource.Swerve: | ||||||
|  |             return opts.contractAddresses.curveBridge; | ||||||
|         case ERC20BridgeSource.Bancor: |         case ERC20BridgeSource.Bancor: | ||||||
|             return opts.contractAddresses.bancorBridge; |             return opts.contractAddresses.bancorBridge; | ||||||
|         case ERC20BridgeSource.Balancer: |         case ERC20BridgeSource.Balancer: | ||||||
| @@ -266,6 +272,20 @@ function createBridgeOrder( | |||||||
|                 ), |                 ), | ||||||
|             ); |             ); | ||||||
|             break; |             break; | ||||||
|  |         case ERC20BridgeSource.Swerve: | ||||||
|  |             const swerveFillData = (fill as CollapsedFill<SwerveFillData>).fillData!; // tslint:disable-line:no-non-null-assertion | ||||||
|  |             makerAssetData = assetDataUtils.encodeERC20BridgeAssetData( | ||||||
|  |                 makerToken, | ||||||
|  |                 bridgeAddress, | ||||||
|  |                 createCurveBridgeData( | ||||||
|  |                     swerveFillData.pool.poolAddress, | ||||||
|  |                     swerveFillData.pool.exchangeFunctionSelector, | ||||||
|  |                     takerToken, | ||||||
|  |                     swerveFillData.fromTokenIdx, | ||||||
|  |                     swerveFillData.toTokenIdx, | ||||||
|  |                 ), | ||||||
|  |             ); | ||||||
|  |             break; | ||||||
|         case ERC20BridgeSource.Balancer: |         case ERC20BridgeSource.Balancer: | ||||||
|             const balancerFillData = (fill as CollapsedFill<BalancerFillData>).fillData!; // tslint:disable-line:no-non-null-assertion |             const balancerFillData = (fill as CollapsedFill<BalancerFillData>).fillData!; // tslint:disable-line:no-non-null-assertion | ||||||
|             makerAssetData = assetDataUtils.encodeERC20BridgeAssetData( |             makerAssetData = assetDataUtils.encodeERC20BridgeAssetData( | ||||||
| @@ -290,6 +310,14 @@ function createBridgeOrder( | |||||||
|                 createUniswapV2BridgeData(uniswapV2FillData.tokenAddressPath), |                 createUniswapV2BridgeData(uniswapV2FillData.tokenAddressPath), | ||||||
|             ); |             ); | ||||||
|             break; |             break; | ||||||
|  |         case ERC20BridgeSource.SushiSwap: | ||||||
|  |             const sushiSwapFillData = (fill as CollapsedFill<SushiSwapFillData>).fillData!; // tslint:disable-line:no-non-null-assertion | ||||||
|  |             makerAssetData = assetDataUtils.encodeERC20BridgeAssetData( | ||||||
|  |                 makerToken, | ||||||
|  |                 bridgeAddress, | ||||||
|  |                 createSushiSwapBridgeData(sushiSwapFillData.tokenAddressPath, sushiSwapFillData.router), | ||||||
|  |             ); | ||||||
|  |             break; | ||||||
|         case ERC20BridgeSource.MultiBridge: |         case ERC20BridgeSource.MultiBridge: | ||||||
|             makerAssetData = assetDataUtils.encodeERC20BridgeAssetData( |             makerAssetData = assetDataUtils.encodeERC20BridgeAssetData( | ||||||
|                 makerToken, |                 makerToken, | ||||||
| @@ -431,25 +459,24 @@ function createCurveBridgeData( | |||||||
|     fromTokenIdx: number, |     fromTokenIdx: number, | ||||||
|     toTokenIdx: number, |     toTokenIdx: number, | ||||||
| ): string { | ): string { | ||||||
|     const curveBridgeDataEncoder = AbiEncoder.create([ |     const encoder = AbiEncoder.create([ | ||||||
|         { name: 'curveAddress', type: 'address' }, |         { name: 'curveAddress', type: 'address' }, | ||||||
|         { name: 'exchangeFunctionSelector', type: 'bytes4' }, |         { name: 'exchangeFunctionSelector', type: 'bytes4' }, | ||||||
|         { name: 'fromTokenAddress', type: 'address' }, |         { name: 'fromTokenAddress', type: 'address' }, | ||||||
|         { name: 'fromTokenIdx', type: 'int128' }, |         { name: 'fromTokenIdx', type: 'int128' }, | ||||||
|         { name: 'toTokenIdx', type: 'int128' }, |         { name: 'toTokenIdx', type: 'int128' }, | ||||||
|     ]); |     ]); | ||||||
|     return curveBridgeDataEncoder.encode([ |     return encoder.encode([curveAddress, exchangeFunctionSelector, takerToken, fromTokenIdx, toTokenIdx]); | ||||||
|         curveAddress, |  | ||||||
|         exchangeFunctionSelector, |  | ||||||
|         takerToken, |  | ||||||
|         fromTokenIdx, |  | ||||||
|         toTokenIdx, |  | ||||||
|     ]); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| function createUniswapV2BridgeData(tokenAddressPath: string[]): string { | function createUniswapV2BridgeData(tokenAddressPath: string[]): string { | ||||||
|     const uniswapV2BridgeDataEncoder = AbiEncoder.create('(address[])'); |     const encoder = AbiEncoder.create('(address[])'); | ||||||
|     return uniswapV2BridgeDataEncoder.encode([tokenAddressPath]); |     return encoder.encode([tokenAddressPath]); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function createSushiSwapBridgeData(tokenAddressPath: string[], router: string): string { | ||||||
|  |     const encoder = AbiEncoder.create('(address[],address)'); | ||||||
|  |     return encoder.encode([tokenAddressPath, router]); | ||||||
| } | } | ||||||
|  |  | ||||||
| function getSlippedBridgeAssetAmounts(fill: CollapsedFill, opts: CreateOrderFromPathOpts): [BigNumber, BigNumber] { | function getSlippedBridgeAssetAmounts(fill: CollapsedFill, opts: CreateOrderFromPathOpts): [BigNumber, BigNumber] { | ||||||
|   | |||||||
| @@ -6,8 +6,8 @@ import { ERC20BridgeSamplerContract } from '../../wrappers'; | |||||||
|  |  | ||||||
| import { BalancerPoolsCache, computeBalancerBuyQuote, computeBalancerSellQuote } from './balancer_utils'; | import { BalancerPoolsCache, computeBalancerBuyQuote, computeBalancerSellQuote } from './balancer_utils'; | ||||||
| import { BancorService } from './bancor_service'; | import { BancorService } from './bancor_service'; | ||||||
| import { MAX_UINT256, NULL_BYTES, ZERO_AMOUNT } from './constants'; | import { MAINNET_SUSHI_SWAP_ROUTER, MAX_UINT256, NULL_BYTES, ZERO_AMOUNT } from './constants'; | ||||||
| import { getCurveInfosForPair } from './curve_utils'; | import { getCurveInfosForPair, getSwerveInfosForPair } from './curve_utils'; | ||||||
| import { getKyberReserveIdsForPair } from './kyber_utils'; | import { getKyberReserveIdsForPair } from './kyber_utils'; | ||||||
| import { getMultiBridgeIntermediateToken } from './multibridge_utils'; | import { getMultiBridgeIntermediateToken } from './multibridge_utils'; | ||||||
| import { getIntermediateTokens } from './multihop_utils'; | import { getIntermediateTokens } from './multihop_utils'; | ||||||
| @@ -27,6 +27,9 @@ import { | |||||||
|     MultiBridgeFillData, |     MultiBridgeFillData, | ||||||
|     MultiHopFillData, |     MultiHopFillData, | ||||||
|     SourceQuoteOperation, |     SourceQuoteOperation, | ||||||
|  |     SushiSwapFillData, | ||||||
|  |     SwerveFillData, | ||||||
|  |     SwerveInfo, | ||||||
|     TokenAdjacencyGraph, |     TokenAdjacencyGraph, | ||||||
|     UniswapV2FillData, |     UniswapV2FillData, | ||||||
| } from './types'; | } from './types'; | ||||||
| @@ -315,6 +318,62 @@ export class SamplerOperations { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public getSwerveSellQuotes( | ||||||
|  |         pool: SwerveInfo, | ||||||
|  |         fromTokenIdx: number, | ||||||
|  |         toTokenIdx: number, | ||||||
|  |         takerFillAmounts: BigNumber[], | ||||||
|  |     ): SourceQuoteOperation<SwerveFillData> { | ||||||
|  |         return new SamplerContractOperation({ | ||||||
|  |             source: ERC20BridgeSource.Swerve, | ||||||
|  |             fillData: { | ||||||
|  |                 pool, | ||||||
|  |                 fromTokenIdx, | ||||||
|  |                 toTokenIdx, | ||||||
|  |             }, | ||||||
|  |             contract: this._samplerContract, | ||||||
|  |             function: this._samplerContract.sampleSellsFromCurve, | ||||||
|  |             params: [ | ||||||
|  |                 { | ||||||
|  |                     poolAddress: pool.poolAddress, | ||||||
|  |                     sellQuoteFunctionSelector: pool.sellQuoteFunctionSelector, | ||||||
|  |                     buyQuoteFunctionSelector: pool.buyQuoteFunctionSelector, | ||||||
|  |                 }, | ||||||
|  |                 new BigNumber(fromTokenIdx), | ||||||
|  |                 new BigNumber(toTokenIdx), | ||||||
|  |                 takerFillAmounts, | ||||||
|  |             ], | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public getSwerveBuyQuotes( | ||||||
|  |         pool: SwerveInfo, | ||||||
|  |         fromTokenIdx: number, | ||||||
|  |         toTokenIdx: number, | ||||||
|  |         makerFillAmounts: BigNumber[], | ||||||
|  |     ): SourceQuoteOperation<SwerveFillData> { | ||||||
|  |         return new SamplerContractOperation({ | ||||||
|  |             source: ERC20BridgeSource.Swerve, | ||||||
|  |             fillData: { | ||||||
|  |                 pool, | ||||||
|  |                 fromTokenIdx, | ||||||
|  |                 toTokenIdx, | ||||||
|  |             }, | ||||||
|  |             contract: this._samplerContract, | ||||||
|  |             function: this._samplerContract.sampleBuysFromCurve, | ||||||
|  |             params: [ | ||||||
|  |                 { | ||||||
|  |                     poolAddress: pool.poolAddress, | ||||||
|  |                     sellQuoteFunctionSelector: pool.sellQuoteFunctionSelector, | ||||||
|  |                     buyQuoteFunctionSelector: pool.buyQuoteFunctionSelector, | ||||||
|  |                 }, | ||||||
|  |                 new BigNumber(fromTokenIdx), | ||||||
|  |                 new BigNumber(toTokenIdx), | ||||||
|  |                 makerFillAmounts, | ||||||
|  |             ], | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public getBalancerSellQuotes( |     public getBalancerSellQuotes( | ||||||
|         poolAddress: string, |         poolAddress: string, | ||||||
|         makerToken: string, |         makerToken: string, | ||||||
| @@ -621,6 +680,32 @@ export class SamplerOperations { | |||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public getSushiSwapSellQuotes( | ||||||
|  |         tokenAddressPath: string[], | ||||||
|  |         takerFillAmounts: BigNumber[], | ||||||
|  |     ): SourceQuoteOperation<SushiSwapFillData> { | ||||||
|  |         return new SamplerContractOperation({ | ||||||
|  |             source: ERC20BridgeSource.SushiSwap, | ||||||
|  |             fillData: { tokenAddressPath, router: MAINNET_SUSHI_SWAP_ROUTER }, | ||||||
|  |             contract: this._samplerContract, | ||||||
|  |             function: this._samplerContract.sampleSellsFromSushiSwap, | ||||||
|  |             params: [MAINNET_SUSHI_SWAP_ROUTER, tokenAddressPath, takerFillAmounts], | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public getSushiSwapBuyQuotes( | ||||||
|  |         tokenAddressPath: string[], | ||||||
|  |         makerFillAmounts: BigNumber[], | ||||||
|  |     ): SourceQuoteOperation<SushiSwapFillData> { | ||||||
|  |         return new SamplerContractOperation({ | ||||||
|  |             source: ERC20BridgeSource.SushiSwap, | ||||||
|  |             fillData: { tokenAddressPath, router: MAINNET_SUSHI_SWAP_ROUTER }, | ||||||
|  |             contract: this._samplerContract, | ||||||
|  |             function: this._samplerContract.sampleBuysFromSushiSwap, | ||||||
|  |             params: [MAINNET_SUSHI_SWAP_ROUTER, tokenAddressPath, makerFillAmounts], | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public getMedianSellRate( |     public getMedianSellRate( | ||||||
|         sources: ERC20BridgeSource[], |         sources: ERC20BridgeSource[], | ||||||
|         makerToken: string, |         makerToken: string, | ||||||
| @@ -784,6 +869,17 @@ export class SamplerOperations { | |||||||
|                                 ); |                                 ); | ||||||
|                             } |                             } | ||||||
|                             return ops; |                             return ops; | ||||||
|  |                         case ERC20BridgeSource.SushiSwap: | ||||||
|  |                             const sushiOps = [this.getSushiSwapSellQuotes([takerToken, makerToken], takerFillAmounts)]; | ||||||
|  |                             if (takerToken !== wethAddress && makerToken !== wethAddress) { | ||||||
|  |                                 sushiOps.push( | ||||||
|  |                                     this.getSushiSwapSellQuotes( | ||||||
|  |                                         [takerToken, wethAddress, makerToken], | ||||||
|  |                                         takerFillAmounts, | ||||||
|  |                                     ), | ||||||
|  |                                 ); | ||||||
|  |                             } | ||||||
|  |                             return sushiOps; | ||||||
|                         case ERC20BridgeSource.Kyber: |                         case ERC20BridgeSource.Kyber: | ||||||
|                             return getKyberReserveIdsForPair(takerToken, makerToken).map(reserveId => |                             return getKyberReserveIdsForPair(takerToken, makerToken).map(reserveId => | ||||||
|                                 this.getKyberSellQuotes(reserveId, makerToken, takerToken, takerFillAmounts), |                                 this.getKyberSellQuotes(reserveId, makerToken, takerToken, takerFillAmounts), | ||||||
| @@ -797,6 +893,15 @@ export class SamplerOperations { | |||||||
|                                     takerFillAmounts, |                                     takerFillAmounts, | ||||||
|                                 ), |                                 ), | ||||||
|                             ); |                             ); | ||||||
|  |                         case ERC20BridgeSource.Swerve: | ||||||
|  |                             return getSwerveInfosForPair(takerToken, makerToken).map(pool => | ||||||
|  |                                 this.getSwerveSellQuotes( | ||||||
|  |                                     pool, | ||||||
|  |                                     pool.tokens.indexOf(takerToken), | ||||||
|  |                                     pool.tokens.indexOf(makerToken), | ||||||
|  |                                     takerFillAmounts, | ||||||
|  |                                 ), | ||||||
|  |                             ); | ||||||
|                         case ERC20BridgeSource.LiquidityProvider: |                         case ERC20BridgeSource.LiquidityProvider: | ||||||
|                             if (liquidityProviderRegistryAddress === undefined) { |                             if (liquidityProviderRegistryAddress === undefined) { | ||||||
|                                 throw new Error( |                                 throw new Error( | ||||||
| @@ -865,6 +970,14 @@ export class SamplerOperations { | |||||||
|                                 ); |                                 ); | ||||||
|                             } |                             } | ||||||
|                             return ops; |                             return ops; | ||||||
|  |                         case ERC20BridgeSource.SushiSwap: | ||||||
|  |                             const sushiOps = [this.getSushiSwapBuyQuotes([takerToken, makerToken], makerFillAmounts)]; | ||||||
|  |                             if (takerToken !== wethAddress && makerToken !== wethAddress) { | ||||||
|  |                                 sushiOps.push( | ||||||
|  |                                     this.getSushiSwapBuyQuotes([takerToken, wethAddress, makerToken], makerFillAmounts), | ||||||
|  |                                 ); | ||||||
|  |                             } | ||||||
|  |                             return sushiOps; | ||||||
|                         case ERC20BridgeSource.Kyber: |                         case ERC20BridgeSource.Kyber: | ||||||
|                             return getKyberReserveIdsForPair(takerToken, makerToken).map(reserveId => |                             return getKyberReserveIdsForPair(takerToken, makerToken).map(reserveId => | ||||||
|                                 this.getKyberBuyQuotes(reserveId, makerToken, takerToken, makerFillAmounts), |                                 this.getKyberBuyQuotes(reserveId, makerToken, takerToken, makerFillAmounts), | ||||||
| @@ -878,6 +991,15 @@ export class SamplerOperations { | |||||||
|                                     makerFillAmounts, |                                     makerFillAmounts, | ||||||
|                                 ), |                                 ), | ||||||
|                             ); |                             ); | ||||||
|  |                         case ERC20BridgeSource.Swerve: | ||||||
|  |                             return getSwerveInfosForPair(takerToken, makerToken).map(pool => | ||||||
|  |                                 this.getSwerveBuyQuotes( | ||||||
|  |                                     pool, | ||||||
|  |                                     pool.tokens.indexOf(takerToken), | ||||||
|  |                                     pool.tokens.indexOf(makerToken), | ||||||
|  |                                     makerFillAmounts, | ||||||
|  |                                 ), | ||||||
|  |                             ); | ||||||
|                         case ERC20BridgeSource.LiquidityProvider: |                         case ERC20BridgeSource.LiquidityProvider: | ||||||
|                             if (liquidityProviderRegistryAddress === undefined) { |                             if (liquidityProviderRegistryAddress === undefined) { | ||||||
|                                 throw new Error( |                                 throw new Error( | ||||||
|   | |||||||
| @@ -41,6 +41,8 @@ export enum ERC20BridgeSource { | |||||||
|     MStable = 'mStable', |     MStable = 'mStable', | ||||||
|     Mooniswap = 'Mooniswap', |     Mooniswap = 'Mooniswap', | ||||||
|     MultiHop = 'MultiHop', |     MultiHop = 'MultiHop', | ||||||
|  |     Swerve = 'Swerve', | ||||||
|  |     SushiSwap = 'SushiSwap', | ||||||
| } | } | ||||||
|  |  | ||||||
| // tslint:disable: enum-naming | // tslint:disable: enum-naming | ||||||
| @@ -69,6 +71,8 @@ export interface CurveInfo { | |||||||
|     tokens: string[]; |     tokens: string[]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export interface SwerveInfo extends CurveInfo {} | ||||||
|  |  | ||||||
| // Internal `fillData` field for `Fill` objects. | // Internal `fillData` field for `Fill` objects. | ||||||
| export interface FillData {} | export interface FillData {} | ||||||
|  |  | ||||||
| @@ -88,6 +92,12 @@ export interface CurveFillData extends FillData { | |||||||
|     curve: CurveInfo; |     curve: CurveInfo; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export interface SwerveFillData extends FillData { | ||||||
|  |     fromTokenIdx: number; | ||||||
|  |     toTokenIdx: number; | ||||||
|  |     pool: SwerveInfo; | ||||||
|  | } | ||||||
|  |  | ||||||
| export interface BalancerFillData extends FillData { | export interface BalancerFillData extends FillData { | ||||||
|     poolAddress: string; |     poolAddress: string; | ||||||
| } | } | ||||||
| @@ -96,6 +106,10 @@ export interface UniswapV2FillData extends FillData { | |||||||
|     tokenAddressPath: string[]; |     tokenAddressPath: string[]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export interface SushiSwapFillData extends UniswapV2FillData { | ||||||
|  |     router: string; | ||||||
|  | } | ||||||
|  |  | ||||||
| export interface LiquidityProviderFillData extends FillData { | export interface LiquidityProviderFillData extends FillData { | ||||||
|     poolAddress: string; |     poolAddress: string; | ||||||
| } | } | ||||||
| @@ -103,6 +117,7 @@ export interface LiquidityProviderFillData extends FillData { | |||||||
| export interface MultiBridgeFillData extends FillData { | export interface MultiBridgeFillData extends FillData { | ||||||
|     poolAddress: string; |     poolAddress: string; | ||||||
| } | } | ||||||
|  |  | ||||||
| export interface BancorFillData extends FillData { | export interface BancorFillData extends FillData { | ||||||
|     path: string[]; |     path: string[]; | ||||||
|     networkAddress: string; |     networkAddress: string; | ||||||
|   | |||||||
| @@ -30,6 +30,7 @@ import * as MStableSampler from '../test/generated-artifacts/MStableSampler.json | |||||||
| import * as MultiBridgeSampler from '../test/generated-artifacts/MultiBridgeSampler.json'; | import * as MultiBridgeSampler from '../test/generated-artifacts/MultiBridgeSampler.json'; | ||||||
| import * as NativeOrderSampler from '../test/generated-artifacts/NativeOrderSampler.json'; | import * as NativeOrderSampler from '../test/generated-artifacts/NativeOrderSampler.json'; | ||||||
| import * as SamplerUtils from '../test/generated-artifacts/SamplerUtils.json'; | import * as SamplerUtils from '../test/generated-artifacts/SamplerUtils.json'; | ||||||
|  | import * as SushiSwapSampler from '../test/generated-artifacts/SushiSwapSampler.json'; | ||||||
| import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json'; | import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json'; | ||||||
| import * as TestNativeOrderSampler from '../test/generated-artifacts/TestNativeOrderSampler.json'; | import * as TestNativeOrderSampler from '../test/generated-artifacts/TestNativeOrderSampler.json'; | ||||||
| import * as TwoHopSampler from '../test/generated-artifacts/TwoHopSampler.json'; | import * as TwoHopSampler from '../test/generated-artifacts/TwoHopSampler.json'; | ||||||
| @@ -49,6 +50,7 @@ export const artifacts = { | |||||||
|     MultiBridgeSampler: MultiBridgeSampler as ContractArtifact, |     MultiBridgeSampler: MultiBridgeSampler as ContractArtifact, | ||||||
|     NativeOrderSampler: NativeOrderSampler as ContractArtifact, |     NativeOrderSampler: NativeOrderSampler as ContractArtifact, | ||||||
|     SamplerUtils: SamplerUtils as ContractArtifact, |     SamplerUtils: SamplerUtils as ContractArtifact, | ||||||
|  |     SushiSwapSampler: SushiSwapSampler as ContractArtifact, | ||||||
|     TwoHopSampler: TwoHopSampler as ContractArtifact, |     TwoHopSampler: TwoHopSampler as ContractArtifact, | ||||||
|     UniswapSampler: UniswapSampler as ContractArtifact, |     UniswapSampler: UniswapSampler as ContractArtifact, | ||||||
|     UniswapV2Sampler: UniswapV2Sampler as ContractArtifact, |     UniswapV2Sampler: UniswapV2Sampler as ContractArtifact, | ||||||
|   | |||||||
| @@ -27,6 +27,16 @@ const MAKER_TOKEN = randomAddress(); | |||||||
| const TAKER_TOKEN = randomAddress(); | const TAKER_TOKEN = randomAddress(); | ||||||
| const MAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(MAKER_TOKEN); | const MAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(MAKER_TOKEN); | ||||||
| const TAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(TAKER_TOKEN); | const TAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(TAKER_TOKEN); | ||||||
|  | const DEFAULT_EXCLUDED = [ | ||||||
|  |     ERC20BridgeSource.UniswapV2, | ||||||
|  |     ERC20BridgeSource.Curve, | ||||||
|  |     ERC20BridgeSource.Balancer, | ||||||
|  |     ERC20BridgeSource.MStable, | ||||||
|  |     ERC20BridgeSource.Mooniswap, | ||||||
|  |     ERC20BridgeSource.Bancor, | ||||||
|  |     ERC20BridgeSource.Swerve, | ||||||
|  |     ERC20BridgeSource.SushiSwap, | ||||||
|  | ]; | ||||||
|  |  | ||||||
| // tslint:disable: custom-no-magic-numbers promise-function-async | // tslint:disable: custom-no-magic-numbers promise-function-async | ||||||
| describe('MarketOperationUtils tests', () => { | describe('MarketOperationUtils tests', () => { | ||||||
| @@ -80,6 +90,8 @@ describe('MarketOperationUtils tests', () => { | |||||||
|                 return ERC20BridgeSource.MStable; |                 return ERC20BridgeSource.MStable; | ||||||
|             case contractAddresses.mooniswapBridge.toLowerCase(): |             case contractAddresses.mooniswapBridge.toLowerCase(): | ||||||
|                 return ERC20BridgeSource.Mooniswap; |                 return ERC20BridgeSource.Mooniswap; | ||||||
|  |             case contractAddresses.sushiswapBridge.toLowerCase(): | ||||||
|  |                 return ERC20BridgeSource.SushiSwap; | ||||||
|             default: |             default: | ||||||
|                 break; |                 break; | ||||||
|         } |         } | ||||||
| @@ -238,11 +250,11 @@ describe('MarketOperationUtils tests', () => { | |||||||
|         [source: string]: Numberish[]; |         [source: string]: Numberish[]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const DEFAULT_RATES: RatesBySource = { |     const ZERO_RATES: RatesBySource = { | ||||||
|         [ERC20BridgeSource.Native]: createDecreasingRates(NUM_SAMPLES), |         [ERC20BridgeSource.Native]: _.times(NUM_SAMPLES, () => 0), | ||||||
|         [ERC20BridgeSource.Eth2Dai]: createDecreasingRates(NUM_SAMPLES), |         [ERC20BridgeSource.Eth2Dai]: _.times(NUM_SAMPLES, () => 0), | ||||||
|         [ERC20BridgeSource.Kyber]: createDecreasingRates(NUM_SAMPLES), |         [ERC20BridgeSource.Uniswap]: _.times(NUM_SAMPLES, () => 0), | ||||||
|         [ERC20BridgeSource.Uniswap]: createDecreasingRates(NUM_SAMPLES), |         [ERC20BridgeSource.Kyber]: _.times(NUM_SAMPLES, () => 0), | ||||||
|         [ERC20BridgeSource.UniswapV2]: _.times(NUM_SAMPLES, () => 0), |         [ERC20BridgeSource.UniswapV2]: _.times(NUM_SAMPLES, () => 0), | ||||||
|         [ERC20BridgeSource.Balancer]: _.times(NUM_SAMPLES, () => 0), |         [ERC20BridgeSource.Balancer]: _.times(NUM_SAMPLES, () => 0), | ||||||
|         [ERC20BridgeSource.Bancor]: _.times(NUM_SAMPLES, () => 0), |         [ERC20BridgeSource.Bancor]: _.times(NUM_SAMPLES, () => 0), | ||||||
| @@ -251,6 +263,15 @@ describe('MarketOperationUtils tests', () => { | |||||||
|         [ERC20BridgeSource.MultiBridge]: _.times(NUM_SAMPLES, () => 0), |         [ERC20BridgeSource.MultiBridge]: _.times(NUM_SAMPLES, () => 0), | ||||||
|         [ERC20BridgeSource.MStable]: _.times(NUM_SAMPLES, () => 0), |         [ERC20BridgeSource.MStable]: _.times(NUM_SAMPLES, () => 0), | ||||||
|         [ERC20BridgeSource.Mooniswap]: _.times(NUM_SAMPLES, () => 0), |         [ERC20BridgeSource.Mooniswap]: _.times(NUM_SAMPLES, () => 0), | ||||||
|  |         [ERC20BridgeSource.Swerve]: _.times(NUM_SAMPLES, () => 0), | ||||||
|  |         [ERC20BridgeSource.SushiSwap]: _.times(NUM_SAMPLES, () => 0), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const DEFAULT_RATES: RatesBySource = { | ||||||
|  |         ...ZERO_RATES, | ||||||
|  |         [ERC20BridgeSource.Native]: createDecreasingRates(NUM_SAMPLES), | ||||||
|  |         [ERC20BridgeSource.Eth2Dai]: createDecreasingRates(NUM_SAMPLES), | ||||||
|  |         [ERC20BridgeSource.Uniswap]: createDecreasingRates(NUM_SAMPLES), | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     interface FillDataBySource { |     interface FillDataBySource { | ||||||
| @@ -273,7 +294,19 @@ describe('MarketOperationUtils tests', () => { | |||||||
|             fromTokenIdx: 0, |             fromTokenIdx: 0, | ||||||
|             toTokenIdx: 1, |             toTokenIdx: 1, | ||||||
|         }, |         }, | ||||||
|  |         [ERC20BridgeSource.Swerve]: { | ||||||
|  |             pool: { | ||||||
|  |                 poolAddress: randomAddress(), | ||||||
|  |                 tokens: [TAKER_TOKEN, MAKER_TOKEN], | ||||||
|  |                 exchangeFunctionSelector: hexUtils.random(4), | ||||||
|  |                 sellQuoteFunctionSelector: hexUtils.random(4), | ||||||
|  |                 buyQuoteFunctionSelector: hexUtils.random(4), | ||||||
|  |             }, | ||||||
|  |             fromTokenIdx: 0, | ||||||
|  |             toTokenIdx: 1, | ||||||
|  |         }, | ||||||
|         [ERC20BridgeSource.LiquidityProvider]: { poolAddress: randomAddress() }, |         [ERC20BridgeSource.LiquidityProvider]: { poolAddress: randomAddress() }, | ||||||
|  |         [ERC20BridgeSource.SushiSwap]: { tokenAddressPath: [] }, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     const DEFAULT_OPS = { |     const DEFAULT_OPS = { | ||||||
| @@ -416,14 +449,7 @@ describe('MarketOperationUtils tests', () => { | |||||||
|                 sampleDistributionBase: 1, |                 sampleDistributionBase: 1, | ||||||
|                 bridgeSlippage: 0, |                 bridgeSlippage: 0, | ||||||
|                 maxFallbackSlippage: 100, |                 maxFallbackSlippage: 100, | ||||||
|                 excludedSources: [ |                 excludedSources: DEFAULT_EXCLUDED, | ||||||
|                     ERC20BridgeSource.UniswapV2, |  | ||||||
|                     ERC20BridgeSource.Curve, |  | ||||||
|                     ERC20BridgeSource.Balancer, |  | ||||||
|                     ERC20BridgeSource.MStable, |  | ||||||
|                     ERC20BridgeSource.Mooniswap, |  | ||||||
|                     ERC20BridgeSource.Bancor, |  | ||||||
|                 ], |  | ||||||
|                 allowFallback: false, |                 allowFallback: false, | ||||||
|                 shouldBatchBridgeOrders: false, |                 shouldBatchBridgeOrders: false, | ||||||
|             }; |             }; | ||||||
| @@ -583,7 +609,7 @@ describe('MarketOperationUtils tests', () => { | |||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             it('can mix convex sources', async () => { |             it('can mix convex sources', async () => { | ||||||
|                 const rates: RatesBySource = {}; |                 const rates: RatesBySource = { ...DEFAULT_RATES }; | ||||||
|                 rates[ERC20BridgeSource.Native] = [0.4, 0.3, 0.2, 0.1]; |                 rates[ERC20BridgeSource.Native] = [0.4, 0.3, 0.2, 0.1]; | ||||||
|                 rates[ERC20BridgeSource.Uniswap] = [0.5, 0.05, 0.05, 0.05]; |                 rates[ERC20BridgeSource.Uniswap] = [0.5, 0.05, 0.05, 0.05]; | ||||||
|                 rates[ERC20BridgeSource.Eth2Dai] = [0.6, 0.05, 0.05, 0.05]; |                 rates[ERC20BridgeSource.Eth2Dai] = [0.6, 0.05, 0.05, 0.05]; | ||||||
| @@ -852,14 +878,7 @@ describe('MarketOperationUtils tests', () => { | |||||||
|                 sampleDistributionBase: 1, |                 sampleDistributionBase: 1, | ||||||
|                 bridgeSlippage: 0, |                 bridgeSlippage: 0, | ||||||
|                 maxFallbackSlippage: 100, |                 maxFallbackSlippage: 100, | ||||||
|                 excludedSources: [ |                 excludedSources: DEFAULT_EXCLUDED, | ||||||
|                     ERC20BridgeSource.Kyber, |  | ||||||
|                     ERC20BridgeSource.UniswapV2, |  | ||||||
|                     ERC20BridgeSource.Curve, |  | ||||||
|                     ERC20BridgeSource.Balancer, |  | ||||||
|                     ERC20BridgeSource.MStable, |  | ||||||
|                     ERC20BridgeSource.Mooniswap, |  | ||||||
|                 ], |  | ||||||
|                 allowFallback: false, |                 allowFallback: false, | ||||||
|                 shouldBatchBridgeOrders: false, |                 shouldBatchBridgeOrders: false, | ||||||
|             }; |             }; | ||||||
| @@ -1019,7 +1038,7 @@ describe('MarketOperationUtils tests', () => { | |||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             it('can mix convex sources', async () => { |             it('can mix convex sources', async () => { | ||||||
|                 const rates: RatesBySource = {}; |                 const rates: RatesBySource = { ...ZERO_RATES }; | ||||||
|                 rates[ERC20BridgeSource.Native] = [0.4, 0.3, 0.2, 0.1]; |                 rates[ERC20BridgeSource.Native] = [0.4, 0.3, 0.2, 0.1]; | ||||||
|                 rates[ERC20BridgeSource.Uniswap] = [0.5, 0.05, 0.05, 0.05]; |                 rates[ERC20BridgeSource.Uniswap] = [0.5, 0.05, 0.05, 0.05]; | ||||||
|                 rates[ERC20BridgeSource.Eth2Dai] = [0.6, 0.05, 0.05, 0.05]; |                 rates[ERC20BridgeSource.Eth2Dai] = [0.6, 0.05, 0.05, 0.05]; | ||||||
| @@ -1049,6 +1068,7 @@ describe('MarketOperationUtils tests', () => { | |||||||
|                 // dropping their effective rates. |                 // dropping their effective rates. | ||||||
|                 const nativeFeeRate = 0.06; |                 const nativeFeeRate = 0.06; | ||||||
|                 const rates: RatesBySource = { |                 const rates: RatesBySource = { | ||||||
|  |                     ...ZERO_RATES, | ||||||
|                     [ERC20BridgeSource.Native]: [1, 0.99, 0.98, 0.97], // Effectively [0.94, ~0.93, ~0.92, ~0.91] |                     [ERC20BridgeSource.Native]: [1, 0.99, 0.98, 0.97], // Effectively [0.94, ~0.93, ~0.92, ~0.91] | ||||||
|                     [ERC20BridgeSource.Uniswap]: [0.96, 0.1, 0.1, 0.1], |                     [ERC20BridgeSource.Uniswap]: [0.96, 0.1, 0.1, 0.1], | ||||||
|                     [ERC20BridgeSource.Eth2Dai]: [0.95, 0.1, 0.1, 0.1], |                     [ERC20BridgeSource.Eth2Dai]: [0.95, 0.1, 0.1, 0.1], | ||||||
| @@ -1086,6 +1106,7 @@ describe('MarketOperationUtils tests', () => { | |||||||
|                 // dropping its effective rates. |                 // dropping its effective rates. | ||||||
|                 const uniswapFeeRate = 0.2; |                 const uniswapFeeRate = 0.2; | ||||||
|                 const rates: RatesBySource = { |                 const rates: RatesBySource = { | ||||||
|  |                     ...ZERO_RATES, | ||||||
|                     [ERC20BridgeSource.Native]: [0.95, 0.1, 0.1, 0.1], |                     [ERC20BridgeSource.Native]: [0.95, 0.1, 0.1, 0.1], | ||||||
|                     // Effectively [0.8, ~0.5, ~0, ~0] |                     // Effectively [0.8, ~0.5, ~0, ~0] | ||||||
|                     [ERC20BridgeSource.Uniswap]: [1, 0.7, 0.2, 0.2], |                     [ERC20BridgeSource.Uniswap]: [1, 0.7, 0.2, 0.2], | ||||||
| @@ -1118,7 +1139,7 @@ describe('MarketOperationUtils tests', () => { | |||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             it('fallback orders use different sources', async () => { |             it('fallback orders use different sources', async () => { | ||||||
|                 const rates: RatesBySource = {}; |                 const rates: RatesBySource = { ...ZERO_RATES }; | ||||||
|                 rates[ERC20BridgeSource.Native] = [0.9, 0.8, 0.5, 0.5]; |                 rates[ERC20BridgeSource.Native] = [0.9, 0.8, 0.5, 0.5]; | ||||||
|                 rates[ERC20BridgeSource.Uniswap] = [0.6, 0.05, 0.01, 0.01]; |                 rates[ERC20BridgeSource.Uniswap] = [0.6, 0.05, 0.01, 0.01]; | ||||||
|                 rates[ERC20BridgeSource.Eth2Dai] = [0.4, 0.3, 0.01, 0.01]; |                 rates[ERC20BridgeSource.Eth2Dai] = [0.4, 0.3, 0.01, 0.01]; | ||||||
| @@ -1138,7 +1159,7 @@ describe('MarketOperationUtils tests', () => { | |||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             it('does not create a fallback if below maxFallbackSlippage', async () => { |             it('does not create a fallback if below maxFallbackSlippage', async () => { | ||||||
|                 const rates: RatesBySource = {}; |                 const rates: RatesBySource = { ...ZERO_RATES }; | ||||||
|                 rates[ERC20BridgeSource.Native] = [1, 1, 0.01, 0.01]; |                 rates[ERC20BridgeSource.Native] = [1, 1, 0.01, 0.01]; | ||||||
|                 rates[ERC20BridgeSource.Uniswap] = [1, 1, 0.01, 0.01]; |                 rates[ERC20BridgeSource.Uniswap] = [1, 1, 0.01, 0.01]; | ||||||
|                 rates[ERC20BridgeSource.Eth2Dai] = [0.49, 0.49, 0.49, 0.49]; |                 rates[ERC20BridgeSource.Eth2Dai] = [0.49, 0.49, 0.49, 0.49]; | ||||||
| @@ -1159,7 +1180,7 @@ describe('MarketOperationUtils tests', () => { | |||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             it('batches contiguous bridge sources', async () => { |             it('batches contiguous bridge sources', async () => { | ||||||
|                 const rates: RatesBySource = {}; |                 const rates: RatesBySource = { ...ZERO_RATES }; | ||||||
|                 rates[ERC20BridgeSource.Native] = [0.5, 0.01, 0.01, 0.01]; |                 rates[ERC20BridgeSource.Native] = [0.5, 0.01, 0.01, 0.01]; | ||||||
|                 rates[ERC20BridgeSource.Eth2Dai] = [0.49, 0.02, 0.01, 0.01]; |                 rates[ERC20BridgeSource.Eth2Dai] = [0.49, 0.02, 0.01, 0.01]; | ||||||
|                 rates[ERC20BridgeSource.Uniswap] = [0.48, 0.01, 0.01, 0.01]; |                 rates[ERC20BridgeSource.Uniswap] = [0.48, 0.01, 0.01, 0.01]; | ||||||
|   | |||||||
| @@ -28,6 +28,7 @@ export * from '../test/generated-wrappers/mooniswap_sampler'; | |||||||
| export * from '../test/generated-wrappers/multi_bridge_sampler'; | export * from '../test/generated-wrappers/multi_bridge_sampler'; | ||||||
| export * from '../test/generated-wrappers/native_order_sampler'; | export * from '../test/generated-wrappers/native_order_sampler'; | ||||||
| export * from '../test/generated-wrappers/sampler_utils'; | export * from '../test/generated-wrappers/sampler_utils'; | ||||||
|  | export * from '../test/generated-wrappers/sushi_swap_sampler'; | ||||||
| export * from '../test/generated-wrappers/test_erc20_bridge_sampler'; | export * from '../test/generated-wrappers/test_erc20_bridge_sampler'; | ||||||
| export * from '../test/generated-wrappers/test_native_order_sampler'; | export * from '../test/generated-wrappers/test_native_order_sampler'; | ||||||
| export * from '../test/generated-wrappers/two_hop_sampler'; | export * from '../test/generated-wrappers/two_hop_sampler'; | ||||||
|   | |||||||
| @@ -33,6 +33,7 @@ | |||||||
|         "test/generated-artifacts/MultiBridgeSampler.json", |         "test/generated-artifacts/MultiBridgeSampler.json", | ||||||
|         "test/generated-artifacts/NativeOrderSampler.json", |         "test/generated-artifacts/NativeOrderSampler.json", | ||||||
|         "test/generated-artifacts/SamplerUtils.json", |         "test/generated-artifacts/SamplerUtils.json", | ||||||
|  |         "test/generated-artifacts/SushiSwapSampler.json", | ||||||
|         "test/generated-artifacts/TestERC20BridgeSampler.json", |         "test/generated-artifacts/TestERC20BridgeSampler.json", | ||||||
|         "test/generated-artifacts/TestNativeOrderSampler.json", |         "test/generated-artifacts/TestNativeOrderSampler.json", | ||||||
|         "test/generated-artifacts/TwoHopSampler.json", |         "test/generated-artifacts/TwoHopSampler.json", | ||||||
|   | |||||||
| @@ -42,6 +42,7 @@ | |||||||
|         "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", |         "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", | ||||||
|         "mStableBridge": "0x2bf04fcea05f0989a14d9afa37aa376baca6b2b3", |         "mStableBridge": "0x2bf04fcea05f0989a14d9afa37aa376baca6b2b3", | ||||||
|         "mooniswapBridge": "0x02b7eca484ad960fca3f7709e0b2ac81eec3069c", |         "mooniswapBridge": "0x02b7eca484ad960fca3f7709e0b2ac81eec3069c", | ||||||
|  |         "sushiswapBridge": "0x47ed0262a0b688dcb836d254c6a2e96b6c48a9f5", | ||||||
|         "transformers": { |         "transformers": { | ||||||
|             "wethTransformer": "0x68c0bb685099dc7cb5c5ce2b26185945b357383e", |             "wethTransformer": "0x68c0bb685099dc7cb5c5ce2b26185945b357383e", | ||||||
|             "payTakerTransformer": "0x49b9df2c58491764cf40cb052dd4243df63622c7", |             "payTakerTransformer": "0x49b9df2c58491764cf40cb052dd4243df63622c7", | ||||||
| @@ -92,6 +93,7 @@ | |||||||
|         "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", |         "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", | ||||||
|         "mStableBridge": "0x0000000000000000000000000000000000000000", |         "mStableBridge": "0x0000000000000000000000000000000000000000", | ||||||
|         "mooniswapBridge": "0x0000000000000000000000000000000000000000", |         "mooniswapBridge": "0x0000000000000000000000000000000000000000", | ||||||
|  |         "sushiswapBridge": "0x0000000000000000000000000000000000000000", | ||||||
|         "transformers": { |         "transformers": { | ||||||
|             "wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437", |             "wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437", | ||||||
|             "payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6", |             "payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6", | ||||||
| @@ -142,6 +144,7 @@ | |||||||
|         "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", |         "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", | ||||||
|         "mStableBridge": "0x0000000000000000000000000000000000000000", |         "mStableBridge": "0x0000000000000000000000000000000000000000", | ||||||
|         "mooniswapBridge": "0x0000000000000000000000000000000000000000", |         "mooniswapBridge": "0x0000000000000000000000000000000000000000", | ||||||
|  |         "sushiswapBridge": "0x0000000000000000000000000000000000000000", | ||||||
|         "transformers": { |         "transformers": { | ||||||
|             "wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437", |             "wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437", | ||||||
|             "payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6", |             "payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6", | ||||||
| @@ -192,6 +195,7 @@ | |||||||
|         "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", |         "exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18", | ||||||
|         "mStableBridge": "0x0000000000000000000000000000000000000000", |         "mStableBridge": "0x0000000000000000000000000000000000000000", | ||||||
|         "mooniswapBridge": "0x0000000000000000000000000000000000000000", |         "mooniswapBridge": "0x0000000000000000000000000000000000000000", | ||||||
|  |         "sushiswapBridge": "0x0000000000000000000000000000000000000000", | ||||||
|         "transformers": { |         "transformers": { | ||||||
|             "wethTransformer": "0x9ce35b5ee9e710535e3988e3f8731d9ca9dba17d", |             "wethTransformer": "0x9ce35b5ee9e710535e3988e3f8731d9ca9dba17d", | ||||||
|             "payTakerTransformer": "0x5a53e7b02a83aa9f60ccf4e424f0442c255bc977", |             "payTakerTransformer": "0x5a53e7b02a83aa9f60ccf4e424f0442c255bc977", | ||||||
| @@ -242,6 +246,7 @@ | |||||||
|         "exchangeProxyFlashWallet": "0xb9682a8e7920b431f1d412b8510f0077410c8faa", |         "exchangeProxyFlashWallet": "0xb9682a8e7920b431f1d412b8510f0077410c8faa", | ||||||
|         "mStableBridge": "0x0000000000000000000000000000000000000000", |         "mStableBridge": "0x0000000000000000000000000000000000000000", | ||||||
|         "mooniswapBridge": "0x0000000000000000000000000000000000000000", |         "mooniswapBridge": "0x0000000000000000000000000000000000000000", | ||||||
|  |         "sushiswapBridge": "0x0000000000000000000000000000000000000000", | ||||||
|         "transformers": { |         "transformers": { | ||||||
|             "wethTransformer": "0xc6b0d3c45a6b5092808196cb00df5c357d55e1d5", |             "wethTransformer": "0xc6b0d3c45a6b5092808196cb00df5c357d55e1d5", | ||||||
|             "payTakerTransformer": "0x7209185959d7227fb77274e1e88151d7c4c368d3", |             "payTakerTransformer": "0x7209185959d7227fb77274e1e88151d7c4c368d3", | ||||||
|   | |||||||
| @@ -43,6 +43,7 @@ export interface ContractAddresses { | |||||||
|     exchangeProxyFlashWallet: string; |     exchangeProxyFlashWallet: string; | ||||||
|     mStableBridge: string; |     mStableBridge: string; | ||||||
|     mooniswapBridge: string; |     mooniswapBridge: string; | ||||||
|  |     sushiswapBridge: string; | ||||||
|     transformers: { |     transformers: { | ||||||
|         wethTransformer: string; |         wethTransformer: string; | ||||||
|         payTakerTransformer: string; |         payTakerTransformer: string; | ||||||
|   | |||||||
| @@ -400,6 +400,7 @@ export async function runMigrationsAsync( | |||||||
|         exchangeProxyGovernor: NULL_ADDRESS, |         exchangeProxyGovernor: NULL_ADDRESS, | ||||||
|         mStableBridge: NULL_ADDRESS, |         mStableBridge: NULL_ADDRESS, | ||||||
|         mooniswapBridge: NULL_ADDRESS, |         mooniswapBridge: NULL_ADDRESS, | ||||||
|  |         sushiswapBridge: NULL_ADDRESS, | ||||||
|         exchangeProxy: exchangeProxy.address, |         exchangeProxy: exchangeProxy.address, | ||||||
|         exchangeProxyAllowanceTarget: exchangeProxyAllowanceTargetAddress, |         exchangeProxyAllowanceTarget: exchangeProxyAllowanceTargetAddress, | ||||||
|         exchangeProxyTransformerDeployer: txDefaults.from, |         exchangeProxyTransformerDeployer: txDefaults.from, | ||||||
|   | |||||||
| @@ -70,6 +70,7 @@ export const docGenConfigs: DocGenConfigs = { | |||||||
|         'MultiAssetData', |         'MultiAssetData', | ||||||
|         'StaticCallAssetData', |         'StaticCallAssetData', | ||||||
|         'MultiAssetDataWithRecursiveDecoding', |         'MultiAssetDataWithRecursiveDecoding', | ||||||
|  |         'OrderPrunerPermittedFeeTypes', | ||||||
|     ], |     ], | ||||||
|     // Some libraries only export types. In those cases, we cannot check if the exported types are part of the |     // Some libraries only export types. In those cases, we cannot check if the exported types are part of the | ||||||
|     // "exported public interface". Thus we add them here and skip those checks. |     // "exported public interface". Thus we add them here and skip those checks. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user