From afe77a432c14538bab78a1737f49fa2e0da83856 Mon Sep 17 00:00:00 2001 From: Noah Khamliche Date: Wed, 30 Mar 2022 15:00:08 -0400 Subject: [PATCH] sampling trouble --- .../transformers/bridges/BridgeAdapter.sol | 9 ++ .../transformers/bridges/BridgeProtocols.sol | 1 + .../transformers/bridges/mixins/MixinGMX.sol | 91 +++++++++++++++++++ contracts/zero-ex/package.json | 2 +- contracts/zero-ex/test/artifacts.ts | 2 + contracts/zero-ex/test/wrappers.ts | 1 + contracts/zero-ex/tsconfig.json | 1 + package.json | 3 +- .../contracts/src/ERC20BridgeSampler.sol | 2 + .../contracts/src/GMXSampler.sol | 40 ++++++++ .../contracts/src/interfaces/IGMX.sol | 23 +++++ packages/asset-swapper/package.json | 5 +- .../bridge_source_utils.ts | 1 + .../utils/market_operation_utils/constants.ts | 24 +++++ .../utils/market_operation_utils/orders.ts | 10 ++ .../sampler_operations.ts | 28 ++++++ .../src/utils/market_operation_utils/types.ts | 11 +++ packages/asset-swapper/test/artifacts.ts | 4 + packages/asset-swapper/test/wrappers.ts | 2 + packages/asset-swapper/tsconfig.json | 2 + packages/protocol-utils/CHANGELOG.json | 8 ++ .../protocol-utils/src/transformer_utils.ts | 1 + yarn.lock | 8 +- 23 files changed, 271 insertions(+), 8 deletions(-) create mode 100644 contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinGMX.sol create mode 100644 packages/asset-swapper/contracts/src/GMXSampler.sol create mode 100644 packages/asset-swapper/contracts/src/interfaces/IGMX.sol diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol index 17d8acce7d..4a9e32e8ce 100644 --- a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol +++ b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol @@ -33,6 +33,7 @@ import "./mixins/MixinCurveV2.sol"; import "./mixins/MixinCryptoCom.sol"; import "./mixins/MixinDodo.sol"; import "./mixins/MixinDodoV2.sol"; +import "./mixins/MixinGMX.sol"; import "./mixins/MixinKyber.sol"; import "./mixins/MixinKyberDmm.sol"; import "./mixins/MixinLido.sol"; @@ -60,6 +61,7 @@ contract BridgeAdapter is MixinCryptoCom, MixinDodo, MixinDodoV2, + MixinGMX, MixinKyber, MixinKyberDmm, MixinLido, @@ -87,6 +89,7 @@ contract BridgeAdapter is MixinCryptoCom() MixinDodo() MixinDodoV2() + MixinGMX() MixinKyber(weth) MixinLido(weth) MixinMakerPSM() @@ -265,6 +268,12 @@ contract BridgeAdapter is sellAmount, order.bridgeData ); + } else if (protocolId == BridgeProtocols.GMX) { + boughtAmount = _tradeGMX( + buyToken, + sellAmount, + order.bridgeData + ); } else { boughtAmount = _tradeZeroExBridge( sellToken, diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol index ea363779e5..5236d3da7e 100644 --- a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol +++ b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol @@ -52,4 +52,5 @@ library BridgeProtocols { uint128 internal constant CLIPPER = 22; // Not used: Clipper is now using PLP interface uint128 internal constant AAVEV2 = 23; uint128 internal constant COMPOUND = 24; + uint128 internal constant GMX = 25; } diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinGMX.sol b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinGMX.sol new file mode 100644 index 0000000000..55820c498c --- /dev/null +++ b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinGMX.sol @@ -0,0 +1,91 @@ +// 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"; +import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; +import "../IBridgeAdapter.sol"; + +/* + UniswapV2 +*/ +interface IGmxRouter { + + // /// @dev Swaps an exact amount of input tokens for as many output tokens as possible, along the route determined by the path. + // /// The first element of path is the input token, the last is the output token, and any intermediate elements represent + // /// intermediate pairs to trade through (if, for example, a direct pair does not exist). + // /// @param _path An array of token addresses. path.length must be >= 2. Pools for each consecutive pair of addresses must exist and have liquidity. + // /// @param _amountIn The amount of input tokens to send. + // /// @param _minOut The minimum amount of output tokens that must be received for the transaction not to revert. + // /// @param _reciever Recipient of the output tokens. + function swap( + address[] memory _path, uint256 _amountIn, uint256 _minOut, address _receiver + ) external; +} + +contract MixinGMX { + + using LibERC20TokenV06 for IERC20TokenV06; + using LibSafeMathV06 for uint256; + + function _tradeGMX( + IERC20TokenV06 buyToken, + uint256 sellAmount, + bytes memory bridgeData + ) + internal + returns (uint256 boughtAmount) + { + IGmxRouter router; + IERC20TokenV06[] memory path; + address[] memory _path; + { + (router, _path) = abi.decode(bridgeData, (IGmxRouter, address[])); + // To get around `abi.decode()` not supporting interface array types. + assembly { path := _path } + } + + require(path.length >= 2, "MixinGMX/PATH_LENGTH_MUST_BE_AT_LEAST_TWO"); + require( + path[path.length - 1] == buyToken, + "MixinGMX/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN" + ); + // Grant the Uniswap router an allowance to sell the first token. + path[0].approveIfBelow(address(router), sellAmount); + + //get minAmountOut + uint256 beforeBalance = buyToken.balanceOf(address(this)); + router.swap( + // Convert to `buyToken` along this path. + _path, + // Sell all tokens we hold. + sellAmount, + // Minimum buy amount. + 0, + // Recipient is `this`. + address(this) + ); + + return buyToken.balanceOf(address(this)).safeSub(beforeBalance); + } +} diff --git a/contracts/zero-ex/package.json b/contracts/zero-ex/package.json index 9272d41742..ef65099f36 100644 --- a/contracts/zero-ex/package.json +++ b/contracts/zero-ex/package.json @@ -43,7 +43,7 @@ "config": { "publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature,OtcOrdersFeature,IOtcOrdersFeature", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|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|MixinBancor|MixinCoFiX|MixinCompound|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinGMX|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": { "type": "git", diff --git a/contracts/zero-ex/test/artifacts.ts b/contracts/zero-ex/test/artifacts.ts index f843d906b6..67107acdb3 100644 --- a/contracts/zero-ex/test/artifacts.ts +++ b/contracts/zero-ex/test/artifacts.ts @@ -109,6 +109,7 @@ import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json'; import * as MixinCurveV2 from '../test/generated-artifacts/MixinCurveV2.json'; import * as MixinDodo from '../test/generated-artifacts/MixinDodo.json'; import * as MixinDodoV2 from '../test/generated-artifacts/MixinDodoV2.json'; +import * as MixinGMX from '../test/generated-artifacts/MixinGMX.json'; import * as MixinKyber from '../test/generated-artifacts/MixinKyber.json'; import * as MixinKyberDmm from '../test/generated-artifacts/MixinKyberDmm.json'; import * as MixinLido from '../test/generated-artifacts/MixinLido.json'; @@ -321,6 +322,7 @@ export const artifacts = { MixinCurveV2: MixinCurveV2 as ContractArtifact, MixinDodo: MixinDodo as ContractArtifact, MixinDodoV2: MixinDodoV2 as ContractArtifact, + MixinGMX: MixinGMX as ContractArtifact, MixinKyber: MixinKyber as ContractArtifact, MixinKyberDmm: MixinKyberDmm as ContractArtifact, MixinLido: MixinLido as ContractArtifact, diff --git a/contracts/zero-ex/test/wrappers.ts b/contracts/zero-ex/test/wrappers.ts index 630dd4af95..34261b955a 100644 --- a/contracts/zero-ex/test/wrappers.ts +++ b/contracts/zero-ex/test/wrappers.ts @@ -107,6 +107,7 @@ export * from '../test/generated-wrappers/mixin_curve'; export * from '../test/generated-wrappers/mixin_curve_v2'; export * from '../test/generated-wrappers/mixin_dodo'; export * from '../test/generated-wrappers/mixin_dodo_v2'; +export * from '../test/generated-wrappers/mixin_g_m_x'; export * from '../test/generated-wrappers/mixin_kyber'; export * from '../test/generated-wrappers/mixin_kyber_dmm'; export * from '../test/generated-wrappers/mixin_lido'; diff --git a/contracts/zero-ex/tsconfig.json b/contracts/zero-ex/tsconfig.json index 32cd919834..fb84e01ba0 100644 --- a/contracts/zero-ex/tsconfig.json +++ b/contracts/zero-ex/tsconfig.json @@ -140,6 +140,7 @@ "test/generated-artifacts/MixinCurveV2.json", "test/generated-artifacts/MixinDodo.json", "test/generated-artifacts/MixinDodoV2.json", + "test/generated-artifacts/MixinGMX.json", "test/generated-artifacts/MixinKyber.json", "test/generated-artifacts/MixinKyberDmm.json", "test/generated-artifacts/MixinLido.json", diff --git a/package.json b/package.json index 73e13054b1..d7ef16c31e 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "wsrun": "^5.2.4" }, "resolutions": { - "merkle-patricia-tree": "3.0.0" + "merkle-patricia-tree": "3.0.0", + "bignumber.js": "9.0.2" } } diff --git a/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol b/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol index 17493e2a46..772ea5bb05 100644 --- a/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol +++ b/packages/asset-swapper/contracts/src/ERC20BridgeSampler.sol @@ -27,6 +27,7 @@ import "./CompoundSampler.sol"; import "./CurveSampler.sol"; import "./DODOSampler.sol"; import "./DODOV2Sampler.sol"; +import "./GMXSampler.sol"; import "./KyberSampler.sol"; import "./KyberDmmSampler.sol"; import "./LidoSampler.sol"; @@ -53,6 +54,7 @@ contract ERC20BridgeSampler is CurveSampler, DODOSampler, DODOV2Sampler, + GMXSampler, KyberSampler, KyberDmmSampler, LidoSampler, diff --git a/packages/asset-swapper/contracts/src/GMXSampler.sol b/packages/asset-swapper/contracts/src/GMXSampler.sol new file mode 100644 index 0000000000..aae58a0aec --- /dev/null +++ b/packages/asset-swapper/contracts/src/GMXSampler.sol @@ -0,0 +1,40 @@ +pragma solidity ^0.6; +pragma experimental ABIEncoderV2; + +import "./interfaces/IGMX.sol"; + + +contract GMXSampler +{ + /// @dev Gas limit for UniswapV2 calls. + + function sampleSellsFromGMX( + address reader, + address vault, + address[] memory path, + uint256[] memory takerTokenAmounts + ) + public + view + returns (uint256[] memory makerTokenAmounts) + { + uint256 numSamples = takerTokenAmounts.length; + makerTokenAmounts = new uint256[](numSamples); + for (uint256 i = 0; i < numSamples; i++) { + try + IGMX(reader).getAmountOut(IVault(vault), path[0], path[1], takerTokenAmounts[i]) + returns (uint256 amountAfterFees, uint256 feeAmount) + { + makerTokenAmounts[i] = amountAfterFees; + // Break early if there are 0 amounts + if (makerTokenAmounts[i] == 0) { + break; + } + } catch (bytes memory) { + // Swallow failures, leaving all results as zero. + break; + } + } + } + +} \ No newline at end of file diff --git a/packages/asset-swapper/contracts/src/interfaces/IGMX.sol b/packages/asset-swapper/contracts/src/interfaces/IGMX.sol new file mode 100644 index 0000000000..12b1c3d87c --- /dev/null +++ b/packages/asset-swapper/contracts/src/interfaces/IGMX.sol @@ -0,0 +1,23 @@ +pragma solidity ^0.6; +pragma experimental ABIEncoderV2; + +interface IGMX { + function getMaxAmountIn(IVault _vault, address _tokenIn, address _tokenOut) + external + view + returns (uint256); + + function getAmountOut(IVault _vault, address _tokenIn, address _tokenOut, uint256 _amountIn) + external + view + returns (uint256, uint256); +} + +interface IVault { + function getFeeBasisPoints(address _token, uint256 _usdgDelta, uint256 _feeBasisPoints, uint256 _taxBasisPoints, bool _increment) external view returns (uint256); + function stableSwapFeeBasisPoints() external view returns (uint256); + function stableTokens(address _token) external view returns (bool); + function tokenDecimals(address _token) external view returns (uint256); + function getMaxPrice(address _token) external view returns (uint256); + function getMinPrice(address _token) external view returns (uint256); +} \ No newline at end of file diff --git a/packages/asset-swapper/package.json b/packages/asset-swapper/package.json index 95a50db6bb..dfc6be74e5 100644 --- a/packages/asset-swapper/package.json +++ b/packages/asset-swapper/package.json @@ -39,7 +39,7 @@ "config": { "publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|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|BalancerV2Sampler|BancorSampler|CompoundSampler|CurveSampler|DODOSampler|DODOV2Sampler|DummyLiquidityProvider|ERC20BridgeSampler|FakeTaker|GMXSampler|IBalancer|IBancor|ICurve|IGMX|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", "postpublish": { "assets": [] } @@ -128,5 +128,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56" + "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56", + "resolutions": {} } diff --git a/packages/asset-swapper/src/utils/market_operation_utils/bridge_source_utils.ts b/packages/asset-swapper/src/utils/market_operation_utils/bridge_source_utils.ts index c2e3fc1397..ddc61ef3e8 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/bridge_source_utils.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/bridge_source_utils.ts @@ -24,6 +24,7 @@ import { ELLIPSIS_BSC_INFOS, FIREBIRDONESWAP_BSC_INFOS, FIREBIRDONESWAP_POLYGON_INFOS, + GMX_ROUTER_BY_CHAIN_ID, IRONSWAP_POLYGON_INFOS, JETSWAP_ROUTER_BY_CHAIN_ID, JULSWAP_ROUTER_BY_CHAIN_ID, diff --git a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts index f8986a70f6..7cbcfea486 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts @@ -19,6 +19,7 @@ import { FillData, FinalUniswapV3FillData, GeistFillData, + GMXFillData, GetMarketOrdersOpts, isFinalUniswapV3FillData, KyberSamplerOpts, @@ -184,6 +185,7 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId( ERC20BridgeSource.KyberDmm, ERC20BridgeSource.AaveV2, ERC20BridgeSource.Synapse, + ERC20BridgeSource.GMX, ]), [ChainId.Fantom]: new SourceFilters([ ERC20BridgeSource.MultiHop, @@ -331,6 +333,7 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId( ERC20BridgeSource.KyberDmm, ERC20BridgeSource.AaveV2, ERC20BridgeSource.Synapse, + ERC20BridgeSource.GMX, ]), [ChainId.Fantom]: new SourceFilters([ ERC20BridgeSource.MultiHop, @@ -2344,6 +2347,26 @@ export const SPOOKYSWAP_ROUTER_BY_CHAIN_ID = valueByChainId( }, NULL_ADDRESS, ); +export const GMX_ROUTER_BY_CHAIN_ID = valueByChainId( + { + [ChainId.Avalanche]: '0x5f719c2f1095f7b9fc68a68e35b51194f4b6abe8', + }, + NULL_ADDRESS, +); + +export const GMX_READER_BY_CHAIN_ID = valueByChainId( + { + [ChainId.Avalanche]: '0x67b789d48c926006f5132bfce4e976f0a7a63d5d', + }, + NULL_ADDRESS, +); + +export const GMX_VAULT_BY_CHAIN_ID = valueByChainId( + { + [ChainId.Avalanche]: '0x9ab2de34a33fb459b538c43f251eb825645e8595', + }, + NULL_ADDRESS, +); export const VIP_ERC20_BRIDGE_SOURCES_BY_CHAIN_ID = valueByChainId( { @@ -2548,6 +2571,7 @@ export const DEFAULT_GAS_SCHEDULE: Required = { // [ERC20BridgeSource.Pangolin]: uniswapV2CloneGasSchedule, [ERC20BridgeSource.TraderJoe]: uniswapV2CloneGasSchedule, + [ERC20BridgeSource.GMX]: () => 300e3, // // Celo diff --git a/packages/asset-swapper/src/utils/market_operation_utils/orders.ts b/packages/asset-swapper/src/utils/market_operation_utils/orders.ts index 2914decb1e..e37714d2a0 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/orders.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/orders.ts @@ -20,6 +20,7 @@ import { FinalUniswapV3FillData, GeistFillData, GenericRouterFillData, + GMXFillData, KyberDmmFillData, KyberFillData, LidoFillData, @@ -208,6 +209,8 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s return encodeBridgeSourceId(BridgeProtocol.AaveV2, 'Geist'); case ERC20BridgeSource.MobiusMoney: return encodeBridgeSourceId(BridgeProtocol.Nerve, 'MobiusMoney'); + case ERC20BridgeSource.GMX: + return encodeBridgeSourceId(BridgeProtocol.GMX, 'GMX'); default: throw new Error(AggregationError.NoBridgeForSource); } @@ -367,6 +370,10 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder const geistFillData = (order as OptimizedMarketBridgeOrder).fillData; bridgeData = encoder.encode([geistFillData.lendingPool, geistFillData.gToken]); break; + case ERC20BridgeSource.GMX: + const gmxFillData = (order as OptimizedMarketBridgeOrder).fillData; + bridgeData = encoder.encode([gmxFillData.reader, gmxFillData.vault, gmxFillData.tokenAddressPath]); + break; default: throw new Error(AggregationError.NoBridgeForSource); @@ -454,6 +461,7 @@ const balancerV2Encoder = AbiEncoder.create([ const routerAddressPathEncoder = AbiEncoder.create('(address,address[])'); const tokenAddressEncoder = AbiEncoder.create([{ name: 'tokenAddress', type: 'address' }]); + export const BRIDGE_ENCODERS: { [key in Exclude< ERC20BridgeSource, @@ -505,6 +513,8 @@ export const BRIDGE_ENCODERS: { [ERC20BridgeSource.SpiritSwap]: routerAddressPathEncoder, [ERC20BridgeSource.SpookySwap]: routerAddressPathEncoder, [ERC20BridgeSource.MorpheusSwap]: routerAddressPathEncoder, + // Avalanche + [ERC20BridgeSource.GMX] : AbiEncoder.create('(address,address,address[])'), // Celo [ERC20BridgeSource.UbeSwap]: routerAddressPathEncoder, // BSC diff --git a/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts b/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts index f59ac4b738..c970d5451b 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts @@ -30,6 +30,9 @@ import { COMPOUND_API_URL_BY_CHAIN_ID, DODOV1_CONFIG_BY_CHAIN_ID, DODOV2_FACTORIES_BY_CHAIN_ID, + GMX_READER_BY_CHAIN_ID, + GMX_ROUTER_BY_CHAIN_ID, + GMX_VAULT_BY_CHAIN_ID, KYBER_CONFIG_BY_CHAIN_ID, KYBER_DMM_ROUTER_BY_CHAIN_ID, LIDO_INFO_BY_CHAIN, @@ -71,6 +74,8 @@ import { GeistFillData, GeistInfo, GenericRouterFillData, + GMXFillData, + GMXQuoteFillData, HopInfo, KyberDmmFillData, KyberFillData, @@ -1213,6 +1218,20 @@ export class SamplerOperations { params: [cToken, takerToken, makerToken, makerFillAmounts], }); } + public getGMXSellQuotes( + reader: string, + vault: string, + tokenAddressPath: string[], + takerFillAmounts: BigNumber[], + ): SourceQuoteOperation { + return new SamplerContractOperation({ + source: ERC20BridgeSource.GMX, + fillData: {reader, vault, tokenAddressPath }, + contract: this._samplerContract, + function: this._samplerContract.sampleSellsFromGMX, + params: [reader, vault, tokenAddressPath, takerFillAmounts], + }); + } public getMedianSellRate( sources: ERC20BridgeSource[], @@ -1605,6 +1624,15 @@ export class SamplerOperations { takerFillAmounts, ); } + case ERC20BridgeSource.GMX: { + + return this.getGMXSellQuotes( + GMX_READER_BY_CHAIN_ID[this.chainId], + GMX_VAULT_BY_CHAIN_ID[this.chainId], + [makerToken, takerToken], + takerFillAmounts, + ); + } default: throw new Error(`Unsupported sell sample source: ${source}`); } diff --git a/packages/asset-swapper/src/utils/market_operation_utils/types.ts b/packages/asset-swapper/src/utils/market_operation_utils/types.ts index ef8d49f48e..6f614d9ee5 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/types.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/types.ts @@ -94,6 +94,7 @@ export enum ERC20BridgeSource { // Avalanche Pangolin = 'Pangolin', TraderJoe = 'TraderJoe', + GMX = 'GMX', // Celo only UbeSwap = 'UbeSwap', MobiusMoney = 'MobiusMoney', @@ -222,6 +223,16 @@ export interface UniswapV2FillData extends FillData { tokenAddressPath: string[]; router: string; } +export interface GMXQuoteFillData extends FillData { + tokenAddressPath: string[]; + reader: string; + vault: string; +} +export interface GMXFillData extends FillData { + reader: string; + vault: string; + tokenAddressPath: string[]; +} export interface ShellFillData extends FillData { poolAddress: string; diff --git a/packages/asset-swapper/test/artifacts.ts b/packages/asset-swapper/test/artifacts.ts index c031b54f9c..0880931efa 100644 --- a/packages/asset-swapper/test/artifacts.ts +++ b/packages/asset-swapper/test/artifacts.ts @@ -17,9 +17,11 @@ 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 FakeTaker from '../test/generated-artifacts/FakeTaker.json'; +import * as GMXSampler from '../test/generated-artifacts/GMXSampler.json'; import * as IBalancer from '../test/generated-artifacts/IBalancer.json'; import * as IBancor from '../test/generated-artifacts/IBancor.json'; import * as ICurve from '../test/generated-artifacts/ICurve.json'; +import * as IGMX from '../test/generated-artifacts/IGMX.json'; import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json'; import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json'; import * as IMStable from '../test/generated-artifacts/IMStable.json'; @@ -59,6 +61,7 @@ export const artifacts = { DODOV2Sampler: DODOV2Sampler as ContractArtifact, ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact, FakeTaker: FakeTaker as ContractArtifact, + GMXSampler: GMXSampler as ContractArtifact, KyberDmmSampler: KyberDmmSampler as ContractArtifact, KyberSampler: KyberSampler as ContractArtifact, LidoSampler: LidoSampler as ContractArtifact, @@ -79,6 +82,7 @@ export const artifacts = { IBalancer: IBalancer as ContractArtifact, IBancor: IBancor as ContractArtifact, ICurve: ICurve as ContractArtifact, + IGMX: IGMX as ContractArtifact, IKyberNetwork: IKyberNetwork as ContractArtifact, IMStable: IMStable as ContractArtifact, IMooniswap: IMooniswap as ContractArtifact, diff --git a/packages/asset-swapper/test/wrappers.ts b/packages/asset-swapper/test/wrappers.ts index ab7db5a605..e8559b23e8 100644 --- a/packages/asset-swapper/test/wrappers.ts +++ b/packages/asset-swapper/test/wrappers.ts @@ -15,6 +15,7 @@ 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/fake_taker'; +export * from '../test/generated-wrappers/g_m_x_sampler'; export * from '../test/generated-wrappers/i_balancer'; export * from '../test/generated-wrappers/i_bancor'; export * from '../test/generated-wrappers/i_curve'; @@ -26,6 +27,7 @@ export * from '../test/generated-wrappers/i_shell'; export * from '../test/generated-wrappers/i_smoothy'; export * from '../test/generated-wrappers/i_uniswap_exchange_quotes'; export * from '../test/generated-wrappers/i_uniswap_v2_router01'; +export * from '../test/generated-wrappers/igmx'; export * from '../test/generated-wrappers/kyber_dmm_sampler'; export * from '../test/generated-wrappers/kyber_sampler'; export * from '../test/generated-wrappers/lido_sampler'; diff --git a/packages/asset-swapper/tsconfig.json b/packages/asset-swapper/tsconfig.json index 47af31e7a4..65e69e2f91 100644 --- a/packages/asset-swapper/tsconfig.json +++ b/packages/asset-swapper/tsconfig.json @@ -18,9 +18,11 @@ "test/generated-artifacts/DummyLiquidityProvider.json", "test/generated-artifacts/ERC20BridgeSampler.json", "test/generated-artifacts/FakeTaker.json", + "test/generated-artifacts/GMXSampler.json", "test/generated-artifacts/IBalancer.json", "test/generated-artifacts/IBancor.json", "test/generated-artifacts/ICurve.json", + "test/generated-artifacts/IGMX.json", "test/generated-artifacts/IKyberNetwork.json", "test/generated-artifacts/IMStable.json", "test/generated-artifacts/IMooniswap.json", diff --git a/packages/protocol-utils/CHANGELOG.json b/packages/protocol-utils/CHANGELOG.json index dfe8b9d15c..7d34af8985 100644 --- a/packages/protocol-utils/CHANGELOG.json +++ b/packages/protocol-utils/CHANGELOG.json @@ -1,4 +1,12 @@ [ + { + "version": "1.12.0", + "changes": [ + { + "note": "Added Support for GMX liquidity source on Avalanche" + } + ] + }, { "timestamp": 1646225739, "version": "1.11.1", diff --git a/packages/protocol-utils/src/transformer_utils.ts b/packages/protocol-utils/src/transformer_utils.ts index 4d57084ab8..823dad8ee2 100644 --- a/packages/protocol-utils/src/transformer_utils.ts +++ b/packages/protocol-utils/src/transformer_utils.ts @@ -134,6 +134,7 @@ export enum BridgeProtocol { Clipper, // Not used: Clipper is now using PLP interface AaveV2, Compound, + GMX, } // tslint:enable: enum-naming diff --git a/yarn.lock b/yarn.lock index b684499538..1801453bda 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3755,10 +3755,10 @@ bigi@1.4.2, bigi@^1.1.0: version "1.4.2" resolved "https://registry.yarnpkg.com/bigi/-/bigi-1.4.2.tgz#9c665a95f88b8b08fc05cfd731f561859d725825" -bignumber.js@7.2.1, bignumber.js@9.0.1, bignumber.js@^9.0.0, bignumber.js@~4.1.0, bignumber.js@~9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5" - integrity sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA== +bignumber.js@7.2.1, bignumber.js@9.0.2, bignumber.js@^9.0.0, bignumber.js@~4.1.0, bignumber.js@~9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.2.tgz#71c6c6bed38de64e24a65ebe16cfcf23ae693673" + integrity sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw== binary-extensions@^2.0.0: version "2.1.0"