feat: DODO V2, Linkswap (#152)
* feat: DODO V2 * Fix typo * feat: Linkswap (#153) * fix: intermediate hops WBTC (#154) * feat: Linkswap * fix: Re-add WBTC in default hop tokens * Update review changes * FQT deploy + no gas limit ETH refund (#155) * `@0x/contracts-zero-ex`: refund ETH with no gas limit in FQT `@0x/contract-addresses`: Deploy FQT * Update packages/contract-addresses/CHANGELOG.json Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com> Co-authored-by: Lawrence Forman <me@merklejerk.com> Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com> Co-authored-by: Lawrence Forman <lawrence@0xproject.com> Co-authored-by: Lawrence Forman <me@merklejerk.com> Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com>
This commit is contained in:
parent
74b240fb88
commit
49cb00a9ab
@ -9,6 +9,18 @@
|
||||
{
|
||||
"note": "Export `CurveLiquidityProviderContract`",
|
||||
"pr": 144
|
||||
},
|
||||
{
|
||||
"note": "Add `DodoV2`",
|
||||
"pr": 152
|
||||
},
|
||||
{
|
||||
"note": "Add `Linkswap`",
|
||||
"pr": 153
|
||||
},
|
||||
{
|
||||
"note": "refund ETH with no gas limit in FQT",
|
||||
"pr": 155
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -273,13 +273,15 @@ contract FillQuoteTransformer is
|
||||
|
||||
// Refund unspent protocol fees.
|
||||
if (state.ethRemaining > 0 && data.refundReceiver != address(0)) {
|
||||
bool transferSuccess;
|
||||
if (data.refundReceiver == REFUND_RECEIVER_TAKER) {
|
||||
context.taker.transfer(state.ethRemaining);
|
||||
(transferSuccess,) = context.taker.call{value: state.ethRemaining}("");
|
||||
} else if (data.refundReceiver == REFUND_RECEIVER_SENDER) {
|
||||
context.sender.transfer(state.ethRemaining);
|
||||
(transferSuccess,) = context.sender.call{value: state.ethRemaining}("");
|
||||
} else {
|
||||
data.refundReceiver.transfer(state.ethRemaining);
|
||||
(transferSuccess,) = data.refundReceiver.call{value: state.ethRemaining}("");
|
||||
}
|
||||
require(transferSuccess, "FillQuoteTransformer/ETHER_TRANSFER_FALIED");
|
||||
}
|
||||
return LibERC20Transformer.TRANSFORMER_SUCCESS;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import "./mixins/MixinCoFiX.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinCryptoCom.sol";
|
||||
import "./mixins/MixinDodo.sol";
|
||||
import "./mixins/MixinDodoV2.sol";
|
||||
import "./mixins/MixinKyber.sol";
|
||||
import "./mixins/MixinMooniswap.sol";
|
||||
import "./mixins/MixinMStable.sol";
|
||||
@ -46,6 +47,7 @@ contract BridgeAdapter is
|
||||
MixinCurve,
|
||||
MixinCryptoCom,
|
||||
MixinDodo,
|
||||
MixinDodoV2,
|
||||
MixinKyber,
|
||||
MixinMooniswap,
|
||||
MixinMStable,
|
||||
@ -64,6 +66,7 @@ contract BridgeAdapter is
|
||||
MixinCurve()
|
||||
MixinCryptoCom()
|
||||
MixinDodo()
|
||||
MixinDodoV2()
|
||||
MixinKyber(weth)
|
||||
MixinMooniswap(weth)
|
||||
MixinMStable()
|
||||
@ -100,7 +103,8 @@ contract BridgeAdapter is
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (order.source == BridgeSource.UNISWAPV2) {
|
||||
} else if (order.source == BridgeSource.UNISWAPV2 ||
|
||||
order.source == BridgeSource.LINKSWAP) {
|
||||
boughtAmount = _tradeUniswapV2(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
@ -162,6 +166,12 @@ contract BridgeAdapter is
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (order.source == BridgeSource.DODOV2) {
|
||||
boughtAmount = _tradeDodoV2(
|
||||
sellToken,
|
||||
sellAmount,
|
||||
order.bridgeData
|
||||
);
|
||||
} else if (order.source == BridgeSource.CRYPTOCOM) {
|
||||
boughtAmount = _tradeCryptoCom(
|
||||
buyToken,
|
||||
|
@ -40,6 +40,8 @@ library BridgeSource {
|
||||
uint256 constant internal SWERVE = 15;
|
||||
uint256 constant internal UNISWAP = 16;
|
||||
uint256 constant internal UNISWAPV2 = 17;
|
||||
uint256 constant internal DODOV2 = 18;
|
||||
uint256 constant internal LINKSWAP = 19;
|
||||
// New sources should be APPENDED to this list, taking the next highest
|
||||
// integer value.
|
||||
}
|
||||
|
@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2021 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 "../IBridgeAdapter.sol";
|
||||
|
||||
|
||||
interface IDODOV2 {
|
||||
function sellBase(address recipient)
|
||||
external
|
||||
returns (uint256);
|
||||
|
||||
function sellQuote(address recipient)
|
||||
external
|
||||
returns (uint256);
|
||||
}
|
||||
|
||||
|
||||
contract MixinDodoV2 {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
function _tradeDodoV2(
|
||||
IERC20TokenV06 sellToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
(IDODOV2 pool, bool isSellBase) =
|
||||
abi.decode(bridgeData, (IDODOV2, bool));
|
||||
|
||||
// Transfer the tokens into the pool
|
||||
sellToken.compatTransfer(address(pool), sellAmount);
|
||||
|
||||
boughtAmount = isSellBase ?
|
||||
pool.sellBase(address(this))
|
||||
: pool.sellQuote(address(this));
|
||||
}
|
||||
}
|
@ -43,7 +43,7 @@
|
||||
"config": {
|
||||
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITokenSpenderFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,TokenSpenderFeature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|BridgeSource|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|INativeOrdersFeature|IOwnableFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|NativeOrdersFeature|OwnableFeature|PayTakerTransformer|PermissionlessTransformerDeployer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestNativeOrdersFeature|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json"
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|BridgeSource|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|INativeOrdersFeature|IOwnableFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinDodoV2|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|NativeOrdersFeature|OwnableFeature|PayTakerTransformer|PermissionlessTransformerDeployer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestNativeOrdersFeature|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -78,6 +78,7 @@ import * as MixinCoFiX from '../test/generated-artifacts/MixinCoFiX.json';
|
||||
import * as MixinCryptoCom from '../test/generated-artifacts/MixinCryptoCom.json';
|
||||
import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json';
|
||||
import * as MixinDodo from '../test/generated-artifacts/MixinDodo.json';
|
||||
import * as MixinDodoV2 from '../test/generated-artifacts/MixinDodoV2.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';
|
||||
@ -219,6 +220,7 @@ export const artifacts = {
|
||||
MixinCryptoCom: MixinCryptoCom as ContractArtifact,
|
||||
MixinCurve: MixinCurve as ContractArtifact,
|
||||
MixinDodo: MixinDodo as ContractArtifact,
|
||||
MixinDodoV2: MixinDodoV2 as ContractArtifact,
|
||||
MixinKyber: MixinKyber as ContractArtifact,
|
||||
MixinMStable: MixinMStable as ContractArtifact,
|
||||
MixinMooniswap: MixinMooniswap as ContractArtifact,
|
||||
|
@ -76,6 +76,7 @@ export * from '../test/generated-wrappers/mixin_co_fi_x';
|
||||
export * from '../test/generated-wrappers/mixin_crypto_com';
|
||||
export * from '../test/generated-wrappers/mixin_curve';
|
||||
export * from '../test/generated-wrappers/mixin_dodo';
|
||||
export * from '../test/generated-wrappers/mixin_dodo_v2';
|
||||
export * from '../test/generated-wrappers/mixin_kyber';
|
||||
export * from '../test/generated-wrappers/mixin_m_stable';
|
||||
export * from '../test/generated-wrappers/mixin_mooniswap';
|
||||
|
@ -105,6 +105,7 @@
|
||||
"test/generated-artifacts/MixinCryptoCom.json",
|
||||
"test/generated-artifacts/MixinCurve.json",
|
||||
"test/generated-artifacts/MixinDodo.json",
|
||||
"test/generated-artifacts/MixinDodoV2.json",
|
||||
"test/generated-artifacts/MixinKyber.json",
|
||||
"test/generated-artifacts/MixinMStable.json",
|
||||
"test/generated-artifacts/MixinMooniswap.json",
|
||||
|
@ -34,6 +34,18 @@
|
||||
"note": "Create `FakeTaker` contract to get result data and gas used",
|
||||
"pr": 151
|
||||
},
|
||||
{
|
||||
"note": "Added support for `Dodo` v2",
|
||||
"pr": 152
|
||||
},
|
||||
{
|
||||
"note": "Added support for `Linkswap`",
|
||||
"pr": 153
|
||||
},
|
||||
{
|
||||
"note": "Re-add WBTC in default intermediate hops",
|
||||
"pr": 154
|
||||
},
|
||||
{
|
||||
"note": "Add an alternative RFQ market making implementation",
|
||||
"pr": 139
|
||||
|
206
packages/asset-swapper/contracts/src/DODOV2Sampler.sol
Normal file
206
packages/asset-swapper/contracts/src/DODOV2Sampler.sol
Normal file
@ -0,0 +1,206 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2021 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;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./DeploymentConstants.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
interface IDODOV2Registry {
|
||||
function getDODOPool(address baseToken, address quoteToken)
|
||||
external
|
||||
view
|
||||
returns (address[] memory machines);
|
||||
}
|
||||
|
||||
interface IDODOV2Pool {
|
||||
function querySellBase(address trader, uint256 payBaseAmount)
|
||||
external
|
||||
view
|
||||
returns (uint256 receiveQuoteAmount, uint256 mtFee);
|
||||
|
||||
function querySellQuote(address trader, uint256 payQuoteAmount)
|
||||
external
|
||||
view
|
||||
returns (uint256 receiveBaseAmount, uint256 mtFee);
|
||||
}
|
||||
|
||||
contract DODOV2Sampler is
|
||||
DeploymentConstants,
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
|
||||
/// @dev Gas limit for DODO V2 calls.
|
||||
uint256 constant private DODO_V2_CALL_GAS = 300e3; // 300k
|
||||
|
||||
/// @dev Sample sell quotes from DODO V2.
|
||||
/// @param registry Address of the registry to look up.
|
||||
/// @param offset offset index for the pool in the registry.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return sellBase whether the bridge needs to sell the base token
|
||||
/// @return pool the DODO pool address
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromDODOV2(
|
||||
address registry,
|
||||
uint256 offset,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool sellBase, address pool, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
(pool, sellBase) = _getNextDODOV2Pool(registry, offset, takerToken, makerToken);
|
||||
if (pool == address(0)) {
|
||||
return (sellBase, pool, makerTokenAmounts);
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
uint256 buyAmount = _sampleSellForApproximateBuyFromDODOV2(
|
||||
abi.encode(takerToken, pool, sellBase), // taker token data
|
||||
abi.encode(makerToken, pool, sellBase), // maker token data
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
// Exit early if the amount is too high for the source to serve
|
||||
if (buyAmount == 0) {
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from DODO.
|
||||
/// @param registry Address of the registry to look up.
|
||||
/// @param offset offset index for the pool in the registry.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token sell amount for each sample.
|
||||
/// @return sellBase whether the bridge needs to sell the base token
|
||||
/// @return pool the DODO pool address
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromDODOV2(
|
||||
address registry,
|
||||
uint256 offset,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool sellBase, address pool, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
(pool, sellBase) = _getNextDODOV2Pool(registry, offset, takerToken, makerToken);
|
||||
if (pool == address(0)) {
|
||||
return (sellBase, pool, takerTokenAmounts);
|
||||
}
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, pool, !sellBase),
|
||||
takerTokenData: abi.encode(takerToken, pool, sellBase),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromDODOV2
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
function _sampleSellForApproximateBuyFromDODOV2(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory /* makerTokenData */,
|
||||
uint256 sellAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
(address takerToken, address pool, bool sellBase) = abi.decode(
|
||||
takerTokenData,
|
||||
(address, address, bool)
|
||||
);
|
||||
|
||||
// We will get called to sell both the taker token and also to sell the maker token
|
||||
// since we use approximate buy for sell and buy functions
|
||||
if (sellBase) {
|
||||
try
|
||||
IDODOV2Pool(pool).querySellBase
|
||||
{ gas: DODO_V2_CALL_GAS }
|
||||
(address(0), sellAmount)
|
||||
returns (uint256 amount, uint256)
|
||||
{
|
||||
return amount;
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
try
|
||||
IDODOV2Pool(pool).querySellQuote
|
||||
{ gas: DODO_V2_CALL_GAS }
|
||||
(address(0), sellAmount)
|
||||
returns (uint256 amount, uint256)
|
||||
{
|
||||
return amount;
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _getNextDODOV2Pool(
|
||||
address registry,
|
||||
uint256 offset,
|
||||
address takerToken,
|
||||
address makerToken
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (address machine, bool sellBase)
|
||||
{
|
||||
// Query in base -> quote direction, if a pool is found then we are selling the base
|
||||
address[] memory machines = IDODOV2Registry(registry).getDODOPool(takerToken, makerToken);
|
||||
sellBase = true;
|
||||
if (machines.length == 0) {
|
||||
// Query in quote -> base direction, if a pool is found then we are selling the quote
|
||||
machines = IDODOV2Registry(registry).getDODOPool(makerToken, takerToken);
|
||||
sellBase = false;
|
||||
}
|
||||
|
||||
if (offset >= machines.length) {
|
||||
return (address(0), false);
|
||||
}
|
||||
|
||||
machine = machines[offset];
|
||||
}
|
||||
|
||||
}
|
@ -24,6 +24,7 @@ import "./BalancerSampler.sol";
|
||||
import "./BancorSampler.sol";
|
||||
import "./CurveSampler.sol";
|
||||
import "./DODOSampler.sol";
|
||||
import "./DODOV2Sampler.sol";
|
||||
import "./Eth2DaiSampler.sol";
|
||||
import "./KyberSampler.sol";
|
||||
import "./LiquidityProviderSampler.sol";
|
||||
@ -44,6 +45,7 @@ contract ERC20BridgeSampler is
|
||||
BancorSampler,
|
||||
CurveSampler,
|
||||
DODOSampler,
|
||||
DODOV2Sampler,
|
||||
Eth2DaiSampler,
|
||||
KyberSampler,
|
||||
LiquidityProviderSampler,
|
||||
|
@ -38,7 +38,7 @@
|
||||
"config": {
|
||||
"publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BancorSampler|CurveSampler|DODOSampler|DeploymentConstants|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|FakeTaker|IBalancer|IBancor|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UtilitySampler).json",
|
||||
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BancorSampler|CurveSampler|DODOSampler|DODOV2Sampler|DeploymentConstants|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|FakeTaker|IBalancer|IBancor|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UtilitySampler).json",
|
||||
"postpublish": {
|
||||
"assets": []
|
||||
}
|
||||
|
@ -1,6 +1,47 @@
|
||||
import { MAINNET_CURVE_INFOS, MAINNET_SNOWSWAP_INFOS, MAINNET_SWERVE_INFOS } from './constants';
|
||||
import { BigNumber, NULL_BYTES } from '@0x/utils';
|
||||
|
||||
import {
|
||||
KYBER_BRIDGED_LIQUIDITY_PREFIX,
|
||||
MAINNET_CURVE_INFOS,
|
||||
MAINNET_SHELL_POOLS,
|
||||
MAINNET_SNOWSWAP_INFOS,
|
||||
MAINNET_SWERVE_INFOS,
|
||||
MAX_DODOV2_POOLS_QUERIED,
|
||||
MAX_KYBER_RESERVES_QUERIED,
|
||||
} from './constants';
|
||||
import { CurveInfo, SnowSwapInfo, SwerveInfo } from './types';
|
||||
|
||||
/**
|
||||
* Filter Kyber reserves which should not be used (0xbb bridged reserves)
|
||||
* @param reserveId Kyber reserveId
|
||||
*/
|
||||
export function isAllowedKyberReserveId(reserveId: string): boolean {
|
||||
return reserveId !== NULL_BYTES && !reserveId.startsWith(KYBER_BRIDGED_LIQUIDITY_PREFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offsets to be used to discover Kyber reserves
|
||||
*/
|
||||
export function getKyberOffsets(): BigNumber[] {
|
||||
return Array(MAX_KYBER_RESERVES_QUERIED)
|
||||
.fill(0)
|
||||
.map((_v, i) => new BigNumber(i));
|
||||
}
|
||||
|
||||
// tslint:disable completed-docs
|
||||
export function getDodoV2Offsets(): BigNumber[] {
|
||||
return Array(MAX_DODOV2_POOLS_QUERIED)
|
||||
.fill(0)
|
||||
.map((_v, i) => new BigNumber(i));
|
||||
}
|
||||
|
||||
// tslint:disable completed-docs
|
||||
export function getShellsForPair(takerToken: string, makerToken: string): string[] {
|
||||
return Object.values(MAINNET_SHELL_POOLS)
|
||||
.filter(c => [makerToken, takerToken].every(t => c.tokens.includes(t)))
|
||||
.map(i => i.poolAddress);
|
||||
}
|
||||
|
||||
// tslint:disable completed-docs
|
||||
export function getCurveInfosForPair(takerToken: string, makerToken: string): CurveInfo[] {
|
||||
return Object.values(MAINNET_CURVE_INFOS).filter(c =>
|
@ -58,9 +58,11 @@ export const SELL_SOURCE_FILTER = new SourceFilters([
|
||||
ERC20BridgeSource.Shell,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
ERC20BridgeSource.Dodo,
|
||||
ERC20BridgeSource.DodoV2,
|
||||
ERC20BridgeSource.Cream,
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
ERC20BridgeSource.CryptoCom,
|
||||
ERC20BridgeSource.Linkswap,
|
||||
]);
|
||||
|
||||
/**
|
||||
@ -83,9 +85,11 @@ export const BUY_SOURCE_FILTER = new SourceFilters([
|
||||
ERC20BridgeSource.SushiSwap,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
ERC20BridgeSource.Dodo,
|
||||
ERC20BridgeSource.DodoV2,
|
||||
ERC20BridgeSource.Cream,
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
ERC20BridgeSource.CryptoCom,
|
||||
ERC20BridgeSource.Linkswap,
|
||||
]);
|
||||
|
||||
/**
|
||||
@ -155,6 +159,7 @@ export const TOKENS = {
|
||||
EURS: '0xdb25f211ab05b1c97d595516f45794528a807ad8',
|
||||
sEUR: '0xd71ecff9342a5ced620049e616c5035f1db98620',
|
||||
sETH: '0x5e74c9036fb86bd7ecdcb084a0673efc32ea31cb',
|
||||
LINK: '0x514910771af9ca656af840dff83e8264ecf986ca',
|
||||
// Mirror Protocol
|
||||
UST: '0xa47c8bf37f92abed4a126bda807a7b7498661acd',
|
||||
MIR: '0x09a3ecafa817268f77be1283176b946c4ff2e608',
|
||||
@ -190,7 +195,7 @@ export const POOLS = {
|
||||
curve_aave: '0xdebf20617708857ebe4f679508e7b7863a8a8eee', // 25.aave
|
||||
};
|
||||
|
||||
export const DEFAULT_INTERMEDIATE_TOKENS = [TOKENS.WETH, TOKENS.USDT, TOKENS.DAI, TOKENS.USDC];
|
||||
export const DEFAULT_INTERMEDIATE_TOKENS = [TOKENS.WETH, TOKENS.USDT, TOKENS.DAI, TOKENS.USDC, TOKENS.WBTC];
|
||||
|
||||
export const DEFAULT_TOKEN_ADJACENCY_GRAPH: TokenAdjacencyGraph = new TokenAdjacencyGraphBuilder({
|
||||
default: DEFAULT_INTERMEDIATE_TOKENS,
|
||||
@ -463,6 +468,8 @@ export const MAINNET_UNISWAP_V1_ROUTER = '0xc0a47dfe034b400b47bdad5fecda2621de6c
|
||||
export const MAINNET_UNISWAP_V2_ROUTER = '0xf164fc0ec4e93095b804a4795bbe1e041497b92a';
|
||||
export const MAINNET_SUSHI_SWAP_ROUTER = '0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f';
|
||||
export const MAINNET_CRYPTO_COM_ROUTER = '0xceb90e4c17d626be0facd78b79c9c87d7ca181b3';
|
||||
export const MAINNET_LINKSWAP_ROUTER = '0xa7ece0911fe8c60bff9e99f8fafcdbe56e07aff1';
|
||||
|
||||
export const MAINNET_MSTABLE_ROUTER = '0xe2f2a5c287993345a840db3b0845fbc70f5935a5';
|
||||
export const MAINNET_OASIS_ROUTER = '0x794e6e91555438afc3ccf1c5076a74f42133d08d';
|
||||
|
||||
@ -471,6 +478,9 @@ export const MAINNET_MOONISWAP_V2_REGISTRY = '0xc4a8b7e29e3c8ec560cd4945c1cf3461
|
||||
export const MAINNET_MOONISWAP_V2_1_REGISTRY = '0xbaf9a5d4b0052359326a6cdab54babaa3a3a9643';
|
||||
|
||||
export const MAINNET_DODO_HELPER = '0x533da777aedce766ceae696bf90f8541a4ba80eb';
|
||||
export const MAINNET_DODOV2_PRIVATE_POOL_FACTORY = '0x6b4fa0bc61eddc928e0df9c7f01e407bfcd3e5ef';
|
||||
export const MAINNET_DODOV2_VENDING_MACHINE_FACTORY = '0x72d220ce168c4f361dd4dee5d826a01ad8598f6c';
|
||||
export const MAX_DODOV2_POOLS_QUERIED = 3;
|
||||
|
||||
export const CURVE_LIQUIDITY_PROVIDER_BY_CHAIN_ID: { [id: string]: string } = {
|
||||
'1': '0x7a6F6a048fE2Dc1397ABa0bf7879d3eacF371C53',
|
||||
@ -574,8 +584,17 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
|
||||
},
|
||||
[ERC20BridgeSource.CryptoCom]: (fillData?: FillData) => {
|
||||
// TODO: Different base cost if to/from ETH.
|
||||
let gas = 90e3 + 20e3 + 60e3; // temporary allowance diff, unrolled FQT
|
||||
const path = (fillData as SushiSwapFillData).tokenAddressPath;
|
||||
let gas = 90e3;
|
||||
const path = (fillData as UniswapV2FillData).tokenAddressPath;
|
||||
if (path.length > 2) {
|
||||
gas += (path.length - 2) * 60e3; // +60k for each hop.
|
||||
}
|
||||
return gas;
|
||||
},
|
||||
[ERC20BridgeSource.Linkswap]: (fillData?: FillData) => {
|
||||
// TODO: Different base cost if to/from ETH.
|
||||
let gas = 90e3;
|
||||
const path = (fillData as UniswapV2FillData).tokenAddressPath;
|
||||
if (path.length > 2) {
|
||||
gas += (path.length - 2) * 60e3; // +60k for each hop.
|
||||
}
|
||||
@ -603,6 +622,7 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
|
||||
// sell quote requires additional calculation and overhead
|
||||
return isSellBase ? 180e3 : 300e3;
|
||||
},
|
||||
[ERC20BridgeSource.DodoV2]: (_fillData?: FillData) => 100e3,
|
||||
[ERC20BridgeSource.SnowSwap]: fillData => {
|
||||
switch ((fillData as SnowSwapFillData).pool.poolAddress.toLowerCase()) {
|
||||
case '0xbf7ccd6c446acfcc5df023043f2167b62e81899b':
|
||||
|
@ -1,20 +0,0 @@
|
||||
import { BigNumber, NULL_BYTES } from '@0x/utils';
|
||||
|
||||
import { KYBER_BRIDGED_LIQUIDITY_PREFIX, MAX_KYBER_RESERVES_QUERIED } from './constants';
|
||||
|
||||
/**
|
||||
* Filter Kyber reserves which should not be used (0xbb bridged reserves)
|
||||
* @param reserveId Kyber reserveId
|
||||
*/
|
||||
export function isAllowedKyberReserveId(reserveId: string): boolean {
|
||||
return reserveId !== NULL_BYTES && !reserveId.startsWith(KYBER_BRIDGED_LIQUIDITY_PREFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offsets to be used to discover Kyber reserves
|
||||
*/
|
||||
export function getKyberOffsets(): BigNumber[] {
|
||||
return Array(MAX_KYBER_RESERVES_QUERIED)
|
||||
.fill(0)
|
||||
.map((_v, i) => new BigNumber(i));
|
||||
}
|
@ -118,6 +118,10 @@ export function getERC20BridgeSourceToBridgeSource(source: ERC20BridgeSource): B
|
||||
return BridgeSource.Uniswap;
|
||||
case ERC20BridgeSource.UniswapV2:
|
||||
return BridgeSource.UniswapV2;
|
||||
case ERC20BridgeSource.DodoV2:
|
||||
return BridgeSource.DodoV2;
|
||||
case ERC20BridgeSource.Linkswap:
|
||||
return BridgeSource.Linkswap;
|
||||
default:
|
||||
throw new Error(AggregationError.NoBridgeForSource);
|
||||
}
|
||||
@ -164,6 +168,7 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
||||
case ERC20BridgeSource.UniswapV2:
|
||||
case ERC20BridgeSource.SushiSwap:
|
||||
case ERC20BridgeSource.CryptoCom:
|
||||
case ERC20BridgeSource.Linkswap:
|
||||
const uniswapV2FillData = (order as OptimizedMarketBridgeOrder<UniswapV2FillData | SushiSwapFillData>)
|
||||
.fillData;
|
||||
bridgeData = encoder.encode([uniswapV2FillData.router, uniswapV2FillData.tokenAddressPath]);
|
||||
@ -180,6 +185,10 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
||||
const dodoFillData = (order as OptimizedMarketBridgeOrder<DODOFillData>).fillData;
|
||||
bridgeData = encoder.encode([MAINNET_DODO_HELPER, dodoFillData.poolAddress, dodoFillData.isSellBase]);
|
||||
break;
|
||||
case ERC20BridgeSource.DodoV2:
|
||||
const dodoV2FillData = (order as OptimizedMarketBridgeOrder<DODOFillData>).fillData;
|
||||
bridgeData = encoder.encode([dodoV2FillData.poolAddress, dodoV2FillData.isSellBase]);
|
||||
break;
|
||||
case ERC20BridgeSource.Shell:
|
||||
const shellFillData = (order as OptimizedMarketBridgeOrder<ShellFillData>).fillData;
|
||||
bridgeData = encoder.encode([shellFillData.poolAddress]);
|
||||
@ -258,6 +267,10 @@ export const BRIDGE_ENCODERS: {
|
||||
{ name: 'poolAddress', type: 'address' },
|
||||
{ name: 'isSellBase', type: 'bool' },
|
||||
]),
|
||||
[ERC20BridgeSource.DodoV2]: AbiEncoder.create([
|
||||
{ name: 'poolAddress', type: 'address' },
|
||||
{ name: 'isSellBase', type: 'bool' },
|
||||
]),
|
||||
// Curve like
|
||||
[ERC20BridgeSource.Curve]: curveEncoder,
|
||||
[ERC20BridgeSource.Swerve]: curveEncoder,
|
||||
@ -267,6 +280,7 @@ export const BRIDGE_ENCODERS: {
|
||||
[ERC20BridgeSource.UniswapV2]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.SushiSwap]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.CryptoCom]: routerAddressPathEncoder,
|
||||
[ERC20BridgeSource.Linkswap]: routerAddressPathEncoder,
|
||||
// Generic pools
|
||||
[ERC20BridgeSource.Shell]: poolEncoder,
|
||||
[ERC20BridgeSource.Mooniswap]: poolEncoder,
|
||||
|
@ -7,20 +7,30 @@ import { ERC20BridgeSamplerContract } from '../../wrappers';
|
||||
|
||||
import { BalancerPoolsCache } from './balancer_utils';
|
||||
import { BancorService } from './bancor_service';
|
||||
import {
|
||||
getCurveInfosForPair,
|
||||
getDodoV2Offsets,
|
||||
getKyberOffsets,
|
||||
getSnowSwapInfosForPair,
|
||||
getSwerveInfosForPair,
|
||||
isAllowedKyberReserveId,
|
||||
} from './bridge_source_utils';
|
||||
import {
|
||||
LIQUIDITY_PROVIDER_REGISTRY,
|
||||
MAINNET_CRYPTO_COM_ROUTER,
|
||||
MAINNET_DODOV2_PRIVATE_POOL_FACTORY,
|
||||
MAINNET_DODOV2_VENDING_MACHINE_FACTORY,
|
||||
MAINNET_LINKSWAP_ROUTER,
|
||||
MAINNET_MOONISWAP_REGISTRY,
|
||||
MAINNET_MOONISWAP_V2_1_REGISTRY,
|
||||
MAINNET_MOONISWAP_V2_REGISTRY,
|
||||
MAINNET_SUSHI_SWAP_ROUTER,
|
||||
MAINNET_UNISWAP_V2_ROUTER,
|
||||
MAX_UINT256,
|
||||
TOKENS,
|
||||
ZERO_AMOUNT,
|
||||
} from './constants';
|
||||
import { CreamPoolsCache } from './cream_utils';
|
||||
import { getCurveInfosForPair, getSnowSwapInfosForPair, getSwerveInfosForPair } from './curve_utils';
|
||||
import { getKyberOffsets, isAllowedKyberReserveId } from './kyber_utils';
|
||||
import { getLiquidityProvidersForPair } from './liquidity_provider_utils';
|
||||
import { getIntermediateTokens } from './multihop_utils';
|
||||
import { SamplerContractOperation } from './sampler_contract_operation';
|
||||
@ -212,28 +222,32 @@ export class SamplerOperations {
|
||||
}
|
||||
|
||||
public getUniswapV2SellQuotes(
|
||||
router: string,
|
||||
tokenAddressPath: string[],
|
||||
takerFillAmounts: BigNumber[],
|
||||
source: ERC20BridgeSource = ERC20BridgeSource.UniswapV2,
|
||||
): SourceQuoteOperation<UniswapV2FillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.UniswapV2,
|
||||
fillData: { tokenAddressPath, router: MAINNET_UNISWAP_V2_ROUTER },
|
||||
source,
|
||||
fillData: { tokenAddressPath, router },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromUniswapV2,
|
||||
params: [MAINNET_UNISWAP_V2_ROUTER, tokenAddressPath, takerFillAmounts],
|
||||
params: [router, tokenAddressPath, takerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getUniswapV2BuyQuotes(
|
||||
router: string,
|
||||
tokenAddressPath: string[],
|
||||
makerFillAmounts: BigNumber[],
|
||||
source: ERC20BridgeSource = ERC20BridgeSource.UniswapV2,
|
||||
): SourceQuoteOperation<UniswapV2FillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.UniswapV2,
|
||||
fillData: { tokenAddressPath, router: MAINNET_UNISWAP_V2_ROUTER },
|
||||
source,
|
||||
fillData: { tokenAddressPath, router },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromUniswapV2,
|
||||
params: [MAINNET_UNISWAP_V2_ROUTER, tokenAddressPath, makerFillAmounts],
|
||||
params: [router, tokenAddressPath, makerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
@ -819,32 +833,6 @@ export class SamplerOperations {
|
||||
});
|
||||
}
|
||||
|
||||
public getCryptoComSellQuotes(
|
||||
tokenAddressPath: string[],
|
||||
takerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<SushiSwapFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.CryptoCom,
|
||||
fillData: { tokenAddressPath, router: MAINNET_CRYPTO_COM_ROUTER },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromSushiSwap,
|
||||
params: [MAINNET_CRYPTO_COM_ROUTER, tokenAddressPath, takerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getCryptoComBuyQuotes(
|
||||
tokenAddressPath: string[],
|
||||
makerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<SushiSwapFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.CryptoCom,
|
||||
fillData: { tokenAddressPath, router: MAINNET_CRYPTO_COM_ROUTER },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromSushiSwap,
|
||||
params: [MAINNET_CRYPTO_COM_ROUTER, tokenAddressPath, makerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getShellSellQuotes(
|
||||
poolAddress: string,
|
||||
makerToken: string,
|
||||
@ -917,6 +905,52 @@ export class SamplerOperations {
|
||||
});
|
||||
}
|
||||
|
||||
public getDODOV2SellQuotes(
|
||||
registry: string,
|
||||
offset: BigNumber,
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<DODOFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.DodoV2,
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromDODOV2,
|
||||
params: [registry, offset, takerToken, makerToken, takerFillAmounts],
|
||||
callback: (callResults: string, fillData: DODOFillData): BigNumber[] => {
|
||||
const [isSellBase, pool, samples] = this._samplerContract.getABIDecodedReturnData<
|
||||
[boolean, string, BigNumber[]]
|
||||
>('sampleSellsFromDODOV2', callResults);
|
||||
fillData.isSellBase = isSellBase;
|
||||
fillData.poolAddress = pool;
|
||||
return samples;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public getDODOV2BuyQuotes(
|
||||
registry: string,
|
||||
offset: BigNumber,
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<DODOFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.DodoV2,
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromDODOV2,
|
||||
params: [registry, offset, takerToken, makerToken, makerFillAmounts],
|
||||
callback: (callResults: string, fillData: DODOFillData): BigNumber[] => {
|
||||
const [isSellBase, pool, samples] = this._samplerContract.getABIDecodedReturnData<
|
||||
[boolean, string, BigNumber[]]
|
||||
>('sampleSellsFromDODOV2', callResults);
|
||||
fillData.isSellBase = isSellBase;
|
||||
fillData.poolAddress = pool;
|
||||
return samples;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public getMedianSellRate(
|
||||
sources: ERC20BridgeSource[],
|
||||
makerToken: string,
|
||||
@ -1015,9 +1049,21 @@ export class SamplerOperations {
|
||||
case ERC20BridgeSource.Uniswap:
|
||||
return this.getUniswapSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||
case ERC20BridgeSource.UniswapV2:
|
||||
const ops = [this.getUniswapV2SellQuotes([takerToken, makerToken], takerFillAmounts)];
|
||||
const ops = [
|
||||
this.getUniswapV2SellQuotes(
|
||||
MAINNET_UNISWAP_V2_ROUTER,
|
||||
[takerToken, makerToken],
|
||||
takerFillAmounts,
|
||||
),
|
||||
];
|
||||
intermediateTokens.forEach(t => {
|
||||
ops.push(this.getUniswapV2SellQuotes([takerToken, t, makerToken], takerFillAmounts));
|
||||
ops.push(
|
||||
this.getUniswapV2SellQuotes(
|
||||
MAINNET_UNISWAP_V2_ROUTER,
|
||||
[takerToken, t, makerToken],
|
||||
takerFillAmounts,
|
||||
),
|
||||
);
|
||||
});
|
||||
return ops;
|
||||
case ERC20BridgeSource.SushiSwap:
|
||||
@ -1030,11 +1076,21 @@ export class SamplerOperations {
|
||||
return sushiOps;
|
||||
case ERC20BridgeSource.CryptoCom:
|
||||
const cryptoComOps = [
|
||||
this.getCryptoComSellQuotes([takerToken, makerToken], takerFillAmounts),
|
||||
this.getUniswapV2SellQuotes(
|
||||
MAINNET_CRYPTO_COM_ROUTER,
|
||||
[takerToken, makerToken],
|
||||
takerFillAmounts,
|
||||
ERC20BridgeSource.CryptoCom,
|
||||
),
|
||||
];
|
||||
intermediateTokens.forEach(t => {
|
||||
cryptoComOps.push(
|
||||
this.getCryptoComSellQuotes([takerToken, t, makerToken], takerFillAmounts),
|
||||
this.getUniswapV2SellQuotes(
|
||||
MAINNET_CRYPTO_COM_ROUTER,
|
||||
[takerToken, t, makerToken],
|
||||
takerFillAmounts,
|
||||
ERC20BridgeSource.CryptoCom,
|
||||
),
|
||||
);
|
||||
});
|
||||
return cryptoComOps;
|
||||
@ -1119,8 +1175,52 @@ export class SamplerOperations {
|
||||
);
|
||||
case ERC20BridgeSource.Dodo:
|
||||
return this.getDODOSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||
case ERC20BridgeSource.DodoV2:
|
||||
return [
|
||||
...getDodoV2Offsets().map(offset =>
|
||||
this.getDODOV2SellQuotes(
|
||||
MAINNET_DODOV2_PRIVATE_POOL_FACTORY,
|
||||
offset,
|
||||
makerToken,
|
||||
takerToken,
|
||||
takerFillAmounts,
|
||||
),
|
||||
),
|
||||
...getDodoV2Offsets().map(offset =>
|
||||
this.getDODOV2SellQuotes(
|
||||
MAINNET_DODOV2_VENDING_MACHINE_FACTORY,
|
||||
offset,
|
||||
makerToken,
|
||||
takerToken,
|
||||
takerFillAmounts,
|
||||
),
|
||||
),
|
||||
];
|
||||
case ERC20BridgeSource.Bancor:
|
||||
return this.getBancorSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||
case ERC20BridgeSource.Linkswap:
|
||||
const linkOps = [
|
||||
this.getUniswapV2SellQuotes(
|
||||
MAINNET_LINKSWAP_ROUTER,
|
||||
[takerToken, makerToken],
|
||||
takerFillAmounts,
|
||||
ERC20BridgeSource.Linkswap,
|
||||
),
|
||||
];
|
||||
// LINK is the base asset in many of the pools on Linkswap
|
||||
getIntermediateTokens(makerToken, takerToken, {
|
||||
default: [TOKENS.LINK, TOKENS.WETH],
|
||||
}).forEach(t => {
|
||||
linkOps.push(
|
||||
this.getUniswapV2SellQuotes(
|
||||
MAINNET_LINKSWAP_ROUTER,
|
||||
[takerToken, t, makerToken],
|
||||
takerFillAmounts,
|
||||
ERC20BridgeSource.Linkswap,
|
||||
),
|
||||
);
|
||||
});
|
||||
return linkOps;
|
||||
default:
|
||||
throw new Error(`Unsupported sell sample source: ${source}`);
|
||||
}
|
||||
@ -1148,9 +1248,21 @@ export class SamplerOperations {
|
||||
case ERC20BridgeSource.Uniswap:
|
||||
return this.getUniswapBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||
case ERC20BridgeSource.UniswapV2:
|
||||
const ops = [this.getUniswapV2BuyQuotes([takerToken, makerToken], makerFillAmounts)];
|
||||
const ops = [
|
||||
this.getUniswapV2BuyQuotes(
|
||||
MAINNET_UNISWAP_V2_ROUTER,
|
||||
[takerToken, makerToken],
|
||||
makerFillAmounts,
|
||||
),
|
||||
];
|
||||
intermediateTokens.forEach(t => {
|
||||
ops.push(this.getUniswapV2BuyQuotes([takerToken, t, makerToken], makerFillAmounts));
|
||||
ops.push(
|
||||
this.getUniswapV2BuyQuotes(
|
||||
MAINNET_UNISWAP_V2_ROUTER,
|
||||
[takerToken, t, makerToken],
|
||||
makerFillAmounts,
|
||||
),
|
||||
);
|
||||
});
|
||||
return ops;
|
||||
case ERC20BridgeSource.SushiSwap:
|
||||
@ -1163,11 +1275,21 @@ export class SamplerOperations {
|
||||
return sushiOps;
|
||||
case ERC20BridgeSource.CryptoCom:
|
||||
const cryptoComOps = [
|
||||
this.getCryptoComBuyQuotes([takerToken, makerToken], makerFillAmounts),
|
||||
this.getUniswapV2BuyQuotes(
|
||||
MAINNET_CRYPTO_COM_ROUTER,
|
||||
[takerToken, makerToken],
|
||||
makerFillAmounts,
|
||||
ERC20BridgeSource.CryptoCom,
|
||||
),
|
||||
];
|
||||
intermediateTokens.forEach(t => {
|
||||
cryptoComOps.push(
|
||||
this.getCryptoComBuyQuotes([takerToken, t, makerToken], makerFillAmounts),
|
||||
this.getUniswapV2BuyQuotes(
|
||||
MAINNET_CRYPTO_COM_ROUTER,
|
||||
[takerToken, t, makerToken],
|
||||
makerFillAmounts,
|
||||
ERC20BridgeSource.CryptoCom,
|
||||
),
|
||||
);
|
||||
});
|
||||
return cryptoComOps;
|
||||
@ -1252,8 +1374,52 @@ export class SamplerOperations {
|
||||
);
|
||||
case ERC20BridgeSource.Dodo:
|
||||
return this.getDODOBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||
case ERC20BridgeSource.DodoV2:
|
||||
return [
|
||||
...getDodoV2Offsets().map(offset =>
|
||||
this.getDODOV2BuyQuotes(
|
||||
MAINNET_DODOV2_PRIVATE_POOL_FACTORY,
|
||||
offset,
|
||||
makerToken,
|
||||
takerToken,
|
||||
makerFillAmounts,
|
||||
),
|
||||
),
|
||||
...getDodoV2Offsets().map(offset =>
|
||||
this.getDODOV2BuyQuotes(
|
||||
MAINNET_DODOV2_VENDING_MACHINE_FACTORY,
|
||||
offset,
|
||||
makerToken,
|
||||
takerToken,
|
||||
makerFillAmounts,
|
||||
),
|
||||
),
|
||||
];
|
||||
case ERC20BridgeSource.Bancor:
|
||||
return this.getBancorBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||
case ERC20BridgeSource.Linkswap:
|
||||
const linkOps = [
|
||||
this.getUniswapV2BuyQuotes(
|
||||
MAINNET_LINKSWAP_ROUTER,
|
||||
[takerToken, makerToken],
|
||||
makerFillAmounts,
|
||||
ERC20BridgeSource.Linkswap,
|
||||
),
|
||||
];
|
||||
// LINK is the base asset in many of the pools on Linkswap
|
||||
getIntermediateTokens(makerToken, takerToken, {
|
||||
default: [TOKENS.LINK, TOKENS.WETH],
|
||||
}).forEach(t => {
|
||||
linkOps.push(
|
||||
this.getUniswapV2BuyQuotes(
|
||||
MAINNET_LINKSWAP_ROUTER,
|
||||
[takerToken, t, makerToken],
|
||||
makerFillAmounts,
|
||||
ERC20BridgeSource.Linkswap,
|
||||
),
|
||||
);
|
||||
});
|
||||
return linkOps;
|
||||
default:
|
||||
throw new Error(`Unsupported buy sample source: ${source}`);
|
||||
}
|
||||
|
@ -54,7 +54,9 @@ export enum ERC20BridgeSource {
|
||||
SnowSwap = 'SnowSwap',
|
||||
SushiSwap = 'SushiSwap',
|
||||
Dodo = 'DODO',
|
||||
DodoV2 = 'DODO_V2',
|
||||
CryptoCom = 'CryptoCom',
|
||||
Linkswap = 'Linkswap',
|
||||
}
|
||||
|
||||
// tslint:disable: enum-naming
|
||||
|
@ -12,6 +12,7 @@ import * as BancorSampler from '../test/generated-artifacts/BancorSampler.json';
|
||||
import * as CurveSampler from '../test/generated-artifacts/CurveSampler.json';
|
||||
import * as DeploymentConstants from '../test/generated-artifacts/DeploymentConstants.json';
|
||||
import * as DODOSampler from '../test/generated-artifacts/DODOSampler.json';
|
||||
import * as DODOV2Sampler from '../test/generated-artifacts/DODOV2Sampler.json';
|
||||
import * as DummyLiquidityProvider from '../test/generated-artifacts/DummyLiquidityProvider.json';
|
||||
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
|
||||
import * as Eth2DaiSampler from '../test/generated-artifacts/Eth2DaiSampler.json';
|
||||
@ -49,6 +50,7 @@ export const artifacts = {
|
||||
BancorSampler: BancorSampler as ContractArtifact,
|
||||
CurveSampler: CurveSampler as ContractArtifact,
|
||||
DODOSampler: DODOSampler as ContractArtifact,
|
||||
DODOV2Sampler: DODOV2Sampler as ContractArtifact,
|
||||
DeploymentConstants: DeploymentConstants as ContractArtifact,
|
||||
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
|
||||
Eth2DaiSampler: Eth2DaiSampler as ContractArtifact,
|
||||
|
@ -343,6 +343,7 @@ describe('DexSampler tests', () => {
|
||||
);
|
||||
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getUniswapV2SellQuotes(
|
||||
NULL_ADDRESS,
|
||||
[expectedMakerToken, expectedTakerToken],
|
||||
expectedTakerFillAmounts,
|
||||
),
|
||||
|
@ -61,8 +61,10 @@ const DEFAULT_EXCLUDED = [
|
||||
ERC20BridgeSource.Shell,
|
||||
ERC20BridgeSource.Cream,
|
||||
ERC20BridgeSource.Dodo,
|
||||
ERC20BridgeSource.DodoV2,
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
ERC20BridgeSource.CryptoCom,
|
||||
ERC20BridgeSource.Linkswap,
|
||||
];
|
||||
const BUY_SOURCES = BUY_SOURCE_FILTER.sources;
|
||||
const SELL_SOURCES = SELL_SOURCE_FILTER.sources;
|
||||
@ -293,7 +295,9 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.Shell]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.Cream]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.Dodo]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.DodoV2]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.CryptoCom]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.Linkswap]: _.times(NUM_SAMPLES, () => 0),
|
||||
};
|
||||
|
||||
const DEFAULT_RATES: RatesBySource = {
|
||||
@ -353,7 +357,9 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.Shell]: { poolAddress: randomAddress() },
|
||||
[ERC20BridgeSource.Cream]: { poolAddress: randomAddress() },
|
||||
[ERC20BridgeSource.Dodo]: {},
|
||||
[ERC20BridgeSource.DodoV2]: {},
|
||||
[ERC20BridgeSource.CryptoCom]: { tokenAddressPath: [] },
|
||||
[ERC20BridgeSource.Linkswap]: { tokenAddressPath: [] },
|
||||
};
|
||||
|
||||
const DEFAULT_OPS = {
|
||||
|
@ -9,6 +9,7 @@ export * from '../test/generated-wrappers/balancer_sampler';
|
||||
export * from '../test/generated-wrappers/bancor_sampler';
|
||||
export * from '../test/generated-wrappers/curve_sampler';
|
||||
export * from '../test/generated-wrappers/d_o_d_o_sampler';
|
||||
export * from '../test/generated-wrappers/d_o_d_o_v2_sampler';
|
||||
export * from '../test/generated-wrappers/deployment_constants';
|
||||
export * from '../test/generated-wrappers/dummy_liquidity_provider';
|
||||
export * from '../test/generated-wrappers/erc20_bridge_sampler';
|
||||
|
@ -12,6 +12,7 @@
|
||||
"test/generated-artifacts/BancorSampler.json",
|
||||
"test/generated-artifacts/CurveSampler.json",
|
||||
"test/generated-artifacts/DODOSampler.json",
|
||||
"test/generated-artifacts/DODOV2Sampler.json",
|
||||
"test/generated-artifacts/DeploymentConstants.json",
|
||||
"test/generated-artifacts/DummyLiquidityProvider.json",
|
||||
"test/generated-artifacts/ERC20BridgeSampler.json",
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "5.11.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Deploy new FQT",
|
||||
"pr": 155
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "5.10.0",
|
||||
"changes": [
|
||||
|
@ -37,7 +37,7 @@
|
||||
"wethTransformer": "0xb2bc06a4efb20fc6553a69dbfa49b7be938034a7",
|
||||
"payTakerTransformer": "0x4638a7ebe75b911b995d0ec73a81e4f85f41f24e",
|
||||
"affiliateFeeTransformer": "0xda6d9fc5998f550a094585cf9171f0e8ee3ac59f",
|
||||
"fillQuoteTransformer": "0xfa6282736af206cb4cfc5cb786d82aecdf1186f9"
|
||||
"fillQuoteTransformer": "0x227e767a9b7517681d1cb6b846aa9e541484c7ab"
|
||||
}
|
||||
},
|
||||
"3": {
|
||||
@ -78,7 +78,7 @@
|
||||
"wethTransformer": "0x05ad19aa3826e0609a19568ffbd1dfe86c6c7184",
|
||||
"payTakerTransformer": "0x6d0ebf2bcd9cc93ec553b60ad201943dcca4e291",
|
||||
"affiliateFeeTransformer": "0x6588256778ca4432fa43983ac685c45efb2379e2",
|
||||
"fillQuoteTransformer": "0xd2a157fe2f72f5fb550826d93a9a57dcf51cc08f"
|
||||
"fillQuoteTransformer": "0x2088a820787ebbe937a0612ef024f1e1d65f9784"
|
||||
}
|
||||
},
|
||||
"4": {
|
||||
|
@ -5,6 +5,10 @@
|
||||
{
|
||||
"note": "Add VIP utils",
|
||||
"pr": 127
|
||||
},
|
||||
{
|
||||
"note": "Add `DodoV2` and `Linkswap` BridgeSource",
|
||||
"pr": 152
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -10,6 +10,7 @@
|
||||
"scripts": {
|
||||
"build": "yarn tsc -b",
|
||||
"build:ci": "yarn build",
|
||||
"watch": "tsc -w -p tsconfig.json",
|
||||
"publish:private": "yarn clean && yarn build && gitpkg publish",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
|
@ -127,6 +127,8 @@ export enum BridgeSource {
|
||||
Swerve,
|
||||
Uniswap,
|
||||
UniswapV2,
|
||||
DodoV2,
|
||||
Linkswap,
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user