diff --git a/packages/asset-swapper/CHANGELOG.json b/packages/asset-swapper/CHANGELOG.json index f93650e73b..1cbf9bdad9 100644 --- a/packages/asset-swapper/CHANGELOG.json +++ b/packages/asset-swapper/CHANGELOG.json @@ -16,6 +16,10 @@ { "version": "6.4.0", "changes": [ + { + "note": "Added Component, Smoothy, Saddle, Curve open pools, tweeks gas schedule, adding SushiSwap as a fee quote source", + "pr": 182 + }, { "note": "Use SOURCE_FLAGS.rfqOrder in comparisonPrice", "pr": 177 diff --git a/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol b/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol index b2ea67648f..fc15071357 100644 --- a/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol +++ b/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol @@ -34,6 +34,7 @@ import "./MStableSampler.sol"; import "./MooniswapSampler.sol"; import "./NativeOrderSampler.sol"; import "./ShellSampler.sol"; +import "./SmoothySampler.sol"; import "./TwoHopSampler.sol"; import "./UniswapSampler.sol"; import "./UniswapV2Sampler.sol"; @@ -55,6 +56,7 @@ contract ERC20BridgeSampler is MultiBridgeSampler, NativeOrderSampler, ShellSampler, + SmoothySampler, TwoHopSampler, UniswapSampler, UniswapV2Sampler, diff --git a/packages/asset-swapper/contracts/src/ShellSampler.sol b/packages/asset-swapper/contracts/src/ShellSampler.sol index 8435f6674a..f580e12cc2 100644 --- a/packages/asset-swapper/contracts/src/ShellSampler.sol +++ b/packages/asset-swapper/contracts/src/ShellSampler.sol @@ -20,10 +20,20 @@ pragma solidity ^0.6; pragma experimental ABIEncoderV2; +import "./ApproximateBuys.sol"; import "./interfaces/IShell.sol"; +import "./SamplerUtils.sol"; -contract ShellSampler + +contract ShellSampler is + SamplerUtils, + ApproximateBuys { + + struct ShellInfo { + address poolAddress; + } + /// @dev Default gas limit for Shell calls. uint256 constant private DEFAULT_CALL_GAS = 300e3; // 300k @@ -56,10 +66,6 @@ contract ShellSampler returns (uint256 amount) { makerTokenAmounts[i] = amount; - // Break early if there are 0 amounts - if (makerTokenAmounts[i] == 0) { - break; - } } catch (bytes memory) { // Swallow failures, leaving all results as zero. break; @@ -84,26 +90,37 @@ contract ShellSampler view returns (uint256[] memory takerTokenAmounts) { - // Initialize array of maker token amounts. - uint256 numSamples = makerTokenAmounts.length; - takerTokenAmounts = new uint256[](numSamples); + return _sampleApproximateBuys( + ApproximateBuyQuoteOpts({ + makerTokenData: abi.encode(makerToken, pool), + takerTokenData: abi.encode(takerToken, pool), + getSellQuoteCallback: _sampleSellForApproximateBuyFromShell + }), + makerTokenAmounts + ); + } - for (uint256 i = 0; i < numSamples; i++) { - try - IShell(pool).viewTargetSwap - {gas: DEFAULT_CALL_GAS} - (takerToken, makerToken, makerTokenAmounts[i]) - returns (uint256 amount) - { - takerTokenAmounts[i] = amount; - // Break early if there are 0 amounts - if (takerTokenAmounts[i] == 0) { - break; - } - } catch (bytes memory) { - // Swallow failures, leaving all results as zero. - break; - } + function _sampleSellForApproximateBuyFromShell( + bytes memory takerTokenData, + bytes memory makerTokenData, + uint256 sellAmount + ) + private + view + returns (uint256 buyAmount) + { + (address takerToken, address pool) = abi.decode(takerTokenData, (address, address)); + (address makerToken) = abi.decode(makerTokenData, (address)); + + try + this.sampleSellsFromShell + (pool, takerToken, makerToken, _toSingleValueArray(sellAmount)) + returns (uint256[] memory amounts) + { + return amounts[0]; + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. + return 0; } } } diff --git a/packages/asset-swapper/contracts/src/SmoothySampler.sol b/packages/asset-swapper/contracts/src/SmoothySampler.sol new file mode 100644 index 0000000000..bd9e06bc04 --- /dev/null +++ b/packages/asset-swapper/contracts/src/SmoothySampler.sol @@ -0,0 +1,156 @@ +// 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; +pragma experimental ABIEncoderV2; + +// import "./interfaces/ISmoothy.sol"; +import "./ApproximateBuys.sol"; +import "./SamplerUtils.sol"; +import "./interfaces/ISmoothy.sol"; + +contract SmoothySampler is + SamplerUtils, + ApproximateBuys +{ + /// @dev Information for sampling from smoothy sources. + struct SmoothyInfo { + address poolAddress; + bytes4 sellQuoteFunctionSelector; + bytes4 buyQuoteFunctionSelector; + } + + /// @dev Base gas limit for Smoothy calls. + uint256 constant private SMOOTHY_CALL_GAS = 600e3; + + /// @dev Sample sell quotes from Smoothy. + /// @param smoothyInfo Smoothy information specific to this token pair. + /// @param fromTokenIdx Index of the taker token (what to sell). + /// @param toTokenIdx Index of the maker token (what to buy). + /// @param takerTokenAmounts Taker token sell amount for each sample. + /// @return makerTokenAmounts Maker amounts bought at each taker token + /// amount. + function sampleSellsFromSmoothy( + SmoothyInfo memory smoothyInfo, + int128 fromTokenIdx, + int128 toTokenIdx, + uint256[] memory takerTokenAmounts + ) + public + view + returns (uint256[] memory makerTokenAmounts) + { + // Basically a Curve fork + + // Smoothy only keep a percentage of its tokens available in reserve + uint256 poolReserveMakerAmount = ISmoothy(smoothyInfo.poolAddress).getBalance(uint256(toTokenIdx)) - + ISmoothy(smoothyInfo.poolAddress)._yBalances(uint256(toTokenIdx)); + (, , , uint256 decimals) = ISmoothy(smoothyInfo.poolAddress).getTokenStats(uint256(toTokenIdx)); + poolReserveMakerAmount = poolReserveMakerAmount/(10**(18-decimals)); + + uint256 numSamples = takerTokenAmounts.length; + makerTokenAmounts = new uint256[](numSamples); + for (uint256 i = 0; i < numSamples; i++) { + (bool didSucceed, bytes memory resultData) = + smoothyInfo.poolAddress.staticcall.gas(SMOOTHY_CALL_GAS)( + abi.encodeWithSelector( + smoothyInfo.sellQuoteFunctionSelector, + fromTokenIdx, + toTokenIdx, + takerTokenAmounts[i] + )); + uint256 buyAmount = 0; + if (didSucceed) { + buyAmount = abi.decode(resultData, (uint256)); + } + + // Make sure the quoted buyAmount is available in the pool reserve + if (buyAmount >= poolReserveMakerAmount) { + // Assign pool reserve amount for all higher samples to break early + for (uint256 j = i; j < numSamples; j++) { + makerTokenAmounts[j] = poolReserveMakerAmount; + } + break; + } else { + makerTokenAmounts[i] = buyAmount; + } + + // Break early if there are 0 amounts + if (makerTokenAmounts[i] == 0) { + break; + } + } + } + + /// @dev Sample buy quotes from Smoothy. + /// @param smoothyInfo Smoothy information specific to this token pair. + /// @param fromTokenIdx Index of the taker token (what to sell). + /// @param toTokenIdx Index of the maker token (what to buy). + /// @param makerTokenAmounts Maker token buy amount for each sample. + /// @return takerTokenAmounts Taker amounts sold at each maker token + /// amount. + function sampleBuysFromSmoothy( + SmoothyInfo memory smoothyInfo, + int128 fromTokenIdx, + int128 toTokenIdx, + uint256[] memory makerTokenAmounts + ) + public + view + returns (uint256[] memory takerTokenAmounts) + { + // Buys not supported so approximate it. + return _sampleApproximateBuys( + ApproximateBuyQuoteOpts({ + makerTokenData: abi.encode(toTokenIdx, smoothyInfo), + takerTokenData: abi.encode(fromTokenIdx, smoothyInfo), + getSellQuoteCallback: _sampleSellForApproximateBuyFromSmoothy + }), + makerTokenAmounts + ); + } + + function _sampleSellForApproximateBuyFromSmoothy( + bytes memory takerTokenData, + bytes memory makerTokenData, + uint256 sellAmount + ) + private + view + returns (uint256 buyAmount) + { + (int128 takerTokenIdx, SmoothyInfo memory smoothyInfo) = + abi.decode(takerTokenData, (int128, SmoothyInfo)); + (int128 makerTokenIdx) = + abi.decode(makerTokenData, (int128)); + (bool success, bytes memory resultData) = + address(this).staticcall(abi.encodeWithSelector( + this.sampleSellsFromSmoothy.selector, + smoothyInfo, + takerTokenIdx, + makerTokenIdx, + _toSingleValueArray(sellAmount) + )); + if (!success) { + return 0; + } + // solhint-disable-next-line indent + return abi.decode(resultData, (uint256[]))[0]; + } +} diff --git a/packages/asset-swapper/contracts/src/interfaces/ISmoothy.sol b/packages/asset-swapper/contracts/src/interfaces/ISmoothy.sol new file mode 100644 index 0000000000..5feb975346 --- /dev/null +++ b/packages/asset-swapper/contracts/src/interfaces/ISmoothy.sol @@ -0,0 +1,45 @@ +// 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; + + +interface ISmoothy { + + function getBalance ( + uint256 tid + ) + external + view + returns (uint256 balance); + + function _yBalances ( + uint256 tid + ) + external + view + returns (uint256 balance); + + function getTokenStats ( + uint256 tid + ) + external + view + returns (uint256 softWeight, uint256 hardWeight, uint256 balance, uint256 decimals); +} diff --git a/packages/asset-swapper/package.json b/packages/asset-swapper/package.json index b18cc4ede3..722202a885 100644 --- a/packages/asset-swapper/package.json +++ b/packages/asset-swapper/package.json @@ -38,7 +38,7 @@ "config": { "publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BancorSampler|CurveSampler|DODOSampler|DODOV2Sampler|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|FakeTaker|IBalancer|IBancor|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UtilitySampler).json", + "abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BancorSampler|CurveSampler|DODOSampler|DODOV2Sampler|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|FakeTaker|IBalancer|IBancor|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|ISmoothy|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SmoothySampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UtilitySampler).json", "postpublish": { "assets": [] } diff --git a/packages/asset-swapper/src/utils/market_operation_utils/bancor_service.ts b/packages/asset-swapper/src/utils/market_operation_utils/bancor_service.ts index 0389f2d628..eccea376eb 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/bancor_service.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/bancor_service.ts @@ -3,11 +3,11 @@ import { SDK } from '@bancor/sdk'; import { Ethereum } from '@bancor/sdk/dist/blockchains/ethereum'; import { BlockchainType } from '@bancor/sdk/dist/types'; -import { TOKENS } from './constants'; +import { MAINNET_TOKENS } from './constants'; const findToken = (tokenAddress: string, graph: object): string => // If we're looking for WETH it is stored by Bancor as the 0xeee address - tokenAddress.toLowerCase() === TOKENS.WETH.toLowerCase() + tokenAddress.toLowerCase() === MAINNET_TOKENS.WETH.toLowerCase() ? '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' : Object.keys(graph).filter(k => k.toLowerCase() === tokenAddress.toLowerCase())[0]; 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 8c7252bc32..f6cd266009 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 @@ -4,20 +4,24 @@ import { BigNumber, NULL_BYTES } from '@0x/utils'; import { BAKERYSWAP_ROUTER_BY_CHAIN_ID, BELT_BSC_INFOS, + COMPONENT_POOLS_BY_CHAIN_ID, CRYPTO_COM_ROUTER_BY_CHAIN_ID, + CURVE_MAINNET_INFOS, ELLIPSIS_BSC_INFOS, KYBER_BRIDGED_LIQUIDITY_PREFIX, KYBER_DMM_ROUTER_BY_CHAIN_ID, - MAINNET_CURVE_INFOS, - MAINNET_SNOWSWAP_INFOS, - MAINNET_SWERVE_INFOS, MAX_DODOV2_POOLS_QUERIED, MAX_KYBER_RESERVES_QUERIED, NERVE_BSC_INFOS, NULL_ADDRESS, PANCAKESWAP_ROUTER_BY_CHAIN_ID, + SADDLE_MAINNET_INFOS, SHELL_POOLS_BY_CHAIN_ID, + SMOOTHY_BSC_INFOS, + SMOOTHY_MAINNET_INFOS, + SNOWSWAP_MAINNET_INFOS, SUSHISWAP_ROUTER_BY_CHAIN_ID, + SWERVE_MAINNET_INFOS, UNISWAPV2_ROUTER_BY_CHAIN_ID, } from './constants'; import { CurveInfo, ERC20BridgeSource } from './types'; @@ -61,12 +65,22 @@ export function getShellsForPair(chainId: ChainId, takerToken: string, makerToke .map(i => i.poolAddress); } +// tslint:disable completed-docs +export function getComponentForPair(chainId: ChainId, takerToken: string, makerToken: string): string[] { + if (chainId !== ChainId.Mainnet) { + return []; + } + return Object.values(COMPONENT_POOLS_BY_CHAIN_ID[chainId]) + .filter(c => [makerToken, takerToken].every(t => c.tokens.includes(t))) + .map(i => i.poolAddress); +} + // tslint:disable completed-docs export function getCurveInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] { if (chainId !== ChainId.Mainnet) { return []; } - return Object.values(MAINNET_CURVE_INFOS).filter(c => + return Object.values(CURVE_MAINNET_INFOS).filter(c => [makerToken, takerToken].every( t => (c.tokens.includes(t) && c.metaToken === undefined) || @@ -79,7 +93,7 @@ export function getSwerveInfosForPair(chainId: ChainId, takerToken: string, make if (chainId !== ChainId.Mainnet) { return []; } - return Object.values(MAINNET_SWERVE_INFOS).filter(c => + return Object.values(SWERVE_MAINNET_INFOS).filter(c => [makerToken, takerToken].every( t => (c.tokens.includes(t) && c.metaToken === undefined) || @@ -92,7 +106,7 @@ export function getSnowSwapInfosForPair(chainId: ChainId, takerToken: string, ma if (chainId !== ChainId.Mainnet) { return []; } - return Object.values(MAINNET_SNOWSWAP_INFOS).filter(c => + return Object.values(SNOWSWAP_MAINNET_INFOS).filter(c => [makerToken, takerToken].every( t => (c.tokens.includes(t) && c.metaToken === undefined) || @@ -140,6 +154,61 @@ export function getEllipsisInfosForPair(chainId: ChainId, takerToken: string, ma ); } +export function getSmoothyInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] { + if (chainId === ChainId.BSC) { + return Object.values(SMOOTHY_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)), + ), + ); + } 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.metaToken !== undefined && + [makerToken, takerToken].includes(c.metaToken)), + ), + ); + } else { + return []; + } +} + +export function getSaddleInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] { + if (chainId !== ChainId.Mainnet) { + return []; + } + 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)), + ), + ); +} + +export function getShellLikeInfosForPair( + chainId: ChainId, + takerToken: string, + makerToken: string, + source: ERC20BridgeSource.Shell | ERC20BridgeSource.Component, +): string[] { + switch (source) { + case ERC20BridgeSource.Shell: + return getShellsForPair(chainId, takerToken, makerToken); + case ERC20BridgeSource.Component: + return getComponentForPair(chainId, takerToken, makerToken); + default: + throw new Error(`Unknown Shell like source ${source}`); + } +} + export function getCurveLikeInfosForPair( chainId: ChainId, takerToken: string, @@ -150,7 +219,9 @@ export function getCurveLikeInfosForPair( | ERC20BridgeSource.SnowSwap | ERC20BridgeSource.Nerve | ERC20BridgeSource.Belt - | ERC20BridgeSource.Ellipsis, + | ERC20BridgeSource.Ellipsis + | ERC20BridgeSource.Smoothy + | ERC20BridgeSource.Saddle, ): CurveInfo[] { switch (source) { case ERC20BridgeSource.Curve: @@ -165,6 +236,10 @@ export function getCurveLikeInfosForPair( return getBeltInfosForPair(chainId, takerToken, makerToken); case ERC20BridgeSource.Ellipsis: return getEllipsisInfosForPair(chainId, takerToken, makerToken); + case ERC20BridgeSource.Smoothy: + return getSmoothyInfosForPair(chainId, takerToken, makerToken); + case ERC20BridgeSource.Saddle: + return getSaddleInfosForPair(chainId, takerToken, makerToken); default: throw new Error(`Unknown Curve like source ${source}`); } 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 d4297ec0e2..646f028aeb 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts @@ -83,6 +83,9 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId( ERC20BridgeSource.Linkswap, ERC20BridgeSource.MakerPsm, ERC20BridgeSource.KyberDmm, + ERC20BridgeSource.Smoothy, + ERC20BridgeSource.Component, + ERC20BridgeSource.Saddle, ]), [ChainId.Ropsten]: new SourceFilters([ERC20BridgeSource.Native]), [ChainId.Rinkeby]: new SourceFilters([ERC20BridgeSource.Native]), @@ -99,6 +102,7 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId( ERC20BridgeSource.Nerve, ERC20BridgeSource.PancakeSwap, ERC20BridgeSource.SushiSwap, + ERC20BridgeSource.Smoothy, ]), }, @@ -134,6 +138,9 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId( ERC20BridgeSource.Linkswap, ERC20BridgeSource.MakerPsm, ERC20BridgeSource.KyberDmm, + ERC20BridgeSource.Smoothy, + ERC20BridgeSource.Component, + ERC20BridgeSource.Saddle, ]), [ChainId.Ropsten]: new SourceFilters([ERC20BridgeSource.Native]), [ChainId.Rinkeby]: new SourceFilters([ERC20BridgeSource.Native]), @@ -150,6 +157,7 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId( ERC20BridgeSource.Nerve, ERC20BridgeSource.PancakeSwap, ERC20BridgeSource.SushiSwap, + ERC20BridgeSource.Smoothy, ]), }, new SourceFilters([]), @@ -202,7 +210,7 @@ const MIRROR_WRAPPED_TOKENS = { // Mainnet tokens // Not an exhaustive list, just enough so we don't repeat ourselves -export const TOKENS = { +export const MAINNET_TOKENS = { WETH: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // Stable Coins DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', @@ -217,66 +225,142 @@ export const TOKENS = { mUSD: '0xe2f2a5c287993345a840db3b0845fbc70f5935a5', USDN: '0x674c6ad92fd080e4004b2312b45f796a192d27a0', dUSD: '0x5bc25f649fc4e26069ddf4cf4010f9f706c23831', + USDP: '0x1456688345527be1f37e9e627da0837d6f08c925', // Bitcoins WBTC: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', RenBTC: '0xeb4c2781e4eba804ce9a9803c67d0893436bb27d', sBTC: '0xfe18be6b3bd88a2d2a7f928d00292e7a9963cfc6', tBTC: '0x8daebade922df735c38c80c7ebd708af50815faa', hBTC: '0x0316eb71485b0ab14103307bf65a021042c6d380', - pBTC: '0xde5331ac4b3630f94853ff322b66407e0d6331e8', + pBTC: '0x5228a22e72ccc52d415ecfd199f99d0665e7733b', bBTC: '0x9be89d2a4cd102d8fecc6bf9da793be995c22541', oBTC: '0x8064d9ae6cdf087b1bcd5bdf3531bd5d8c537a68', // aTokens (Aave) aDAI: '0x028171bca77440897b824ca71d1c56cac55b68a3', aUSDC: '0xbcca60bb61934080951369a648fb03df4f96263c', aUSDT: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', + aSUSD: '0x6c5024cd4f8a59110119c56f8933403a539555eb', // Other MKR: '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2', EURS: '0xdb25f211ab05b1c97d595516f45794528a807ad8', sEUR: '0xd71ecff9342a5ced620049e616c5035f1db98620', sETH: '0x5e74c9036fb86bd7ecdcb084a0673efc32ea31cb', + stETH: '0xae7ab96520de3a18e5e111b5eaab095312d7fe84', LINK: '0x514910771af9ca656af840dff83e8264ecf986ca', MANA: '0x0f5d2fb29fb7d3cfee444a200298f468908cc942', KNC: '0xdd974d5c2e2928dea5f71b9825b8b646686bd200', AAVE: '0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9', + sLINK: '0xbbc455cb4f1b9e4bfc4b73970d360c8f032efee6', + yUSD: '0x5dbcf33d8c2e976c6b560249878e6f1491bca25c', + ybCRV: '0x2994529c0652d127b7842094103715ec5299bbed', + yCRV: '0xdf5e0e81dff6faf3a7e52ba697820c5e32d806a8', + bCRV: '0x3b3ac5386837dc563660fb6a0937dfaa5924333b', + yDAI: '0xacd43e627e64355f1861cec6d3a6688b31a6f952', + yUSDC: '0x597ad1e0c13bfe8025993d9e79c69e1c0233522e', + yUSDT: '0x2f08119c6f07c006695e079aafc638b8789faf18', + yTUSD: '0x37d19d1c4e1fa9dc47bd1ea12f742a0887eda74a', + crETH: '0xcbc1065255cbc3ab41a6868c22d1f1c573ab89fd', + ankrETH: '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb', + vETH: '0x898bad2774eb97cf6b94605677f43b41871410b1', // Mirror Protocol UST: '0xa47c8bf37f92abed4a126bda807a7b7498661acd', MIR: '0x09a3ecafa817268f77be1283176b946c4ff2e608', ...MIRROR_WRAPPED_TOKENS, + // StableSwap "open pools" (crv.finance) + STABLEx: '0xcd91538b91b4ba7797d39a2f66e63810b50a33d0', + alUSD: '0xbc6da0fe9ad5f3b0d58160288917aa56653660e9', + FRAX: '0x853d955acef822db058eb8505911ed77f175b99e', +}; + +export const BSC_TOKENS = { + BUSD: '0xe9e7cea3dedca5984780bafc599bd69add087d56', + USDT: '0x55d398326f99059ff775485246999027b3197955', + USDC: '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d', + DAI: '0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3', + PAX: '0xb7f8cd00c5a06c0537e2abff0b58033d02e5e094', + UST: '0x23396cf899ca06c4472205fc903bdb4de249d6fc', }; export const CURVE_POOLS = { - curve_compound: '0xa2b47e3d5c44877cca798226b7b8118f9bfb7a56', // 0.Compound + compound: '0xa2b47e3d5c44877cca798226b7b8118f9bfb7a56', // 0.Compound // 1.USDT is dead - curve_PAX: '0x06364f10b501e868329afbc005b3492902d6c763', // 2.PAX - // 3. 0x45f783cce6b7ff23b2ab2d70e416cdb7d6055f51 y-pool is dead - // 4. 0x79a8c46dea5ada233abaffd40f3a0a2b1e5a4f27 BUSD is dead - curve_sUSD: '0xa5407eae9ba41422680e2e00537571bcc53efbfd', // 5.sUSD - curve_renBTC: '0x93054188d876f558f4a66b2ef1d97d16edf0895b', // 6.ren - curve_sBTC: '0x7fc77b5c7614e1533320ea6ddc2eb61fa00a9714', // 7.sbtc - curve_HBTC: '0x4ca9b3063ec5866a4b82e437059d2c43d1be596f', // 8.hbtc - curve_TRI: '0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7', // 9.3pool - curve_GUSD: '0x4f062658eaaf2c1ccf8c8e36d6824cdf41167956', // 10.gusd - curve_HUSD: '0x3ef6a01a0f81d6046290f3e2a8c5b843e738e604', // 11.husd + PAX: '0x06364f10b501e868329afbc005b3492902d6c763', // 2.PAX + // 3.y is dead + // 3.bUSD is dead + sUSD: '0xa5407eae9ba41422680e2e00537571bcc53efbfd', // 5.sUSD + renBTC: '0x93054188d876f558f4a66b2ef1d97d16edf0895b', // 6.ren + sBTC: '0x7fc77b5c7614e1533320ea6ddc2eb61fa00a9714', // 7.sbtc + HBTC: '0x4ca9b3063ec5866a4b82e437059d2c43d1be596f', // 8.hbtc + TRI: '0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7', // 9.3pool + GUSD: '0x4f062658eaaf2c1ccf8c8e36d6824cdf41167956', // 10.gusd + HUSD: '0x3ef6a01a0f81d6046290f3e2a8c5b843e738e604', // 11.husd // 12.usdk is dead - curve_USDN: '0x0f9cb53ebe405d49a0bbdbd291a65ff571bc83e1', // 13.usdn + USDN: '0x0f9cb53ebe405d49a0bbdbd291a65ff571bc83e1', // 13.usdn // 14.linkusd is dead - curve_mUSD: '0x8474ddbe98f5aa3179b3b3f5942d724afcdec9f6', // 15.musd + mUSD: '0x8474ddbe98f5aa3179b3b3f5942d724afcdec9f6', // 15.musd // 16.rsv is dead - curve_tBTC: '0xc25099792e9349c7dd09759744ea681c7de2cb66', // 17.tbtc - curve_dUSD: '0x8038c01a0390a8c547446a0b2c18fc9aefecc10c', // 18.dusd - curve_pBTC: '0x5228a22e72ccc52d415ecfd199f99d0665e7733b', // 19.pbtc - curve_bBTC: '0x071c661b4deefb59e2a3ddb20db036821eee8f4b', // 20.bbtc - curve_oBTC: '0xd81da8d904b52208541bade1bd6595d8a251f8dd', // 21.obtc - curve_UST: '0x890f4e345b1daed0367a877a1612f86a1f86985f', // 22.ust - curve_eurs: '0x0ce6a5ff5217e38315f87032cf90686c96627caa', // 23.eurs - // curve_seth: '0xc5424b857f758e906013f3555dad202e4bdb4567', // 24.seth - curve_aave: '0xdebf20617708857ebe4f679508e7b7863a8a8eee', // 25.aave + dUSD: '0x8038c01a0390a8c547446a0b2c18fc9aefecc10c', // 17.dusd + tBTC: '0xc25099792e9349c7dd09759744ea681c7de2cb66', // 18.tbtc + pBTC: '0x7f55dde206dbad629c080068923b36fe9d6bdbef', // 19.pbtc + bBTC: '0x071c661b4deefb59e2a3ddb20db036821eee8f4b', // 20.bbtc + oBTC: '0xd81da8d904b52208541bade1bd6595d8a251f8dd', // 21.obtc + UST: '0x890f4e345b1daed0367a877a1612f86a1f86985f', // 22.ust + eurs: '0x0ce6a5ff5217e38315f87032cf90686c96627caa', // 23.eurs + // seth: '0xc5424b857f758e906013f3555dad202e4bdb4567', // 24.seth + aave: '0xdebf20617708857ebe4f679508e7b7863a8a8eee', // 25.aave + // curve steth: '0xdc24316b9ae028f1497c275eb9192a3ea0f67022' // 26.stETH + saave: '0xeb16ae0052ed37f479f7fe63849198df1765a733', // saave + // ankreth: '0xa96a65c051bf88b4095ee1f2451c2a9d43f53ae2', // ankreth + USDP: '0x42d7025938bec20b69cbae5a77421082407f053a', // usdp + ib: '0x2dded6da1bf5dbdf597c45fcfaa3194e53ecfeaf', // iron bank + link: '0xf178c0b5bb7e7abf4e12a4838c7b7c5ba2c623c0', // link + // StableSwap "open pools" (crv.finance) + TUSD: '0xecd5e75afb02efa118af914515d6521aabd189f1', + STABLEx: '0x3252efd4ea2d6c78091a1f43982ee2c3659cc3d1', + alUSD: '0x43b4fdfd4ff969587185cdb6f0bd875c5fc83f8c', + FRAX: '0xd632f22692fac7611d2aa1c0d552930d43caed3b', +}; + +export const SWERVE_POOLS = { + y: '0x329239599afb305da0a2ec69c58f8a6697f9f88d', +}; + +export const SNOWSWAP_POOLS = { + yUSD: '0xbf7ccd6c446acfcc5df023043f2167b62e81899b', + yVault: '0x4571753311e37ddb44faa8fb78a6df9a6e3c6c0b', + eth: '0x16bea2e63adade5984298d53a4d4d9c09e278192', +}; + +export const SMOOTHY_POOLS = { + syUSD: '0xe5859f4efc09027a9b718781dcb2c6910cac6e91', +}; + +export const SADDLE_POOLS = { + stables: '0x3911f80530595fbd01ab1516ab61255d75aeb066', + bitcoins: '0x4f6a43ad7cba042606decaca730d4ce0a57ac62e', +}; + +export const NERVE_POOLS = { + threePool: '0x1b3771a66ee31180906972580ade9b81afc5fcdc', +}; + +export const BELT_POOLS = { + vPool: '0xf16d312d119c13dd27fd0dc814b0bcdcaaa62dfd', +}; + +export const ELLIPSIS_POOLS = { + threePool: '0x160caed03795365f3a589f10c379ffa7d75d4e76', }; export const DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID = valueByChainId( { - [ChainId.Mainnet]: [TOKENS.WETH, TOKENS.USDT, TOKENS.DAI, TOKENS.USDC, TOKENS.WBTC], + [ChainId.Mainnet]: [ + MAINNET_TOKENS.WETH, + MAINNET_TOKENS.USDT, + MAINNET_TOKENS.DAI, + MAINNET_TOKENS.USDC, + MAINNET_TOKENS.WBTC, + ], [ChainId.BSC]: [ '0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c', // WBNB '0xe9e7cea3dedca5984780bafc599bd69add087d56', // BUSD @@ -297,10 +381,10 @@ export const DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID = valueByChainId { builder - .add(TOKENS.MIR, TOKENS.UST) - .add(TOKENS.UST, [TOKENS.MIR, ...Object.values(MIRROR_WRAPPED_TOKENS)]) - .add(TOKENS.USDT, TOKENS.UST); - Object.values(MIRROR_WRAPPED_TOKENS).forEach(t => builder.add(t, TOKENS.UST)); + .add(MAINNET_TOKENS.MIR, MAINNET_TOKENS.UST) + .add(MAINNET_TOKENS.UST, [MAINNET_TOKENS.MIR, ...Object.values(MIRROR_WRAPPED_TOKENS)]) + .add(MAINNET_TOKENS.USDT, MAINNET_TOKENS.UST); + Object.values(MIRROR_WRAPPED_TOKENS).forEach(t => builder.add(t, MAINNET_TOKENS.UST)); }) // Build .build(), @@ -313,7 +397,7 @@ export const DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID = valueByChainId( { - [ChainId.Mainnet]: TOKENS.WETH, + [ChainId.Mainnet]: MAINNET_TOKENS.WETH, [ChainId.BSC]: '0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c', // WBNB }, NULL_ADDRESS, @@ -321,274 +405,315 @@ export const NATIVE_FEE_TOKEN_BY_CHAIN_ID = valueByChainId( export const NATIVE_FEE_TOKEN_AMOUNT_BY_CHAIN_ID = valueByChainId({}, ONE_ETHER); +// 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 createCurveExchangePool = (info: { tokens: string[]; pool: string; gasSchedule: number }) => ({ + exchangeFunctionSelector: CurveFunctionSelectors.exchange, + sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy, + buyQuoteFunctionSelector: CurveFunctionSelectors.None, + tokens: info.tokens, + metaToken: undefined, + poolAddress: info.pool, + gasSchedule: info.gasSchedule, +}); + +const createCurveExchangeUnderlyingPool = (info: { tokens: string[]; pool: string; gasSchedule: number }) => ({ + exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, + sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, + buyQuoteFunctionSelector: CurveFunctionSelectors.None, + tokens: info.tokens, + metaToken: undefined, + poolAddress: info.pool, + gasSchedule: info.gasSchedule, +}); + +const createCurveMetaTriPool = (info: { token: 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, + poolAddress: info.pool, + gasSchedule: info.gasSchedule, +}); + +const createCurveMetaTriBtcPool = (info: { token: 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, + poolAddress: info.pool, + gasSchedule: info.gasSchedule, +}); + /** * Mainnet Curve configuration * The tokens are in order of their index, which each curve defines * I.e DaiUsdc curve has DAI as index 0 and USDC as index 1 */ -export const MAINNET_CURVE_INFOS: { [name: string]: CurveInfo } = { - [CURVE_POOLS.curve_compound]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx_underlying, - poolAddress: CURVE_POOLS.curve_compound, - tokens: [TOKENS.DAI, TOKENS.USDC], +export const CURVE_MAINNET_INFOS: { [name: string]: CurveInfo } = { + [CURVE_POOLS.compound]: createCurveExchangeUnderlyingPool({ + tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC], + pool: CURVE_POOLS.compound, + gasSchedule: 597e3, + }), + [CURVE_POOLS.PAX]: createCurveExchangeUnderlyingPool({ + tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT, MAINNET_TOKENS.PAX], + pool: CURVE_POOLS.PAX, + gasSchedule: 752e3, + }), + [CURVE_POOLS.sUSD]: createCurveExchangeUnderlyingPool({ + tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT, MAINNET_TOKENS.sUSD], + pool: CURVE_POOLS.sUSD, + gasSchedule: 312e3, + }), + [CURVE_POOLS.renBTC]: createCurveExchangePool({ + tokens: [MAINNET_TOKENS.RenBTC, MAINNET_TOKENS.WBTC], + pool: CURVE_POOLS.renBTC, + gasSchedule: 181e3, + }), + [CURVE_POOLS.sBTC]: createCurveExchangePool({ + tokens: [MAINNET_TOKENS.RenBTC, MAINNET_TOKENS.WBTC, MAINNET_TOKENS.sBTC], + pool: CURVE_POOLS.sBTC, + gasSchedule: 337e3, + }), + [CURVE_POOLS.HBTC]: createCurveExchangePool({ + tokens: [MAINNET_TOKENS.hBTC, MAINNET_TOKENS.WBTC], + pool: CURVE_POOLS.HBTC, + gasSchedule: 220e3, + }), + [CURVE_POOLS.TRI]: createCurveExchangePool({ + tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT], + pool: CURVE_POOLS.TRI, + gasSchedule: 186e3, + }), + [CURVE_POOLS.GUSD]: createCurveMetaTriPool({ + token: MAINNET_TOKENS.GUSD, + pool: CURVE_POOLS.GUSD, + gasSchedule: 421e3, + }), + [CURVE_POOLS.HUSD]: createCurveMetaTriPool({ + token: MAINNET_TOKENS.HUSD, + pool: CURVE_POOLS.HUSD, + gasSchedule: 406e3, + }), + [CURVE_POOLS.USDN]: createCurveMetaTriPool({ + token: MAINNET_TOKENS.USDN, + pool: CURVE_POOLS.USDN, + gasSchedule: 408e3, + }), + [CURVE_POOLS.mUSD]: createCurveMetaTriPool({ + token: MAINNET_TOKENS.mUSD, + pool: CURVE_POOLS.mUSD, + gasSchedule: 395e3, + }), + [CURVE_POOLS.dUSD]: createCurveMetaTriPool({ + token: MAINNET_TOKENS.dUSD, + pool: CURVE_POOLS.dUSD, + gasSchedule: 381e3, + }), + [CURVE_POOLS.tBTC]: createCurveMetaTriBtcPool({ + token: MAINNET_TOKENS.tBTC, + pool: CURVE_POOLS.tBTC, + gasSchedule: 492e3, + }), + [CURVE_POOLS.pBTC]: createCurveMetaTriBtcPool({ + token: MAINNET_TOKENS.pBTC, + pool: CURVE_POOLS.pBTC, + gasSchedule: 513e3, + }), + [CURVE_POOLS.bBTC]: createCurveMetaTriBtcPool({ + token: MAINNET_TOKENS.bBTC, + pool: CURVE_POOLS.bBTC, + gasSchedule: 507e3, + }), + [CURVE_POOLS.oBTC]: createCurveMetaTriBtcPool({ + token: MAINNET_TOKENS.oBTC, + pool: CURVE_POOLS.oBTC, + gasSchedule: 498e3, + }), + [CURVE_POOLS.UST]: createCurveMetaTriPool({ + token: MAINNET_TOKENS.UST, + pool: CURVE_POOLS.UST, + gasSchedule: 350e3, + }), + [CURVE_POOLS.eurs]: createCurveExchangePool({ + tokens: [MAINNET_TOKENS.EURS, MAINNET_TOKENS.sEUR], + pool: CURVE_POOLS.eurs, + gasSchedule: 330e3, + }), + [CURVE_POOLS.aave]: createCurveExchangeUnderlyingPool({ + tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT], + pool: CURVE_POOLS.aave, + gasSchedule: 590e3, + }), + [CURVE_POOLS.aave]: createCurveExchangePool({ + tokens: [MAINNET_TOKENS.aDAI, MAINNET_TOKENS.aUSDC, MAINNET_TOKENS.aUSDT], + pool: CURVE_POOLS.aave, + gasSchedule: 590e3, + }), + [CURVE_POOLS.saave]: createCurveExchangeUnderlyingPool({ + tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.sUSD], + pool: CURVE_POOLS.saave, + gasSchedule: 590e3, + }), + [CURVE_POOLS.saave]: createCurveExchangePool({ + tokens: [MAINNET_TOKENS.aDAI, MAINNET_TOKENS.aSUSD], + pool: CURVE_POOLS.saave, + gasSchedule: 590e3, + }), + [CURVE_POOLS.USDP]: createCurveMetaTriPool({ + token: MAINNET_TOKENS.USDP, + pool: CURVE_POOLS.USDP, + gasSchedule: 384e3, + }), + [CURVE_POOLS.ib]: createCurveExchangeUnderlyingPool({ + tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT], + pool: CURVE_POOLS.ib, + gasSchedule: 656e3, + }), + [CURVE_POOLS.link]: createCurveExchangePool({ + tokens: [MAINNET_TOKENS.LINK, MAINNET_TOKENS.sLINK], + pool: CURVE_POOLS.link, + gasSchedule: 329e3, + }), + [CURVE_POOLS.TUSD]: createCurveMetaTriPool({ + token: MAINNET_TOKENS.TUSD, + pool: CURVE_POOLS.TUSD, + gasSchedule: 414e3, + }), + [CURVE_POOLS.STABLEx]: createCurveMetaTriPool({ + token: MAINNET_TOKENS.STABLEx, + pool: CURVE_POOLS.STABLEx, + gasSchedule: 407e3, + }), + [CURVE_POOLS.alUSD]: createCurveMetaTriPool({ + token: MAINNET_TOKENS.alUSD, + pool: CURVE_POOLS.alUSD, + gasSchedule: 397e3, + }), + [CURVE_POOLS.FRAX]: createCurveMetaTriPool({ + token: MAINNET_TOKENS.FRAX, + pool: CURVE_POOLS.FRAX, + gasSchedule: 397e3, + }), +}; + +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], + pool: SWERVE_POOLS.y, + gasSchedule: 150e3, + }), +}; + +export const SNOWSWAP_MAINNET_INFOS: { [name: string]: CurveInfo } = { + [SNOWSWAP_POOLS.yUSD]: createCurveExchangePool({ + tokens: [MAINNET_TOKENS.yUSD, MAINNET_TOKENS.ybCRV], + pool: SNOWSWAP_POOLS.yUSD, + gasSchedule: 1000e3, + }), + [SNOWSWAP_POOLS.yUSD]: createCurveExchangeUnderlyingPool({ + tokens: [MAINNET_TOKENS.yCRV, MAINNET_TOKENS.bCRV], + pool: SNOWSWAP_POOLS.yUSD, + gasSchedule: 1000e3, + }), + [SNOWSWAP_POOLS.yVault]: createCurveExchangePool({ + tokens: [MAINNET_TOKENS.yDAI, MAINNET_TOKENS.yUSDC, MAINNET_TOKENS.yUSDT, MAINNET_TOKENS.yTUSD], + pool: SNOWSWAP_POOLS.yVault, + gasSchedule: 1500e3, + }), + [SNOWSWAP_POOLS.eth]: createCurveExchangePool({ + tokens: [MAINNET_TOKENS.WETH, MAINNET_TOKENS.vETH, MAINNET_TOKENS.ankrETH, MAINNET_TOKENS.crETH], + pool: SNOWSWAP_POOLS.eth, + gasSchedule: 1000e3, + }), +}; + +export const BELT_BSC_INFOS: { [name: string]: CurveInfo } = { + [BELT_POOLS.vPool]: createCurveExchangeUnderlyingPool({ + tokens: [BSC_TOKENS.DAI, BSC_TOKENS.USDC, BSC_TOKENS.USDT, BSC_TOKENS.BUSD], + pool: BELT_POOLS.vPool, + gasSchedule: 4500e3, + }), +}; + +export const ELLIPSIS_BSC_INFOS: { [name: string]: CurveInfo } = { + [ELLIPSIS_POOLS.threePool]: createCurveExchangePool({ + tokens: [BSC_TOKENS.BUSD, BSC_TOKENS.USDC, BSC_TOKENS.USDT], + pool: ELLIPSIS_POOLS.threePool, + gasSchedule: 150e3, + }), +}; + +// Curve pools like using custom selectors +export const SADDLE_MAINNET_INFOS: { [name: string]: CurveInfo } = { + [SADDLE_POOLS.stables]: { + exchangeFunctionSelector: CurveFunctionSelectors.swap, + sellQuoteFunctionSelector: CurveFunctionSelectors.calculateSwap, + buyQuoteFunctionSelector: CurveFunctionSelectors.None, + poolAddress: SADDLE_POOLS.stables, + tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT], metaToken: undefined, + gasSchedule: 220e3, }, - [CURVE_POOLS.curve_PAX]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_PAX, - tokens: [TOKENS.DAI, TOKENS.USDC, TOKENS.USDT, TOKENS.PAX], - metaToken: undefined, - }, - [CURVE_POOLS.curve_sUSD]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_sUSD, - tokens: [TOKENS.DAI, TOKENS.USDC, TOKENS.USDT, TOKENS.sUSD], - metaToken: undefined, - }, - [CURVE_POOLS.curve_renBTC]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_renBTC, - tokens: [TOKENS.RenBTC, TOKENS.WBTC], - metaToken: undefined, - }, - [CURVE_POOLS.curve_sBTC]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_sBTC, - tokens: [TOKENS.RenBTC, TOKENS.WBTC, TOKENS.sBTC], - metaToken: undefined, - }, - [CURVE_POOLS.curve_HBTC]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_HBTC, - tokens: [TOKENS.hBTC, TOKENS.WBTC], - metaToken: undefined, - }, - [CURVE_POOLS.curve_TRI]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_TRI, - tokens: [TOKENS.DAI, TOKENS.USDC, TOKENS.USDT], - metaToken: undefined, - }, - [CURVE_POOLS.curve_GUSD]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_GUSD, - tokens: [TOKENS.GUSD, TOKENS.DAI, TOKENS.USDC, TOKENS.USDT], - metaToken: TOKENS.GUSD, - }, - [CURVE_POOLS.curve_HUSD]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_HUSD, - tokens: [TOKENS.HUSD, TOKENS.DAI, TOKENS.USDC, TOKENS.USDT], - metaToken: TOKENS.HUSD, - }, - [CURVE_POOLS.curve_USDN]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_USDN, - tokens: [TOKENS.USDN, TOKENS.DAI, TOKENS.USDC, TOKENS.USDT], - metaToken: TOKENS.USDN, - }, - [CURVE_POOLS.curve_mUSD]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_mUSD, - tokens: [TOKENS.mUSD, TOKENS.DAI, TOKENS.USDC, TOKENS.USDT], - metaToken: TOKENS.mUSD, - }, - [CURVE_POOLS.curve_tBTC]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_tBTC, - tokens: [TOKENS.tBTC, TOKENS.RenBTC, TOKENS.WBTC, TOKENS.sBTC], - metaToken: TOKENS.tBTC, - }, - [CURVE_POOLS.curve_dUSD]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_dUSD, - tokens: [TOKENS.dUSD, TOKENS.DAI, TOKENS.USDC, TOKENS.USDT], - metaToken: TOKENS.dUSD, - }, - [CURVE_POOLS.curve_pBTC]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_pBTC, - tokens: [TOKENS.pBTC, TOKENS.RenBTC, TOKENS.WBTC, TOKENS.sBTC], - metaToken: TOKENS.pBTC, - }, - [CURVE_POOLS.curve_bBTC]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_bBTC, - tokens: [TOKENS.bBTC, TOKENS.RenBTC, TOKENS.WBTC, TOKENS.sBTC], - metaToken: TOKENS.bBTC, - }, - [CURVE_POOLS.curve_oBTC]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_oBTC, - tokens: [TOKENS.oBTC, TOKENS.RenBTC, TOKENS.WBTC, TOKENS.sBTC], - metaToken: TOKENS.oBTC, - }, - [CURVE_POOLS.curve_UST]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_UST, - tokens: [TOKENS.UST, TOKENS.DAI, TOKENS.USDC, TOKENS.USDT], - metaToken: TOKENS.UST, - }, - [CURVE_POOLS.curve_eurs]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_eurs, - tokens: [TOKENS.EURS, TOKENS.sEUR], - metaToken: undefined, - }, - // [POOLS.curve_seth]: { - // exchangeFunctionSelector: CurveFunctionSelectors.exchange, - // sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy, + // TODO:Romain having "Cannot swap more than you own" error when running simbot + // [SADDLE_POOLS.bitcoins]: { + // exchangeFunctionSelector: CurveFunctionSelectors.swap, + // sellQuoteFunctionSelector: CurveFunctionSelectors.calculateSwap, // buyQuoteFunctionSelector: CurveFunctionSelectors.None, - // poolAddress: POOLS.curve_seth, - // tokens: [TOKENS.ETH, TOKENS.sETH], + // poolAddress: SADDLE_POOLS.stables, + // tokens: [MAINNET_TOKENS.tBTC, MAINNET_TOKENS.WBTC, MAINNET_TOKENS.RenBTC, MAINNET_TOKENS.sBTC], // metaToken: undefined, + // gasSchedule: 220e3, // }, - [CURVE_POOLS.curve_aave]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, +}; + +export const SMOOTHY_MAINNET_INFOS: { [name: string]: CurveInfo } = { + [SMOOTHY_POOLS.syUSD]: { + exchangeFunctionSelector: CurveFunctionSelectors.swap_uint256, + sellQuoteFunctionSelector: CurveFunctionSelectors.get_swap_amount, buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_aave, - tokens: [TOKENS.DAI, TOKENS.USDC, TOKENS.USDT], - metaToken: undefined, - }, - [CURVE_POOLS.curve_aave]: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: CURVE_POOLS.curve_aave, - tokens: [TOKENS.aDAI, TOKENS.aUSDC, TOKENS.aUSDT], + poolAddress: SMOOTHY_POOLS.syUSD, + tokens: [ + MAINNET_TOKENS.USDT, + MAINNET_TOKENS.USDC, + MAINNET_TOKENS.DAI, + MAINNET_TOKENS.TUSD, + MAINNET_TOKENS.sUSD, + MAINNET_TOKENS.BUSD, + MAINNET_TOKENS.PAX, + MAINNET_TOKENS.GUSD, + ], metaToken: undefined, + gasSchedule: 200e3, }, }; -export const MAINNET_SWERVE_INFOS: { [name: string]: CurveInfo } = { - swUSD: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy, +export const SMOOTHY_BSC_INFOS: { [name: string]: CurveInfo } = { + [SMOOTHY_POOLS.syUSD]: { + exchangeFunctionSelector: CurveFunctionSelectors.swap_uint256, + sellQuoteFunctionSelector: CurveFunctionSelectors.get_swap_amount, buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: '0x329239599afb305da0a2ec69c58f8a6697f9f88d', // _target: 0xa5407eae9ba41422680e2e00537571bcc53efbfd - tokens: [TOKENS.DAI, TOKENS.USDC, TOKENS.USDT, TOKENS.TUSD], - metaToken: undefined, - }, -}; - -export const MAINNET_SNOWSWAP_INFOS: { [name: string]: CurveInfo } = { - yVaultCurve: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy, - buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx, - poolAddress: '0xbf7ccd6c446acfcc5df023043f2167b62e81899b', - tokens: [ - '0x5dbcf33d8c2e976c6b560249878e6f1491bca25c', // yUSD - '0x2994529c0652d127b7842094103715ec5299bbed', // ybCRV - ], - metaToken: undefined, - }, - yVaultCurveUnderlying: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx_underlying, - poolAddress: '0xbf7ccd6c446acfcc5df023043f2167b62e81899b', - tokens: [ - '0xdf5e0e81dff6faf3a7e52ba697820c5e32d806a8', // yCRV - '0x3b3ac5386837dc563660fb6a0937dfaa5924333b', // bCRV - ], - metaToken: undefined, - }, - yVaultUSD: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy, - buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx, - poolAddress: '0x4571753311e37ddb44faa8fb78a6df9a6e3c6c0b', - tokens: [ - '0xacd43e627e64355f1861cec6d3a6688b31a6f952', // yDAI - '0x597ad1e0c13bfe8025993d9e79c69e1c0233522e', // yUSDC - '0x2f08119c6f07c006695e079aafc638b8789faf18', // yUSDT - '0x37d19d1c4e1fa9dc47bd1ea12f742a0887eda74a', // yTUSD - ], + 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, + gasSchedule: 100e3, }, }; export const NERVE_BSC_INFOS: { [name: string]: CurveInfo } = { - ['0x1b3771a66ee31180906972580ade9b81afc5fcdc']: { + [NERVE_POOLS.threePool]: { exchangeFunctionSelector: CurveFunctionSelectors.swap, sellQuoteFunctionSelector: CurveFunctionSelectors.calculateSwap, buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: '0x1b3771a66ee31180906972580ade9b81afc5fcdc', - tokens: [ - '0xe9e7cea3dedca5984780bafc599bd69add087d56', // BUSD - '0x55d398326f99059ff775485246999027b3197955', // BUSD-T - '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d', // USDC - ], - metaToken: undefined, - }, -}; - -export const BELT_BSC_INFOS: { [name: string]: CurveInfo } = { - ['0xf16d312d119c13dd27fd0dc814b0bcdcaaa62dfd']: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: '0xf16d312d119c13dd27fd0dc814b0bcdcaaa62dfd', - tokens: [ - '0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3', // bDAI - '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d', // USDC - '0x55d398326f99059ff775485246999027b3197955', // BUSD-T - '0xe9e7cea3dedca5984780bafc599bd69add087d56', // BUSD - ], - metaToken: undefined, - }, -}; - -export const ELLIPSIS_BSC_INFOS: { [name: string]: CurveInfo } = { - ['0x160caed03795365f3a589f10c379ffa7d75d4e76']: { - exchangeFunctionSelector: CurveFunctionSelectors.exchange, - sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy, - buyQuoteFunctionSelector: CurveFunctionSelectors.None, - poolAddress: '0x160caed03795365f3a589f10c379ffa7d75d4e76', - tokens: [ - '0xe9e7cea3dedca5984780bafc599bd69add087d56', // BUSD - '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d', // USDC - '0x55d398326f99059ff775485246999027b3197955', // BUSD-T - ], + poolAddress: NERVE_POOLS.threePool, + tokens: [BSC_TOKENS.BUSD, BSC_TOKENS.USDT, BSC_TOKENS.USDC], metaToken: undefined, + gasSchedule: 150e3, }, }; @@ -605,7 +730,7 @@ export const KYBER_CONFIG_BY_CHAIN_ID = valueByChainId( [ChainId.Mainnet]: { networkProxy: '0x9aab3f75489902f3a48495025729a0af77d4b11e', hintHandler: '0xa1C0Fa73c39CFBcC11ec9Eb1Afc665aba9996E2C', - weth: TOKENS.WETH, + weth: MAINNET_TOKENS.WETH, }, }, { @@ -620,20 +745,20 @@ export const LIQUIDITY_PROVIDER_REGISTRY_BY_CHAIN_ID = valueByChainId - [takerToken, makerToken].includes(TOKENS.WETH) ? 160e3 : 280e3, + [takerToken, makerToken].includes(MAINNET_TOKENS.WETH) ? 160e3 : 280e3, }, }, }, @@ -780,11 +905,11 @@ export const SHELL_POOLS_BY_CHAIN_ID = valueByChainId( [ChainId.Mainnet]: { StableCoins: { poolAddress: '0x8f26d7bab7a73309141a291525c965ecdea7bf42', - tokens: [TOKENS.USDC, TOKENS.USDT, TOKENS.sUSD, TOKENS.DAI], + tokens: [MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT, MAINNET_TOKENS.sUSD, MAINNET_TOKENS.DAI], }, Bitcoin: { poolAddress: '0xc2d019b901f8d4fdb2b9a65b5d226ad88c66ee8d', - tokens: [TOKENS.RenBTC, TOKENS.WBTC, TOKENS.sBTC], + tokens: [MAINNET_TOKENS.RenBTC, MAINNET_TOKENS.WBTC, MAINNET_TOKENS.sBTC], }, }, }, @@ -800,6 +925,31 @@ export const SHELL_POOLS_BY_CHAIN_ID = valueByChainId( }, ); +export const COMPONENT_POOLS_BY_CHAIN_ID = valueByChainId( + { + [ChainId.Mainnet]: { + USDP_USDC_USDT: { + poolAddress: '0x49519631b404e06ca79c9c7b0dc91648d86f08db', + tokens: [MAINNET_TOKENS.USDP, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT], + }, + USDP_DAI_SUSD: { + poolAddress: '0x6477960dd932d29518d7e8087d5ea3d11e606068', + tokens: [MAINNET_TOKENS.USDP, MAINNET_TOKENS.DAI, MAINNET_TOKENS.sUSD], + }, + }, + }, + { + USDP_USDC_USDT: { + poolAddress: NULL_ADDRESS, + tokens: [] as string[], + }, + USDP_DAI_SUSD: { + poolAddress: NULL_ADDRESS, + tokens: [] as string[], + }, + }, +); + export const BALANCER_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer'; export const BALANCER_TOP_POOLS_FETCHED = 250; export const BALANCER_MAX_POOLS_FETCHED = 3; @@ -844,41 +994,14 @@ export const DEFAULT_GAS_SCHEDULE: Required = { }, [ERC20BridgeSource.Eth2Dai]: () => 400e3, [ERC20BridgeSource.Kyber]: () => 450e3, - [ERC20BridgeSource.Curve]: fillData => { - const poolAddress = (fillData as CurveFillData).pool.poolAddress.toLowerCase(); - switch (poolAddress) { - case CURVE_POOLS.curve_renBTC: - case CURVE_POOLS.curve_sBTC: - case CURVE_POOLS.curve_sUSD: - case CURVE_POOLS.curve_HBTC: - case CURVE_POOLS.curve_TRI: - return 150e3; - case CURVE_POOLS.curve_USDN: - case CURVE_POOLS.curve_mUSD: - return 300e3; - case CURVE_POOLS.curve_GUSD: - case CURVE_POOLS.curve_HUSD: - return 310e3; - case CURVE_POOLS.curve_tBTC: - return 370e3; - case CURVE_POOLS.curve_UST: - return 500e3; - case CURVE_POOLS.curve_dUSD: - case CURVE_POOLS.curve_bBTC: - case CURVE_POOLS.curve_oBTC: - case CURVE_POOLS.curve_eurs: - return 600e3; - case CURVE_POOLS.curve_compound: - return 750e3; - case CURVE_POOLS.curve_aave: - return 800e3; - case CURVE_POOLS.curve_PAX: - return 850e3; - // case POOLS.curve_seth: - default: - throw new Error(`Unrecognized Curve address: ${poolAddress}`); - } - }, + [ERC20BridgeSource.Curve]: 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, + [ERC20BridgeSource.Belt]: fillData => (fillData as CurveFillData).pool.gasSchedule, + [ERC20BridgeSource.Ellipsis]: fillData => (fillData as CurveFillData).pool.gasSchedule, + [ERC20BridgeSource.Smoothy]: fillData => (fillData as CurveFillData).pool.gasSchedule, + [ERC20BridgeSource.Saddle]: fillData => (fillData as CurveFillData).pool.gasSchedule, [ERC20BridgeSource.MultiBridge]: () => 350e3, [ERC20BridgeSource.UniswapV2]: (fillData?: FillData) => { // TODO: Different base cost if to/from ETH. @@ -930,9 +1053,8 @@ export const DEFAULT_GAS_SCHEDULE: Required = { } }, [ERC20BridgeSource.Mooniswap]: () => 130e3, - [ERC20BridgeSource.Swerve]: () => 150e3, - [ERC20BridgeSource.Nerve]: () => 150e3, [ERC20BridgeSource.Shell]: () => 170e3, + [ERC20BridgeSource.Component]: () => 188e3, [ERC20BridgeSource.MultiHop]: (fillData?: FillData) => { const firstHop = (fillData as MultiHopFillData).firstHopSource; const secondHop = (fillData as MultiHopFillData).secondHopSource; @@ -950,16 +1072,6 @@ export const DEFAULT_GAS_SCHEDULE: Required = { return isSellBase ? 180e3 : 300e3; }, [ERC20BridgeSource.DodoV2]: (_fillData?: FillData) => 100e3, - [ERC20BridgeSource.SnowSwap]: fillData => { - switch ((fillData as CurveFillData).pool.poolAddress.toLowerCase()) { - case '0xbf7ccd6c446acfcc5df023043f2167b62e81899b': - return 1000e3; - case '0x4571753311e37ddb44faa8fb78a6df9a6e3c6c0b': - return 1500e3; - default: - throw new Error('Unrecognized SnowSwap address'); - } - }, [ERC20BridgeSource.Bancor]: (fillData?: FillData) => { let gas = 200e3; const path = (fillData as BancorFillData).path; @@ -998,8 +1110,6 @@ export const DEFAULT_GAS_SCHEDULE: Required = { } return gas; }, - [ERC20BridgeSource.Belt]: () => 4500e3, - [ERC20BridgeSource.Ellipsis]: () => 150e3, }; export const DEFAULT_FEE_SCHEDULE: Required = { ...DEFAULT_GAS_SCHEDULE }; 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 790e4fd6be..662a13f443 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/orders.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/orders.ts @@ -128,6 +128,12 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s return encodeBridgeSourceId(BridgeProtocol.Curve, 'Belt'); case ERC20BridgeSource.Ellipsis: return encodeBridgeSourceId(BridgeProtocol.Curve, 'Ellipsis'); + case ERC20BridgeSource.Component: + return encodeBridgeSourceId(BridgeProtocol.Shell, 'Component'); + case ERC20BridgeSource.Smoothy: + return encodeBridgeSourceId(BridgeProtocol.Curve, 'Smoothy'); + case ERC20BridgeSource.Saddle: + return encodeBridgeSourceId(BridgeProtocol.Nerve, 'Saddle'); default: throw new Error(AggregationError.NoBridgeForSource); } @@ -155,6 +161,8 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder case ERC20BridgeSource.Nerve: case ERC20BridgeSource.Belt: case ERC20BridgeSource.Ellipsis: + case ERC20BridgeSource.Smoothy: + case ERC20BridgeSource.Saddle: const curveFillData = (order as OptimizedMarketBridgeOrder).fillData; bridgeData = encoder.encode([ curveFillData.pool.poolAddress, @@ -203,6 +211,7 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder bridgeData = encoder.encode([dodoV2FillData.poolAddress, dodoV2FillData.isSellBase]); break; case ERC20BridgeSource.Shell: + case ERC20BridgeSource.Component: const shellFillData = (order as OptimizedMarketBridgeOrder).fillData; bridgeData = encoder.encode([shellFillData.poolAddress]); break; @@ -302,6 +311,8 @@ export const BRIDGE_ENCODERS: { [ERC20BridgeSource.Nerve]: curveEncoder, [ERC20BridgeSource.Belt]: curveEncoder, [ERC20BridgeSource.Ellipsis]: curveEncoder, + [ERC20BridgeSource.Smoothy]: curveEncoder, + [ERC20BridgeSource.Saddle]: curveEncoder, // UniswapV2 like, (router, address[]) [ERC20BridgeSource.Bancor]: routerAddressPathEncoder, [ERC20BridgeSource.UniswapV2]: routerAddressPathEncoder, @@ -311,6 +322,7 @@ export const BRIDGE_ENCODERS: { [ERC20BridgeSource.KyberDmm]: routerAddressPathEncoder, // Generic pools [ERC20BridgeSource.Shell]: poolEncoder, + [ERC20BridgeSource.Component]: poolEncoder, [ERC20BridgeSource.Mooniswap]: poolEncoder, [ERC20BridgeSource.Eth2Dai]: poolEncoder, [ERC20BridgeSource.MStable]: poolEncoder, 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 8282f5d0f3..9e47d32852 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 @@ -12,7 +12,7 @@ import { getCurveLikeInfosForPair, getDodoV2Offsets, getKyberOffsets, - getShellsForPair, + getShellLikeInfosForPair, isAllowedKyberReserveId, isBadTokenForSource, isValidAddress, @@ -25,6 +25,7 @@ import { KYBER_CONFIG_BY_CHAIN_ID, LINKSWAP_ROUTER_BY_CHAIN_ID, LIQUIDITY_PROVIDER_REGISTRY_BY_CHAIN_ID, + MAINNET_TOKENS, MAKER_PSM_INFO_BY_CHAIN_ID, MAX_UINT256, MOONISWAP_REGISTRIES_BY_CHAIN_ID, @@ -34,7 +35,6 @@ import { NULL_BYTES, OASIS_ROUTER_BY_CHAIN_ID, SELL_SOURCE_FILTER_BY_CHAIN_ID, - TOKENS, UNISWAPV1_ROUTER_BY_CHAIN_ID, ZERO_AMOUNT, } from './constants'; @@ -403,6 +403,62 @@ export class SamplerOperations { }); } + public getSmoothySellQuotes( + pool: CurveInfo, + fromTokenIdx: number, + toTokenIdx: number, + takerFillAmounts: BigNumber[], + ): SourceQuoteOperation { + return new SamplerContractOperation({ + source: ERC20BridgeSource.Smoothy, + fillData: { + pool, + fromTokenIdx, + toTokenIdx, + }, + contract: this._samplerContract, + function: this._samplerContract.sampleSellsFromSmoothy, + params: [ + { + poolAddress: pool.poolAddress, + sellQuoteFunctionSelector: pool.sellQuoteFunctionSelector, + buyQuoteFunctionSelector: pool.buyQuoteFunctionSelector, + }, + new BigNumber(fromTokenIdx), + new BigNumber(toTokenIdx), + takerFillAmounts, + ], + }); + } + + public getSmoothyBuyQuotes( + pool: CurveInfo, + fromTokenIdx: number, + toTokenIdx: number, + makerFillAmounts: BigNumber[], + ): SourceQuoteOperation { + return new SamplerContractOperation({ + source: ERC20BridgeSource.Smoothy, + fillData: { + pool, + fromTokenIdx, + toTokenIdx, + }, + contract: this._samplerContract, + function: this._samplerContract.sampleBuysFromSmoothy, + params: [ + { + poolAddress: pool.poolAddress, + sellQuoteFunctionSelector: pool.sellQuoteFunctionSelector, + buyQuoteFunctionSelector: pool.buyQuoteFunctionSelector, + }, + new BigNumber(fromTokenIdx), + new BigNumber(toTokenIdx), + makerFillAmounts, + ], + }); + } + public getBalancerSellQuotes( poolAddress: string, makerToken: string, @@ -750,9 +806,10 @@ export class SamplerOperations { makerToken: string, takerToken: string, takerFillAmounts: BigNumber[], + source: ERC20BridgeSource = ERC20BridgeSource.Shell, ): SourceQuoteOperation { return new SamplerContractOperation({ - source: ERC20BridgeSource.Shell, + source, fillData: { poolAddress }, contract: this._samplerContract, function: this._samplerContract.sampleSellsFromShell, @@ -765,9 +822,10 @@ export class SamplerOperations { makerToken: string, takerToken: string, makerFillAmounts: BigNumber[], + source: ERC20BridgeSource = ERC20BridgeSource.Shell, ): SourceQuoteOperation { return new SamplerContractOperation({ - source: ERC20BridgeSource.Shell, + source, fillData: { poolAddress }, contract: this._samplerContract, function: this._samplerContract.sampleBuysFromShell, @@ -1054,6 +1112,7 @@ export class SamplerOperations { case ERC20BridgeSource.Nerve: case ERC20BridgeSource.Belt: case ERC20BridgeSource.Ellipsis: + case ERC20BridgeSource.Saddle: return getCurveLikeInfosForPair(this.chainId, takerToken, makerToken, source).map(pool => this.getCurveSellQuotes( pool, @@ -1063,6 +1122,20 @@ export class SamplerOperations { source, ), ); + case ERC20BridgeSource.Smoothy: + return getCurveLikeInfosForPair(this.chainId, takerToken, makerToken, source).map(pool => + this.getSmoothySellQuotes( + pool, + pool.tokens.indexOf(takerToken), + pool.tokens.indexOf(makerToken), + takerFillAmounts, + ), + ); + case ERC20BridgeSource.Shell: + case ERC20BridgeSource.Component: + return getShellLikeInfosForPair(this.chainId, takerToken, makerToken, source).map(pool => + this.getShellSellQuotes(pool, makerToken, takerToken, takerFillAmounts, source), + ); case ERC20BridgeSource.LiquidityProvider: return getLiquidityProvidersForPair( this.liquidityProviderRegistry, @@ -1118,10 +1191,6 @@ export class SamplerOperations { ERC20BridgeSource.Cream, ), ); - case ERC20BridgeSource.Shell: - return getShellsForPair(this.chainId, takerToken, makerToken).map(pool => - this.getShellSellQuotes(pool, makerToken, takerToken, takerFillAmounts), - ); case ERC20BridgeSource.Dodo: if (!isValidAddress(DODO_CONFIG_BY_CHAIN_ID[this.chainId].registry)) { return []; @@ -1165,7 +1234,7 @@ export class SamplerOperations { return [ [takerToken, makerToken], ...getIntermediateTokens(makerToken, takerToken, { - default: [TOKENS.LINK, TOKENS.WETH], + default: [MAINNET_TOKENS.LINK, MAINNET_TOKENS.WETH], }).map(t => [takerToken, t, makerToken]), ].map(path => this.getUniswapV2SellQuotes( @@ -1252,6 +1321,7 @@ export class SamplerOperations { case ERC20BridgeSource.Nerve: case ERC20BridgeSource.Belt: case ERC20BridgeSource.Ellipsis: + case ERC20BridgeSource.Saddle: return getCurveLikeInfosForPair(this.chainId, takerToken, makerToken, source).map(pool => this.getCurveBuyQuotes( pool, @@ -1261,6 +1331,20 @@ export class SamplerOperations { source, ), ); + case ERC20BridgeSource.Smoothy: + return getCurveLikeInfosForPair(this.chainId, takerToken, makerToken, source).map(pool => + this.getSmoothyBuyQuotes( + pool, + pool.tokens.indexOf(takerToken), + pool.tokens.indexOf(makerToken), + makerFillAmounts, + ), + ); + case ERC20BridgeSource.Shell: + case ERC20BridgeSource.Component: + return getShellLikeInfosForPair(this.chainId, takerToken, makerToken, source).map(pool => + this.getShellBuyQuotes(pool, makerToken, takerToken, makerFillAmounts, source), + ); case ERC20BridgeSource.LiquidityProvider: return getLiquidityProvidersForPair( this.liquidityProviderRegistry, @@ -1316,10 +1400,6 @@ export class SamplerOperations { ERC20BridgeSource.Cream, ), ); - case ERC20BridgeSource.Shell: - return getShellsForPair(this.chainId, takerToken, makerToken).map(pool => - this.getShellBuyQuotes(pool, makerToken, takerToken, makerFillAmounts), - ); case ERC20BridgeSource.Dodo: if (!isValidAddress(DODO_CONFIG_BY_CHAIN_ID[this.chainId].registry)) { return []; @@ -1358,7 +1438,7 @@ export class SamplerOperations { [takerToken, makerToken], // LINK is the base asset in many of the pools on Linkswap ...getIntermediateTokens(makerToken, takerToken, { - default: [TOKENS.LINK, TOKENS.WETH], + default: [MAINNET_TOKENS.LINK, MAINNET_TOKENS.WETH], }).map(t => [takerToken, t, makerToken]), ].map(path => this.getUniswapV2BuyQuotes( 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 018d5dea6d..7e8d6aaf47 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/types.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/types.ts @@ -60,7 +60,10 @@ export enum ERC20BridgeSource { CryptoCom = 'CryptoCom', Linkswap = 'Linkswap', KyberDmm = 'KyberDMM', - // Other + Smoothy = 'Smoothy', + Component = 'Component', + Saddle = 'Saddle', + // BSC only PancakeSwap = 'PancakeSwap', BakerySwap = 'BakerySwap', Nerve = 'Nerve', @@ -80,9 +83,12 @@ export enum CurveFunctionSelectors { get_dx_underlying = '0x0e71d1b9', get_dy = '0x5e0d443f', get_dx = '0x67df02ca', - // Nerve BSC - swap = '0x91695586', - calculateSwap = '0xa95b089f', + // Smoothy + swap_uint256 = '0x5673b02d', // swap(uint256,uint256,uint256,uint256) + get_swap_amount = '0x45cf2ef6', // getSwapAmount(uint256,uint256,uint256) + // Nerve BSC, Saddle Mainnet + swap = '0x91695586', // swap(uint8,uint8,uint256,uint256,uint256) + calculateSwap = '0xa95b089f', // calculateSwap(uint8,uint8,uint256) } // tslint:enable: enum-naming @@ -96,6 +102,7 @@ export interface CurveInfo { poolAddress: string; tokens: string[]; metaToken: string | undefined; + gasSchedule: number; } /** diff --git a/packages/asset-swapper/test/artifacts.ts b/packages/asset-swapper/test/artifacts.ts index 1426472111..26fd731eae 100644 --- a/packages/asset-swapper/test/artifacts.ts +++ b/packages/asset-swapper/test/artifacts.ts @@ -25,6 +25,7 @@ import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json'; import * as IMStable from '../test/generated-artifacts/IMStable.json'; import * as IMultiBridge from '../test/generated-artifacts/IMultiBridge.json'; import * as IShell from '../test/generated-artifacts/IShell.json'; +import * as ISmoothy from '../test/generated-artifacts/ISmoothy.json'; import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json'; import * as IUniswapV2Router01 from '../test/generated-artifacts/IUniswapV2Router01.json'; import * as KyberSampler from '../test/generated-artifacts/KyberSampler.json'; @@ -36,6 +37,7 @@ import * as MultiBridgeSampler from '../test/generated-artifacts/MultiBridgeSamp import * as NativeOrderSampler from '../test/generated-artifacts/NativeOrderSampler.json'; import * as SamplerUtils from '../test/generated-artifacts/SamplerUtils.json'; import * as ShellSampler from '../test/generated-artifacts/ShellSampler.json'; +import * as SmoothySampler from '../test/generated-artifacts/SmoothySampler.json'; import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json'; import * as TestNativeOrderSampler from '../test/generated-artifacts/TestNativeOrderSampler.json'; import * as TwoHopSampler from '../test/generated-artifacts/TwoHopSampler.json'; @@ -62,6 +64,7 @@ export const artifacts = { NativeOrderSampler: NativeOrderSampler as ContractArtifact, SamplerUtils: SamplerUtils as ContractArtifact, ShellSampler: ShellSampler as ContractArtifact, + SmoothySampler: SmoothySampler as ContractArtifact, TwoHopSampler: TwoHopSampler as ContractArtifact, UniswapSampler: UniswapSampler as ContractArtifact, UniswapV2Sampler: UniswapV2Sampler as ContractArtifact, @@ -75,6 +78,7 @@ export const artifacts = { IMooniswap: IMooniswap as ContractArtifact, IMultiBridge: IMultiBridge as ContractArtifact, IShell: IShell as ContractArtifact, + ISmoothy: ISmoothy as ContractArtifact, IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact, IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact, DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact, diff --git a/packages/asset-swapper/test/contracts/bridge_sampler_mainnet_test.ts b/packages/asset-swapper/test/contracts/bridge_sampler_mainnet_test.ts index fcee58267e..00bfb5e438 100644 --- a/packages/asset-swapper/test/contracts/bridge_sampler_mainnet_test.ts +++ b/packages/asset-swapper/test/contracts/bridge_sampler_mainnet_test.ts @@ -3,7 +3,7 @@ import { blockchainTests, describe, expect, toBaseUnitAmount, Web3ProviderEngine import { RPCSubprovider } from '@0x/subproviders'; import { BigNumber, NULL_BYTES, providerUtils } from '@0x/utils'; -import { KYBER_CONFIG_BY_CHAIN_ID, TOKENS } from '../../src/utils/market_operation_utils/constants'; +import { KYBER_CONFIG_BY_CHAIN_ID, MAINNET_TOKENS } from '../../src/utils/market_operation_utils/constants'; import { artifacts } from '../artifacts'; import { ERC20BridgeSamplerContract } from '../wrappers'; @@ -80,9 +80,9 @@ blockchainTests.skip('Mainnet Sampler Tests', env => { }); }); describe('Kyber', () => { - const WETH = TOKENS.WETH; - const DAI = TOKENS.DAI; - const USDC = TOKENS.USDC; + const WETH = MAINNET_TOKENS.WETH; + const DAI = MAINNET_TOKENS.DAI; + const USDC = MAINNET_TOKENS.USDC; const RESERVE_OFFSET = new BigNumber(0); const KYBER_OPTS = { ...KYBER_CONFIG_BY_CHAIN_ID[ChainId.Mainnet], diff --git a/packages/asset-swapper/test/market_operation_utils_test.ts b/packages/asset-swapper/test/market_operation_utils_test.ts index 6a3e9e8e21..aebec17eda 100644 --- a/packages/asset-swapper/test/market_operation_utils_test.ts +++ b/packages/asset-swapper/test/market_operation_utils_test.ts @@ -69,6 +69,9 @@ const DEFAULT_EXCLUDED = [ ERC20BridgeSource.BakerySwap, ERC20BridgeSource.MakerPsm, ERC20BridgeSource.KyberDmm, + ERC20BridgeSource.Smoothy, + ERC20BridgeSource.Component, + ERC20BridgeSource.Saddle, ]; const BUY_SOURCES = BUY_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].sources; const SELL_SOURCES = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].sources; @@ -339,12 +342,35 @@ describe('MarketOperationUtils tests', () => { fromTokenIdx: 0, toTokenIdx: 1, }, + [ERC20BridgeSource.Smoothy]: { + pool: { + poolAddress: randomAddress(), + tokens: [TAKER_TOKEN, MAKER_TOKEN], + exchangeFunctionSelector: hexUtils.random(4), + sellQuoteFunctionSelector: hexUtils.random(4), + buyQuoteFunctionSelector: hexUtils.random(4), + }, + fromTokenIdx: 0, + toTokenIdx: 1, + }, + [ERC20BridgeSource.Saddle]: { + pool: { + poolAddress: randomAddress(), + tokens: [TAKER_TOKEN, MAKER_TOKEN], + exchangeFunctionSelector: hexUtils.random(4), + sellQuoteFunctionSelector: hexUtils.random(4), + buyQuoteFunctionSelector: hexUtils.random(4), + }, + fromTokenIdx: 0, + toTokenIdx: 1, + }, [ERC20BridgeSource.LiquidityProvider]: { poolAddress: randomAddress() }, [ERC20BridgeSource.SushiSwap]: { tokenAddressPath: [] }, [ERC20BridgeSource.Mooniswap]: { poolAddress: randomAddress() }, [ERC20BridgeSource.Native]: { order: new LimitOrder() }, [ERC20BridgeSource.MultiHop]: {}, [ERC20BridgeSource.Shell]: { poolAddress: randomAddress() }, + [ERC20BridgeSource.Component]: { poolAddress: randomAddress() }, [ERC20BridgeSource.Cream]: { poolAddress: randomAddress() }, [ERC20BridgeSource.Dodo]: {}, [ERC20BridgeSource.DodoV2]: {}, diff --git a/packages/asset-swapper/test/wrappers.ts b/packages/asset-swapper/test/wrappers.ts index 27d1114273..338e0f9885 100644 --- a/packages/asset-swapper/test/wrappers.ts +++ b/packages/asset-swapper/test/wrappers.ts @@ -23,6 +23,7 @@ export * from '../test/generated-wrappers/i_m_stable'; export * from '../test/generated-wrappers/i_mooniswap'; export * from '../test/generated-wrappers/i_multi_bridge'; export * from '../test/generated-wrappers/i_shell'; +export * from '../test/generated-wrappers/i_smoothy'; export * from '../test/generated-wrappers/i_uniswap_exchange_quotes'; export * from '../test/generated-wrappers/i_uniswap_v2_router01'; export * from '../test/generated-wrappers/kyber_sampler'; @@ -34,6 +35,7 @@ export * from '../test/generated-wrappers/multi_bridge_sampler'; export * from '../test/generated-wrappers/native_order_sampler'; export * from '../test/generated-wrappers/sampler_utils'; export * from '../test/generated-wrappers/shell_sampler'; +export * from '../test/generated-wrappers/smoothy_sampler'; export * from '../test/generated-wrappers/test_erc20_bridge_sampler'; export * from '../test/generated-wrappers/test_native_order_sampler'; export * from '../test/generated-wrappers/two_hop_sampler'; diff --git a/packages/asset-swapper/tsconfig.json b/packages/asset-swapper/tsconfig.json index 4ef9298c50..1103ae24bd 100644 --- a/packages/asset-swapper/tsconfig.json +++ b/packages/asset-swapper/tsconfig.json @@ -26,6 +26,7 @@ "test/generated-artifacts/IMooniswap.json", "test/generated-artifacts/IMultiBridge.json", "test/generated-artifacts/IShell.json", + "test/generated-artifacts/ISmoothy.json", "test/generated-artifacts/IUniswapExchangeQuotes.json", "test/generated-artifacts/IUniswapV2Router01.json", "test/generated-artifacts/KyberSampler.json", @@ -37,6 +38,7 @@ "test/generated-artifacts/NativeOrderSampler.json", "test/generated-artifacts/SamplerUtils.json", "test/generated-artifacts/ShellSampler.json", + "test/generated-artifacts/SmoothySampler.json", "test/generated-artifacts/TestERC20BridgeSampler.json", "test/generated-artifacts/TestNativeOrderSampler.json", "test/generated-artifacts/TwoHopSampler.json", diff --git a/packages/protocol-utils/CHANGELOG.json b/packages/protocol-utils/CHANGELOG.json index 523a5f69a3..423d1c0c27 100644 --- a/packages/protocol-utils/CHANGELOG.json +++ b/packages/protocol-utils/CHANGELOG.json @@ -2,6 +2,10 @@ { "version": "1.4.0", "changes": [ + { + "note": "Added Smoothy, Component, Saddle", + "pr": 182 + }, { "note": "Added Nerve", "pr": 181 diff --git a/packages/protocol-utils/src/transformer_utils.ts b/packages/protocol-utils/src/transformer_utils.ts index 19169c9c8a..3c91817de9 100644 --- a/packages/protocol-utils/src/transformer_utils.ts +++ b/packages/protocol-utils/src/transformer_utils.ts @@ -126,6 +126,9 @@ export enum BridgeProtocol { CoFiX, Nerve, MakerPsm, + Smoothy, + Component, + Saddle, } // tslint:enable: enum-naming