AS: Balancer V2 batchSwap (#462)
* Draft. PoC pseudo code showing general idea for resuing SOR path creation logic and adding multihop support. * Add actual Balancer SDK function calls. * Update to handle buys. * Correct taker>maker for buy. * Draft. PoC pseudo code showing general idea for resuing SOR path creation logic and adding multihop support. * make it build * rebase * add BalancerV2Batch protocol * add BalancerV2Batch protocol * get balancer v2 multihop working * fix BalancerV2Batch for sells (buys still iffy) * fix buys, appease linter and prettier * remove unused RPC URL from balancer sdk construction * update changelogs * clean up comments add event loop yield in `BalancerV2SwapInfoCache.loadTopPools()` * add negative result check on balancerv2batch swap output * compiler hack * reintroduce CompilerHack * delete unused multibridge sampler * remove compilerhack * reintroduce compilerhack * try to fix CI compile errors * plz work * plz work * pretty plz work * yay it works, also address feedback * appease linter * deploy new FQTs Co-authored-by: johngrantuk <johngrantuk@googlemail.com> Co-authored-by: Lawrence Forman <me@merklejerk.com>
This commit is contained in:
parent
7c51412e2f
commit
470e9a4697
@ -19,7 +19,6 @@ jobs:
|
|||||||
command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
|
command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
|
||||||
- setup_remote_docker
|
- setup_remote_docker
|
||||||
- run: yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci
|
- run: yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci
|
||||||
- run: yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts
|
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: repo-{{ .Environment.CIRCLE_SHA1 }}
|
key: repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
paths:
|
paths:
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "0.32.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Add support for `BalancerV2Batch` fills in FQT",
|
||||||
|
"pr": 462
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1648739346,
|
"timestamp": 1648739346,
|
||||||
"version": "0.31.2",
|
"version": "0.31.2",
|
||||||
|
@ -25,6 +25,7 @@ import "./BridgeProtocols.sol";
|
|||||||
import "./mixins/MixinAaveV2.sol";
|
import "./mixins/MixinAaveV2.sol";
|
||||||
import "./mixins/MixinBalancer.sol";
|
import "./mixins/MixinBalancer.sol";
|
||||||
import "./mixins/MixinBalancerV2.sol";
|
import "./mixins/MixinBalancerV2.sol";
|
||||||
|
import "./mixins/MixinBalancerV2Batch.sol";
|
||||||
import "./mixins/MixinBancor.sol";
|
import "./mixins/MixinBancor.sol";
|
||||||
import "./mixins/MixinCoFiX.sol";
|
import "./mixins/MixinCoFiX.sol";
|
||||||
import "./mixins/MixinCompound.sol";
|
import "./mixins/MixinCompound.sol";
|
||||||
@ -52,6 +53,7 @@ contract BridgeAdapter is
|
|||||||
MixinAaveV2,
|
MixinAaveV2,
|
||||||
MixinBalancer,
|
MixinBalancer,
|
||||||
MixinBalancerV2,
|
MixinBalancerV2,
|
||||||
|
MixinBalancerV2Batch,
|
||||||
MixinBancor,
|
MixinBancor,
|
||||||
MixinCoFiX,
|
MixinCoFiX,
|
||||||
MixinCompound,
|
MixinCompound,
|
||||||
@ -159,6 +161,11 @@ contract BridgeAdapter is
|
|||||||
sellAmount,
|
sellAmount,
|
||||||
order.bridgeData
|
order.bridgeData
|
||||||
);
|
);
|
||||||
|
} else if (protocolId == BridgeProtocols.BALANCERV2BATCH) {
|
||||||
|
boughtAmount = _tradeBalancerV2Batch(
|
||||||
|
sellAmount,
|
||||||
|
order.bridgeData
|
||||||
|
);
|
||||||
} else if (protocolId == BridgeProtocols.KYBER) {
|
} else if (protocolId == BridgeProtocols.KYBER) {
|
||||||
boughtAmount = _tradeKyber(
|
boughtAmount = _tradeKyber(
|
||||||
sellToken,
|
sellToken,
|
||||||
|
@ -27,29 +27,30 @@ library BridgeProtocols {
|
|||||||
// A incrementally increasing, append-only list of protocol IDs.
|
// A incrementally increasing, append-only list of protocol IDs.
|
||||||
// We don't use an enum so solidity doesn't throw when we pass in a
|
// We don't use an enum so solidity doesn't throw when we pass in a
|
||||||
// new protocol ID that hasn't been rolled up yet.
|
// new protocol ID that hasn't been rolled up yet.
|
||||||
uint128 internal constant UNKNOWN = 0;
|
uint128 internal constant UNKNOWN = 0;
|
||||||
uint128 internal constant CURVE = 1;
|
uint128 internal constant CURVE = 1;
|
||||||
uint128 internal constant UNISWAPV2 = 2;
|
uint128 internal constant UNISWAPV2 = 2;
|
||||||
uint128 internal constant UNISWAP = 3;
|
uint128 internal constant UNISWAP = 3;
|
||||||
uint128 internal constant BALANCER = 4;
|
uint128 internal constant BALANCER = 4;
|
||||||
uint128 internal constant KYBER = 5;
|
uint128 internal constant KYBER = 5;
|
||||||
uint128 internal constant MOONISWAP = 6;
|
uint128 internal constant MOONISWAP = 6;
|
||||||
uint128 internal constant MSTABLE = 7;
|
uint128 internal constant MSTABLE = 7;
|
||||||
uint128 internal constant OASIS = 8;
|
uint128 internal constant OASIS = 8;
|
||||||
uint128 internal constant SHELL = 9;
|
uint128 internal constant SHELL = 9;
|
||||||
uint128 internal constant DODO = 10;
|
uint128 internal constant DODO = 10;
|
||||||
uint128 internal constant DODOV2 = 11;
|
uint128 internal constant DODOV2 = 11;
|
||||||
uint128 internal constant CRYPTOCOM = 12;
|
uint128 internal constant CRYPTOCOM = 12;
|
||||||
uint128 internal constant BANCOR = 13;
|
uint128 internal constant BANCOR = 13;
|
||||||
uint128 internal constant COFIX = 14;
|
uint128 internal constant COFIX = 14;
|
||||||
uint128 internal constant NERVE = 15;
|
uint128 internal constant NERVE = 15;
|
||||||
uint128 internal constant MAKERPSM = 16;
|
uint128 internal constant MAKERPSM = 16;
|
||||||
uint128 internal constant BALANCERV2 = 17;
|
uint128 internal constant BALANCERV2 = 17;
|
||||||
uint128 internal constant UNISWAPV3 = 18;
|
uint128 internal constant UNISWAPV3 = 18;
|
||||||
uint128 internal constant KYBERDMM = 19;
|
uint128 internal constant KYBERDMM = 19;
|
||||||
uint128 internal constant CURVEV2 = 20;
|
uint128 internal constant CURVEV2 = 20;
|
||||||
uint128 internal constant LIDO = 21;
|
uint128 internal constant LIDO = 21;
|
||||||
uint128 internal constant CLIPPER = 22; // Not used: Clipper is now using PLP interface
|
uint128 internal constant CLIPPER = 22; // Not used: Clipper is now using PLP interface
|
||||||
uint128 internal constant AAVEV2 = 23;
|
uint128 internal constant AAVEV2 = 23;
|
||||||
uint128 internal constant COMPOUND = 24;
|
uint128 internal constant COMPOUND = 24;
|
||||||
|
uint128 internal constant BALANCERV2BATCH = 25;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2020 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.6.5;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||||
|
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||||
|
|
||||||
|
|
||||||
|
interface IBalancerV2BatchSwapVault {
|
||||||
|
|
||||||
|
enum SwapKind { GIVEN_IN, GIVEN_OUT }
|
||||||
|
|
||||||
|
struct BatchSwapStep {
|
||||||
|
bytes32 poolId;
|
||||||
|
uint256 assetInIndex;
|
||||||
|
uint256 assetOutIndex;
|
||||||
|
uint256 amount;
|
||||||
|
bytes userData;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FundManagement {
|
||||||
|
address sender;
|
||||||
|
bool fromInternalBalance;
|
||||||
|
address payable recipient;
|
||||||
|
bool toInternalBalance;
|
||||||
|
}
|
||||||
|
|
||||||
|
function batchSwap(
|
||||||
|
SwapKind kind,
|
||||||
|
BatchSwapStep[] calldata swaps,
|
||||||
|
IERC20TokenV06[] calldata assets,
|
||||||
|
FundManagement calldata funds,
|
||||||
|
int256[] calldata limits,
|
||||||
|
uint256 deadline
|
||||||
|
) external returns (int256[] memory amounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
contract MixinBalancerV2Batch {
|
||||||
|
|
||||||
|
using LibERC20TokenV06 for IERC20TokenV06;
|
||||||
|
|
||||||
|
struct BalancerV2BatchBridgeData {
|
||||||
|
IBalancerV2BatchSwapVault vault;
|
||||||
|
IBalancerV2BatchSwapVault.BatchSwapStep[] swapSteps;
|
||||||
|
IERC20TokenV06[] assets;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _tradeBalancerV2Batch(
|
||||||
|
uint256 sellAmount,
|
||||||
|
bytes memory bridgeData
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
returns (uint256 boughtAmount)
|
||||||
|
{
|
||||||
|
// Decode the bridge data.
|
||||||
|
(
|
||||||
|
IBalancerV2BatchSwapVault vault,
|
||||||
|
IBalancerV2BatchSwapVault.BatchSwapStep[] memory swapSteps,
|
||||||
|
address[] memory assets_
|
||||||
|
) = abi.decode(bridgeData, (IBalancerV2BatchSwapVault, IBalancerV2BatchSwapVault.BatchSwapStep[], address[]));
|
||||||
|
IERC20TokenV06[] memory assets;
|
||||||
|
assembly { assets := assets_ }
|
||||||
|
|
||||||
|
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||||
|
assets[0].approveIfBelow(address(vault), sellAmount);
|
||||||
|
|
||||||
|
swapSteps[0].amount = sellAmount;
|
||||||
|
int256[] memory limits = new int256[](assets.length);
|
||||||
|
for (uint256 i = 0; i < limits.length; ++i) {
|
||||||
|
limits[i] = type(int256).max;
|
||||||
|
}
|
||||||
|
|
||||||
|
int256[] memory amounts = vault.batchSwap(
|
||||||
|
IBalancerV2BatchSwapVault.SwapKind.GIVEN_IN,
|
||||||
|
swapSteps,
|
||||||
|
assets,
|
||||||
|
IBalancerV2BatchSwapVault.FundManagement({
|
||||||
|
sender: address(this),
|
||||||
|
fromInternalBalance: false,
|
||||||
|
recipient: payable(address(this)),
|
||||||
|
toInternalBalance: false
|
||||||
|
}),
|
||||||
|
limits,
|
||||||
|
block.timestamp + 1
|
||||||
|
);
|
||||||
|
require(amounts[amounts.length - 1] <= 0, 'Unexpected BalancerV2Batch output');
|
||||||
|
return uint256(amounts[amounts.length - 1] * -1);
|
||||||
|
}
|
||||||
|
}
|
@ -43,7 +43,7 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature,OtcOrdersFeature,IOtcOrdersFeature",
|
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature,OtcOrdersFeature,IOtcOrdersFeature",
|
||||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|ERC1155OrdersFeature|ERC165Feature|ERC721OrdersFeature|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinERC1155Spender|FixinERC721Spender|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC1155OrdersFeature|IERC1155Token|IERC165Feature|IERC20Bridge|IERC20Transformer|IERC721OrdersFeature|IERC721Token|IFeature|IFeeRecipient|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|IPropertyValidator|ISimpleFunctionRegistryFeature|IStaking|ITakerCallback|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC1155OrdersStorage|LibERC20Transformer|LibERC721OrdersStorage|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNFTOrder|LibNFTOrdersRichErrors|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAaveV2|MixinBalancer|MixinBalancerV2|MixinBancor|MixinCoFiX|MixinCompound|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NFTOrders|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFeeRecipient|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC1155Token|TestMintableERC20Token|TestMintableERC721Token|TestMooniswap|TestNFTOrderPresigner|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestPropertyValidator|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json"
|
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|ERC1155OrdersFeature|ERC165Feature|ERC721OrdersFeature|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinERC1155Spender|FixinERC721Spender|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC1155OrdersFeature|IERC1155Token|IERC165Feature|IERC20Bridge|IERC20Transformer|IERC721OrdersFeature|IERC721Token|IFeature|IFeeRecipient|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|IPropertyValidator|ISimpleFunctionRegistryFeature|IStaking|ITakerCallback|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC1155OrdersStorage|LibERC20Transformer|LibERC721OrdersStorage|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNFTOrder|LibNFTOrdersRichErrors|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAaveV2|MixinBalancer|MixinBalancerV2|MixinBalancerV2Batch|MixinBancor|MixinCoFiX|MixinCompound|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NFTOrders|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFeeRecipient|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC1155Token|TestMintableERC20Token|TestMintableERC721Token|TestMooniswap|TestNFTOrderPresigner|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestPropertyValidator|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -101,6 +101,7 @@ import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransa
|
|||||||
import * as MixinAaveV2 from '../test/generated-artifacts/MixinAaveV2.json';
|
import * as MixinAaveV2 from '../test/generated-artifacts/MixinAaveV2.json';
|
||||||
import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json';
|
import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json';
|
||||||
import * as MixinBalancerV2 from '../test/generated-artifacts/MixinBalancerV2.json';
|
import * as MixinBalancerV2 from '../test/generated-artifacts/MixinBalancerV2.json';
|
||||||
|
import * as MixinBalancerV2Batch from '../test/generated-artifacts/MixinBalancerV2Batch.json';
|
||||||
import * as MixinBancor from '../test/generated-artifacts/MixinBancor.json';
|
import * as MixinBancor from '../test/generated-artifacts/MixinBancor.json';
|
||||||
import * as MixinCoFiX from '../test/generated-artifacts/MixinCoFiX.json';
|
import * as MixinCoFiX from '../test/generated-artifacts/MixinCoFiX.json';
|
||||||
import * as MixinCompound from '../test/generated-artifacts/MixinCompound.json';
|
import * as MixinCompound from '../test/generated-artifacts/MixinCompound.json';
|
||||||
@ -313,6 +314,7 @@ export const artifacts = {
|
|||||||
MixinAaveV2: MixinAaveV2 as ContractArtifact,
|
MixinAaveV2: MixinAaveV2 as ContractArtifact,
|
||||||
MixinBalancer: MixinBalancer as ContractArtifact,
|
MixinBalancer: MixinBalancer as ContractArtifact,
|
||||||
MixinBalancerV2: MixinBalancerV2 as ContractArtifact,
|
MixinBalancerV2: MixinBalancerV2 as ContractArtifact,
|
||||||
|
MixinBalancerV2Batch: MixinBalancerV2Batch as ContractArtifact,
|
||||||
MixinBancor: MixinBancor as ContractArtifact,
|
MixinBancor: MixinBancor as ContractArtifact,
|
||||||
MixinCoFiX: MixinCoFiX as ContractArtifact,
|
MixinCoFiX: MixinCoFiX as ContractArtifact,
|
||||||
MixinCompound: MixinCompound as ContractArtifact,
|
MixinCompound: MixinCompound as ContractArtifact,
|
||||||
|
@ -99,6 +99,7 @@ export * from '../test/generated-wrappers/meta_transactions_feature';
|
|||||||
export * from '../test/generated-wrappers/mixin_aave_v2';
|
export * from '../test/generated-wrappers/mixin_aave_v2';
|
||||||
export * from '../test/generated-wrappers/mixin_balancer';
|
export * from '../test/generated-wrappers/mixin_balancer';
|
||||||
export * from '../test/generated-wrappers/mixin_balancer_v2';
|
export * from '../test/generated-wrappers/mixin_balancer_v2';
|
||||||
|
export * from '../test/generated-wrappers/mixin_balancer_v2_batch';
|
||||||
export * from '../test/generated-wrappers/mixin_bancor';
|
export * from '../test/generated-wrappers/mixin_bancor';
|
||||||
export * from '../test/generated-wrappers/mixin_co_fi_x';
|
export * from '../test/generated-wrappers/mixin_co_fi_x';
|
||||||
export * from '../test/generated-wrappers/mixin_compound';
|
export * from '../test/generated-wrappers/mixin_compound';
|
||||||
|
@ -132,6 +132,7 @@
|
|||||||
"test/generated-artifacts/MixinAaveV2.json",
|
"test/generated-artifacts/MixinAaveV2.json",
|
||||||
"test/generated-artifacts/MixinBalancer.json",
|
"test/generated-artifacts/MixinBalancer.json",
|
||||||
"test/generated-artifacts/MixinBalancerV2.json",
|
"test/generated-artifacts/MixinBalancerV2.json",
|
||||||
|
"test/generated-artifacts/MixinBalancerV2Batch.json",
|
||||||
"test/generated-artifacts/MixinBancor.json",
|
"test/generated-artifacts/MixinBancor.json",
|
||||||
"test/generated-artifacts/MixinCoFiX.json",
|
"test/generated-artifacts/MixinCoFiX.json",
|
||||||
"test/generated-artifacts/MixinCompound.json",
|
"test/generated-artifacts/MixinCompound.json",
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "16.57.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Add BalancerV2 batch swap support",
|
||||||
|
"pr": 462
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "16.56.0",
|
"version": "16.56.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
"shouldSaveStandardInput": true,
|
"shouldSaveStandardInput": true,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "istanbul",
|
"evmVersion": "istanbul",
|
||||||
"optimizer": { "enabled": true, "runs": 200, "details": { "yul": true, "deduplicate": true } },
|
"optimizer": { "enabled": true, "runs": 200, "details": { "yul": false, "deduplicate": true } },
|
||||||
"outputSelection": {
|
"outputSelection": {
|
||||||
"*": {
|
"*": {
|
||||||
"*": [
|
"*": [
|
||||||
|
105
packages/asset-swapper/contracts/src/BalancerV2BatchSampler.sol
Normal file
105
packages/asset-swapper/contracts/src/BalancerV2BatchSampler.sol
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2021 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.6;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "./interfaces/IBalancerV2Vault.sol";
|
||||||
|
import "./BalancerV2Common.sol";
|
||||||
|
|
||||||
|
contract BalancerV2BatchSampler is BalancerV2Common {
|
||||||
|
|
||||||
|
// Replaces amount for first step with each takerTokenAmount and calls queryBatchSwap using supplied steps
|
||||||
|
/// @dev Sample sell quotes from Balancer V2 supporting multihops.
|
||||||
|
/// @param swapSteps Array of swap steps (can be >= 1).
|
||||||
|
/// @param swapAssets Array of token address for swaps.
|
||||||
|
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||||
|
function sampleMultihopSellsFromBalancerV2(
|
||||||
|
IBalancerV2Vault vault,
|
||||||
|
IBalancerV2Vault.BatchSwapStep[] memory swapSteps,
|
||||||
|
address[] memory swapAssets,
|
||||||
|
uint256[] memory takerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
returns (uint256[] memory makerTokenAmounts)
|
||||||
|
{
|
||||||
|
uint256 numSamples = takerTokenAmounts.length;
|
||||||
|
makerTokenAmounts = new uint256[](numSamples);
|
||||||
|
IBalancerV2Vault.FundManagement memory swapFunds =
|
||||||
|
_createSwapFunds();
|
||||||
|
|
||||||
|
for (uint256 i = 0; i < numSamples; i++) {
|
||||||
|
swapSteps[0].amount = takerTokenAmounts[i];
|
||||||
|
try
|
||||||
|
// For sells we specify the takerToken which is what the vault will receive from the trade
|
||||||
|
vault.queryBatchSwap(IBalancerV2Vault.SwapKind.GIVEN_IN, swapSteps, swapAssets, swapFunds)
|
||||||
|
// amounts represent pool balance deltas from the swap (incoming balance, outgoing balance)
|
||||||
|
returns (int256[] memory amounts) {
|
||||||
|
// Outgoing balance is negative so we need to flip the sign
|
||||||
|
// Note - queryBatchSwap will return a delta for each token in the assets array and last asset should be tokenOut
|
||||||
|
int256 amountOutFromPool = amounts[amounts.length - 1] * -1;
|
||||||
|
if (amountOutFromPool <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
makerTokenAmounts[i] = uint256(amountOutFromPool);
|
||||||
|
} catch {
|
||||||
|
// Swallow failures, leaving all results as zero.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replaces amount for first step with each makerTokenAmount and calls queryBatchSwap using supplied steps
|
||||||
|
/// @dev Sample buy quotes from Balancer V2 supporting multihops.
|
||||||
|
/// @param swapSteps Array of swap steps (can be >= 1).
|
||||||
|
/// @param swapAssets Array of token address for swaps.
|
||||||
|
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||||
|
function sampleMultihopBuysFromBalancerV2(
|
||||||
|
IBalancerV2Vault vault,
|
||||||
|
IBalancerV2Vault.BatchSwapStep[] memory swapSteps,
|
||||||
|
address[] memory swapAssets,
|
||||||
|
uint256[] memory makerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
returns (uint256[] memory takerTokenAmounts)
|
||||||
|
{
|
||||||
|
uint256 numSamples = makerTokenAmounts.length;
|
||||||
|
takerTokenAmounts = new uint256[](numSamples);
|
||||||
|
IBalancerV2Vault.FundManagement memory swapFunds =
|
||||||
|
_createSwapFunds();
|
||||||
|
|
||||||
|
for (uint256 i = 0; i < numSamples; i++) {
|
||||||
|
swapSteps[0].amount = makerTokenAmounts[i];
|
||||||
|
try
|
||||||
|
// Uses GIVEN_OUT type for Buy
|
||||||
|
vault.queryBatchSwap(IBalancerV2Vault.SwapKind.GIVEN_OUT, swapSteps, swapAssets, swapFunds)
|
||||||
|
// amounts represent pool balance deltas from the swap (incoming balance, outgoing balance)
|
||||||
|
returns (int256[] memory amounts) {
|
||||||
|
int256 amountIntoPool = amounts[0];
|
||||||
|
if (amountIntoPool <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
takerTokenAmounts[i] = uint256(amountIntoPool);
|
||||||
|
} catch {
|
||||||
|
// Swallow failures, leaving all results as zero.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
packages/asset-swapper/contracts/src/BalancerV2Common.sol
Normal file
41
packages/asset-swapper/contracts/src/BalancerV2Common.sol
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2021 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.6;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "./interfaces/IBalancerV2Vault.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract BalancerV2Common {
|
||||||
|
|
||||||
|
function _createSwapFunds()
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (IBalancerV2Vault.FundManagement memory)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
IBalancerV2Vault.FundManagement({
|
||||||
|
sender: address(this),
|
||||||
|
fromInternalBalance: false,
|
||||||
|
recipient: payable(address(this)),
|
||||||
|
toInternalBalance: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -21,44 +21,11 @@ pragma solidity ^0.6;
|
|||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "./SamplerUtils.sol";
|
import "./SamplerUtils.sol";
|
||||||
|
import "./interfaces/IBalancerV2Vault.sol";
|
||||||
|
import "./BalancerV2Common.sol";
|
||||||
|
|
||||||
/// @dev Minimal Balancer V2 Vault interface
|
|
||||||
/// for documentation refer to https://github.com/balancer-labs/balancer-core-v2/blob/master/contracts/vault/interfaces/IVault.sol
|
|
||||||
interface IBalancerV2Vault {
|
|
||||||
enum SwapKind { GIVEN_IN, GIVEN_OUT }
|
|
||||||
|
|
||||||
struct BatchSwapStep {
|
contract BalancerV2Sampler is SamplerUtils, BalancerV2Common {
|
||||||
bytes32 poolId;
|
|
||||||
uint256 assetInIndex;
|
|
||||||
uint256 assetOutIndex;
|
|
||||||
uint256 amount;
|
|
||||||
bytes userData;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FundManagement {
|
|
||||||
address sender;
|
|
||||||
bool fromInternalBalance;
|
|
||||||
address payable recipient;
|
|
||||||
bool toInternalBalance;
|
|
||||||
}
|
|
||||||
|
|
||||||
function queryBatchSwap(
|
|
||||||
SwapKind kind,
|
|
||||||
BatchSwapStep[] calldata swaps,
|
|
||||||
IAsset[] calldata assets,
|
|
||||||
FundManagement calldata funds
|
|
||||||
) external returns (int256[] memory assetDeltas);
|
|
||||||
}
|
|
||||||
interface IAsset {
|
|
||||||
// solhint-disable-previous-line no-empty-blocks
|
|
||||||
}
|
|
||||||
|
|
||||||
contract BalancerV2Sampler is SamplerUtils {
|
|
||||||
|
|
||||||
struct BalancerV2PoolInfo {
|
|
||||||
bytes32 poolId;
|
|
||||||
address vault;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Sample sell quotes from Balancer V2.
|
/// @dev Sample sell quotes from Balancer V2.
|
||||||
/// @param poolInfo Struct with pool related data
|
/// @param poolInfo Struct with pool related data
|
||||||
@ -68,7 +35,7 @@ contract BalancerV2Sampler is SamplerUtils {
|
|||||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||||
/// amount.
|
/// amount.
|
||||||
function sampleSellsFromBalancerV2(
|
function sampleSellsFromBalancerV2(
|
||||||
BalancerV2PoolInfo memory poolInfo,
|
IBalancerV2Vault.BalancerV2PoolInfo memory poolInfo,
|
||||||
address takerToken,
|
address takerToken,
|
||||||
address makerToken,
|
address makerToken,
|
||||||
uint256[] memory takerTokenAmounts
|
uint256[] memory takerTokenAmounts
|
||||||
@ -78,9 +45,9 @@ contract BalancerV2Sampler is SamplerUtils {
|
|||||||
{
|
{
|
||||||
_assertValidPair(makerToken, takerToken);
|
_assertValidPair(makerToken, takerToken);
|
||||||
IBalancerV2Vault vault = IBalancerV2Vault(poolInfo.vault);
|
IBalancerV2Vault vault = IBalancerV2Vault(poolInfo.vault);
|
||||||
IAsset[] memory swapAssets = new IAsset[](2);
|
address[] memory swapAssets = new address[](2);
|
||||||
swapAssets[0] = IAsset(takerToken);
|
swapAssets[0] = takerToken;
|
||||||
swapAssets[1] = IAsset(makerToken);
|
swapAssets[1] = makerToken;
|
||||||
|
|
||||||
uint256 numSamples = takerTokenAmounts.length;
|
uint256 numSamples = takerTokenAmounts.length;
|
||||||
makerTokenAmounts = new uint256[](numSamples);
|
makerTokenAmounts = new uint256[](numSamples);
|
||||||
@ -97,7 +64,7 @@ contract BalancerV2Sampler is SamplerUtils {
|
|||||||
// amounts represent pool balance deltas from the swap (incoming balance, outgoing balance)
|
// amounts represent pool balance deltas from the swap (incoming balance, outgoing balance)
|
||||||
returns (int256[] memory amounts) {
|
returns (int256[] memory amounts) {
|
||||||
// Outgoing balance is negative so we need to flip the sign
|
// Outgoing balance is negative so we need to flip the sign
|
||||||
int256 amountOutFromPool = amounts[1] * -1;
|
int256 amountOutFromPool = amounts[amounts.length - 1] * -1;
|
||||||
if (amountOutFromPool <= 0) {
|
if (amountOutFromPool <= 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -117,7 +84,7 @@ contract BalancerV2Sampler is SamplerUtils {
|
|||||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||||
/// amount.
|
/// amount.
|
||||||
function sampleBuysFromBalancerV2(
|
function sampleBuysFromBalancerV2(
|
||||||
BalancerV2PoolInfo memory poolInfo,
|
IBalancerV2Vault.BalancerV2PoolInfo memory poolInfo,
|
||||||
address takerToken,
|
address takerToken,
|
||||||
address makerToken,
|
address makerToken,
|
||||||
uint256[] memory makerTokenAmounts
|
uint256[] memory makerTokenAmounts
|
||||||
@ -127,9 +94,9 @@ contract BalancerV2Sampler is SamplerUtils {
|
|||||||
{
|
{
|
||||||
_assertValidPair(makerToken, takerToken);
|
_assertValidPair(makerToken, takerToken);
|
||||||
IBalancerV2Vault vault = IBalancerV2Vault(poolInfo.vault);
|
IBalancerV2Vault vault = IBalancerV2Vault(poolInfo.vault);
|
||||||
IAsset[] memory swapAssets = new IAsset[](2);
|
address[] memory swapAssets = new address[](2);
|
||||||
swapAssets[0] = IAsset(takerToken);
|
swapAssets[0] = takerToken;
|
||||||
swapAssets[1] = IAsset(makerToken);
|
swapAssets[1] = makerToken;
|
||||||
|
|
||||||
uint256 numSamples = makerTokenAmounts.length;
|
uint256 numSamples = makerTokenAmounts.length;
|
||||||
takerTokenAmounts = new uint256[](numSamples);
|
takerTokenAmounts = new uint256[](numSamples);
|
||||||
@ -157,7 +124,7 @@ contract BalancerV2Sampler is SamplerUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _createSwapSteps(
|
function _createSwapSteps(
|
||||||
BalancerV2PoolInfo memory poolInfo,
|
IBalancerV2Vault.BalancerV2PoolInfo memory poolInfo,
|
||||||
uint256 amount
|
uint256 amount
|
||||||
) private pure returns (IBalancerV2Vault.BatchSwapStep[] memory) {
|
) private pure returns (IBalancerV2Vault.BatchSwapStep[] memory) {
|
||||||
IBalancerV2Vault.BatchSwapStep[] memory swapSteps =
|
IBalancerV2Vault.BatchSwapStep[] memory swapSteps =
|
||||||
@ -172,18 +139,4 @@ contract BalancerV2Sampler is SamplerUtils {
|
|||||||
|
|
||||||
return swapSteps;
|
return swapSteps;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _createSwapFunds()
|
|
||||||
private
|
|
||||||
view
|
|
||||||
returns (IBalancerV2Vault.FundManagement memory)
|
|
||||||
{
|
|
||||||
return
|
|
||||||
IBalancerV2Vault.FundManagement({
|
|
||||||
sender: address(this),
|
|
||||||
fromInternalBalance: false,
|
|
||||||
recipient: payable(address(this)),
|
|
||||||
toInternalBalance: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,8 @@ pragma experimental ABIEncoderV2;
|
|||||||
|
|
||||||
import "./interfaces/IBancor.sol";
|
import "./interfaces/IBancor.sol";
|
||||||
|
|
||||||
contract CompilerHack {}
|
|
||||||
|
|
||||||
contract BancorSampler is CompilerHack {
|
contract BancorSampler {
|
||||||
|
|
||||||
/// @dev Base gas limit for Bancor calls.
|
/// @dev Base gas limit for Bancor calls.
|
||||||
uint256 constant private BANCOR_CALL_GAS = 300e3; // 300k
|
uint256 constant private BANCOR_CALL_GAS = 300e3; // 300k
|
||||||
|
@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
|
|||||||
|
|
||||||
import "./BalancerSampler.sol";
|
import "./BalancerSampler.sol";
|
||||||
import "./BalancerV2Sampler.sol";
|
import "./BalancerV2Sampler.sol";
|
||||||
|
import "./BalancerV2BatchSampler.sol";
|
||||||
import "./BancorSampler.sol";
|
import "./BancorSampler.sol";
|
||||||
import "./CompoundSampler.sol";
|
import "./CompoundSampler.sol";
|
||||||
import "./CurveSampler.sol";
|
import "./CurveSampler.sol";
|
||||||
@ -32,7 +33,6 @@ import "./KyberDmmSampler.sol";
|
|||||||
import "./LidoSampler.sol";
|
import "./LidoSampler.sol";
|
||||||
import "./LiquidityProviderSampler.sol";
|
import "./LiquidityProviderSampler.sol";
|
||||||
import "./MakerPSMSampler.sol";
|
import "./MakerPSMSampler.sol";
|
||||||
import "./MultiBridgeSampler.sol";
|
|
||||||
import "./MStableSampler.sol";
|
import "./MStableSampler.sol";
|
||||||
import "./MooniswapSampler.sol";
|
import "./MooniswapSampler.sol";
|
||||||
import "./NativeOrderSampler.sol";
|
import "./NativeOrderSampler.sol";
|
||||||
@ -48,6 +48,7 @@ import "./UtilitySampler.sol";
|
|||||||
contract ERC20BridgeSampler is
|
contract ERC20BridgeSampler is
|
||||||
BalancerSampler,
|
BalancerSampler,
|
||||||
BalancerV2Sampler,
|
BalancerV2Sampler,
|
||||||
|
BalancerV2BatchSampler,
|
||||||
BancorSampler,
|
BancorSampler,
|
||||||
CompoundSampler,
|
CompoundSampler,
|
||||||
CurveSampler,
|
CurveSampler,
|
||||||
@ -60,7 +61,6 @@ contract ERC20BridgeSampler is
|
|||||||
MakerPSMSampler,
|
MakerPSMSampler,
|
||||||
MStableSampler,
|
MStableSampler,
|
||||||
MooniswapSampler,
|
MooniswapSampler,
|
||||||
MultiBridgeSampler,
|
|
||||||
NativeOrderSampler,
|
NativeOrderSampler,
|
||||||
ShellSampler,
|
ShellSampler,
|
||||||
SmoothySampler,
|
SmoothySampler,
|
||||||
@ -92,4 +92,6 @@ contract ERC20BridgeSampler is
|
|||||||
(callResults[i].success, callResults[i].data) = address(this).call(callDatas[i]);
|
(callResults[i].success, callResults[i].data) = address(this).call(callDatas[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
receive() external payable {}
|
||||||
}
|
}
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
// 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/IMultiBridge.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract MultiBridgeSampler {
|
|
||||||
|
|
||||||
/// @dev Default gas limit for multibridge calls.
|
|
||||||
uint256 constant private DEFAULT_CALL_GAS = 400e3; // 400k
|
|
||||||
|
|
||||||
/// @dev Sample sell quotes from MultiBridge.
|
|
||||||
/// @param multibridge Address of the MultiBridge contract.
|
|
||||||
/// @param takerToken Address of the taker token (what to sell).
|
|
||||||
/// @param intermediateToken The address of the intermediate token to
|
|
||||||
/// use in an indirect route.
|
|
||||||
/// @param makerToken Address 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 sampleSellsFromMultiBridge(
|
|
||||||
address multibridge,
|
|
||||||
address takerToken,
|
|
||||||
address intermediateToken,
|
|
||||||
address makerToken,
|
|
||||||
uint256[] memory takerTokenAmounts
|
|
||||||
)
|
|
||||||
public
|
|
||||||
view
|
|
||||||
returns (uint256[] memory makerTokenAmounts)
|
|
||||||
{
|
|
||||||
// Initialize array of maker token amounts.
|
|
||||||
uint256 numSamples = takerTokenAmounts.length;
|
|
||||||
makerTokenAmounts = new uint256[](numSamples);
|
|
||||||
|
|
||||||
// If no address provided, return all zeros.
|
|
||||||
if (multibridge == address(0)) {
|
|
||||||
return makerTokenAmounts;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint256 i = 0; i < numSamples; i++) {
|
|
||||||
(bool didSucceed, bytes memory resultData) =
|
|
||||||
multibridge.staticcall.gas(DEFAULT_CALL_GAS)(
|
|
||||||
abi.encodeWithSelector(
|
|
||||||
IMultiBridge(0).getSellQuote.selector,
|
|
||||||
takerToken,
|
|
||||||
intermediateToken,
|
|
||||||
makerToken,
|
|
||||||
takerTokenAmounts[i]
|
|
||||||
));
|
|
||||||
uint256 buyAmount = 0;
|
|
||||||
if (didSucceed) {
|
|
||||||
buyAmount = abi.decode(resultData, (uint256));
|
|
||||||
}
|
|
||||||
// Exit early if the amount is too high for the source to serve
|
|
||||||
if (buyAmount == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
makerTokenAmounts[i] = buyAmount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,54 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
/// @dev Minimal Balancer V2 Vault interface
|
||||||
|
/// for documentation refer to https://github.com/balancer-labs/balancer-core-v2/blob/master/contracts/vault/interfaces/IVault.sol
|
||||||
|
interface IBalancerV2Vault {
|
||||||
|
enum SwapKind { GIVEN_IN, GIVEN_OUT }
|
||||||
|
|
||||||
|
struct BatchSwapStep {
|
||||||
|
bytes32 poolId;
|
||||||
|
uint256 assetInIndex;
|
||||||
|
uint256 assetOutIndex;
|
||||||
|
uint256 amount;
|
||||||
|
bytes userData;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FundManagement {
|
||||||
|
address sender;
|
||||||
|
bool fromInternalBalance;
|
||||||
|
address payable recipient;
|
||||||
|
bool toInternalBalance;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BalancerV2PoolInfo {
|
||||||
|
bytes32 poolId;
|
||||||
|
address vault;
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryBatchSwap(
|
||||||
|
SwapKind kind,
|
||||||
|
BatchSwapStep[] calldata swaps,
|
||||||
|
address[] calldata assets,
|
||||||
|
FundManagement calldata funds
|
||||||
|
) external returns (int256[] memory assetDeltas);
|
||||||
|
}
|
@ -1,39 +0,0 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
pragma solidity ^0.6;
|
|
||||||
pragma experimental ABIEncoderV2;
|
|
||||||
|
|
||||||
|
|
||||||
contract DummyLiquidityProvider
|
|
||||||
{
|
|
||||||
/// @dev Quotes the amount of `makerToken` that would be obtained by
|
|
||||||
/// selling `sellAmount` of `takerToken`.
|
|
||||||
/// @param sellAmount Amount of `takerToken` to sell.
|
|
||||||
/// @return makerTokenAmount Amount of `makerToken` that would be obtained.
|
|
||||||
function getSellQuote(
|
|
||||||
address, /* takerToken */
|
|
||||||
address, /* makerToken */
|
|
||||||
uint256 sellAmount
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (uint256 makerTokenAmount)
|
|
||||||
{
|
|
||||||
makerTokenAmount = sellAmount - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Quotes the amount of `takerToken` that would need to be sold in
|
|
||||||
/// order to obtain `buyAmount` of `makerToken`.
|
|
||||||
/// @param buyAmount Amount of `makerToken` to buy.
|
|
||||||
/// @return takerTokenAmount Amount of `takerToken` that would need to be sold.
|
|
||||||
function getBuyQuote(
|
|
||||||
address, /* takerToken */
|
|
||||||
address, /* makerToken */
|
|
||||||
uint256 buyAmount
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (uint256 takerTokenAmount)
|
|
||||||
{
|
|
||||||
takerTokenAmount = buyAmount + 1;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,455 +0,0 @@
|
|||||||
// 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 "../src/ERC20BridgeSampler.sol";
|
|
||||||
import "../src/interfaces/IKyberNetwork.sol";
|
|
||||||
import "../src/interfaces/IUniswapV2Router01.sol";
|
|
||||||
|
|
||||||
|
|
||||||
library LibDeterministicQuotes {
|
|
||||||
|
|
||||||
address private constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
|
||||||
uint256 private constant RATE_DENOMINATOR = 1 ether;
|
|
||||||
uint256 private constant MIN_RATE = RATE_DENOMINATOR / 100;
|
|
||||||
uint256 private constant MAX_RATE = 100 * RATE_DENOMINATOR;
|
|
||||||
uint8 private constant MIN_DECIMALS = 4;
|
|
||||||
uint8 private constant MAX_DECIMALS = 20;
|
|
||||||
|
|
||||||
function getDeterministicSellQuote(
|
|
||||||
bytes32 salt,
|
|
||||||
address sellToken,
|
|
||||||
address buyToken,
|
|
||||||
uint256 sellAmount
|
|
||||||
)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (uint256 buyAmount)
|
|
||||||
{
|
|
||||||
uint256 sellBase = uint256(10) ** getDeterministicTokenDecimals(sellToken);
|
|
||||||
uint256 buyBase = uint256(10) ** getDeterministicTokenDecimals(buyToken);
|
|
||||||
uint256 rate = getDeterministicRate(salt, sellToken, buyToken);
|
|
||||||
return sellAmount * rate * buyBase / sellBase / RATE_DENOMINATOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDeterministicBuyQuote(
|
|
||||||
bytes32 salt,
|
|
||||||
address sellToken,
|
|
||||||
address buyToken,
|
|
||||||
uint256 buyAmount
|
|
||||||
)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (uint256 sellAmount)
|
|
||||||
{
|
|
||||||
uint256 sellBase = uint256(10) ** getDeterministicTokenDecimals(sellToken);
|
|
||||||
uint256 buyBase = uint256(10) ** getDeterministicTokenDecimals(buyToken);
|
|
||||||
uint256 rate = getDeterministicRate(salt, sellToken, buyToken);
|
|
||||||
return buyAmount * RATE_DENOMINATOR * sellBase / rate / buyBase;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDeterministicTokenDecimals(address token)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (uint8 decimals)
|
|
||||||
{
|
|
||||||
if (token == WETH_ADDRESS) {
|
|
||||||
return 18;
|
|
||||||
}
|
|
||||||
bytes32 seed = keccak256(abi.encodePacked(token));
|
|
||||||
return uint8(uint256(seed) % (MAX_DECIMALS - MIN_DECIMALS)) + MIN_DECIMALS;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDeterministicRate(bytes32 salt, address sellToken, address buyToken)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (uint256 rate)
|
|
||||||
{
|
|
||||||
bytes32 seed = keccak256(abi.encodePacked(salt, sellToken, buyToken));
|
|
||||||
return uint256(seed) % (MAX_RATE - MIN_RATE) + MIN_RATE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
contract TestDeploymentConstants {
|
|
||||||
|
|
||||||
// solhint-disable separate-by-one-line-in-contract
|
|
||||||
|
|
||||||
// Mainnet addresses ///////////////////////////////////////////////////////
|
|
||||||
/// @dev Mainnet address of the WETH contract.
|
|
||||||
address constant private WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
|
||||||
|
|
||||||
/// @dev Overridable way to get the WETH address.
|
|
||||||
/// @return wethAddress The WETH address.
|
|
||||||
function _getWethAddress()
|
|
||||||
internal
|
|
||||||
view
|
|
||||||
returns (address wethAddress)
|
|
||||||
{
|
|
||||||
return WETH_ADDRESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
contract FailTrigger {
|
|
||||||
|
|
||||||
// Give this address a balance to force operations to fail.
|
|
||||||
address payable constant public FAILURE_ADDRESS = 0xe9dB8717BC5DFB20aaf538b4a5a02B7791FF430C;
|
|
||||||
|
|
||||||
// Funds `FAILURE_ADDRESS`.
|
|
||||||
function enableFailTrigger() external payable {
|
|
||||||
FAILURE_ADDRESS.transfer(msg.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _revertIfShouldFail() internal view {
|
|
||||||
if (FAILURE_ADDRESS.balance != 0) {
|
|
||||||
revert("FAIL_TRIGGERED");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
contract TestERC20BridgeSamplerUniswapExchange is
|
|
||||||
IUniswapExchangeQuotes,
|
|
||||||
TestDeploymentConstants,
|
|
||||||
FailTrigger
|
|
||||||
{
|
|
||||||
bytes32 constant private BASE_SALT = 0x1d6a6a0506b0b4a554b907a4c29d9f4674e461989d9c1921feb17b26716385ab;
|
|
||||||
|
|
||||||
address public tokenAddress;
|
|
||||||
bytes32 public salt;
|
|
||||||
|
|
||||||
constructor(address _tokenAddress) public {
|
|
||||||
tokenAddress = _tokenAddress;
|
|
||||||
salt = keccak256(abi.encodePacked(BASE_SALT, _tokenAddress));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deterministic `IUniswapExchangeQuotes.getEthToTokenInputPrice()`.
|
|
||||||
function getEthToTokenInputPrice(
|
|
||||||
uint256 ethSold
|
|
||||||
)
|
|
||||||
override
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (uint256 tokensBought)
|
|
||||||
{
|
|
||||||
_revertIfShouldFail();
|
|
||||||
return LibDeterministicQuotes.getDeterministicSellQuote(
|
|
||||||
salt,
|
|
||||||
tokenAddress,
|
|
||||||
_getWethAddress(),
|
|
||||||
ethSold
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deterministic `IUniswapExchangeQuotes.getEthToTokenOutputPrice()`.
|
|
||||||
function getEthToTokenOutputPrice(
|
|
||||||
uint256 tokensBought
|
|
||||||
)
|
|
||||||
override
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (uint256 ethSold)
|
|
||||||
{
|
|
||||||
_revertIfShouldFail();
|
|
||||||
return LibDeterministicQuotes.getDeterministicBuyQuote(
|
|
||||||
salt,
|
|
||||||
_getWethAddress(),
|
|
||||||
tokenAddress,
|
|
||||||
tokensBought
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deterministic `IUniswapExchangeQuotes.getTokenToEthInputPrice()`.
|
|
||||||
function getTokenToEthInputPrice(
|
|
||||||
uint256 tokensSold
|
|
||||||
)
|
|
||||||
override
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (uint256 ethBought)
|
|
||||||
{
|
|
||||||
_revertIfShouldFail();
|
|
||||||
return LibDeterministicQuotes.getDeterministicSellQuote(
|
|
||||||
salt,
|
|
||||||
tokenAddress,
|
|
||||||
_getWethAddress(),
|
|
||||||
tokensSold
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deterministic `IUniswapExchangeQuotes.getTokenToEthOutputPrice()`.
|
|
||||||
function getTokenToEthOutputPrice(
|
|
||||||
uint256 ethBought
|
|
||||||
)
|
|
||||||
override
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (uint256 tokensSold)
|
|
||||||
{
|
|
||||||
_revertIfShouldFail();
|
|
||||||
return LibDeterministicQuotes.getDeterministicBuyQuote(
|
|
||||||
salt,
|
|
||||||
_getWethAddress(),
|
|
||||||
tokenAddress,
|
|
||||||
ethBought
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
contract TestERC20BridgeSamplerUniswapV2Router01 is
|
|
||||||
IUniswapV2Router01,
|
|
||||||
TestDeploymentConstants,
|
|
||||||
FailTrigger
|
|
||||||
{
|
|
||||||
bytes32 constant private SALT = 0xadc7fcb33c735913b8635927e66896b356a53a912ab2ceff929e60a04b53b3c1;
|
|
||||||
|
|
||||||
// Deterministic `IUniswapV2Router01.getAmountsOut()`.
|
|
||||||
function getAmountsOut(uint256 amountIn, address[] calldata path)
|
|
||||||
override
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (uint256[] memory amounts)
|
|
||||||
{
|
|
||||||
require(path.length >= 2, "PATH_TOO_SHORT");
|
|
||||||
_revertIfShouldFail();
|
|
||||||
amounts = new uint256[](path.length);
|
|
||||||
amounts[0] = amountIn;
|
|
||||||
for (uint256 i = 0; i < path.length - 1; ++i) {
|
|
||||||
amounts[i + 1] = LibDeterministicQuotes.getDeterministicSellQuote(
|
|
||||||
SALT,
|
|
||||||
path[i],
|
|
||||||
path[i + 1],
|
|
||||||
amounts[i]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deterministic `IUniswapV2Router01.getAmountsInt()`.
|
|
||||||
function getAmountsIn(uint256 amountOut, address[] calldata path)
|
|
||||||
override
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (uint256[] memory amounts)
|
|
||||||
{
|
|
||||||
require(path.length >= 2, "PATH_TOO_SHORT");
|
|
||||||
_revertIfShouldFail();
|
|
||||||
amounts = new uint256[](path.length);
|
|
||||||
amounts[path.length - 1] = amountOut;
|
|
||||||
for (uint256 i = path.length - 1; i > 0; --i) {
|
|
||||||
amounts[i - 1] = LibDeterministicQuotes.getDeterministicBuyQuote(
|
|
||||||
SALT,
|
|
||||||
path[i - 1],
|
|
||||||
path[i],
|
|
||||||
amounts[i]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// solhint-disable space-after-comma
|
|
||||||
contract TestERC20BridgeSamplerKyberNetwork is
|
|
||||||
TestDeploymentConstants,
|
|
||||||
FailTrigger
|
|
||||||
{
|
|
||||||
bytes32 constant private SALT = 0x0ff3ca9d46195c39f9a12afb74207b4970349fb3cfb1e459bbf170298d326bc7;
|
|
||||||
address constant public ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
|
||||||
|
|
||||||
enum TradeType {BestOfAll, MaskIn, MaskOut, Split}
|
|
||||||
enum ProcessWithRate {NotRequired, Required}
|
|
||||||
|
|
||||||
// IKyberHintHandler
|
|
||||||
function buildTokenToEthHint(
|
|
||||||
address tokenSrc,
|
|
||||||
TradeType /* tokenToEthType */,
|
|
||||||
bytes32[] calldata /* tokenToEthReserveIds */,
|
|
||||||
uint256[] calldata /* tokenToEthSplits */
|
|
||||||
) external view returns (bytes memory hint)
|
|
||||||
{
|
|
||||||
return abi.encode(tokenSrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildEthToTokenHint(
|
|
||||||
address tokenDest,
|
|
||||||
TradeType /* ethToTokenType */,
|
|
||||||
bytes32[] calldata /* ethToTokenReserveIds */,
|
|
||||||
uint256[] calldata /* ethToTokenSplits */
|
|
||||||
) external view returns (bytes memory hint)
|
|
||||||
{
|
|
||||||
return abi.encode(tokenDest);
|
|
||||||
}
|
|
||||||
|
|
||||||
// IKyberHintHandler
|
|
||||||
function buildTokenToTokenHint(
|
|
||||||
address tokenSrc,
|
|
||||||
TradeType /* tokenToEthType */,
|
|
||||||
bytes32[] calldata /* tokenToEthReserveIds */,
|
|
||||||
uint256[] calldata /* tokenToEthSplits */,
|
|
||||||
address /* tokenDest */,
|
|
||||||
TradeType /* EthToTokenType */,
|
|
||||||
bytes32[] calldata /* EthToTokenReserveIds */,
|
|
||||||
uint256[] calldata /* EthToTokenSplits */
|
|
||||||
) external view returns (bytes memory hint)
|
|
||||||
{
|
|
||||||
return abi.encode(tokenSrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// IKyberHintHandler
|
|
||||||
function getTradingReserves(
|
|
||||||
address tokenSrc,
|
|
||||||
address tokenDest,
|
|
||||||
bool isTokenToToken,
|
|
||||||
bytes calldata hint
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (
|
|
||||||
bytes32[] memory reserveIds,
|
|
||||||
uint256[] memory splitValuesBps,
|
|
||||||
ProcessWithRate processWithRate
|
|
||||||
)
|
|
||||||
{
|
|
||||||
reserveIds = new bytes32[](1);
|
|
||||||
reserveIds[0] = bytes32(uint256(1));
|
|
||||||
splitValuesBps = new uint256[](0);
|
|
||||||
processWithRate = ProcessWithRate.NotRequired;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deterministic `IKyberNetworkProxy.getExpectedRateAfterFee()`.
|
|
||||||
function getExpectedRateAfterFee(
|
|
||||||
address fromToken,
|
|
||||||
address toToken,
|
|
||||||
uint256 /* srcQty */,
|
|
||||||
uint256 /* fee */,
|
|
||||||
bytes calldata /* hint */
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns
|
|
||||||
(uint256 expectedRate)
|
|
||||||
{
|
|
||||||
_revertIfShouldFail();
|
|
||||||
fromToken = fromToken == ETH_ADDRESS ? _getWethAddress() : fromToken;
|
|
||||||
toToken = toToken == ETH_ADDRESS ? _getWethAddress() : toToken;
|
|
||||||
expectedRate = LibDeterministicQuotes.getDeterministicRate(
|
|
||||||
SALT,
|
|
||||||
fromToken,
|
|
||||||
toToken
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deterministic `IKyberNetworkProxy.getExpectedRate()`.
|
|
||||||
function getExpectedRate(
|
|
||||||
address fromToken,
|
|
||||||
address toToken,
|
|
||||||
uint256
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (uint256 expectedRate, uint256)
|
|
||||||
{
|
|
||||||
_revertIfShouldFail();
|
|
||||||
fromToken = fromToken == ETH_ADDRESS ? _getWethAddress() : fromToken;
|
|
||||||
toToken = toToken == ETH_ADDRESS ? _getWethAddress() : toToken;
|
|
||||||
expectedRate = LibDeterministicQuotes.getDeterministicRate(
|
|
||||||
SALT,
|
|
||||||
fromToken,
|
|
||||||
toToken
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
contract TestERC20BridgeSamplerUniswapExchangeFactory is
|
|
||||||
IUniswapExchangeFactory
|
|
||||||
{
|
|
||||||
mapping (address => IUniswapExchangeQuotes) private _exchangesByToken;
|
|
||||||
|
|
||||||
// Creates Uniswap exchange contracts for tokens.
|
|
||||||
function createTokenExchanges(address[] calldata tokenAddresses)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
for (uint256 i = 0; i < tokenAddresses.length; i++) {
|
|
||||||
address tokenAddress = tokenAddresses[i];
|
|
||||||
_exchangesByToken[tokenAddress] =
|
|
||||||
new TestERC20BridgeSamplerUniswapExchange(tokenAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// `IUniswapExchangeFactory.getExchange()`.
|
|
||||||
function getExchange(address tokenAddress)
|
|
||||||
override
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (address)
|
|
||||||
{
|
|
||||||
return address(_exchangesByToken[tokenAddress]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
contract TestERC20BridgeSampler is
|
|
||||||
ERC20BridgeSampler,
|
|
||||||
FailTrigger
|
|
||||||
{
|
|
||||||
TestERC20BridgeSamplerUniswapExchangeFactory public uniswap;
|
|
||||||
TestERC20BridgeSamplerUniswapV2Router01 public uniswapV2Router;
|
|
||||||
TestERC20BridgeSamplerKyberNetwork public kyber;
|
|
||||||
|
|
||||||
uint8 private constant MAX_ORDER_STATUS = uint8(IExchange.OrderStatus.CANCELLED) + 1;
|
|
||||||
|
|
||||||
constructor() public ERC20BridgeSampler() {
|
|
||||||
uniswap = new TestERC20BridgeSamplerUniswapExchangeFactory();
|
|
||||||
uniswapV2Router = new TestERC20BridgeSamplerUniswapV2Router01();
|
|
||||||
kyber = new TestERC20BridgeSamplerKyberNetwork();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates Uniswap exchange contracts for tokens.
|
|
||||||
function createTokenExchanges(address[] calldata tokenAddresses)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
uniswap.createTokenExchanges(tokenAddresses);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overridden to return deterministic states.
|
|
||||||
function getLimitOrderFillableTakerAmount(
|
|
||||||
IExchange.LimitOrder memory order,
|
|
||||||
IExchange.Signature memory,
|
|
||||||
IExchange
|
|
||||||
)
|
|
||||||
override
|
|
||||||
public
|
|
||||||
view
|
|
||||||
returns (uint256 fillableTakerAmount)
|
|
||||||
{
|
|
||||||
return uint256(keccak256(abi.encode(order.salt))) % order.takerAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overriden to return deterministic decimals.
|
|
||||||
function _getTokenDecimals(address tokenAddress)
|
|
||||||
override
|
|
||||||
internal
|
|
||||||
view
|
|
||||||
returns (uint8 decimals)
|
|
||||||
{
|
|
||||||
return LibDeterministicQuotes.getDeterministicTokenDecimals(tokenAddress);
|
|
||||||
}
|
|
||||||
}
|
|
@ -39,7 +39,7 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker",
|
"publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker",
|
||||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||||
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BalancerV2Sampler|BancorSampler|CompoundSampler|CurveSampler|DODOSampler|DODOV2Sampler|DummyLiquidityProvider|ERC20BridgeSampler|FakeTaker|IBalancer|IBancor|ICurve|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|ISmoothy|IUniswapExchangeQuotes|IUniswapV2Router01|KyberDmmSampler|KyberSampler|LidoSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SmoothySampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UniswapV3Sampler|UtilitySampler).json",
|
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BalancerV2BatchSampler|BalancerV2Common|BalancerV2Sampler|BancorSampler|CompoundSampler|CurveSampler|DODOSampler|DODOV2Sampler|ERC20BridgeSampler|FakeTaker|IBalancer|IBalancerV2Vault|IBancor|ICurve|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|ISmoothy|IUniswapExchangeQuotes|IUniswapV2Router01|KyberDmmSampler|KyberSampler|LidoSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SmoothySampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UniswapV3Sampler|UtilitySampler).json",
|
||||||
"postpublish": {
|
"postpublish": {
|
||||||
"assets": []
|
"assets": []
|
||||||
}
|
}
|
||||||
@ -73,6 +73,7 @@
|
|||||||
"@0x/typescript-typings": "^5.3.1",
|
"@0x/typescript-typings": "^5.3.1",
|
||||||
"@0x/utils": "^6.5.3",
|
"@0x/utils": "^6.5.3",
|
||||||
"@0x/web3-wrapper": "^7.6.5",
|
"@0x/web3-wrapper": "^7.6.5",
|
||||||
|
"@balancer-labs/sdk": "^0.1.6",
|
||||||
"@balancer-labs/sor": "0.3.2",
|
"@balancer-labs/sor": "0.3.2",
|
||||||
"@bancor/sdk": "0.2.9",
|
"@bancor/sdk": "0.2.9",
|
||||||
"@ethersproject/abi": "^5.0.1",
|
"@ethersproject/abi": "^5.0.1",
|
||||||
@ -90,7 +91,8 @@
|
|||||||
"graphql": "^15.4.0",
|
"graphql": "^15.4.0",
|
||||||
"graphql-request": "^3.4.0",
|
"graphql-request": "^3.4.0",
|
||||||
"heartbeats": "^5.0.1",
|
"heartbeats": "^5.0.1",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11",
|
||||||
|
"sorV2": "npm:@balancer-labs/sor"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^5.8.0",
|
"@0x/abi-gen": "^5.8.0",
|
||||||
|
@ -8,6 +8,7 @@ import { TokenAdjacencyGraphBuilder } from '../token_adjacency_graph_builder';
|
|||||||
import { SourceFilters } from './source_filters';
|
import { SourceFilters } from './source_filters';
|
||||||
import {
|
import {
|
||||||
AaveV2FillData,
|
AaveV2FillData,
|
||||||
|
BalancerV2BatchSwapFillData,
|
||||||
BancorFillData,
|
BancorFillData,
|
||||||
CompoundFillData,
|
CompoundFillData,
|
||||||
CurveFillData,
|
CurveFillData,
|
||||||
@ -2156,11 +2157,12 @@ export const BALANCER_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/ba
|
|||||||
export const BALANCER_TOP_POOLS_FETCHED = 250;
|
export const BALANCER_TOP_POOLS_FETCHED = 250;
|
||||||
export const BALANCER_MAX_POOLS_FETCHED = 3;
|
export const BALANCER_MAX_POOLS_FETCHED = 3;
|
||||||
|
|
||||||
export const BALANCER_V2_SUBGRAPH_URL_BY_CHAIN = valueByChainId<string>(
|
export const BALANCER_V2_SUBGRAPH_URL_BY_CHAIN = valueByChainId(
|
||||||
{
|
{
|
||||||
|
[ChainId.Mainnet]: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2',
|
||||||
[ChainId.Polygon]: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-polygon-v2',
|
[ChainId.Polygon]: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-polygon-v2',
|
||||||
},
|
},
|
||||||
'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2',
|
null,
|
||||||
);
|
);
|
||||||
|
|
||||||
export const BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN = valueByChainId<string>(
|
export const BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN = valueByChainId<string>(
|
||||||
@ -2433,7 +2435,9 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
|
|||||||
[ERC20BridgeSource.Linkswap]: uniswapV2CloneGasSchedule,
|
[ERC20BridgeSource.Linkswap]: uniswapV2CloneGasSchedule,
|
||||||
[ERC20BridgeSource.ShibaSwap]: uniswapV2CloneGasSchedule,
|
[ERC20BridgeSource.ShibaSwap]: uniswapV2CloneGasSchedule,
|
||||||
[ERC20BridgeSource.Balancer]: () => 120e3,
|
[ERC20BridgeSource.Balancer]: () => 120e3,
|
||||||
[ERC20BridgeSource.BalancerV2]: () => 100e3,
|
[ERC20BridgeSource.BalancerV2]: (fillData?: FillData) => {
|
||||||
|
return 100e3 + ((fillData as BalancerV2BatchSwapFillData).swapSteps.length - 1) * 50e3;
|
||||||
|
},
|
||||||
[ERC20BridgeSource.Cream]: () => 120e3,
|
[ERC20BridgeSource.Cream]: () => 120e3,
|
||||||
[ERC20BridgeSource.MStable]: () => 200e3,
|
[ERC20BridgeSource.MStable]: () => 200e3,
|
||||||
[ERC20BridgeSource.MakerPsm]: (fillData?: FillData) => {
|
[ERC20BridgeSource.MakerPsm]: (fillData?: FillData) => {
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
AaveV2FillData,
|
AaveV2FillData,
|
||||||
AggregationError,
|
AggregationError,
|
||||||
BalancerFillData,
|
BalancerFillData,
|
||||||
|
BalancerV2BatchSwapFillData,
|
||||||
BalancerV2FillData,
|
BalancerV2FillData,
|
||||||
BancorFillData,
|
BancorFillData,
|
||||||
CollapsedFill,
|
CollapsedFill,
|
||||||
@ -86,7 +87,7 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s
|
|||||||
case ERC20BridgeSource.Balancer:
|
case ERC20BridgeSource.Balancer:
|
||||||
return encodeBridgeSourceId(BridgeProtocol.Balancer, 'Balancer');
|
return encodeBridgeSourceId(BridgeProtocol.Balancer, 'Balancer');
|
||||||
case ERC20BridgeSource.BalancerV2:
|
case ERC20BridgeSource.BalancerV2:
|
||||||
return encodeBridgeSourceId(BridgeProtocol.BalancerV2, 'BalancerV2');
|
return encodeBridgeSourceId(BridgeProtocol.BalancerV2Batch, 'BalancerV2');
|
||||||
case ERC20BridgeSource.Bancor:
|
case ERC20BridgeSource.Bancor:
|
||||||
return encodeBridgeSourceId(BridgeProtocol.Bancor, 'Bancor');
|
return encodeBridgeSourceId(BridgeProtocol.Bancor, 'Bancor');
|
||||||
// case ERC20BridgeSource.CoFiX:
|
// case ERC20BridgeSource.CoFiX:
|
||||||
@ -258,9 +259,18 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
|
|||||||
bridgeData = encoder.encode([balancerFillData.poolAddress]);
|
bridgeData = encoder.encode([balancerFillData.poolAddress]);
|
||||||
break;
|
break;
|
||||||
case ERC20BridgeSource.BalancerV2:
|
case ERC20BridgeSource.BalancerV2:
|
||||||
|
{
|
||||||
|
const balancerV2FillData = (order as OptimizedMarketBridgeOrder<BalancerV2BatchSwapFillData>).fillData;
|
||||||
|
bridgeData = encoder.encode([
|
||||||
|
balancerV2FillData.vault,
|
||||||
|
balancerV2FillData.swapSteps,
|
||||||
|
balancerV2FillData.assets,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case ERC20BridgeSource.Beethovenx:
|
case ERC20BridgeSource.Beethovenx:
|
||||||
const balancerV2FillData = (order as OptimizedMarketBridgeOrder<BalancerV2FillData>).fillData;
|
const beethovenFillData = (order as OptimizedMarketBridgeOrder<BalancerV2FillData>).fillData;
|
||||||
const { vault, poolId } = balancerV2FillData;
|
const { vault, poolId } = beethovenFillData;
|
||||||
bridgeData = encoder.encode([vault, poolId]);
|
bridgeData = encoder.encode([vault, poolId]);
|
||||||
break;
|
break;
|
||||||
case ERC20BridgeSource.Bancor:
|
case ERC20BridgeSource.Bancor:
|
||||||
@ -533,7 +543,21 @@ export const BRIDGE_ENCODERS: {
|
|||||||
[ERC20BridgeSource.Uniswap]: poolEncoder,
|
[ERC20BridgeSource.Uniswap]: poolEncoder,
|
||||||
// Custom integrations
|
// Custom integrations
|
||||||
[ERC20BridgeSource.MakerPsm]: makerPsmEncoder,
|
[ERC20BridgeSource.MakerPsm]: makerPsmEncoder,
|
||||||
[ERC20BridgeSource.BalancerV2]: balancerV2Encoder,
|
[ERC20BridgeSource.BalancerV2]: AbiEncoder.create([
|
||||||
|
{ name: 'vault', type: 'address' },
|
||||||
|
{
|
||||||
|
name: 'swapSteps',
|
||||||
|
type: 'tuple[]',
|
||||||
|
components: [
|
||||||
|
{ name: 'poolId', type: 'bytes32' },
|
||||||
|
{ name: 'assetInIndex', type: 'uint256' },
|
||||||
|
{ name: 'assetOutIndex', type: 'uint256' },
|
||||||
|
{ name: 'amount', type: 'uint256' },
|
||||||
|
{ name: 'userData', type: 'bytes' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ name: 'assets', type: 'address[]' },
|
||||||
|
]),
|
||||||
[ERC20BridgeSource.Beethovenx]: balancerV2Encoder,
|
[ERC20BridgeSource.Beethovenx]: balancerV2Encoder,
|
||||||
[ERC20BridgeSource.UniswapV3]: AbiEncoder.create([
|
[ERC20BridgeSource.UniswapV3]: AbiEncoder.create([
|
||||||
{ name: 'router', type: 'address' },
|
{ name: 'router', type: 'address' },
|
||||||
|
@ -51,7 +51,7 @@ export class BalancerV2PoolsCache extends PoolsCache {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
chainId: ChainId,
|
chainId: ChainId,
|
||||||
private readonly subgraphUrl: string = BALANCER_V2_SUBGRAPH_URL_BY_CHAIN[chainId],
|
private readonly subgraphUrl: string = BALANCER_V2_SUBGRAPH_URL_BY_CHAIN[chainId]!,
|
||||||
private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
|
private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
|
||||||
private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED,
|
private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED,
|
||||||
private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER,
|
private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER,
|
||||||
|
@ -0,0 +1,190 @@
|
|||||||
|
import { ChainId } from '@0x/contract-addresses';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import {
|
||||||
|
BalancerSDK,
|
||||||
|
BalancerSdkConfig,
|
||||||
|
formatSequence,
|
||||||
|
getTokenAddressesForSwap,
|
||||||
|
NewPath,
|
||||||
|
parseToPoolsDict,
|
||||||
|
PoolDictionary,
|
||||||
|
RouteProposer,
|
||||||
|
SwapTypes,
|
||||||
|
} from '@balancer-labs/sdk';
|
||||||
|
|
||||||
|
import { DEFAULT_WARNING_LOGGER } from '../../../constants';
|
||||||
|
import { LogFunction } from '../../../types';
|
||||||
|
import { BALANCER_V2_SUBGRAPH_URL_BY_CHAIN, ONE_SECOND_MS } from '../constants';
|
||||||
|
import { BalancerSwapInfo, BalancerSwaps } from '../types';
|
||||||
|
|
||||||
|
import { CacheValue, EMPTY_BALANCER_SWAPS, SwapInfoCache } from './pair_swaps_cache';
|
||||||
|
import { SubgraphPoolDataService } from './sgPoolDataService';
|
||||||
|
|
||||||
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
|
const ONE_DAY_MS = 24 * 60 * 60 * ONE_SECOND_MS;
|
||||||
|
|
||||||
|
export interface BalancerPoolResponse {
|
||||||
|
poolType: string;
|
||||||
|
id: string;
|
||||||
|
tokens: Array<{ address: string }>;
|
||||||
|
tokensList: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BalancerV2SwapInfoCache extends SwapInfoCache {
|
||||||
|
private static readonly _MAX_POOLS_PER_PATH = 4;
|
||||||
|
private static readonly _MAX_CANDIDATE_PATHS_PER_PAIR = 2;
|
||||||
|
private readonly _routeProposer: RouteProposer;
|
||||||
|
private readonly _poolDataService: SubgraphPoolDataService;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
chainId: ChainId,
|
||||||
|
subgraphUrl: string | null = BALANCER_V2_SUBGRAPH_URL_BY_CHAIN[chainId],
|
||||||
|
private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER,
|
||||||
|
cache: { [key: string]: CacheValue } = {},
|
||||||
|
) {
|
||||||
|
super(cache);
|
||||||
|
const config: BalancerSdkConfig = {
|
||||||
|
network: chainId as number, // wtf TS
|
||||||
|
rpcUrl: '', // Not actually used by SDK for this.
|
||||||
|
};
|
||||||
|
const balancerSdk = new BalancerSDK(config);
|
||||||
|
// The RouteProposer finds paths between a token pair using direct/multihop/linearPool routes
|
||||||
|
this._routeProposer = balancerSdk.sor.routeProposer;
|
||||||
|
// Uses Subgraph to retrieve up to date pool data required for routeProposer
|
||||||
|
this._poolDataService = new SubgraphPoolDataService({
|
||||||
|
chainId,
|
||||||
|
subgraphUrl,
|
||||||
|
});
|
||||||
|
void this._loadTopPoolsAsync();
|
||||||
|
// Reload the top pools every 12 hours
|
||||||
|
setInterval(async () => void this._loadTopPoolsAsync(), ONE_DAY_MS / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async _loadTopPoolsAsync(): Promise<void> {
|
||||||
|
const fromToSwapInfo: {
|
||||||
|
[from: string]: { [to: string]: BalancerSwaps };
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
// Retrieve pool data from Subgraph
|
||||||
|
const pools = await this._poolDataService.getPools();
|
||||||
|
// timestamp is used for Element pools
|
||||||
|
const timestamp = Math.floor(Date.now() / ONE_SECOND_MS);
|
||||||
|
const poolsDict = parseToPoolsDict(pools, timestamp);
|
||||||
|
|
||||||
|
for (const pool of pools) {
|
||||||
|
const { tokensList } = pool;
|
||||||
|
// tslint:disable-next-line: await-promise
|
||||||
|
await null; // This loop can be CPU heavy so yield to event loop.
|
||||||
|
for (const from of tokensList) {
|
||||||
|
for (const to of tokensList.filter(t => t.toLowerCase() !== from.toLowerCase())) {
|
||||||
|
fromToSwapInfo[from] = fromToSwapInfo[from] || {};
|
||||||
|
// If a record for pair already exists skip as all paths alreay found
|
||||||
|
if (fromToSwapInfo[from][to]) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const expiresAt = Date.now() + this._cacheTimeMs;
|
||||||
|
// Retrieve swap steps and assets for a token pair
|
||||||
|
// This only needs to be called once per pair as all paths will be created from single call
|
||||||
|
const pairSwapInfo = this._getPoolPairSwapInfo(poolsDict, from, to);
|
||||||
|
fromToSwapInfo[from][to] = pairSwapInfo;
|
||||||
|
this._cacheSwapInfoForPair(from, to, fromToSwapInfo[from][to], expiresAt);
|
||||||
|
} catch (err) {
|
||||||
|
this._warningLogger(err, `Failed to load Balancer V2 top pools`);
|
||||||
|
// soldier on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will retrieve fresh pair and path data from Subgraph and return and array of swap info for pair..
|
||||||
|
* @param takerToken Address of takerToken.
|
||||||
|
* @param makerToken Address of makerToken.
|
||||||
|
* @returns Swap data for pair consisting of assets and swap steps for ExactIn and ExactOut swap types.
|
||||||
|
*/
|
||||||
|
protected async _fetchSwapInfoForPairAsync(takerToken: string, makerToken: string): Promise<BalancerSwaps> {
|
||||||
|
try {
|
||||||
|
// retrieve up to date pools from SG
|
||||||
|
const pools = await this._poolDataService.getPools();
|
||||||
|
|
||||||
|
// timestamp is used for Element pools
|
||||||
|
const timestamp = Math.floor(Date.now() / ONE_SECOND_MS);
|
||||||
|
const poolDictionary = parseToPoolsDict(pools, timestamp);
|
||||||
|
return this._getPoolPairSwapInfo(poolDictionary, takerToken, makerToken);
|
||||||
|
} catch (e) {
|
||||||
|
return EMPTY_BALANCER_SWAPS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses pool data from provided dictionary to find top swap paths for token pair.
|
||||||
|
* @param pools Dictionary of pool data.
|
||||||
|
* @param takerToken Address of taker token.
|
||||||
|
* @param makerToken Address of maker token.
|
||||||
|
* @returns Swap data for pair consisting of assets and swap steps for ExactIn and ExactOut swap types.
|
||||||
|
*/
|
||||||
|
private _getPoolPairSwapInfo(pools: PoolDictionary, takerToken: string, makerToken: string): BalancerSwaps {
|
||||||
|
/*
|
||||||
|
Uses Balancer SDK to construct available paths for pair.
|
||||||
|
Paths can be direct, i.e. both tokens are in same pool or multihop.
|
||||||
|
Will also create paths for the new Balancer Linear pools.
|
||||||
|
These are returned in order of available liquidity which is useful for filtering.
|
||||||
|
*/
|
||||||
|
const paths = this._routeProposer.getCandidatePathsFromDict(
|
||||||
|
takerToken,
|
||||||
|
makerToken,
|
||||||
|
SwapTypes.SwapExactIn,
|
||||||
|
pools,
|
||||||
|
BalancerV2SwapInfoCache._MAX_POOLS_PER_PATH,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (paths.length === 0) {
|
||||||
|
return EMPTY_BALANCER_SWAPS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert paths data to swap information suitable for queryBatchSwap. Only use top 2 liquid paths
|
||||||
|
return formatSwaps(paths.slice(0, BalancerV2SwapInfoCache._MAX_CANDIDATE_PATHS_PER_PAIR));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an array of Balancer paths, returns swap information that can be passed to queryBatchSwap.
|
||||||
|
* @param paths Array of Balancer paths.
|
||||||
|
* @returns Formatted swap data consisting of assets and swap steps for ExactIn and ExactOut swap types.
|
||||||
|
*/
|
||||||
|
function formatSwaps(paths: NewPath[]): BalancerSwaps {
|
||||||
|
const formattedSwapsExactIn: BalancerSwapInfo[] = [];
|
||||||
|
const formattedSwapsExactOut: BalancerSwapInfo[] = [];
|
||||||
|
let assets: string[];
|
||||||
|
paths.forEach(path => {
|
||||||
|
// Add a swap amount for each swap so we can use formatSequence. (This will be overwritten with actual amount during query)
|
||||||
|
path.swaps.forEach(s => (s.swapAmount = '0'));
|
||||||
|
const tokenAddresses = getTokenAddressesForSwap(path.swaps);
|
||||||
|
// Formats for both ExactIn and ExactOut swap types
|
||||||
|
const swapsExactIn = formatSequence(SwapTypes.SwapExactIn, path.swaps, tokenAddresses);
|
||||||
|
const swapsExactOut = formatSequence(SwapTypes.SwapExactOut, path.swaps, tokenAddresses);
|
||||||
|
assets = tokenAddresses;
|
||||||
|
formattedSwapsExactIn.push({
|
||||||
|
assets,
|
||||||
|
swapSteps: swapsExactIn.map(s => ({
|
||||||
|
...s,
|
||||||
|
amount: new BigNumber(s.amount),
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
formattedSwapsExactOut.push({
|
||||||
|
assets,
|
||||||
|
swapSteps: swapsExactOut.map(s => ({
|
||||||
|
...s,
|
||||||
|
amount: new BigNumber(s.amount),
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const formattedSwaps: BalancerSwaps = {
|
||||||
|
swapInfoExactIn: formattedSwapsExactIn,
|
||||||
|
swapInfoExactOut: formattedSwapsExactOut,
|
||||||
|
};
|
||||||
|
return formattedSwaps;
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
import { BalancerSwaps } from '../types';
|
||||||
|
|
||||||
|
import { ONE_HOUR_IN_SECONDS, ONE_SECOND_MS } from '../constants';
|
||||||
|
|
||||||
|
export interface CacheValue {
|
||||||
|
expiresAt: number;
|
||||||
|
balancerSwaps: BalancerSwaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tslint:disable:custom-no-magic-numbers
|
||||||
|
// Cache results for 30mins
|
||||||
|
const DEFAULT_CACHE_TIME_MS = (ONE_HOUR_IN_SECONDS / 2) * ONE_SECOND_MS;
|
||||||
|
const DEFAULT_TIMEOUT_MS = ONE_SECOND_MS;
|
||||||
|
export const EMPTY_BALANCER_SWAPS = { swapInfoExactIn: [], swapInfoExactOut: [] };
|
||||||
|
// tslint:enable:custom-no-magic-numbers
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caches SwapInfo for a pair of tokens.
|
||||||
|
* SwapInfo includes swap steps and asset information for those swap steps.
|
||||||
|
*/
|
||||||
|
export abstract class SwapInfoCache {
|
||||||
|
protected static _isExpired(value: CacheValue): boolean {
|
||||||
|
return Date.now() >= value.expiresAt;
|
||||||
|
}
|
||||||
|
constructor(
|
||||||
|
protected readonly _cache: { [key: string]: CacheValue },
|
||||||
|
protected readonly _cacheTimeMs: number = DEFAULT_CACHE_TIME_MS,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public async getFreshPoolsForPairAsync(
|
||||||
|
takerToken: string,
|
||||||
|
makerToken: string,
|
||||||
|
timeoutMs: number = DEFAULT_TIMEOUT_MS,
|
||||||
|
): Promise<BalancerSwaps> {
|
||||||
|
const timeout = new Promise<BalancerSwaps>(resolve => setTimeout(resolve, timeoutMs, []));
|
||||||
|
return Promise.race([this._getAndSaveFreshSwapInfoForPairAsync(takerToken, makerToken), timeout]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCachedSwapInfoForPair(
|
||||||
|
takerToken: string,
|
||||||
|
makerToken: string,
|
||||||
|
ignoreExpired: boolean = true,
|
||||||
|
): BalancerSwaps | undefined {
|
||||||
|
const key = JSON.stringify([takerToken, makerToken]);
|
||||||
|
const value = this._cache[key];
|
||||||
|
if (ignoreExpired) {
|
||||||
|
return value === undefined ? EMPTY_BALANCER_SWAPS : value.balancerSwaps;
|
||||||
|
}
|
||||||
|
if (!value) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (SwapInfoCache._isExpired(value)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return value.balancerSwaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public isFresh(takerToken: string, makerToken: string): boolean {
|
||||||
|
const cached = this.getCachedSwapInfoForPair(takerToken, makerToken, false);
|
||||||
|
return cached !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async _getAndSaveFreshSwapInfoForPairAsync(
|
||||||
|
takerToken: string,
|
||||||
|
makerToken: string,
|
||||||
|
): Promise<BalancerSwaps> {
|
||||||
|
const key = JSON.stringify([takerToken, makerToken]);
|
||||||
|
const value = this._cache[key];
|
||||||
|
if (value === undefined || value.expiresAt >= Date.now()) {
|
||||||
|
const swapInfo = await this._fetchSwapInfoForPairAsync(takerToken, makerToken);
|
||||||
|
const expiresAt = Date.now() + this._cacheTimeMs;
|
||||||
|
this._cacheSwapInfoForPair(takerToken, makerToken, swapInfo, expiresAt);
|
||||||
|
}
|
||||||
|
return this._cache[key].balancerSwaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _cacheSwapInfoForPair(
|
||||||
|
takerToken: string,
|
||||||
|
makerToken: string,
|
||||||
|
swapInfo: BalancerSwaps,
|
||||||
|
expiresAt: number,
|
||||||
|
): void {
|
||||||
|
const key = JSON.stringify([takerToken, makerToken]);
|
||||||
|
this._cache[key] = {
|
||||||
|
expiresAt,
|
||||||
|
balancerSwaps: swapInfo,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract _fetchSwapInfoForPairAsync(takerToken: string, makerToken: string): Promise<BalancerSwaps>;
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
import { ChainId } from '@0x/contract-addresses';
|
||||||
|
import { logUtils } from '@0x/utils';
|
||||||
|
import { PoolDataService, SubgraphPoolBase } from '@balancer-labs/sdk';
|
||||||
|
import { gql, request } from 'graphql-request';
|
||||||
|
|
||||||
|
const queryWithLinear = gql`
|
||||||
|
query fetchTopPoolsWithLinear($maxPoolsFetched: Int!) {
|
||||||
|
pools: pools(
|
||||||
|
first: $maxPoolsFetched
|
||||||
|
where: { swapEnabled: true }
|
||||||
|
orderBy: totalLiquidity
|
||||||
|
orderDirection: desc
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
address
|
||||||
|
poolType
|
||||||
|
swapFee
|
||||||
|
totalShares
|
||||||
|
tokens {
|
||||||
|
address
|
||||||
|
balance
|
||||||
|
decimals
|
||||||
|
weight
|
||||||
|
priceRate
|
||||||
|
}
|
||||||
|
tokensList
|
||||||
|
totalWeight
|
||||||
|
amp
|
||||||
|
expiryTime
|
||||||
|
unitSeconds
|
||||||
|
principalToken
|
||||||
|
baseToken
|
||||||
|
swapEnabled
|
||||||
|
wrappedIndex
|
||||||
|
mainIndex
|
||||||
|
lowerTarget
|
||||||
|
upperTarget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const queryWithOutLinear = gql`
|
||||||
|
query fetchTopPoolsWithoutLinear($maxPoolsFetched: Int!) {
|
||||||
|
pools: pools(
|
||||||
|
first: $maxPoolsFetched
|
||||||
|
where: { swapEnabled: true }
|
||||||
|
orderBy: totalLiquidity
|
||||||
|
orderDirection: desc
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
address
|
||||||
|
poolType
|
||||||
|
swapFee
|
||||||
|
totalShares
|
||||||
|
tokens {
|
||||||
|
address
|
||||||
|
balance
|
||||||
|
decimals
|
||||||
|
weight
|
||||||
|
priceRate
|
||||||
|
}
|
||||||
|
tokensList
|
||||||
|
totalWeight
|
||||||
|
amp
|
||||||
|
expiryTime
|
||||||
|
unitSeconds
|
||||||
|
principalToken
|
||||||
|
baseToken
|
||||||
|
swapEnabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const QUERY_BY_CHAIN_ID: { [chainId: number]: string } = {
|
||||||
|
[ChainId.Mainnet]: queryWithLinear,
|
||||||
|
[ChainId.Polygon]: queryWithOutLinear,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DEFAULT_MAX_POOLS_FETCHED = 96;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple service to query required info from Subgraph for Balancer Pools.
|
||||||
|
* Because Balancer Subgraphs have slightly different schema depending on network the queries are adjusted as needed.
|
||||||
|
*/
|
||||||
|
export class SubgraphPoolDataService implements PoolDataService {
|
||||||
|
private readonly _gqlQuery: string | undefined;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _config: {
|
||||||
|
chainId: number;
|
||||||
|
subgraphUrl: string | null;
|
||||||
|
maxPoolsFetched?: number;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
this._config.maxPoolsFetched = this._config.maxPoolsFetched || DEFAULT_MAX_POOLS_FETCHED;
|
||||||
|
this._gqlQuery = QUERY_BY_CHAIN_ID[this._config.chainId];
|
||||||
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line: async-suffix
|
||||||
|
public async getPools(): Promise<SubgraphPoolBase[]> {
|
||||||
|
if (!this._gqlQuery || !this._config.subgraphUrl) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const { pools } = await request<{ pools: SubgraphPoolBase[] }>(this._config.subgraphUrl, this._gqlQuery, {
|
||||||
|
maxPoolsFetched: this._config.maxPoolsFetched,
|
||||||
|
});
|
||||||
|
return pools;
|
||||||
|
} catch (err) {
|
||||||
|
logUtils.warn(`Failed to fetch BalancerV2 subgraph pools: ${err.message}`);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,9 +5,8 @@ import { SamplerOverrides } from '../../types';
|
|||||||
import { ERC20BridgeSamplerContract } from '../../wrappers';
|
import { ERC20BridgeSamplerContract } from '../../wrappers';
|
||||||
|
|
||||||
import { BancorService } from './bancor_service';
|
import { BancorService } from './bancor_service';
|
||||||
import { PoolsCache } from './pools_cache';
|
import { PoolsCacheMap, SamplerOperations } from './sampler_operations';
|
||||||
import { SamplerOperations } from './sampler_operations';
|
import { BatchedOperation, LiquidityProviderRegistry, TokenAdjacencyGraph } from './types';
|
||||||
import { BatchedOperation, ERC20BridgeSource, LiquidityProviderRegistry, TokenAdjacencyGraph } from './types';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate sample amounts up to `maxFillAmount`.
|
* Generate sample amounts up to `maxFillAmount`.
|
||||||
@ -37,7 +36,7 @@ export class DexOrderSampler extends SamplerOperations {
|
|||||||
public readonly chainId: ChainId,
|
public readonly chainId: ChainId,
|
||||||
_samplerContract: ERC20BridgeSamplerContract,
|
_samplerContract: ERC20BridgeSamplerContract,
|
||||||
private readonly _samplerOverrides?: SamplerOverrides,
|
private readonly _samplerOverrides?: SamplerOverrides,
|
||||||
poolsCaches?: { [key in ERC20BridgeSource]: PoolsCache },
|
poolsCaches?: PoolsCacheMap,
|
||||||
tokenAdjacencyGraph?: TokenAdjacencyGraph,
|
tokenAdjacencyGraph?: TokenAdjacencyGraph,
|
||||||
liquidityProviderRegistry?: LiquidityProviderRegistry,
|
liquidityProviderRegistry?: LiquidityProviderRegistry,
|
||||||
bancorServiceFn: () => Promise<BancorService | undefined> = async () => undefined,
|
bancorServiceFn: () => Promise<BancorService | undefined> = async () => undefined,
|
||||||
|
@ -51,6 +51,7 @@ import { getGeistInfoForPair } from './geist_utils';
|
|||||||
import { getLiquidityProvidersForPair } from './liquidity_provider_utils';
|
import { getLiquidityProvidersForPair } from './liquidity_provider_utils';
|
||||||
import { getIntermediateTokens } from './multihop_utils';
|
import { getIntermediateTokens } from './multihop_utils';
|
||||||
import { BalancerPoolsCache, BalancerV2PoolsCache, CreamPoolsCache, PoolsCache } from './pools_cache';
|
import { BalancerPoolsCache, BalancerV2PoolsCache, CreamPoolsCache, PoolsCache } from './pools_cache';
|
||||||
|
import { BalancerV2SwapInfoCache } from './pools_cache/balancer_v2_utils_new';
|
||||||
import { SamplerContractOperation } from './sampler_contract_operation';
|
import { SamplerContractOperation } from './sampler_contract_operation';
|
||||||
import { SamplerNoOperation } from './sampler_no_operation';
|
import { SamplerNoOperation } from './sampler_no_operation';
|
||||||
import { SourceFilters } from './source_filters';
|
import { SourceFilters } from './source_filters';
|
||||||
@ -58,6 +59,8 @@ import {
|
|||||||
AaveV2FillData,
|
AaveV2FillData,
|
||||||
AaveV2Info,
|
AaveV2Info,
|
||||||
BalancerFillData,
|
BalancerFillData,
|
||||||
|
BalancerSwapInfo,
|
||||||
|
BalancerV2BatchSwapFillData,
|
||||||
BalancerV2FillData,
|
BalancerV2FillData,
|
||||||
BalancerV2PoolInfo,
|
BalancerV2PoolInfo,
|
||||||
BancorFillData,
|
BancorFillData,
|
||||||
@ -103,6 +106,10 @@ export const TWO_HOP_SOURCE_FILTERS = SourceFilters.all().exclude([
|
|||||||
*/
|
*/
|
||||||
export const BATCH_SOURCE_FILTERS = SourceFilters.all().exclude([ERC20BridgeSource.MultiHop, ERC20BridgeSource.Native]);
|
export const BATCH_SOURCE_FILTERS = SourceFilters.all().exclude([ERC20BridgeSource.MultiHop, ERC20BridgeSource.Native]);
|
||||||
|
|
||||||
|
export type PoolsCacheMap = { [key in Exclude<SourcesWithPoolsCache, ERC20BridgeSource.BalancerV2>]: PoolsCache } & {
|
||||||
|
[ERC20BridgeSource.BalancerV2]: BalancerV2SwapInfoCache;
|
||||||
|
};
|
||||||
|
|
||||||
// tslint:disable:no-inferred-empty-object-type no-unbound-method
|
// tslint:disable:no-inferred-empty-object-type no-unbound-method
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,7 +118,7 @@ export const BATCH_SOURCE_FILTERS = SourceFilters.all().exclude([ERC20BridgeSour
|
|||||||
*/
|
*/
|
||||||
export class SamplerOperations {
|
export class SamplerOperations {
|
||||||
public readonly liquidityProviderRegistry: LiquidityProviderRegistry;
|
public readonly liquidityProviderRegistry: LiquidityProviderRegistry;
|
||||||
public readonly poolsCaches: { [key in SourcesWithPoolsCache]: PoolsCache };
|
public readonly poolsCaches: PoolsCacheMap;
|
||||||
public readonly aaveReservesCache: AaveV2ReservesCache | undefined;
|
public readonly aaveReservesCache: AaveV2ReservesCache | undefined;
|
||||||
public readonly compoundCTokenCache: CompoundCTokenCache | undefined;
|
public readonly compoundCTokenCache: CompoundCTokenCache | undefined;
|
||||||
protected _bancorService?: BancorService;
|
protected _bancorService?: BancorService;
|
||||||
@ -126,7 +133,7 @@ export class SamplerOperations {
|
|||||||
constructor(
|
constructor(
|
||||||
public readonly chainId: ChainId,
|
public readonly chainId: ChainId,
|
||||||
protected readonly _samplerContract: ERC20BridgeSamplerContract,
|
protected readonly _samplerContract: ERC20BridgeSamplerContract,
|
||||||
poolsCaches?: { [key in SourcesWithPoolsCache]: PoolsCache },
|
poolsCaches?: PoolsCacheMap,
|
||||||
protected readonly tokenAdjacencyGraph: TokenAdjacencyGraph = { default: [] },
|
protected readonly tokenAdjacencyGraph: TokenAdjacencyGraph = { default: [] },
|
||||||
liquidityProviderRegistry: LiquidityProviderRegistry = {},
|
liquidityProviderRegistry: LiquidityProviderRegistry = {},
|
||||||
bancorServiceFn: () => Promise<BancorService | undefined> = async () => undefined,
|
bancorServiceFn: () => Promise<BancorService | undefined> = async () => undefined,
|
||||||
@ -138,13 +145,13 @@ export class SamplerOperations {
|
|||||||
this.poolsCaches = poolsCaches
|
this.poolsCaches = poolsCaches
|
||||||
? poolsCaches
|
? poolsCaches
|
||||||
: {
|
: {
|
||||||
[ERC20BridgeSource.BalancerV2]: new BalancerV2PoolsCache(chainId),
|
|
||||||
[ERC20BridgeSource.Beethovenx]: new BalancerV2PoolsCache(
|
[ERC20BridgeSource.Beethovenx]: new BalancerV2PoolsCache(
|
||||||
chainId,
|
chainId,
|
||||||
BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN[chainId],
|
BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN[chainId],
|
||||||
),
|
),
|
||||||
[ERC20BridgeSource.Balancer]: new BalancerPoolsCache(),
|
[ERC20BridgeSource.Balancer]: new BalancerPoolsCache(),
|
||||||
[ERC20BridgeSource.Cream]: new CreamPoolsCache(),
|
[ERC20BridgeSource.Cream]: new CreamPoolsCache(),
|
||||||
|
[ERC20BridgeSource.BalancerV2]: new BalancerV2SwapInfoCache(chainId),
|
||||||
};
|
};
|
||||||
|
|
||||||
const aaveSubgraphUrl = AAVE_V2_SUBGRAPH_URL_BY_CHAIN_ID[chainId];
|
const aaveSubgraphUrl = AAVE_V2_SUBGRAPH_URL_BY_CHAIN_ID[chainId];
|
||||||
@ -564,6 +571,49 @@ export class SamplerOperations {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getBalancerV2MulthopSellQuotes(
|
||||||
|
vault: string,
|
||||||
|
quoteSwaps: BalancerSwapInfo, // Should always be sell swap steps.
|
||||||
|
fillSwaps: BalancerSwapInfo, // Should always be sell swap steps.
|
||||||
|
takerFillAmounts: BigNumber[],
|
||||||
|
source: ERC20BridgeSource,
|
||||||
|
): SourceQuoteOperation<BalancerV2BatchSwapFillData> {
|
||||||
|
const quoteSwapSteps = quoteSwaps.swapSteps.map(s => ({
|
||||||
|
...s,
|
||||||
|
assetInIndex: new BigNumber(s.assetInIndex),
|
||||||
|
assetOutIndex: new BigNumber(s.assetOutIndex),
|
||||||
|
}));
|
||||||
|
return new SamplerContractOperation({
|
||||||
|
source,
|
||||||
|
fillData: { vault, swapSteps: fillSwaps.swapSteps, assets: fillSwaps.assets },
|
||||||
|
contract: this._samplerContract,
|
||||||
|
function: this._samplerContract.sampleMultihopSellsFromBalancerV2,
|
||||||
|
params: [vault, quoteSwapSteps, quoteSwaps.assets, takerFillAmounts],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getBalancerV2MulthopBuyQuotes(
|
||||||
|
vault: string,
|
||||||
|
quoteSwaps: BalancerSwapInfo, // Should always be buy swap steps.
|
||||||
|
fillSwaps: BalancerSwapInfo, // Should always be a sell quote.
|
||||||
|
makerFillAmounts: BigNumber[],
|
||||||
|
source: ERC20BridgeSource,
|
||||||
|
): SourceQuoteOperation<BalancerV2BatchSwapFillData> {
|
||||||
|
const quoteSwapSteps = quoteSwaps.swapSteps.map(s => ({
|
||||||
|
...s,
|
||||||
|
assetInIndex: new BigNumber(s.assetInIndex),
|
||||||
|
assetOutIndex: new BigNumber(s.assetOutIndex),
|
||||||
|
}));
|
||||||
|
return new SamplerContractOperation({
|
||||||
|
source,
|
||||||
|
// NOTE: fillData is set up for sells but quote function is set up for buys.
|
||||||
|
fillData: { vault, swapSteps: fillSwaps.swapSteps, assets: fillSwaps.assets },
|
||||||
|
contract: this._samplerContract,
|
||||||
|
function: this._samplerContract.sampleMultihopBuysFromBalancerV2,
|
||||||
|
params: [vault, quoteSwapSteps, quoteSwaps.assets, makerFillAmounts],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public getBalancerV2SellQuotes(
|
public getBalancerV2SellQuotes(
|
||||||
poolInfo: BalancerV2PoolInfo,
|
poolInfo: BalancerV2PoolInfo,
|
||||||
makerToken: string,
|
makerToken: string,
|
||||||
@ -1448,15 +1498,23 @@ export class SamplerOperations {
|
|||||||
ERC20BridgeSource.Balancer,
|
ERC20BridgeSource.Balancer,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
case ERC20BridgeSource.BalancerV2:
|
case ERC20BridgeSource.BalancerV2: {
|
||||||
case ERC20BridgeSource.Beethovenx:
|
const swaps = this.poolsCaches[source].getCachedSwapInfoForPair(takerToken, makerToken);
|
||||||
|
|
||||||
|
const vault = BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[this.chainId];
|
||||||
|
if (!swaps || vault === NULL_ADDRESS) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
// Changed to retrieve queryBatchSwap for swap steps > 1 of length
|
||||||
|
return swaps.swapInfoExactIn.map(swapInfo =>
|
||||||
|
this.getBalancerV2MulthopSellQuotes(vault, swapInfo, swapInfo, takerFillAmounts, source),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case ERC20BridgeSource.Beethovenx: {
|
||||||
const poolIds =
|
const poolIds =
|
||||||
this.poolsCaches[source].getCachedPoolAddressesForPair(takerToken, makerToken) || [];
|
this.poolsCaches[source].getCachedPoolAddressesForPair(takerToken, makerToken) || [];
|
||||||
|
|
||||||
const vault =
|
const vault = BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId];
|
||||||
source === ERC20BridgeSource.BalancerV2
|
|
||||||
? BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[this.chainId]
|
|
||||||
: BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId];
|
|
||||||
if (vault === NULL_ADDRESS) {
|
if (vault === NULL_ADDRESS) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -1469,6 +1527,7 @@ export class SamplerOperations {
|
|||||||
source,
|
source,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
case ERC20BridgeSource.Cream:
|
case ERC20BridgeSource.Cream:
|
||||||
return (
|
return (
|
||||||
this.poolsCaches[ERC20BridgeSource.Cream].getCachedPoolAddressesForPair(
|
this.poolsCaches[ERC20BridgeSource.Cream].getCachedPoolAddressesForPair(
|
||||||
@ -1762,15 +1821,29 @@ export class SamplerOperations {
|
|||||||
ERC20BridgeSource.Balancer,
|
ERC20BridgeSource.Balancer,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
case ERC20BridgeSource.BalancerV2:
|
case ERC20BridgeSource.BalancerV2: {
|
||||||
case ERC20BridgeSource.Beethovenx:
|
const swaps = this.poolsCaches[source].getCachedSwapInfoForPair(takerToken, makerToken);
|
||||||
|
|
||||||
|
const vault = BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[this.chainId];
|
||||||
|
if (!swaps || vault === NULL_ADDRESS) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
// Changed to retrieve queryBatchSwap for swap steps > 1 of length
|
||||||
|
return swaps.swapInfoExactOut.map((quoteSwapInfo, i) =>
|
||||||
|
this.getBalancerV2MulthopBuyQuotes(
|
||||||
|
vault,
|
||||||
|
quoteSwapInfo,
|
||||||
|
swaps.swapInfoExactIn[i],
|
||||||
|
makerFillAmounts,
|
||||||
|
source,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case ERC20BridgeSource.Beethovenx: {
|
||||||
const poolIds =
|
const poolIds =
|
||||||
this.poolsCaches[source].getCachedPoolAddressesForPair(takerToken, makerToken) || [];
|
this.poolsCaches[source].getCachedPoolAddressesForPair(takerToken, makerToken) || [];
|
||||||
|
|
||||||
const vault =
|
const vault = BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId];
|
||||||
source === ERC20BridgeSource.BalancerV2
|
|
||||||
? BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[this.chainId]
|
|
||||||
: BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId];
|
|
||||||
if (vault === NULL_ADDRESS) {
|
if (vault === NULL_ADDRESS) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -1783,6 +1856,7 @@ export class SamplerOperations {
|
|||||||
source,
|
source,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
case ERC20BridgeSource.Cream:
|
case ERC20BridgeSource.Cream:
|
||||||
return (
|
return (
|
||||||
this.poolsCaches[ERC20BridgeSource.Cream].getCachedPoolAddressesForPair(
|
this.poolsCaches[ERC20BridgeSource.Cream].getCachedPoolAddressesForPair(
|
||||||
|
@ -209,6 +209,23 @@ export interface CurveFillData extends FillData {
|
|||||||
pool: CurveInfo;
|
pool: CurveInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BalancerBatchSwapStep {
|
||||||
|
poolId: string;
|
||||||
|
assetInIndex: number;
|
||||||
|
assetOutIndex: number;
|
||||||
|
amount: BigNumber;
|
||||||
|
userData: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BalancerSwaps {
|
||||||
|
swapInfoExactIn: BalancerSwapInfo[];
|
||||||
|
swapInfoExactOut: BalancerSwapInfo[];
|
||||||
|
}
|
||||||
|
export interface BalancerSwapInfo {
|
||||||
|
assets: string[];
|
||||||
|
swapSteps: BalancerBatchSwapStep[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface BalancerFillData extends FillData {
|
export interface BalancerFillData extends FillData {
|
||||||
poolAddress: string;
|
poolAddress: string;
|
||||||
}
|
}
|
||||||
@ -218,6 +235,12 @@ export interface BalancerV2FillData extends FillData {
|
|||||||
poolId: string;
|
poolId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BalancerV2BatchSwapFillData extends FillData {
|
||||||
|
vault: string;
|
||||||
|
swapSteps: BalancerBatchSwapStep[];
|
||||||
|
assets: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface UniswapV2FillData extends FillData {
|
export interface UniswapV2FillData extends FillData {
|
||||||
tokenAddressPath: string[];
|
tokenAddressPath: string[];
|
||||||
router: string;
|
router: string;
|
||||||
|
@ -8,16 +8,18 @@ import { ContractArtifact } from 'ethereum-types';
|
|||||||
import * as ApproximateBuys from '../test/generated-artifacts/ApproximateBuys.json';
|
import * as ApproximateBuys from '../test/generated-artifacts/ApproximateBuys.json';
|
||||||
import * as BalanceChecker from '../test/generated-artifacts/BalanceChecker.json';
|
import * as BalanceChecker from '../test/generated-artifacts/BalanceChecker.json';
|
||||||
import * as BalancerSampler from '../test/generated-artifacts/BalancerSampler.json';
|
import * as BalancerSampler from '../test/generated-artifacts/BalancerSampler.json';
|
||||||
|
import * as BalancerV2BatchSampler from '../test/generated-artifacts/BalancerV2BatchSampler.json';
|
||||||
|
import * as BalancerV2Common from '../test/generated-artifacts/BalancerV2Common.json';
|
||||||
import * as BalancerV2Sampler from '../test/generated-artifacts/BalancerV2Sampler.json';
|
import * as BalancerV2Sampler from '../test/generated-artifacts/BalancerV2Sampler.json';
|
||||||
import * as BancorSampler from '../test/generated-artifacts/BancorSampler.json';
|
import * as BancorSampler from '../test/generated-artifacts/BancorSampler.json';
|
||||||
import * as CompoundSampler from '../test/generated-artifacts/CompoundSampler.json';
|
import * as CompoundSampler from '../test/generated-artifacts/CompoundSampler.json';
|
||||||
import * as CurveSampler from '../test/generated-artifacts/CurveSampler.json';
|
import * as CurveSampler from '../test/generated-artifacts/CurveSampler.json';
|
||||||
import * as DODOSampler from '../test/generated-artifacts/DODOSampler.json';
|
import * as DODOSampler from '../test/generated-artifacts/DODOSampler.json';
|
||||||
import * as DODOV2Sampler from '../test/generated-artifacts/DODOV2Sampler.json';
|
import * as DODOV2Sampler from '../test/generated-artifacts/DODOV2Sampler.json';
|
||||||
import * as DummyLiquidityProvider from '../test/generated-artifacts/DummyLiquidityProvider.json';
|
|
||||||
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
|
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
|
||||||
import * as FakeTaker from '../test/generated-artifacts/FakeTaker.json';
|
import * as FakeTaker from '../test/generated-artifacts/FakeTaker.json';
|
||||||
import * as IBalancer from '../test/generated-artifacts/IBalancer.json';
|
import * as IBalancer from '../test/generated-artifacts/IBalancer.json';
|
||||||
|
import * as IBalancerV2Vault from '../test/generated-artifacts/IBalancerV2Vault.json';
|
||||||
import * as IBancor from '../test/generated-artifacts/IBancor.json';
|
import * as IBancor from '../test/generated-artifacts/IBancor.json';
|
||||||
import * as ICurve from '../test/generated-artifacts/ICurve.json';
|
import * as ICurve from '../test/generated-artifacts/ICurve.json';
|
||||||
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
|
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
|
||||||
@ -35,12 +37,10 @@ import * as LiquidityProviderSampler from '../test/generated-artifacts/Liquidity
|
|||||||
import * as MakerPSMSampler from '../test/generated-artifacts/MakerPSMSampler.json';
|
import * as MakerPSMSampler from '../test/generated-artifacts/MakerPSMSampler.json';
|
||||||
import * as MooniswapSampler from '../test/generated-artifacts/MooniswapSampler.json';
|
import * as MooniswapSampler from '../test/generated-artifacts/MooniswapSampler.json';
|
||||||
import * as MStableSampler from '../test/generated-artifacts/MStableSampler.json';
|
import * as MStableSampler from '../test/generated-artifacts/MStableSampler.json';
|
||||||
import * as MultiBridgeSampler from '../test/generated-artifacts/MultiBridgeSampler.json';
|
|
||||||
import * as NativeOrderSampler from '../test/generated-artifacts/NativeOrderSampler.json';
|
import * as NativeOrderSampler from '../test/generated-artifacts/NativeOrderSampler.json';
|
||||||
import * as SamplerUtils from '../test/generated-artifacts/SamplerUtils.json';
|
import * as SamplerUtils from '../test/generated-artifacts/SamplerUtils.json';
|
||||||
import * as ShellSampler from '../test/generated-artifacts/ShellSampler.json';
|
import * as ShellSampler from '../test/generated-artifacts/ShellSampler.json';
|
||||||
import * as SmoothySampler from '../test/generated-artifacts/SmoothySampler.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 TestNativeOrderSampler from '../test/generated-artifacts/TestNativeOrderSampler.json';
|
||||||
import * as TwoHopSampler from '../test/generated-artifacts/TwoHopSampler.json';
|
import * as TwoHopSampler from '../test/generated-artifacts/TwoHopSampler.json';
|
||||||
import * as UniswapSampler from '../test/generated-artifacts/UniswapSampler.json';
|
import * as UniswapSampler from '../test/generated-artifacts/UniswapSampler.json';
|
||||||
@ -51,6 +51,8 @@ export const artifacts = {
|
|||||||
ApproximateBuys: ApproximateBuys as ContractArtifact,
|
ApproximateBuys: ApproximateBuys as ContractArtifact,
|
||||||
BalanceChecker: BalanceChecker as ContractArtifact,
|
BalanceChecker: BalanceChecker as ContractArtifact,
|
||||||
BalancerSampler: BalancerSampler as ContractArtifact,
|
BalancerSampler: BalancerSampler as ContractArtifact,
|
||||||
|
BalancerV2BatchSampler: BalancerV2BatchSampler as ContractArtifact,
|
||||||
|
BalancerV2Common: BalancerV2Common as ContractArtifact,
|
||||||
BalancerV2Sampler: BalancerV2Sampler as ContractArtifact,
|
BalancerV2Sampler: BalancerV2Sampler as ContractArtifact,
|
||||||
BancorSampler: BancorSampler as ContractArtifact,
|
BancorSampler: BancorSampler as ContractArtifact,
|
||||||
CompoundSampler: CompoundSampler as ContractArtifact,
|
CompoundSampler: CompoundSampler as ContractArtifact,
|
||||||
@ -66,7 +68,6 @@ export const artifacts = {
|
|||||||
MStableSampler: MStableSampler as ContractArtifact,
|
MStableSampler: MStableSampler as ContractArtifact,
|
||||||
MakerPSMSampler: MakerPSMSampler as ContractArtifact,
|
MakerPSMSampler: MakerPSMSampler as ContractArtifact,
|
||||||
MooniswapSampler: MooniswapSampler as ContractArtifact,
|
MooniswapSampler: MooniswapSampler as ContractArtifact,
|
||||||
MultiBridgeSampler: MultiBridgeSampler as ContractArtifact,
|
|
||||||
NativeOrderSampler: NativeOrderSampler as ContractArtifact,
|
NativeOrderSampler: NativeOrderSampler as ContractArtifact,
|
||||||
SamplerUtils: SamplerUtils as ContractArtifact,
|
SamplerUtils: SamplerUtils as ContractArtifact,
|
||||||
ShellSampler: ShellSampler as ContractArtifact,
|
ShellSampler: ShellSampler as ContractArtifact,
|
||||||
@ -77,6 +78,7 @@ export const artifacts = {
|
|||||||
UniswapV3Sampler: UniswapV3Sampler as ContractArtifact,
|
UniswapV3Sampler: UniswapV3Sampler as ContractArtifact,
|
||||||
UtilitySampler: UtilitySampler as ContractArtifact,
|
UtilitySampler: UtilitySampler as ContractArtifact,
|
||||||
IBalancer: IBalancer as ContractArtifact,
|
IBalancer: IBalancer as ContractArtifact,
|
||||||
|
IBalancerV2Vault: IBalancerV2Vault as ContractArtifact,
|
||||||
IBancor: IBancor as ContractArtifact,
|
IBancor: IBancor as ContractArtifact,
|
||||||
ICurve: ICurve as ContractArtifact,
|
ICurve: ICurve as ContractArtifact,
|
||||||
IKyberNetwork: IKyberNetwork as ContractArtifact,
|
IKyberNetwork: IKyberNetwork as ContractArtifact,
|
||||||
@ -87,7 +89,5 @@ export const artifacts = {
|
|||||||
ISmoothy: ISmoothy as ContractArtifact,
|
ISmoothy: ISmoothy as ContractArtifact,
|
||||||
IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
|
IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
|
||||||
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
|
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
|
||||||
DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact,
|
|
||||||
TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact,
|
|
||||||
TestNativeOrderSampler: TestNativeOrderSampler as ContractArtifact,
|
TestNativeOrderSampler: TestNativeOrderSampler as ContractArtifact,
|
||||||
};
|
};
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -6,16 +6,18 @@
|
|||||||
export * from '../test/generated-wrappers/approximate_buys';
|
export * from '../test/generated-wrappers/approximate_buys';
|
||||||
export * from '../test/generated-wrappers/balance_checker';
|
export * from '../test/generated-wrappers/balance_checker';
|
||||||
export * from '../test/generated-wrappers/balancer_sampler';
|
export * from '../test/generated-wrappers/balancer_sampler';
|
||||||
|
export * from '../test/generated-wrappers/balancer_v2_batch_sampler';
|
||||||
|
export * from '../test/generated-wrappers/balancer_v2_common';
|
||||||
export * from '../test/generated-wrappers/balancer_v2_sampler';
|
export * from '../test/generated-wrappers/balancer_v2_sampler';
|
||||||
export * from '../test/generated-wrappers/bancor_sampler';
|
export * from '../test/generated-wrappers/bancor_sampler';
|
||||||
export * from '../test/generated-wrappers/compound_sampler';
|
export * from '../test/generated-wrappers/compound_sampler';
|
||||||
export * from '../test/generated-wrappers/curve_sampler';
|
export * from '../test/generated-wrappers/curve_sampler';
|
||||||
export * from '../test/generated-wrappers/d_o_d_o_sampler';
|
export * from '../test/generated-wrappers/d_o_d_o_sampler';
|
||||||
export * from '../test/generated-wrappers/d_o_d_o_v2_sampler';
|
export * from '../test/generated-wrappers/d_o_d_o_v2_sampler';
|
||||||
export * from '../test/generated-wrappers/dummy_liquidity_provider';
|
|
||||||
export * from '../test/generated-wrappers/erc20_bridge_sampler';
|
export * from '../test/generated-wrappers/erc20_bridge_sampler';
|
||||||
export * from '../test/generated-wrappers/fake_taker';
|
export * from '../test/generated-wrappers/fake_taker';
|
||||||
export * from '../test/generated-wrappers/i_balancer';
|
export * from '../test/generated-wrappers/i_balancer';
|
||||||
|
export * from '../test/generated-wrappers/i_balancer_v2_vault';
|
||||||
export * from '../test/generated-wrappers/i_bancor';
|
export * from '../test/generated-wrappers/i_bancor';
|
||||||
export * from '../test/generated-wrappers/i_curve';
|
export * from '../test/generated-wrappers/i_curve';
|
||||||
export * from '../test/generated-wrappers/i_kyber_network';
|
export * from '../test/generated-wrappers/i_kyber_network';
|
||||||
@ -33,12 +35,10 @@ export * from '../test/generated-wrappers/liquidity_provider_sampler';
|
|||||||
export * from '../test/generated-wrappers/m_stable_sampler';
|
export * from '../test/generated-wrappers/m_stable_sampler';
|
||||||
export * from '../test/generated-wrappers/maker_p_s_m_sampler';
|
export * from '../test/generated-wrappers/maker_p_s_m_sampler';
|
||||||
export * from '../test/generated-wrappers/mooniswap_sampler';
|
export * from '../test/generated-wrappers/mooniswap_sampler';
|
||||||
export * from '../test/generated-wrappers/multi_bridge_sampler';
|
|
||||||
export * from '../test/generated-wrappers/native_order_sampler';
|
export * from '../test/generated-wrappers/native_order_sampler';
|
||||||
export * from '../test/generated-wrappers/sampler_utils';
|
export * from '../test/generated-wrappers/sampler_utils';
|
||||||
export * from '../test/generated-wrappers/shell_sampler';
|
export * from '../test/generated-wrappers/shell_sampler';
|
||||||
export * from '../test/generated-wrappers/smoothy_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/test_native_order_sampler';
|
||||||
export * from '../test/generated-wrappers/two_hop_sampler';
|
export * from '../test/generated-wrappers/two_hop_sampler';
|
||||||
export * from '../test/generated-wrappers/uniswap_sampler';
|
export * from '../test/generated-wrappers/uniswap_sampler';
|
||||||
|
@ -9,16 +9,18 @@
|
|||||||
"test/generated-artifacts/ApproximateBuys.json",
|
"test/generated-artifacts/ApproximateBuys.json",
|
||||||
"test/generated-artifacts/BalanceChecker.json",
|
"test/generated-artifacts/BalanceChecker.json",
|
||||||
"test/generated-artifacts/BalancerSampler.json",
|
"test/generated-artifacts/BalancerSampler.json",
|
||||||
|
"test/generated-artifacts/BalancerV2BatchSampler.json",
|
||||||
|
"test/generated-artifacts/BalancerV2Common.json",
|
||||||
"test/generated-artifacts/BalancerV2Sampler.json",
|
"test/generated-artifacts/BalancerV2Sampler.json",
|
||||||
"test/generated-artifacts/BancorSampler.json",
|
"test/generated-artifacts/BancorSampler.json",
|
||||||
"test/generated-artifacts/CompoundSampler.json",
|
"test/generated-artifacts/CompoundSampler.json",
|
||||||
"test/generated-artifacts/CurveSampler.json",
|
"test/generated-artifacts/CurveSampler.json",
|
||||||
"test/generated-artifacts/DODOSampler.json",
|
"test/generated-artifacts/DODOSampler.json",
|
||||||
"test/generated-artifacts/DODOV2Sampler.json",
|
"test/generated-artifacts/DODOV2Sampler.json",
|
||||||
"test/generated-artifacts/DummyLiquidityProvider.json",
|
|
||||||
"test/generated-artifacts/ERC20BridgeSampler.json",
|
"test/generated-artifacts/ERC20BridgeSampler.json",
|
||||||
"test/generated-artifacts/FakeTaker.json",
|
"test/generated-artifacts/FakeTaker.json",
|
||||||
"test/generated-artifacts/IBalancer.json",
|
"test/generated-artifacts/IBalancer.json",
|
||||||
|
"test/generated-artifacts/IBalancerV2Vault.json",
|
||||||
"test/generated-artifacts/IBancor.json",
|
"test/generated-artifacts/IBancor.json",
|
||||||
"test/generated-artifacts/ICurve.json",
|
"test/generated-artifacts/ICurve.json",
|
||||||
"test/generated-artifacts/IKyberNetwork.json",
|
"test/generated-artifacts/IKyberNetwork.json",
|
||||||
@ -36,12 +38,10 @@
|
|||||||
"test/generated-artifacts/MStableSampler.json",
|
"test/generated-artifacts/MStableSampler.json",
|
||||||
"test/generated-artifacts/MakerPSMSampler.json",
|
"test/generated-artifacts/MakerPSMSampler.json",
|
||||||
"test/generated-artifacts/MooniswapSampler.json",
|
"test/generated-artifacts/MooniswapSampler.json",
|
||||||
"test/generated-artifacts/MultiBridgeSampler.json",
|
|
||||||
"test/generated-artifacts/NativeOrderSampler.json",
|
"test/generated-artifacts/NativeOrderSampler.json",
|
||||||
"test/generated-artifacts/SamplerUtils.json",
|
"test/generated-artifacts/SamplerUtils.json",
|
||||||
"test/generated-artifacts/ShellSampler.json",
|
"test/generated-artifacts/ShellSampler.json",
|
||||||
"test/generated-artifacts/SmoothySampler.json",
|
"test/generated-artifacts/SmoothySampler.json",
|
||||||
"test/generated-artifacts/TestERC20BridgeSampler.json",
|
|
||||||
"test/generated-artifacts/TestNativeOrderSampler.json",
|
"test/generated-artifacts/TestNativeOrderSampler.json",
|
||||||
"test/generated-artifacts/TwoHopSampler.json",
|
"test/generated-artifacts/TwoHopSampler.json",
|
||||||
"test/generated-artifacts/UniswapSampler.json",
|
"test/generated-artifacts/UniswapSampler.json",
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "6.13.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Redeploy FQT on mainnet and polygon",
|
||||||
|
"pr": 462
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1648739346,
|
"timestamp": 1648739346,
|
||||||
"version": "6.12.1",
|
"version": "6.12.1",
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
"wethTransformer": "0xb2bc06a4efb20fc6553a69dbfa49b7be938034a7",
|
"wethTransformer": "0xb2bc06a4efb20fc6553a69dbfa49b7be938034a7",
|
||||||
"payTakerTransformer": "0x4638a7ebe75b911b995d0ec73a81e4f85f41f24e",
|
"payTakerTransformer": "0x4638a7ebe75b911b995d0ec73a81e4f85f41f24e",
|
||||||
"affiliateFeeTransformer": "0xda6d9fc5998f550a094585cf9171f0e8ee3ac59f",
|
"affiliateFeeTransformer": "0xda6d9fc5998f550a094585cf9171f0e8ee3ac59f",
|
||||||
"fillQuoteTransformer": "0xb4fa284689c9784a60d840eb136bb16c5246191f",
|
"fillQuoteTransformer": "0xadbe39f2988a8be1c1120f05e28cc888b150c8a6",
|
||||||
"positiveSlippageFeeTransformer": "0xa9416ce1dbde8d331210c07b5c253d94ee4cc3fd"
|
"positiveSlippageFeeTransformer": "0xa9416ce1dbde8d331210c07b5c253d94ee4cc3fd"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -289,7 +289,7 @@
|
|||||||
"wethTransformer": "0xe309d011cc6f189a3e8dcba85922715a019fed38",
|
"wethTransformer": "0xe309d011cc6f189a3e8dcba85922715a019fed38",
|
||||||
"payTakerTransformer": "0x5ba7b9be86cda01cfbf56e0fb97184783be9dda1",
|
"payTakerTransformer": "0x5ba7b9be86cda01cfbf56e0fb97184783be9dda1",
|
||||||
"affiliateFeeTransformer": "0xbed27284b42e5684e987169cf1da09c5d6c49fa8",
|
"affiliateFeeTransformer": "0xbed27284b42e5684e987169cf1da09c5d6c49fa8",
|
||||||
"fillQuoteTransformer": "0xd3afdf4a8ea9183e76c9c2306cda03ea4afffea5",
|
"fillQuoteTransformer": "0xd4a518760030dae1adbde9496f8a3b478e83932a",
|
||||||
"positiveSlippageFeeTransformer": "0x4cd8f1c0df4d40fcc1e073845d5f6f4ed5cc8dab"
|
"positiveSlippageFeeTransformer": "0x4cd8f1c0df4d40fcc1e073845d5f6f4ed5cc8dab"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "11.12.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Add `BalancerV2Batch` to `BridgeProtocol` enum",
|
||||||
|
"pr": 462
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1648739346,
|
"timestamp": 1648739346,
|
||||||
"version": "1.11.2",
|
"version": "1.11.2",
|
||||||
|
@ -134,6 +134,7 @@ export enum BridgeProtocol {
|
|||||||
Clipper, // Not used: Clipper is now using PLP interface
|
Clipper, // Not used: Clipper is now using PLP interface
|
||||||
AaveV2,
|
AaveV2,
|
||||||
Compound,
|
Compound,
|
||||||
|
BalancerV2Batch,
|
||||||
}
|
}
|
||||||
// tslint:enable: enum-naming
|
// tslint:enable: enum-naming
|
||||||
|
|
||||||
|
53
yarn.lock
53
yarn.lock
@ -1384,6 +1384,17 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
|
"@balancer-labs/sdk@^0.1.6":
|
||||||
|
version "0.1.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@balancer-labs/sdk/-/sdk-0.1.6.tgz#1a6f0aacfada7b0afbdf02259ef40ed37d3ecbcb"
|
||||||
|
integrity sha512-r9s7Y2XJks+8V53kqwaqHDAETipgFSEQxI7TFHYigoOtWp/sUaZnlu0kDMv3NuDvya0+t9gp5a0VxbztLwcn+g==
|
||||||
|
dependencies:
|
||||||
|
"@balancer-labs/sor" "^4.0.0-beta.2"
|
||||||
|
axios "^0.24.0"
|
||||||
|
graphql "^15.6.1"
|
||||||
|
graphql-request "^3.5.0"
|
||||||
|
lodash "^4.17.21"
|
||||||
|
|
||||||
"@balancer-labs/sor@0.3.2":
|
"@balancer-labs/sor@0.3.2":
|
||||||
version "0.3.2"
|
version "0.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-0.3.2.tgz#b05c63a07031c2ea13ed0d2670f5105cfaa40523"
|
resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-0.3.2.tgz#b05c63a07031c2ea13ed0d2670f5105cfaa40523"
|
||||||
@ -1393,6 +1404,13 @@
|
|||||||
isomorphic-fetch "^2.2.1"
|
isomorphic-fetch "^2.2.1"
|
||||||
typescript "^3.8.3"
|
typescript "^3.8.3"
|
||||||
|
|
||||||
|
"@balancer-labs/sor@^4.0.0-beta.2":
|
||||||
|
version "4.0.0-beta.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.0.0-beta.2.tgz#17ee901c7434f9a5702653488b1a3ec6e1f926f1"
|
||||||
|
integrity sha512-ylDxsMDKpoynOQIH4PhucYc7bkXddjL6GRFCF2BwnQ4Yoy7vBOT7S0zJvIkKuUG6MSUdoTBaAtWckxXBJiNxyA==
|
||||||
|
dependencies:
|
||||||
|
isomorphic-fetch "^2.2.1"
|
||||||
|
|
||||||
"@bancor/sdk@0.2.9":
|
"@bancor/sdk@0.2.9":
|
||||||
version "0.2.9"
|
version "0.2.9"
|
||||||
resolved "https://registry.yarnpkg.com/@bancor/sdk/-/sdk-0.2.9.tgz#2e4c168dc9d667709e3ed85eac3b15362c5676d8"
|
resolved "https://registry.yarnpkg.com/@bancor/sdk/-/sdk-0.2.9.tgz#2e4c168dc9d667709e3ed85eac3b15362c5676d8"
|
||||||
@ -3252,6 +3270,13 @@ axios@^0.21.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects "^1.10.0"
|
follow-redirects "^1.10.0"
|
||||||
|
|
||||||
|
axios@^0.24.0:
|
||||||
|
version "0.24.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6"
|
||||||
|
integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==
|
||||||
|
dependencies:
|
||||||
|
follow-redirects "^1.14.4"
|
||||||
|
|
||||||
babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
|
babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
|
||||||
version "6.26.0"
|
version "6.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
|
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
|
||||||
@ -6515,7 +6540,7 @@ follow-redirects@^1.10.0:
|
|||||||
version "1.13.3"
|
version "1.13.3"
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
|
||||||
|
|
||||||
follow-redirects@^1.12.1:
|
follow-redirects@^1.12.1, follow-redirects@^1.14.4:
|
||||||
version "1.14.9"
|
version "1.14.9"
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7"
|
||||||
integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==
|
integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==
|
||||||
@ -7031,10 +7056,24 @@ graphql-request@^3.4.0:
|
|||||||
extract-files "^9.0.0"
|
extract-files "^9.0.0"
|
||||||
form-data "^3.0.0"
|
form-data "^3.0.0"
|
||||||
|
|
||||||
|
graphql-request@^3.5.0:
|
||||||
|
version "3.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-3.7.0.tgz#c7406e537084f8b9788541e3e6704340ca13055b"
|
||||||
|
integrity sha512-dw5PxHCgBneN2DDNqpWu8QkbbJ07oOziy8z+bK/TAXufsOLaETuVO4GkXrbs0WjhdKhBMN3BkpN/RIvUHkmNUQ==
|
||||||
|
dependencies:
|
||||||
|
cross-fetch "^3.0.6"
|
||||||
|
extract-files "^9.0.0"
|
||||||
|
form-data "^3.0.0"
|
||||||
|
|
||||||
graphql@^15.4.0:
|
graphql@^15.4.0:
|
||||||
version "15.5.0"
|
version "15.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.0.tgz#39d19494dbe69d1ea719915b578bf920344a69d5"
|
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.0.tgz#39d19494dbe69d1ea719915b578bf920344a69d5"
|
||||||
|
|
||||||
|
graphql@^15.6.1:
|
||||||
|
version "15.8.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38"
|
||||||
|
integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==
|
||||||
|
|
||||||
growl@1.10.5:
|
growl@1.10.5:
|
||||||
version "1.10.5"
|
version "1.10.5"
|
||||||
resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
|
resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
|
||||||
@ -8393,6 +8432,11 @@ lodash@4.17.20, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.
|
|||||||
version "4.17.20"
|
version "4.17.20"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
|
||||||
|
|
||||||
|
lodash@^4.17.21:
|
||||||
|
version "4.17.21"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||||
|
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||||
|
|
||||||
log-driver@^1.2.7:
|
log-driver@^1.2.7:
|
||||||
version "1.2.7"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8"
|
resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8"
|
||||||
@ -11223,6 +11267,13 @@ solidity-parser-antlr@^0.4.2:
|
|||||||
version "0.4.11"
|
version "0.4.11"
|
||||||
resolved "https://registry.yarnpkg.com/solidity-parser-antlr/-/solidity-parser-antlr-0.4.11.tgz#af43e1f13b3b88309a875455f5d6e565b05ee5f1"
|
resolved "https://registry.yarnpkg.com/solidity-parser-antlr/-/solidity-parser-antlr-0.4.11.tgz#af43e1f13b3b88309a875455f5d6e565b05ee5f1"
|
||||||
|
|
||||||
|
"sorV2@npm:@balancer-labs/sor":
|
||||||
|
version "4.0.0-beta.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.0.0-beta.1.tgz#fb8b3f2d9bb5cec5c79446e0062aab7cdfcabccb"
|
||||||
|
integrity sha512-L3eMBRA51egMNKHkLktOr3sNJuqgoz24AfJkpzU4w1I66m9HlOPY/E3FgYKWO+1cXJ2sQZWDH3pEjnWMRnNbNg==
|
||||||
|
dependencies:
|
||||||
|
isomorphic-fetch "^2.2.1"
|
||||||
|
|
||||||
sort-keys@^2.0.0:
|
sort-keys@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128"
|
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user