chore: Component.finance, Smoothy.finance, Saddle.finance, Curve open pools, Gas schedule [TKR-1] (#182)

* chore: Component.finance, Smoothy.finance (mainnet + BSC), Saddle.finance, Curve open pools, adjusting gas schedule, fixing Shell buys

* chore: adding a Sampler for Smoothy.finance to only use whats in the contracts reserve

* fix: Smoothy sampler, only use approx. for buys, removing y and BUSD curve pools

* add CHANGELOGs

* fix: prettier

* add: FRAX Curve open pool

* fix: prettier

* chore: adjusting gas schedule for BSC Smoothy
This commit is contained in:
Romain Butteaud 2021-04-08 18:07:12 -07:00 committed by GitHub
parent 76dda9eeda
commit c1f8df0eca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 942 additions and 393 deletions

View File

@ -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

View File

@ -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,

View File

@ -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;
}
}
}

View File

@ -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];
}
}

View File

@ -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);
}

View File

@ -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": []
}

View File

@ -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];

View File

@ -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}`);
}

View File

@ -83,6 +83,9 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
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<SourceFilters>(
ERC20BridgeSource.Nerve,
ERC20BridgeSource.PancakeSwap,
ERC20BridgeSource.SushiSwap,
ERC20BridgeSource.Smoothy,
]),
},
@ -134,6 +138,9 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
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<SourceFilters>(
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<string[]>(
{
[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<TokenAdj
// Mirror Protocol
.tap(builder => {
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<TokenAdj
export const NATIVE_FEE_TOKEN_BY_CHAIN_ID = valueByChainId<string>(
{
[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<string>(
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<KyberSamplerOpts>(
[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<LiquidityP
[ChainId.Mainnet]: {
['0x1d0d407c5af8c86f0a6494de86e56ae21e46a951']: {
tokens: [
TOKENS.WETH,
TOKENS.USDC,
TOKENS.USDT,
TOKENS.WBTC,
TOKENS.PAX,
TOKENS.LINK,
TOKENS.KNC,
TOKENS.MANA,
TOKENS.DAI,
TOKENS.BUSD,
TOKENS.AAVE,
MAINNET_TOKENS.WETH,
MAINNET_TOKENS.USDC,
MAINNET_TOKENS.USDT,
MAINNET_TOKENS.WBTC,
MAINNET_TOKENS.PAX,
MAINNET_TOKENS.LINK,
MAINNET_TOKENS.KNC,
MAINNET_TOKENS.MANA,
MAINNET_TOKENS.DAI,
MAINNET_TOKENS.BUSD,
MAINNET_TOKENS.AAVE,
],
gasCost: (takerToken: string, makerToken: string) =>
[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<FeeSchedule> = {
},
[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<FeeSchedule> = {
}
},
[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<FeeSchedule> = {
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<FeeSchedule> = {
}
return gas;
},
[ERC20BridgeSource.Belt]: () => 4500e3,
[ERC20BridgeSource.Ellipsis]: () => 150e3,
};
export const DEFAULT_FEE_SCHEDULE: Required<FeeSchedule> = { ...DEFAULT_GAS_SCHEDULE };

View File

@ -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<CurveFillData>).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<ShellFillData>).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,

View File

@ -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<CurveFillData> {
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<CurveFillData> {
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<ShellFillData> {
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(

View File

@ -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;
}
/**

View File

@ -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,

View File

@ -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],

View File

@ -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]: {},

View File

@ -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';

View File

@ -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",

View File

@ -2,6 +2,10 @@
{
"version": "1.4.0",
"changes": [
{
"note": "Added Smoothy, Component, Saddle",
"pr": 182
},
{
"note": "Added Nerve",
"pr": 181

View File

@ -126,6 +126,9 @@ export enum BridgeProtocol {
CoFiX,
Nerve,
MakerPsm,
Smoothy,
Component,
Saddle,
}
// tslint:enable: enum-naming