diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol index 9e854815f8..bf08a46557 100644 --- a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol +++ b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol @@ -27,6 +27,7 @@ import "./mixins/MixinBalancerV2.sol"; import "./mixins/MixinBancor.sol"; import "./mixins/MixinCoFiX.sol"; import "./mixins/MixinCurve.sol"; +import "./mixins/MixinCurveV2.sol"; import "./mixins/MixinCryptoCom.sol"; import "./mixins/MixinDodo.sol"; import "./mixins/MixinDodoV2.sol"; @@ -50,6 +51,7 @@ contract BridgeAdapter is MixinBancor, MixinCoFiX, MixinCurve, + MixinCurveV2, MixinCryptoCom, MixinDodo, MixinDodoV2, @@ -73,6 +75,7 @@ contract BridgeAdapter is MixinBancor(weth) MixinCoFiX() MixinCurve(weth) + MixinCurveV2() MixinCryptoCom() MixinDodo() MixinDodoV2() @@ -107,6 +110,13 @@ contract BridgeAdapter is sellAmount, order.bridgeData ); + } else if (protocolId == BridgeProtocols.CURVEV2) { + boughtAmount = _tradeCurveV2( + sellToken, + buyToken, + sellAmount, + order.bridgeData + ); } else if (protocolId == BridgeProtocols.UNISWAPV3) { boughtAmount = _tradeUniswapV3( sellToken, diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol index 01135e5cd4..a38e65236c 100644 --- a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol +++ b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol @@ -47,4 +47,5 @@ library BridgeProtocols { uint128 internal constant BALANCERV2 = 17; uint128 internal constant UNISWAPV3 = 18; uint128 internal constant KYBERDMM = 19; + uint128 internal constant CURVEV2 = 20; } diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinCurveV2.sol b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinCurveV2.sol new file mode 100644 index 0000000000..ebb49f455d --- /dev/null +++ b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinCurveV2.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + + Copyright 2020 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.6.5; +pragma experimental ABIEncoderV2; + +import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol"; +import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol"; +import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; +import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; + +contract MixinCurveV2 { + + using LibERC20TokenV06 for IERC20TokenV06; + using LibSafeMathV06 for uint256; + using LibRichErrorsV06 for bytes; + + struct CurveBridgeDataV2 { + address curveAddress; + bytes4 exchangeFunctionSelector; + int128 fromCoinIdx; + int128 toCoinIdx; + } + + function _tradeCurveV2( + IERC20TokenV06 sellToken, + IERC20TokenV06 buyToken, + uint256 sellAmount, + bytes memory bridgeData + ) + internal + returns (uint256 boughtAmount) + { + // Decode the bridge data to get the Curve metadata. + CurveBridgeDataV2 memory data = abi.decode(bridgeData, (CurveBridgeDataV2)); + sellToken.approveIfBelow(data.curveAddress, sellAmount); + + uint256 beforeBalance = buyToken.balanceOf(address(this)); + (bool success, bytes memory resultData) = + data.curveAddress.call(abi.encodeWithSelector( + data.exchangeFunctionSelector, + data.fromCoinIdx, + data.toCoinIdx, + // dx + sellAmount, + // min dy + 1 + )); + if (!success) { + resultData.rrevert(); + } + + return buyToken.balanceOf(address(this)).safeSub(beforeBalance); + } +} diff --git a/contracts/zero-ex/package.json b/contracts/zero-ex/package.json index be711c9a00..3b45545491 100644 --- a/contracts/zero-ex/package.json +++ b/contracts/zero-ex/package.json @@ -43,7 +43,7 @@ "config": { "publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature,OtcOrdersFeature,IOtcOrdersFeature", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBalancerV2|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMooniswap|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json" + "abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBalancerV2|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMooniswap|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json" }, "repository": { "type": "git", diff --git a/contracts/zero-ex/test/artifacts.ts b/contracts/zero-ex/test/artifacts.ts index e5f2410fe5..1599ed4d0b 100644 --- a/contracts/zero-ex/test/artifacts.ts +++ b/contracts/zero-ex/test/artifacts.ts @@ -85,6 +85,7 @@ import * as MixinBancor from '../test/generated-artifacts/MixinBancor.json'; 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 MixinCurveV2 from '../test/generated-artifacts/MixinCurveV2.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'; @@ -258,6 +259,7 @@ export const artifacts = { MixinCoFiX: MixinCoFiX as ContractArtifact, MixinCryptoCom: MixinCryptoCom as ContractArtifact, MixinCurve: MixinCurve as ContractArtifact, + MixinCurveV2: MixinCurveV2 as ContractArtifact, MixinDodo: MixinDodo as ContractArtifact, MixinDodoV2: MixinDodoV2 as ContractArtifact, MixinKyber: MixinKyber as ContractArtifact, diff --git a/contracts/zero-ex/test/wrappers.ts b/contracts/zero-ex/test/wrappers.ts index 2663b32227..c58e88a941 100644 --- a/contracts/zero-ex/test/wrappers.ts +++ b/contracts/zero-ex/test/wrappers.ts @@ -83,6 +83,7 @@ export * from '../test/generated-wrappers/mixin_bancor'; 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_curve_v2'; export * from '../test/generated-wrappers/mixin_dodo'; export * from '../test/generated-wrappers/mixin_dodo_v2'; export * from '../test/generated-wrappers/mixin_kyber'; diff --git a/contracts/zero-ex/tsconfig.json b/contracts/zero-ex/tsconfig.json index 1aa6432947..e5ca3d66f8 100644 --- a/contracts/zero-ex/tsconfig.json +++ b/contracts/zero-ex/tsconfig.json @@ -116,6 +116,7 @@ "test/generated-artifacts/MixinCoFiX.json", "test/generated-artifacts/MixinCryptoCom.json", "test/generated-artifacts/MixinCurve.json", + "test/generated-artifacts/MixinCurveV2.json", "test/generated-artifacts/MixinDodo.json", "test/generated-artifacts/MixinDodoV2.json", "test/generated-artifacts/MixinKyber.json", diff --git a/packages/asset-swapper/src/utils/market_operation_utils/bridge_source_utils.ts b/packages/asset-swapper/src/utils/market_operation_utils/bridge_source_utils.ts index 80c9600563..ad43c1e8d2 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/bridge_source_utils.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/bridge_source_utils.ts @@ -12,6 +12,8 @@ import { CRYPTO_COM_ROUTER_BY_CHAIN_ID, CURVE_MAINNET_INFOS, CURVE_POLYGON_INFOS, + CURVE_V2_MAINNET_INFOS, + CURVE_V2_POLYGON_INFOS, DFYN_ROUTER_BY_CHAIN_ID, ELLIPSIS_BSC_INFOS, JULSWAP_ROUTER_BY_CHAIN_ID, @@ -107,20 +109,44 @@ export function getCurveInfosForPair(chainId: ChainId, takerToken: string, maker return Object.values(CURVE_MAINNET_INFOS).filter(c => [makerToken, takerToken].every( t => - (c.tokens.includes(t) && c.metaToken === undefined) || + (c.tokens.includes(t) && c.metaTokens === undefined) || (c.tokens.includes(t) && - c.metaToken !== undefined && - [makerToken, takerToken].includes(c.metaToken)), + [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), ), ); case ChainId.Polygon: return Object.values(CURVE_POLYGON_INFOS).filter(c => [makerToken, takerToken].every( t => - (c.tokens.includes(t) && c.metaToken === undefined) || + (c.tokens.includes(t) && c.metaTokens === undefined) || (c.tokens.includes(t) && - c.metaToken !== undefined && - [makerToken, takerToken].includes(c.metaToken)), + [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), + ), + ); + default: + return []; + } +} + +// tslint:disable completed-docs +export function getCurveV2InfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] { + switch (chainId) { + case ChainId.Mainnet: + return Object.values(CURVE_V2_MAINNET_INFOS).filter(c => + [makerToken, takerToken].every( + t => + (c.tokens.includes(t) && c.metaTokens === undefined) || + (c.tokens.includes(t) && + [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), + ), + ); + case ChainId.Polygon: + return Object.values(CURVE_V2_POLYGON_INFOS).filter(c => + [makerToken, takerToken].every( + t => + (c.tokens.includes(t) && c.metaTokens === undefined) || + (c.tokens.includes(t) && + [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), ), ); default: @@ -135,8 +161,8 @@ export function getSwerveInfosForPair(chainId: ChainId, takerToken: string, make return Object.values(SWERVE_MAINNET_INFOS).filter(c => [makerToken, takerToken].every( t => - (c.tokens.includes(t) && c.metaToken === undefined) || - (c.tokens.includes(t) && c.metaToken !== undefined && [makerToken, takerToken].includes(c.metaToken)), + (c.tokens.includes(t) && c.metaTokens === undefined) || + (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), ), ); } @@ -148,8 +174,8 @@ export function getSnowSwapInfosForPair(chainId: ChainId, takerToken: string, ma return Object.values(SNOWSWAP_MAINNET_INFOS).filter(c => [makerToken, takerToken].every( t => - (c.tokens.includes(t) && c.metaToken === undefined) || - (c.tokens.includes(t) && c.metaToken !== undefined && [makerToken, takerToken].includes(c.metaToken)), + (c.tokens.includes(t) && c.metaTokens === undefined) || + (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), ), ); } @@ -161,8 +187,8 @@ export function getNerveInfosForPair(chainId: ChainId, takerToken: string, maker return Object.values(NERVE_BSC_INFOS).filter(c => [makerToken, takerToken].every( t => - (c.tokens.includes(t) && c.metaToken === undefined) || - (c.tokens.includes(t) && c.metaToken !== undefined && [makerToken, takerToken].includes(c.metaToken)), + (c.tokens.includes(t) && c.metaTokens === undefined) || + (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), ), ); } @@ -174,8 +200,8 @@ export function getBeltInfosForPair(chainId: ChainId, takerToken: string, makerT return Object.values(BELT_BSC_INFOS).filter(c => [makerToken, takerToken].every( t => - (c.tokens.includes(t) && c.metaToken === undefined) || - (c.tokens.includes(t) && c.metaToken !== undefined && [makerToken, takerToken].includes(c.metaToken)), + (c.tokens.includes(t) && c.metaTokens === undefined) || + (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), ), ); } @@ -187,8 +213,8 @@ export function getEllipsisInfosForPair(chainId: ChainId, takerToken: string, ma return Object.values(ELLIPSIS_BSC_INFOS).filter(c => [makerToken, takerToken].every( t => - (c.tokens.includes(t) && c.metaToken === undefined) || - (c.tokens.includes(t) && c.metaToken !== undefined && [makerToken, takerToken].includes(c.metaToken)), + (c.tokens.includes(t) && c.metaTokens === undefined) || + (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), ), ); } @@ -198,20 +224,18 @@ export function getSmoothyInfosForPair(chainId: ChainId, takerToken: string, mak return Object.values(SMOOTHY_BSC_INFOS).filter(c => [makerToken, takerToken].every( t => - (c.tokens.includes(t) && c.metaToken === undefined) || + (c.tokens.includes(t) && c.metaTokens === undefined) || (c.tokens.includes(t) && - c.metaToken !== undefined && - [makerToken, takerToken].includes(c.metaToken)), + [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), ), ); } else if (chainId === ChainId.Mainnet) { return Object.values(SMOOTHY_MAINNET_INFOS).filter(c => [makerToken, takerToken].every( t => - (c.tokens.includes(t) && c.metaToken === undefined) || + (c.tokens.includes(t) && c.metaTokens === undefined) || (c.tokens.includes(t) && - c.metaToken !== undefined && - [makerToken, takerToken].includes(c.metaToken)), + [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), ), ); } else { @@ -226,8 +250,8 @@ export function getSaddleInfosForPair(chainId: ChainId, takerToken: string, make return Object.values(SADDLE_MAINNET_INFOS).filter(c => [makerToken, takerToken].every( t => - (c.tokens.includes(t) && c.metaToken === undefined) || - (c.tokens.includes(t) && c.metaToken !== undefined && [makerToken, takerToken].includes(c.metaToken)), + (c.tokens.includes(t) && c.metaTokens === undefined) || + (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), ), ); } @@ -239,8 +263,8 @@ export function getXSigmaInfosForPair(chainId: ChainId, takerToken: string, make return Object.values(XSIGMA_MAINNET_INFOS).filter(c => [makerToken, takerToken].every( t => - (c.tokens.includes(t) && c.metaToken === undefined) || - (c.tokens.includes(t) && c.metaToken !== undefined && [makerToken, takerToken].includes(c.metaToken)), + (c.tokens.includes(t) && c.metaTokens === undefined) || + (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), ), ); } @@ -274,6 +298,7 @@ export function getCurveLikeInfosForPair( makerToken: string, source: | ERC20BridgeSource.Curve + | ERC20BridgeSource.CurveV2 | ERC20BridgeSource.Swerve | ERC20BridgeSource.SnowSwap | ERC20BridgeSource.Nerve @@ -288,6 +313,9 @@ export function getCurveLikeInfosForPair( case ERC20BridgeSource.Curve: pools = getCurveInfosForPair(chainId, takerToken, makerToken); break; + case ERC20BridgeSource.CurveV2: + pools = getCurveV2InfosForPair(chainId, takerToken, makerToken); + break; case ERC20BridgeSource.Swerve: pools = getSwerveInfosForPair(chainId, takerToken, makerToken); break; diff --git a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts index 2370296e98..68df8f7ec2 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts @@ -94,6 +94,7 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId( ERC20BridgeSource.Saddle, ERC20BridgeSource.XSigma, ERC20BridgeSource.UniswapV3, + ERC20BridgeSource.CurveV2, ]), [ChainId.Ropsten]: new SourceFilters([ ERC20BridgeSource.Kyber, @@ -136,6 +137,7 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId( ERC20BridgeSource.Curve, ERC20BridgeSource.DodoV2, ERC20BridgeSource.Dodo, + ERC20BridgeSource.CurveV2, ]), }, new SourceFilters([]), @@ -176,6 +178,7 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId( ERC20BridgeSource.Saddle, ERC20BridgeSource.XSigma, ERC20BridgeSource.UniswapV3, + ERC20BridgeSource.CurveV2, ]), [ChainId.Ropsten]: new SourceFilters([ ERC20BridgeSource.Kyber, @@ -218,6 +221,7 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId( ERC20BridgeSource.Curve, ERC20BridgeSource.DodoV2, ERC20BridgeSource.Dodo, + ERC20BridgeSource.CurveV2, ]), }, new SourceFilters([]), @@ -399,10 +403,18 @@ export const CURVE_POOLS = { BUSD: '0x4807862aa8b2bf68830e4c8dc86d0e9a998e085a', }; +export const CURVE_V2_POOLS = { + tricrypto: '0x80466c64868e1ab14a1ddf27a676c3fcbe638fe5', +}; + export const CURVE_POLYGON_POOLS = { aave: '0x445fe580ef8d70ff569ab36e80c647af338db351', }; +export const CURVE_V2_POLYGON_POOLS = { + atricrypto: '0x3fcd5de6a9fc8a99995c406c77dda3ed7e406f81', +}; + export const SWERVE_POOLS = { y: '0x329239599afb305da0a2ec69c58f8a6697f9f88d', }; @@ -523,13 +535,15 @@ export const NATIVE_FEE_TOKEN_AMOUNT_BY_CHAIN_ID = valueByChainId( // Order dependent const CURVE_TRI_POOL_MAINNET_TOKENS = [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT]; const CURVE_TRI_BTC_POOL_TOKEN = [MAINNET_TOKENS.RenBTC, MAINNET_TOKENS.WBTC, MAINNET_TOKENS.sBTC]; +const CURVE_POLYGON_ATRICRYPTO_UNDERLYING_TOKENS = [POLYGON_TOKENS.DAI, POLYGON_TOKENS.USDC, POLYGON_TOKENS.USDT]; +const CURVE_POLYGON_ATRICRYPTO_TOKENS = [POLYGON_TOKENS.amDAI, POLYGON_TOKENS.amUSDC, POLYGON_TOKENS.amUSDT]; const createCurveExchangePool = (info: { tokens: string[]; pool: string; gasSchedule: number }) => ({ exchangeFunctionSelector: CurveFunctionSelectors.exchange, sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy, buyQuoteFunctionSelector: CurveFunctionSelectors.None, tokens: info.tokens, - metaToken: undefined, + metaTokens: undefined, poolAddress: info.pool, gasSchedule: info.gasSchedule, }); @@ -539,27 +553,47 @@ const createCurveExchangeUnderlyingPool = (info: { tokens: string[]; pool: strin sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, buyQuoteFunctionSelector: CurveFunctionSelectors.None, tokens: info.tokens, - metaToken: undefined, + metaTokens: undefined, poolAddress: info.pool, gasSchedule: info.gasSchedule, }); -const createCurveMetaTriPool = (info: { token: string; pool: string; gasSchedule: number }) => ({ +const createCurveMetaTriPool = (info: { tokens: string[]; pool: string; gasSchedule: number }) => ({ exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, buyQuoteFunctionSelector: CurveFunctionSelectors.None, - tokens: [info.token, ...CURVE_TRI_POOL_MAINNET_TOKENS], - metaToken: info.token, + tokens: [...info.tokens, ...CURVE_TRI_POOL_MAINNET_TOKENS], + metaTokens: info.tokens, poolAddress: info.pool, gasSchedule: info.gasSchedule, }); -const createCurveMetaTriBtcPool = (info: { token: string; pool: string; gasSchedule: number }) => ({ +const createCurveMetaTriBtcPool = (info: { tokens: string[]; pool: string; gasSchedule: number }) => ({ exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, buyQuoteFunctionSelector: CurveFunctionSelectors.None, - tokens: [info.token, ...CURVE_TRI_BTC_POOL_TOKEN], - metaToken: info.token, + tokens: [...info.tokens, ...CURVE_TRI_BTC_POOL_TOKEN], + metaTokens: info.tokens, + poolAddress: info.pool, + gasSchedule: info.gasSchedule, +}); + +const createCurveExchangeV2Pool = (info: { tokens: string[]; pool: string; gasSchedule: number }) => ({ + exchangeFunctionSelector: CurveFunctionSelectors.exchange_v2, + sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_v2, + buyQuoteFunctionSelector: CurveFunctionSelectors.None, + tokens: info.tokens, + metaTokens: undefined, + poolAddress: info.pool, + gasSchedule: info.gasSchedule, +}); + +const createCurveV2MetaTriPool = (info: { tokens: string[]; pool: string; gasSchedule: number }) => ({ + exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying_v2, + sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying_v2, + buyQuoteFunctionSelector: CurveFunctionSelectors.None, + tokens: [...CURVE_POLYGON_ATRICRYPTO_UNDERLYING_TOKENS, ...info.tokens], + metaTokens: info.tokens, poolAddress: info.pool, gasSchedule: info.gasSchedule, }); @@ -606,52 +640,52 @@ export const CURVE_MAINNET_INFOS: { [name: string]: CurveInfo } = { gasSchedule: 176e3, }), [CURVE_POOLS.GUSD]: createCurveMetaTriPool({ - token: MAINNET_TOKENS.GUSD, + tokens: [MAINNET_TOKENS.GUSD], pool: CURVE_POOLS.GUSD, gasSchedule: 411e3, }), [CURVE_POOLS.HUSD]: createCurveMetaTriPool({ - token: MAINNET_TOKENS.HUSD, + tokens: [MAINNET_TOKENS.HUSD], pool: CURVE_POOLS.HUSD, gasSchedule: 396e3, }), [CURVE_POOLS.USDN]: createCurveMetaTriPool({ - token: MAINNET_TOKENS.USDN, + tokens: [MAINNET_TOKENS.USDN], pool: CURVE_POOLS.USDN, gasSchedule: 398e3, }), [CURVE_POOLS.mUSD]: createCurveMetaTriPool({ - token: MAINNET_TOKENS.mUSD, + tokens: [MAINNET_TOKENS.mUSD], pool: CURVE_POOLS.mUSD, gasSchedule: 385e3, }), [CURVE_POOLS.dUSD]: createCurveMetaTriPool({ - token: MAINNET_TOKENS.dUSD, + tokens: [MAINNET_TOKENS.dUSD], pool: CURVE_POOLS.dUSD, gasSchedule: 371e3, }), [CURVE_POOLS.tBTC]: createCurveMetaTriBtcPool({ - token: MAINNET_TOKENS.tBTC, + tokens: [MAINNET_TOKENS.tBTC], pool: CURVE_POOLS.tBTC, gasSchedule: 482e3, }), [CURVE_POOLS.pBTC]: createCurveMetaTriBtcPool({ - token: MAINNET_TOKENS.pBTC, + tokens: [MAINNET_TOKENS.pBTC], pool: CURVE_POOLS.pBTC, gasSchedule: 503e3, }), [CURVE_POOLS.bBTC]: createCurveMetaTriBtcPool({ - token: MAINNET_TOKENS.bBTC, + tokens: [MAINNET_TOKENS.bBTC], pool: CURVE_POOLS.bBTC, gasSchedule: 497e3, }), [CURVE_POOLS.oBTC]: createCurveMetaTriBtcPool({ - token: MAINNET_TOKENS.oBTC, + tokens: [MAINNET_TOKENS.oBTC], pool: CURVE_POOLS.oBTC, gasSchedule: 488e3, }), [CURVE_POOLS.UST]: createCurveMetaTriPool({ - token: MAINNET_TOKENS.UST, + tokens: [MAINNET_TOKENS.UST], pool: CURVE_POOLS.UST, gasSchedule: 340e3, }), @@ -681,7 +715,7 @@ export const CURVE_MAINNET_INFOS: { [name: string]: CurveInfo } = { gasSchedule: 580e3, }), [CURVE_POOLS.USDP]: createCurveMetaTriPool({ - token: MAINNET_TOKENS.USDP, + tokens: [MAINNET_TOKENS.USDP], pool: CURVE_POOLS.USDP, gasSchedule: 374e3, }), @@ -696,32 +730,32 @@ export const CURVE_MAINNET_INFOS: { [name: string]: CurveInfo } = { gasSchedule: 319e3, }), [CURVE_POOLS.TUSD]: createCurveMetaTriPool({ - token: MAINNET_TOKENS.TUSD, + tokens: [MAINNET_TOKENS.TUSD], pool: CURVE_POOLS.TUSD, gasSchedule: 404e3, }), [CURVE_POOLS.STABLEx]: createCurveMetaTriPool({ - token: MAINNET_TOKENS.STABLEx, + tokens: [MAINNET_TOKENS.STABLEx], pool: CURVE_POOLS.STABLEx, gasSchedule: 397e3, }), [CURVE_POOLS.alUSD]: createCurveMetaTriPool({ - token: MAINNET_TOKENS.alUSD, + tokens: [MAINNET_TOKENS.alUSD], pool: CURVE_POOLS.alUSD, gasSchedule: 387e3, }), [CURVE_POOLS.FRAX]: createCurveMetaTriPool({ - token: MAINNET_TOKENS.FRAX, + tokens: [MAINNET_TOKENS.FRAX], pool: CURVE_POOLS.FRAX, gasSchedule: 387e3, }), [CURVE_POOLS.LUSD]: createCurveMetaTriPool({ - token: MAINNET_TOKENS.LUSD, + tokens: [MAINNET_TOKENS.LUSD], pool: CURVE_POOLS.LUSD, gasSchedule: 387e3, }), [CURVE_POOLS.BUSD]: createCurveMetaTriPool({ - token: MAINNET_TOKENS.BUSD, + tokens: [MAINNET_TOKENS.BUSD], pool: CURVE_POOLS.BUSD, gasSchedule: 387e3, }), @@ -745,19 +779,35 @@ export const CURVE_MAINNET_INFOS: { [name: string]: CurveInfo } = { }), }; +export const CURVE_V2_MAINNET_INFOS: { [name: string]: CurveInfo } = { + [CURVE_V2_POOLS.tricrypto]: createCurveExchangeV2Pool({ + tokens: [MAINNET_TOKENS.USDT, MAINNET_TOKENS.WBTC, MAINNET_TOKENS.WETH], + pool: CURVE_V2_POOLS.tricrypto, + gasSchedule: 300e3, + }), +}; + export const CURVE_POLYGON_INFOS: { [name: string]: CurveInfo } = { ['aave_exchangeunderlying']: createCurveExchangeUnderlyingPool({ - tokens: [POLYGON_TOKENS.DAI, POLYGON_TOKENS.USDC, POLYGON_TOKENS.USDT], + tokens: CURVE_POLYGON_ATRICRYPTO_UNDERLYING_TOKENS, pool: CURVE_POLYGON_POOLS.aave, gasSchedule: 300e3, }), ['aave_exchange']: createCurveExchangePool({ - tokens: [POLYGON_TOKENS.amDAI, POLYGON_TOKENS.amUSDC, POLYGON_TOKENS.amUSDT], + tokens: CURVE_POLYGON_ATRICRYPTO_TOKENS, pool: CURVE_POLYGON_POOLS.aave, gasSchedule: 150e3, }), }; +export const CURVE_V2_POLYGON_INFOS: { [name: string]: CurveInfo } = { + [CURVE_V2_POLYGON_POOLS.atricrypto]: createCurveV2MetaTriPool({ + tokens: [POLYGON_TOKENS.WBTC, POLYGON_TOKENS.WETH], + pool: CURVE_V2_POLYGON_POOLS.atricrypto, + gasSchedule: 300e3, + }), +}; + export const SWERVE_MAINNET_INFOS: { [name: string]: CurveInfo } = { [SWERVE_POOLS.y]: createCurveExchangePool({ tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT, MAINNET_TOKENS.TUSD], @@ -822,7 +872,7 @@ export const SADDLE_MAINNET_INFOS: { [name: string]: CurveInfo } = { buyQuoteFunctionSelector: CurveFunctionSelectors.None, poolAddress: SADDLE_POOLS.stables, tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT], - metaToken: undefined, + metaTokens: undefined, gasSchedule: 150e3, }, [SADDLE_POOLS.bitcoins]: { @@ -831,7 +881,7 @@ export const SADDLE_MAINNET_INFOS: { [name: string]: CurveInfo } = { buyQuoteFunctionSelector: CurveFunctionSelectors.None, poolAddress: SADDLE_POOLS.bitcoins, tokens: [MAINNET_TOKENS.tBTC, MAINNET_TOKENS.WBTC, MAINNET_TOKENS.RenBTC, MAINNET_TOKENS.sBTC], - metaToken: undefined, + metaTokens: undefined, gasSchedule: 150e3, }, }; @@ -852,7 +902,7 @@ export const SMOOTHY_MAINNET_INFOS: { [name: string]: CurveInfo } = { MAINNET_TOKENS.PAX, MAINNET_TOKENS.GUSD, ], - metaToken: undefined, + metaTokens: undefined, gasSchedule: 190e3, }, }; @@ -864,7 +914,7 @@ export const SMOOTHY_BSC_INFOS: { [name: string]: CurveInfo } = { buyQuoteFunctionSelector: CurveFunctionSelectors.None, poolAddress: SMOOTHY_POOLS.syUSD, tokens: [BSC_TOKENS.BUSD, BSC_TOKENS.USDT, BSC_TOKENS.USDC, BSC_TOKENS.DAI, BSC_TOKENS.PAX, BSC_TOKENS.UST], - metaToken: undefined, + metaTokens: undefined, gasSchedule: 90e3, }, }; @@ -876,7 +926,7 @@ export const NERVE_BSC_INFOS: { [name: string]: CurveInfo } = { buyQuoteFunctionSelector: CurveFunctionSelectors.None, poolAddress: NERVE_POOLS.threePool, tokens: [BSC_TOKENS.BUSD, BSC_TOKENS.USDT, BSC_TOKENS.USDC], - metaToken: undefined, + metaTokens: undefined, gasSchedule: 140e3, }, }; @@ -1300,6 +1350,7 @@ export const DEFAULT_GAS_SCHEDULE: Required = { [ERC20BridgeSource.Eth2Dai]: () => 400e3, [ERC20BridgeSource.Kyber]: () => 450e3, [ERC20BridgeSource.Curve]: fillData => (fillData as CurveFillData).pool.gasSchedule, + [ERC20BridgeSource.CurveV2]: fillData => (fillData as CurveFillData).pool.gasSchedule, [ERC20BridgeSource.Swerve]: fillData => (fillData as CurveFillData).pool.gasSchedule, [ERC20BridgeSource.SnowSwap]: fillData => (fillData as CurveFillData).pool.gasSchedule, [ERC20BridgeSource.Nerve]: fillData => (fillData as CurveFillData).pool.gasSchedule, diff --git a/packages/asset-swapper/src/utils/market_operation_utils/orders.ts b/packages/asset-swapper/src/utils/market_operation_utils/orders.ts index d5a85d0726..a8c8a62b13 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/orders.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/orders.ts @@ -161,6 +161,8 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'ComethSwap'); case ERC20BridgeSource.Dfyn: return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'Dfyn'); + case ERC20BridgeSource.CurveV2: + return encodeBridgeSourceId(BridgeProtocol.CurveV2, 'CurveV2'); default: throw new Error(AggregationError.NoBridgeForSource); } @@ -183,6 +185,7 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder switch (order.source) { case ERC20BridgeSource.Curve: + case ERC20BridgeSource.CurveV2: case ERC20BridgeSource.Swerve: case ERC20BridgeSource.SnowSwap: case ERC20BridgeSource.Nerve: @@ -392,6 +395,7 @@ export const BRIDGE_ENCODERS: { ]), // Curve like [ERC20BridgeSource.Curve]: curveEncoder, + [ERC20BridgeSource.CurveV2]: curveEncoder, [ERC20BridgeSource.Swerve]: curveEncoder, [ERC20BridgeSource.SnowSwap]: curveEncoder, [ERC20BridgeSource.Nerve]: curveEncoder, diff --git a/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts b/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts index f971089f02..7ce8b4b131 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts @@ -1213,6 +1213,7 @@ export class SamplerOperations { ), ); case ERC20BridgeSource.Curve: + case ERC20BridgeSource.CurveV2: case ERC20BridgeSource.Swerve: case ERC20BridgeSource.SnowSwap: case ERC20BridgeSource.Nerve: @@ -1466,6 +1467,7 @@ export class SamplerOperations { ), ); case ERC20BridgeSource.Curve: + case ERC20BridgeSource.CurveV2: case ERC20BridgeSource.Swerve: case ERC20BridgeSource.SnowSwap: case ERC20BridgeSource.Nerve: diff --git a/packages/asset-swapper/src/utils/market_operation_utils/types.ts b/packages/asset-swapper/src/utils/market_operation_utils/types.ts index f151bb934d..1bba9442d3 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/types.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/types.ts @@ -66,6 +66,7 @@ export enum ERC20BridgeSource { Saddle = 'Saddle', XSigma = 'xSigma', UniswapV3 = 'Uniswap_V3', + CurveV2 = 'Curve_V2', // BSC only PancakeSwap = 'PancakeSwap', PancakeSwapV2 = 'PancakeSwap_V2', @@ -96,6 +97,11 @@ export enum CurveFunctionSelectors { get_dx_underlying = '0x0e71d1b9', get_dy = '0x5e0d443f', get_dx = '0x67df02ca', + // Curve V2 + exchange_v2 = '0x5b41b908', + exchange_underlying_v2 = '0x65b2489b', + get_dy_v2 = '0x556d6e9f', + get_dy_underlying_v2 = '0x85f11d1e', // Smoothy swap_uint256 = '0x5673b02d', // swap(uint256,uint256,uint256,uint256) get_swap_amount = '0x45cf2ef6', // getSwapAmount(uint256,uint256,uint256) @@ -114,7 +120,7 @@ export interface CurveInfo { buyQuoteFunctionSelector: CurveFunctionSelectors; poolAddress: string; tokens: string[]; - metaToken: string | undefined; + metaTokens: string[] | undefined; gasSchedule: number; } diff --git a/packages/contract-addresses/addresses.json b/packages/contract-addresses/addresses.json index 7b6e0ef47d..67bfab9249 100644 --- a/packages/contract-addresses/addresses.json +++ b/packages/contract-addresses/addresses.json @@ -36,7 +36,7 @@ "wethTransformer": "0xb2bc06a4efb20fc6553a69dbfa49b7be938034a7", "payTakerTransformer": "0x4638a7ebe75b911b995d0ec73a81e4f85f41f24e", "affiliateFeeTransformer": "0xda6d9fc5998f550a094585cf9171f0e8ee3ac59f", - "fillQuoteTransformer": "0xd12a34076a4d9eac4cb82d87411d958641d0db9b", + "fillQuoteTransformer": "0x75665d9a15a5212db8668bc3eb46fe09df8335af", "positiveSlippageFeeTransformer": "0xa9416ce1dbde8d331210c07b5c253d94ee4cc3fd" } }, @@ -77,7 +77,7 @@ "wethTransformer": "0x05ad19aa3826e0609a19568ffbd1dfe86c6c7184", "payTakerTransformer": "0x6d0ebf2bcd9cc93ec553b60ad201943dcca4e291", "affiliateFeeTransformer": "0x6588256778ca4432fa43983ac685c45efb2379e2", - "fillQuoteTransformer": "0xfdabf2a405034fd9034ddc51ba1189cbed6bd651", + "fillQuoteTransformer": "0xc7d935c79e4f01ed29e92950a158807b31f7b799", "positiveSlippageFeeTransformer": "0x8b332f700fd37e71c5c5b26c4d78b5ca63dd33b2" } }, @@ -282,7 +282,7 @@ "wethTransformer": "0xe309d011cc6f189a3e8dcba85922715a019fed38", "payTakerTransformer": "0x5ba7b9be86cda01cfbf56e0fb97184783be9dda1", "affiliateFeeTransformer": "0xbed27284b42e5684e987169cf1da09c5d6c49fa8", - "fillQuoteTransformer": "0x2a0b60642d58ca819a6f3a3b4a6066be0df0486c", + "fillQuoteTransformer": "0xf708d512b8a82e2862543a630403327174410baf", "positiveSlippageFeeTransformer": "0x4cd8f1c0df4d40fcc1e073845d5f6f4ed5cc8dab" } }, diff --git a/packages/protocol-utils/src/transformer_utils.ts b/packages/protocol-utils/src/transformer_utils.ts index fe1e0f9804..97b302910a 100644 --- a/packages/protocol-utils/src/transformer_utils.ts +++ b/packages/protocol-utils/src/transformer_utils.ts @@ -129,6 +129,7 @@ export enum BridgeProtocol { BalancerV2, UniswapV3, KyberDmm, + CurveV2, } // tslint:enable: enum-naming