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`",
|
"note": "Export `CurveLiquidityProviderContract`",
|
||||||
"pr": 144
|
"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.
|
// Refund unspent protocol fees.
|
||||||
if (state.ethRemaining > 0 && data.refundReceiver != address(0)) {
|
if (state.ethRemaining > 0 && data.refundReceiver != address(0)) {
|
||||||
|
bool transferSuccess;
|
||||||
if (data.refundReceiver == REFUND_RECEIVER_TAKER) {
|
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) {
|
} else if (data.refundReceiver == REFUND_RECEIVER_SENDER) {
|
||||||
context.sender.transfer(state.ethRemaining);
|
(transferSuccess,) = context.sender.call{value: state.ethRemaining}("");
|
||||||
} else {
|
} else {
|
||||||
data.refundReceiver.transfer(state.ethRemaining);
|
(transferSuccess,) = data.refundReceiver.call{value: state.ethRemaining}("");
|
||||||
}
|
}
|
||||||
|
require(transferSuccess, "FillQuoteTransformer/ETHER_TRANSFER_FALIED");
|
||||||
}
|
}
|
||||||
return LibERC20Transformer.TRANSFORMER_SUCCESS;
|
return LibERC20Transformer.TRANSFORMER_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import "./mixins/MixinCoFiX.sol";
|
|||||||
import "./mixins/MixinCurve.sol";
|
import "./mixins/MixinCurve.sol";
|
||||||
import "./mixins/MixinCryptoCom.sol";
|
import "./mixins/MixinCryptoCom.sol";
|
||||||
import "./mixins/MixinDodo.sol";
|
import "./mixins/MixinDodo.sol";
|
||||||
|
import "./mixins/MixinDodoV2.sol";
|
||||||
import "./mixins/MixinKyber.sol";
|
import "./mixins/MixinKyber.sol";
|
||||||
import "./mixins/MixinMooniswap.sol";
|
import "./mixins/MixinMooniswap.sol";
|
||||||
import "./mixins/MixinMStable.sol";
|
import "./mixins/MixinMStable.sol";
|
||||||
@ -46,6 +47,7 @@ contract BridgeAdapter is
|
|||||||
MixinCurve,
|
MixinCurve,
|
||||||
MixinCryptoCom,
|
MixinCryptoCom,
|
||||||
MixinDodo,
|
MixinDodo,
|
||||||
|
MixinDodoV2,
|
||||||
MixinKyber,
|
MixinKyber,
|
||||||
MixinMooniswap,
|
MixinMooniswap,
|
||||||
MixinMStable,
|
MixinMStable,
|
||||||
@ -64,6 +66,7 @@ contract BridgeAdapter is
|
|||||||
MixinCurve()
|
MixinCurve()
|
||||||
MixinCryptoCom()
|
MixinCryptoCom()
|
||||||
MixinDodo()
|
MixinDodo()
|
||||||
|
MixinDodoV2()
|
||||||
MixinKyber(weth)
|
MixinKyber(weth)
|
||||||
MixinMooniswap(weth)
|
MixinMooniswap(weth)
|
||||||
MixinMStable()
|
MixinMStable()
|
||||||
@ -100,7 +103,8 @@ contract BridgeAdapter is
|
|||||||
sellAmount,
|
sellAmount,
|
||||||
order.bridgeData
|
order.bridgeData
|
||||||
);
|
);
|
||||||
} else if (order.source == BridgeSource.UNISWAPV2) {
|
} else if (order.source == BridgeSource.UNISWAPV2 ||
|
||||||
|
order.source == BridgeSource.LINKSWAP) {
|
||||||
boughtAmount = _tradeUniswapV2(
|
boughtAmount = _tradeUniswapV2(
|
||||||
buyToken,
|
buyToken,
|
||||||
sellAmount,
|
sellAmount,
|
||||||
@ -162,6 +166,12 @@ contract BridgeAdapter is
|
|||||||
sellAmount,
|
sellAmount,
|
||||||
order.bridgeData
|
order.bridgeData
|
||||||
);
|
);
|
||||||
|
} else if (order.source == BridgeSource.DODOV2) {
|
||||||
|
boughtAmount = _tradeDodoV2(
|
||||||
|
sellToken,
|
||||||
|
sellAmount,
|
||||||
|
order.bridgeData
|
||||||
|
);
|
||||||
} else if (order.source == BridgeSource.CRYPTOCOM) {
|
} else if (order.source == BridgeSource.CRYPTOCOM) {
|
||||||
boughtAmount = _tradeCryptoCom(
|
boughtAmount = _tradeCryptoCom(
|
||||||
buyToken,
|
buyToken,
|
||||||
|
@ -40,6 +40,8 @@ library BridgeSource {
|
|||||||
uint256 constant internal SWERVE = 15;
|
uint256 constant internal SWERVE = 15;
|
||||||
uint256 constant internal UNISWAP = 16;
|
uint256 constant internal UNISWAP = 16;
|
||||||
uint256 constant internal UNISWAPV2 = 17;
|
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
|
// New sources should be APPENDED to this list, taking the next highest
|
||||||
// integer value.
|
// 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": {
|
"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",
|
"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: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": {
|
"repository": {
|
||||||
"type": "git",
|
"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 MixinCryptoCom from '../test/generated-artifacts/MixinCryptoCom.json';
|
||||||
import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json';
|
import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json';
|
||||||
import * as MixinDodo from '../test/generated-artifacts/MixinDodo.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 MixinKyber from '../test/generated-artifacts/MixinKyber.json';
|
||||||
import * as MixinMooniswap from '../test/generated-artifacts/MixinMooniswap.json';
|
import * as MixinMooniswap from '../test/generated-artifacts/MixinMooniswap.json';
|
||||||
import * as MixinMStable from '../test/generated-artifacts/MixinMStable.json';
|
import * as MixinMStable from '../test/generated-artifacts/MixinMStable.json';
|
||||||
@ -219,6 +220,7 @@ export const artifacts = {
|
|||||||
MixinCryptoCom: MixinCryptoCom as ContractArtifact,
|
MixinCryptoCom: MixinCryptoCom as ContractArtifact,
|
||||||
MixinCurve: MixinCurve as ContractArtifact,
|
MixinCurve: MixinCurve as ContractArtifact,
|
||||||
MixinDodo: MixinDodo as ContractArtifact,
|
MixinDodo: MixinDodo as ContractArtifact,
|
||||||
|
MixinDodoV2: MixinDodoV2 as ContractArtifact,
|
||||||
MixinKyber: MixinKyber as ContractArtifact,
|
MixinKyber: MixinKyber as ContractArtifact,
|
||||||
MixinMStable: MixinMStable as ContractArtifact,
|
MixinMStable: MixinMStable as ContractArtifact,
|
||||||
MixinMooniswap: MixinMooniswap 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_crypto_com';
|
||||||
export * from '../test/generated-wrappers/mixin_curve';
|
export * from '../test/generated-wrappers/mixin_curve';
|
||||||
export * from '../test/generated-wrappers/mixin_dodo';
|
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_kyber';
|
||||||
export * from '../test/generated-wrappers/mixin_m_stable';
|
export * from '../test/generated-wrappers/mixin_m_stable';
|
||||||
export * from '../test/generated-wrappers/mixin_mooniswap';
|
export * from '../test/generated-wrappers/mixin_mooniswap';
|
||||||
|
@ -105,6 +105,7 @@
|
|||||||
"test/generated-artifacts/MixinCryptoCom.json",
|
"test/generated-artifacts/MixinCryptoCom.json",
|
||||||
"test/generated-artifacts/MixinCurve.json",
|
"test/generated-artifacts/MixinCurve.json",
|
||||||
"test/generated-artifacts/MixinDodo.json",
|
"test/generated-artifacts/MixinDodo.json",
|
||||||
|
"test/generated-artifacts/MixinDodoV2.json",
|
||||||
"test/generated-artifacts/MixinKyber.json",
|
"test/generated-artifacts/MixinKyber.json",
|
||||||
"test/generated-artifacts/MixinMStable.json",
|
"test/generated-artifacts/MixinMStable.json",
|
||||||
"test/generated-artifacts/MixinMooniswap.json",
|
"test/generated-artifacts/MixinMooniswap.json",
|
||||||
|
@ -34,6 +34,18 @@
|
|||||||
"note": "Create `FakeTaker` contract to get result data and gas used",
|
"note": "Create `FakeTaker` contract to get result data and gas used",
|
||||||
"pr": 151
|
"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",
|
"note": "Add an alternative RFQ market making implementation",
|
||||||
"pr": 139
|
"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 "./BancorSampler.sol";
|
||||||
import "./CurveSampler.sol";
|
import "./CurveSampler.sol";
|
||||||
import "./DODOSampler.sol";
|
import "./DODOSampler.sol";
|
||||||
|
import "./DODOV2Sampler.sol";
|
||||||
import "./Eth2DaiSampler.sol";
|
import "./Eth2DaiSampler.sol";
|
||||||
import "./KyberSampler.sol";
|
import "./KyberSampler.sol";
|
||||||
import "./LiquidityProviderSampler.sol";
|
import "./LiquidityProviderSampler.sol";
|
||||||
@ -44,6 +45,7 @@ contract ERC20BridgeSampler is
|
|||||||
BancorSampler,
|
BancorSampler,
|
||||||
CurveSampler,
|
CurveSampler,
|
||||||
DODOSampler,
|
DODOSampler,
|
||||||
|
DODOV2Sampler,
|
||||||
Eth2DaiSampler,
|
Eth2DaiSampler,
|
||||||
KyberSampler,
|
KyberSampler,
|
||||||
LiquidityProviderSampler,
|
LiquidityProviderSampler,
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker",
|
"publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker",
|
||||||
"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|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": {
|
"postpublish": {
|
||||||
"assets": []
|
"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';
|
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
|
// 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 =>
|
return Object.values(MAINNET_CURVE_INFOS).filter(c =>
|
@ -58,9 +58,11 @@ export const SELL_SOURCE_FILTER = new SourceFilters([
|
|||||||
ERC20BridgeSource.Shell,
|
ERC20BridgeSource.Shell,
|
||||||
ERC20BridgeSource.MultiHop,
|
ERC20BridgeSource.MultiHop,
|
||||||
ERC20BridgeSource.Dodo,
|
ERC20BridgeSource.Dodo,
|
||||||
|
ERC20BridgeSource.DodoV2,
|
||||||
ERC20BridgeSource.Cream,
|
ERC20BridgeSource.Cream,
|
||||||
ERC20BridgeSource.LiquidityProvider,
|
ERC20BridgeSource.LiquidityProvider,
|
||||||
ERC20BridgeSource.CryptoCom,
|
ERC20BridgeSource.CryptoCom,
|
||||||
|
ERC20BridgeSource.Linkswap,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,9 +85,11 @@ export const BUY_SOURCE_FILTER = new SourceFilters([
|
|||||||
ERC20BridgeSource.SushiSwap,
|
ERC20BridgeSource.SushiSwap,
|
||||||
ERC20BridgeSource.MultiHop,
|
ERC20BridgeSource.MultiHop,
|
||||||
ERC20BridgeSource.Dodo,
|
ERC20BridgeSource.Dodo,
|
||||||
|
ERC20BridgeSource.DodoV2,
|
||||||
ERC20BridgeSource.Cream,
|
ERC20BridgeSource.Cream,
|
||||||
ERC20BridgeSource.LiquidityProvider,
|
ERC20BridgeSource.LiquidityProvider,
|
||||||
ERC20BridgeSource.CryptoCom,
|
ERC20BridgeSource.CryptoCom,
|
||||||
|
ERC20BridgeSource.Linkswap,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -155,6 +159,7 @@ export const TOKENS = {
|
|||||||
EURS: '0xdb25f211ab05b1c97d595516f45794528a807ad8',
|
EURS: '0xdb25f211ab05b1c97d595516f45794528a807ad8',
|
||||||
sEUR: '0xd71ecff9342a5ced620049e616c5035f1db98620',
|
sEUR: '0xd71ecff9342a5ced620049e616c5035f1db98620',
|
||||||
sETH: '0x5e74c9036fb86bd7ecdcb084a0673efc32ea31cb',
|
sETH: '0x5e74c9036fb86bd7ecdcb084a0673efc32ea31cb',
|
||||||
|
LINK: '0x514910771af9ca656af840dff83e8264ecf986ca',
|
||||||
// Mirror Protocol
|
// Mirror Protocol
|
||||||
UST: '0xa47c8bf37f92abed4a126bda807a7b7498661acd',
|
UST: '0xa47c8bf37f92abed4a126bda807a7b7498661acd',
|
||||||
MIR: '0x09a3ecafa817268f77be1283176b946c4ff2e608',
|
MIR: '0x09a3ecafa817268f77be1283176b946c4ff2e608',
|
||||||
@ -190,7 +195,7 @@ export const POOLS = {
|
|||||||
curve_aave: '0xdebf20617708857ebe4f679508e7b7863a8a8eee', // 25.aave
|
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({
|
export const DEFAULT_TOKEN_ADJACENCY_GRAPH: TokenAdjacencyGraph = new TokenAdjacencyGraphBuilder({
|
||||||
default: DEFAULT_INTERMEDIATE_TOKENS,
|
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_UNISWAP_V2_ROUTER = '0xf164fc0ec4e93095b804a4795bbe1e041497b92a';
|
||||||
export const MAINNET_SUSHI_SWAP_ROUTER = '0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f';
|
export const MAINNET_SUSHI_SWAP_ROUTER = '0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f';
|
||||||
export const MAINNET_CRYPTO_COM_ROUTER = '0xceb90e4c17d626be0facd78b79c9c87d7ca181b3';
|
export const MAINNET_CRYPTO_COM_ROUTER = '0xceb90e4c17d626be0facd78b79c9c87d7ca181b3';
|
||||||
|
export const MAINNET_LINKSWAP_ROUTER = '0xa7ece0911fe8c60bff9e99f8fafcdbe56e07aff1';
|
||||||
|
|
||||||
export const MAINNET_MSTABLE_ROUTER = '0xe2f2a5c287993345a840db3b0845fbc70f5935a5';
|
export const MAINNET_MSTABLE_ROUTER = '0xe2f2a5c287993345a840db3b0845fbc70f5935a5';
|
||||||
export const MAINNET_OASIS_ROUTER = '0x794e6e91555438afc3ccf1c5076a74f42133d08d';
|
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_MOONISWAP_V2_1_REGISTRY = '0xbaf9a5d4b0052359326a6cdab54babaa3a3a9643';
|
||||||
|
|
||||||
export const MAINNET_DODO_HELPER = '0x533da777aedce766ceae696bf90f8541a4ba80eb';
|
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 } = {
|
export const CURVE_LIQUIDITY_PROVIDER_BY_CHAIN_ID: { [id: string]: string } = {
|
||||||
'1': '0x7a6F6a048fE2Dc1397ABa0bf7879d3eacF371C53',
|
'1': '0x7a6F6a048fE2Dc1397ABa0bf7879d3eacF371C53',
|
||||||
@ -574,8 +584,17 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
|
|||||||
},
|
},
|
||||||
[ERC20BridgeSource.CryptoCom]: (fillData?: FillData) => {
|
[ERC20BridgeSource.CryptoCom]: (fillData?: FillData) => {
|
||||||
// TODO: Different base cost if to/from ETH.
|
// TODO: Different base cost if to/from ETH.
|
||||||
let gas = 90e3 + 20e3 + 60e3; // temporary allowance diff, unrolled FQT
|
let gas = 90e3;
|
||||||
const path = (fillData as SushiSwapFillData).tokenAddressPath;
|
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) {
|
if (path.length > 2) {
|
||||||
gas += (path.length - 2) * 60e3; // +60k for each hop.
|
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
|
// sell quote requires additional calculation and overhead
|
||||||
return isSellBase ? 180e3 : 300e3;
|
return isSellBase ? 180e3 : 300e3;
|
||||||
},
|
},
|
||||||
|
[ERC20BridgeSource.DodoV2]: (_fillData?: FillData) => 100e3,
|
||||||
[ERC20BridgeSource.SnowSwap]: fillData => {
|
[ERC20BridgeSource.SnowSwap]: fillData => {
|
||||||
switch ((fillData as SnowSwapFillData).pool.poolAddress.toLowerCase()) {
|
switch ((fillData as SnowSwapFillData).pool.poolAddress.toLowerCase()) {
|
||||||
case '0xbf7ccd6c446acfcc5df023043f2167b62e81899b':
|
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;
|
return BridgeSource.Uniswap;
|
||||||
case ERC20BridgeSource.UniswapV2:
|
case ERC20BridgeSource.UniswapV2:
|
||||||
return BridgeSource.UniswapV2;
|
return BridgeSource.UniswapV2;
|
||||||
|
case ERC20BridgeSource.DodoV2:
|
||||||
|
return BridgeSource.DodoV2;
|
||||||
|
case ERC20BridgeSource.Linkswap:
|
||||||
|
return BridgeSource.Linkswap;
|
||||||
default:
|
default:
|
||||||
throw new Error(AggregationError.NoBridgeForSource);
|
throw new Error(AggregationError.NoBridgeForSource);
|
||||||
}
|
}
|
||||||
@ -164,6 +168,7 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
|||||||
case ERC20BridgeSource.UniswapV2:
|
case ERC20BridgeSource.UniswapV2:
|
||||||
case ERC20BridgeSource.SushiSwap:
|
case ERC20BridgeSource.SushiSwap:
|
||||||
case ERC20BridgeSource.CryptoCom:
|
case ERC20BridgeSource.CryptoCom:
|
||||||
|
case ERC20BridgeSource.Linkswap:
|
||||||
const uniswapV2FillData = (order as OptimizedMarketBridgeOrder<UniswapV2FillData | SushiSwapFillData>)
|
const uniswapV2FillData = (order as OptimizedMarketBridgeOrder<UniswapV2FillData | SushiSwapFillData>)
|
||||||
.fillData;
|
.fillData;
|
||||||
bridgeData = encoder.encode([uniswapV2FillData.router, uniswapV2FillData.tokenAddressPath]);
|
bridgeData = encoder.encode([uniswapV2FillData.router, uniswapV2FillData.tokenAddressPath]);
|
||||||
@ -180,6 +185,10 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
|||||||
const dodoFillData = (order as OptimizedMarketBridgeOrder<DODOFillData>).fillData;
|
const dodoFillData = (order as OptimizedMarketBridgeOrder<DODOFillData>).fillData;
|
||||||
bridgeData = encoder.encode([MAINNET_DODO_HELPER, dodoFillData.poolAddress, dodoFillData.isSellBase]);
|
bridgeData = encoder.encode([MAINNET_DODO_HELPER, dodoFillData.poolAddress, dodoFillData.isSellBase]);
|
||||||
break;
|
break;
|
||||||
|
case ERC20BridgeSource.DodoV2:
|
||||||
|
const dodoV2FillData = (order as OptimizedMarketBridgeOrder<DODOFillData>).fillData;
|
||||||
|
bridgeData = encoder.encode([dodoV2FillData.poolAddress, dodoV2FillData.isSellBase]);
|
||||||
|
break;
|
||||||
case ERC20BridgeSource.Shell:
|
case ERC20BridgeSource.Shell:
|
||||||
const shellFillData = (order as OptimizedMarketBridgeOrder<ShellFillData>).fillData;
|
const shellFillData = (order as OptimizedMarketBridgeOrder<ShellFillData>).fillData;
|
||||||
bridgeData = encoder.encode([shellFillData.poolAddress]);
|
bridgeData = encoder.encode([shellFillData.poolAddress]);
|
||||||
@ -258,6 +267,10 @@ export const BRIDGE_ENCODERS: {
|
|||||||
{ name: 'poolAddress', type: 'address' },
|
{ name: 'poolAddress', type: 'address' },
|
||||||
{ name: 'isSellBase', type: 'bool' },
|
{ name: 'isSellBase', type: 'bool' },
|
||||||
]),
|
]),
|
||||||
|
[ERC20BridgeSource.DodoV2]: AbiEncoder.create([
|
||||||
|
{ name: 'poolAddress', type: 'address' },
|
||||||
|
{ name: 'isSellBase', type: 'bool' },
|
||||||
|
]),
|
||||||
// Curve like
|
// Curve like
|
||||||
[ERC20BridgeSource.Curve]: curveEncoder,
|
[ERC20BridgeSource.Curve]: curveEncoder,
|
||||||
[ERC20BridgeSource.Swerve]: curveEncoder,
|
[ERC20BridgeSource.Swerve]: curveEncoder,
|
||||||
@ -267,6 +280,7 @@ export const BRIDGE_ENCODERS: {
|
|||||||
[ERC20BridgeSource.UniswapV2]: routerAddressPathEncoder,
|
[ERC20BridgeSource.UniswapV2]: routerAddressPathEncoder,
|
||||||
[ERC20BridgeSource.SushiSwap]: routerAddressPathEncoder,
|
[ERC20BridgeSource.SushiSwap]: routerAddressPathEncoder,
|
||||||
[ERC20BridgeSource.CryptoCom]: routerAddressPathEncoder,
|
[ERC20BridgeSource.CryptoCom]: routerAddressPathEncoder,
|
||||||
|
[ERC20BridgeSource.Linkswap]: routerAddressPathEncoder,
|
||||||
// Generic pools
|
// Generic pools
|
||||||
[ERC20BridgeSource.Shell]: poolEncoder,
|
[ERC20BridgeSource.Shell]: poolEncoder,
|
||||||
[ERC20BridgeSource.Mooniswap]: poolEncoder,
|
[ERC20BridgeSource.Mooniswap]: poolEncoder,
|
||||||
|
@ -7,20 +7,30 @@ import { ERC20BridgeSamplerContract } from '../../wrappers';
|
|||||||
|
|
||||||
import { BalancerPoolsCache } from './balancer_utils';
|
import { BalancerPoolsCache } from './balancer_utils';
|
||||||
import { BancorService } from './bancor_service';
|
import { BancorService } from './bancor_service';
|
||||||
|
import {
|
||||||
|
getCurveInfosForPair,
|
||||||
|
getDodoV2Offsets,
|
||||||
|
getKyberOffsets,
|
||||||
|
getSnowSwapInfosForPair,
|
||||||
|
getSwerveInfosForPair,
|
||||||
|
isAllowedKyberReserveId,
|
||||||
|
} from './bridge_source_utils';
|
||||||
import {
|
import {
|
||||||
LIQUIDITY_PROVIDER_REGISTRY,
|
LIQUIDITY_PROVIDER_REGISTRY,
|
||||||
MAINNET_CRYPTO_COM_ROUTER,
|
MAINNET_CRYPTO_COM_ROUTER,
|
||||||
|
MAINNET_DODOV2_PRIVATE_POOL_FACTORY,
|
||||||
|
MAINNET_DODOV2_VENDING_MACHINE_FACTORY,
|
||||||
|
MAINNET_LINKSWAP_ROUTER,
|
||||||
MAINNET_MOONISWAP_REGISTRY,
|
MAINNET_MOONISWAP_REGISTRY,
|
||||||
MAINNET_MOONISWAP_V2_1_REGISTRY,
|
MAINNET_MOONISWAP_V2_1_REGISTRY,
|
||||||
MAINNET_MOONISWAP_V2_REGISTRY,
|
MAINNET_MOONISWAP_V2_REGISTRY,
|
||||||
MAINNET_SUSHI_SWAP_ROUTER,
|
MAINNET_SUSHI_SWAP_ROUTER,
|
||||||
MAINNET_UNISWAP_V2_ROUTER,
|
MAINNET_UNISWAP_V2_ROUTER,
|
||||||
MAX_UINT256,
|
MAX_UINT256,
|
||||||
|
TOKENS,
|
||||||
ZERO_AMOUNT,
|
ZERO_AMOUNT,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import { CreamPoolsCache } from './cream_utils';
|
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 { getLiquidityProvidersForPair } from './liquidity_provider_utils';
|
||||||
import { getIntermediateTokens } from './multihop_utils';
|
import { getIntermediateTokens } from './multihop_utils';
|
||||||
import { SamplerContractOperation } from './sampler_contract_operation';
|
import { SamplerContractOperation } from './sampler_contract_operation';
|
||||||
@ -212,28 +222,32 @@ export class SamplerOperations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getUniswapV2SellQuotes(
|
public getUniswapV2SellQuotes(
|
||||||
|
router: string,
|
||||||
tokenAddressPath: string[],
|
tokenAddressPath: string[],
|
||||||
takerFillAmounts: BigNumber[],
|
takerFillAmounts: BigNumber[],
|
||||||
|
source: ERC20BridgeSource = ERC20BridgeSource.UniswapV2,
|
||||||
): SourceQuoteOperation<UniswapV2FillData> {
|
): SourceQuoteOperation<UniswapV2FillData> {
|
||||||
return new SamplerContractOperation({
|
return new SamplerContractOperation({
|
||||||
source: ERC20BridgeSource.UniswapV2,
|
source,
|
||||||
fillData: { tokenAddressPath, router: MAINNET_UNISWAP_V2_ROUTER },
|
fillData: { tokenAddressPath, router },
|
||||||
contract: this._samplerContract,
|
contract: this._samplerContract,
|
||||||
function: this._samplerContract.sampleSellsFromUniswapV2,
|
function: this._samplerContract.sampleSellsFromUniswapV2,
|
||||||
params: [MAINNET_UNISWAP_V2_ROUTER, tokenAddressPath, takerFillAmounts],
|
params: [router, tokenAddressPath, takerFillAmounts],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUniswapV2BuyQuotes(
|
public getUniswapV2BuyQuotes(
|
||||||
|
router: string,
|
||||||
tokenAddressPath: string[],
|
tokenAddressPath: string[],
|
||||||
makerFillAmounts: BigNumber[],
|
makerFillAmounts: BigNumber[],
|
||||||
|
source: ERC20BridgeSource = ERC20BridgeSource.UniswapV2,
|
||||||
): SourceQuoteOperation<UniswapV2FillData> {
|
): SourceQuoteOperation<UniswapV2FillData> {
|
||||||
return new SamplerContractOperation({
|
return new SamplerContractOperation({
|
||||||
source: ERC20BridgeSource.UniswapV2,
|
source,
|
||||||
fillData: { tokenAddressPath, router: MAINNET_UNISWAP_V2_ROUTER },
|
fillData: { tokenAddressPath, router },
|
||||||
contract: this._samplerContract,
|
contract: this._samplerContract,
|
||||||
function: this._samplerContract.sampleBuysFromUniswapV2,
|
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(
|
public getShellSellQuotes(
|
||||||
poolAddress: string,
|
poolAddress: string,
|
||||||
makerToken: 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(
|
public getMedianSellRate(
|
||||||
sources: ERC20BridgeSource[],
|
sources: ERC20BridgeSource[],
|
||||||
makerToken: string,
|
makerToken: string,
|
||||||
@ -1015,9 +1049,21 @@ export class SamplerOperations {
|
|||||||
case ERC20BridgeSource.Uniswap:
|
case ERC20BridgeSource.Uniswap:
|
||||||
return this.getUniswapSellQuotes(makerToken, takerToken, takerFillAmounts);
|
return this.getUniswapSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||||
case ERC20BridgeSource.UniswapV2:
|
case ERC20BridgeSource.UniswapV2:
|
||||||
const ops = [this.getUniswapV2SellQuotes([takerToken, makerToken], takerFillAmounts)];
|
const ops = [
|
||||||
|
this.getUniswapV2SellQuotes(
|
||||||
|
MAINNET_UNISWAP_V2_ROUTER,
|
||||||
|
[takerToken, makerToken],
|
||||||
|
takerFillAmounts,
|
||||||
|
),
|
||||||
|
];
|
||||||
intermediateTokens.forEach(t => {
|
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;
|
return ops;
|
||||||
case ERC20BridgeSource.SushiSwap:
|
case ERC20BridgeSource.SushiSwap:
|
||||||
@ -1030,11 +1076,21 @@ export class SamplerOperations {
|
|||||||
return sushiOps;
|
return sushiOps;
|
||||||
case ERC20BridgeSource.CryptoCom:
|
case ERC20BridgeSource.CryptoCom:
|
||||||
const cryptoComOps = [
|
const cryptoComOps = [
|
||||||
this.getCryptoComSellQuotes([takerToken, makerToken], takerFillAmounts),
|
this.getUniswapV2SellQuotes(
|
||||||
|
MAINNET_CRYPTO_COM_ROUTER,
|
||||||
|
[takerToken, makerToken],
|
||||||
|
takerFillAmounts,
|
||||||
|
ERC20BridgeSource.CryptoCom,
|
||||||
|
),
|
||||||
];
|
];
|
||||||
intermediateTokens.forEach(t => {
|
intermediateTokens.forEach(t => {
|
||||||
cryptoComOps.push(
|
cryptoComOps.push(
|
||||||
this.getCryptoComSellQuotes([takerToken, t, makerToken], takerFillAmounts),
|
this.getUniswapV2SellQuotes(
|
||||||
|
MAINNET_CRYPTO_COM_ROUTER,
|
||||||
|
[takerToken, t, makerToken],
|
||||||
|
takerFillAmounts,
|
||||||
|
ERC20BridgeSource.CryptoCom,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
return cryptoComOps;
|
return cryptoComOps;
|
||||||
@ -1119,8 +1175,52 @@ export class SamplerOperations {
|
|||||||
);
|
);
|
||||||
case ERC20BridgeSource.Dodo:
|
case ERC20BridgeSource.Dodo:
|
||||||
return this.getDODOSellQuotes(makerToken, takerToken, takerFillAmounts);
|
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:
|
case ERC20BridgeSource.Bancor:
|
||||||
return this.getBancorSellQuotes(makerToken, takerToken, takerFillAmounts);
|
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:
|
default:
|
||||||
throw new Error(`Unsupported sell sample source: ${source}`);
|
throw new Error(`Unsupported sell sample source: ${source}`);
|
||||||
}
|
}
|
||||||
@ -1148,9 +1248,21 @@ export class SamplerOperations {
|
|||||||
case ERC20BridgeSource.Uniswap:
|
case ERC20BridgeSource.Uniswap:
|
||||||
return this.getUniswapBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
return this.getUniswapBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||||
case ERC20BridgeSource.UniswapV2:
|
case ERC20BridgeSource.UniswapV2:
|
||||||
const ops = [this.getUniswapV2BuyQuotes([takerToken, makerToken], makerFillAmounts)];
|
const ops = [
|
||||||
|
this.getUniswapV2BuyQuotes(
|
||||||
|
MAINNET_UNISWAP_V2_ROUTER,
|
||||||
|
[takerToken, makerToken],
|
||||||
|
makerFillAmounts,
|
||||||
|
),
|
||||||
|
];
|
||||||
intermediateTokens.forEach(t => {
|
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;
|
return ops;
|
||||||
case ERC20BridgeSource.SushiSwap:
|
case ERC20BridgeSource.SushiSwap:
|
||||||
@ -1163,11 +1275,21 @@ export class SamplerOperations {
|
|||||||
return sushiOps;
|
return sushiOps;
|
||||||
case ERC20BridgeSource.CryptoCom:
|
case ERC20BridgeSource.CryptoCom:
|
||||||
const cryptoComOps = [
|
const cryptoComOps = [
|
||||||
this.getCryptoComBuyQuotes([takerToken, makerToken], makerFillAmounts),
|
this.getUniswapV2BuyQuotes(
|
||||||
|
MAINNET_CRYPTO_COM_ROUTER,
|
||||||
|
[takerToken, makerToken],
|
||||||
|
makerFillAmounts,
|
||||||
|
ERC20BridgeSource.CryptoCom,
|
||||||
|
),
|
||||||
];
|
];
|
||||||
intermediateTokens.forEach(t => {
|
intermediateTokens.forEach(t => {
|
||||||
cryptoComOps.push(
|
cryptoComOps.push(
|
||||||
this.getCryptoComBuyQuotes([takerToken, t, makerToken], makerFillAmounts),
|
this.getUniswapV2BuyQuotes(
|
||||||
|
MAINNET_CRYPTO_COM_ROUTER,
|
||||||
|
[takerToken, t, makerToken],
|
||||||
|
makerFillAmounts,
|
||||||
|
ERC20BridgeSource.CryptoCom,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
return cryptoComOps;
|
return cryptoComOps;
|
||||||
@ -1252,8 +1374,52 @@ export class SamplerOperations {
|
|||||||
);
|
);
|
||||||
case ERC20BridgeSource.Dodo:
|
case ERC20BridgeSource.Dodo:
|
||||||
return this.getDODOBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
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:
|
case ERC20BridgeSource.Bancor:
|
||||||
return this.getBancorBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
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:
|
default:
|
||||||
throw new Error(`Unsupported buy sample source: ${source}`);
|
throw new Error(`Unsupported buy sample source: ${source}`);
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,9 @@ export enum ERC20BridgeSource {
|
|||||||
SnowSwap = 'SnowSwap',
|
SnowSwap = 'SnowSwap',
|
||||||
SushiSwap = 'SushiSwap',
|
SushiSwap = 'SushiSwap',
|
||||||
Dodo = 'DODO',
|
Dodo = 'DODO',
|
||||||
|
DodoV2 = 'DODO_V2',
|
||||||
CryptoCom = 'CryptoCom',
|
CryptoCom = 'CryptoCom',
|
||||||
|
Linkswap = 'Linkswap',
|
||||||
}
|
}
|
||||||
|
|
||||||
// tslint:disable: enum-naming
|
// 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 CurveSampler from '../test/generated-artifacts/CurveSampler.json';
|
||||||
import * as DeploymentConstants from '../test/generated-artifacts/DeploymentConstants.json';
|
import * as DeploymentConstants from '../test/generated-artifacts/DeploymentConstants.json';
|
||||||
import * as DODOSampler from '../test/generated-artifacts/DODOSampler.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 DummyLiquidityProvider from '../test/generated-artifacts/DummyLiquidityProvider.json';
|
||||||
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
|
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
|
||||||
import * as Eth2DaiSampler from '../test/generated-artifacts/Eth2DaiSampler.json';
|
import * as Eth2DaiSampler from '../test/generated-artifacts/Eth2DaiSampler.json';
|
||||||
@ -49,6 +50,7 @@ export const artifacts = {
|
|||||||
BancorSampler: BancorSampler as ContractArtifact,
|
BancorSampler: BancorSampler as ContractArtifact,
|
||||||
CurveSampler: CurveSampler as ContractArtifact,
|
CurveSampler: CurveSampler as ContractArtifact,
|
||||||
DODOSampler: DODOSampler as ContractArtifact,
|
DODOSampler: DODOSampler as ContractArtifact,
|
||||||
|
DODOV2Sampler: DODOV2Sampler as ContractArtifact,
|
||||||
DeploymentConstants: DeploymentConstants as ContractArtifact,
|
DeploymentConstants: DeploymentConstants as ContractArtifact,
|
||||||
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
|
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
|
||||||
Eth2DaiSampler: Eth2DaiSampler as ContractArtifact,
|
Eth2DaiSampler: Eth2DaiSampler as ContractArtifact,
|
||||||
|
@ -343,6 +343,7 @@ describe('DexSampler tests', () => {
|
|||||||
);
|
);
|
||||||
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
||||||
dexOrderSampler.getUniswapV2SellQuotes(
|
dexOrderSampler.getUniswapV2SellQuotes(
|
||||||
|
NULL_ADDRESS,
|
||||||
[expectedMakerToken, expectedTakerToken],
|
[expectedMakerToken, expectedTakerToken],
|
||||||
expectedTakerFillAmounts,
|
expectedTakerFillAmounts,
|
||||||
),
|
),
|
||||||
|
@ -61,8 +61,10 @@ const DEFAULT_EXCLUDED = [
|
|||||||
ERC20BridgeSource.Shell,
|
ERC20BridgeSource.Shell,
|
||||||
ERC20BridgeSource.Cream,
|
ERC20BridgeSource.Cream,
|
||||||
ERC20BridgeSource.Dodo,
|
ERC20BridgeSource.Dodo,
|
||||||
|
ERC20BridgeSource.DodoV2,
|
||||||
ERC20BridgeSource.LiquidityProvider,
|
ERC20BridgeSource.LiquidityProvider,
|
||||||
ERC20BridgeSource.CryptoCom,
|
ERC20BridgeSource.CryptoCom,
|
||||||
|
ERC20BridgeSource.Linkswap,
|
||||||
];
|
];
|
||||||
const BUY_SOURCES = BUY_SOURCE_FILTER.sources;
|
const BUY_SOURCES = BUY_SOURCE_FILTER.sources;
|
||||||
const SELL_SOURCES = SELL_SOURCE_FILTER.sources;
|
const SELL_SOURCES = SELL_SOURCE_FILTER.sources;
|
||||||
@ -293,7 +295,9 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
[ERC20BridgeSource.Shell]: _.times(NUM_SAMPLES, () => 0),
|
[ERC20BridgeSource.Shell]: _.times(NUM_SAMPLES, () => 0),
|
||||||
[ERC20BridgeSource.Cream]: _.times(NUM_SAMPLES, () => 0),
|
[ERC20BridgeSource.Cream]: _.times(NUM_SAMPLES, () => 0),
|
||||||
[ERC20BridgeSource.Dodo]: _.times(NUM_SAMPLES, () => 0),
|
[ERC20BridgeSource.Dodo]: _.times(NUM_SAMPLES, () => 0),
|
||||||
|
[ERC20BridgeSource.DodoV2]: _.times(NUM_SAMPLES, () => 0),
|
||||||
[ERC20BridgeSource.CryptoCom]: _.times(NUM_SAMPLES, () => 0),
|
[ERC20BridgeSource.CryptoCom]: _.times(NUM_SAMPLES, () => 0),
|
||||||
|
[ERC20BridgeSource.Linkswap]: _.times(NUM_SAMPLES, () => 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_RATES: RatesBySource = {
|
const DEFAULT_RATES: RatesBySource = {
|
||||||
@ -353,7 +357,9 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
[ERC20BridgeSource.Shell]: { poolAddress: randomAddress() },
|
[ERC20BridgeSource.Shell]: { poolAddress: randomAddress() },
|
||||||
[ERC20BridgeSource.Cream]: { poolAddress: randomAddress() },
|
[ERC20BridgeSource.Cream]: { poolAddress: randomAddress() },
|
||||||
[ERC20BridgeSource.Dodo]: {},
|
[ERC20BridgeSource.Dodo]: {},
|
||||||
|
[ERC20BridgeSource.DodoV2]: {},
|
||||||
[ERC20BridgeSource.CryptoCom]: { tokenAddressPath: [] },
|
[ERC20BridgeSource.CryptoCom]: { tokenAddressPath: [] },
|
||||||
|
[ERC20BridgeSource.Linkswap]: { tokenAddressPath: [] },
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_OPS = {
|
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/bancor_sampler';
|
||||||
export * from '../test/generated-wrappers/curve_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_sampler';
|
||||||
|
export * from '../test/generated-wrappers/d_o_d_o_v2_sampler';
|
||||||
export * from '../test/generated-wrappers/deployment_constants';
|
export * from '../test/generated-wrappers/deployment_constants';
|
||||||
export * from '../test/generated-wrappers/dummy_liquidity_provider';
|
export * from '../test/generated-wrappers/dummy_liquidity_provider';
|
||||||
export * from '../test/generated-wrappers/erc20_bridge_sampler';
|
export * from '../test/generated-wrappers/erc20_bridge_sampler';
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
"test/generated-artifacts/BancorSampler.json",
|
"test/generated-artifacts/BancorSampler.json",
|
||||||
"test/generated-artifacts/CurveSampler.json",
|
"test/generated-artifacts/CurveSampler.json",
|
||||||
"test/generated-artifacts/DODOSampler.json",
|
"test/generated-artifacts/DODOSampler.json",
|
||||||
|
"test/generated-artifacts/DODOV2Sampler.json",
|
||||||
"test/generated-artifacts/DeploymentConstants.json",
|
"test/generated-artifacts/DeploymentConstants.json",
|
||||||
"test/generated-artifacts/DummyLiquidityProvider.json",
|
"test/generated-artifacts/DummyLiquidityProvider.json",
|
||||||
"test/generated-artifacts/ERC20BridgeSampler.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",
|
"version": "5.10.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
"wethTransformer": "0xb2bc06a4efb20fc6553a69dbfa49b7be938034a7",
|
"wethTransformer": "0xb2bc06a4efb20fc6553a69dbfa49b7be938034a7",
|
||||||
"payTakerTransformer": "0x4638a7ebe75b911b995d0ec73a81e4f85f41f24e",
|
"payTakerTransformer": "0x4638a7ebe75b911b995d0ec73a81e4f85f41f24e",
|
||||||
"affiliateFeeTransformer": "0xda6d9fc5998f550a094585cf9171f0e8ee3ac59f",
|
"affiliateFeeTransformer": "0xda6d9fc5998f550a094585cf9171f0e8ee3ac59f",
|
||||||
"fillQuoteTransformer": "0xfa6282736af206cb4cfc5cb786d82aecdf1186f9"
|
"fillQuoteTransformer": "0x227e767a9b7517681d1cb6b846aa9e541484c7ab"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
@ -78,7 +78,7 @@
|
|||||||
"wethTransformer": "0x05ad19aa3826e0609a19568ffbd1dfe86c6c7184",
|
"wethTransformer": "0x05ad19aa3826e0609a19568ffbd1dfe86c6c7184",
|
||||||
"payTakerTransformer": "0x6d0ebf2bcd9cc93ec553b60ad201943dcca4e291",
|
"payTakerTransformer": "0x6d0ebf2bcd9cc93ec553b60ad201943dcca4e291",
|
||||||
"affiliateFeeTransformer": "0x6588256778ca4432fa43983ac685c45efb2379e2",
|
"affiliateFeeTransformer": "0x6588256778ca4432fa43983ac685c45efb2379e2",
|
||||||
"fillQuoteTransformer": "0xd2a157fe2f72f5fb550826d93a9a57dcf51cc08f"
|
"fillQuoteTransformer": "0x2088a820787ebbe937a0612ef024f1e1d65f9784"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"4": {
|
"4": {
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
{
|
{
|
||||||
"note": "Add VIP utils",
|
"note": "Add VIP utils",
|
||||||
"pr": 127
|
"pr": 127
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add `DodoV2` and `Linkswap` BridgeSource",
|
||||||
|
"pr": 152
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "yarn tsc -b",
|
"build": "yarn tsc -b",
|
||||||
"build:ci": "yarn build",
|
"build:ci": "yarn build",
|
||||||
|
"watch": "tsc -w -p tsconfig.json",
|
||||||
"publish:private": "yarn clean && yarn build && gitpkg publish",
|
"publish:private": "yarn clean && yarn build && gitpkg publish",
|
||||||
"test": "yarn run_mocha",
|
"test": "yarn run_mocha",
|
||||||
"rebuild_and_test": "run-s build test",
|
"rebuild_and_test": "run-s build test",
|
||||||
|
@ -127,6 +127,8 @@ export enum BridgeSource {
|
|||||||
Swerve,
|
Swerve,
|
||||||
Uniswap,
|
Uniswap,
|
||||||
UniswapV2,
|
UniswapV2,
|
||||||
|
DodoV2,
|
||||||
|
Linkswap,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user