Compare commits
23 Commits
protocol@2
...
circleci-e
Author | SHA1 | Date | |
---|---|---|---|
|
aa96e53271 | ||
|
4090a001f2 | ||
|
736cf8026e | ||
|
882f2bb829 | ||
|
337d483a3e | ||
|
51a581136b | ||
|
c1835e7423 | ||
|
ee54177ca2 | ||
|
5acc01a4e1 | ||
|
30fafaa672 | ||
|
d3d4a08f91 | ||
|
9ce090c8cd | ||
|
980d60deb8 | ||
|
d6d79e51e7 | ||
|
3ef5de93bb | ||
|
ab7dc33ca4 | ||
|
14dcee5bb6 | ||
|
9856e78609 | ||
|
5756d7c563 | ||
|
2577caaf5a | ||
|
603813191f | ||
|
0484519e4d | ||
|
275542b6b2 |
@@ -10,6 +10,7 @@ jobs:
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- checkout
|
||||
- run: git submodule update --init --recursive
|
||||
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
|
||||
- run:
|
||||
name: install-yarn
|
||||
@@ -27,6 +28,17 @@ jobs:
|
||||
path: ~/repo/packages/abi-gen/test-cli/output
|
||||
- store_artifacts:
|
||||
path: ~/repo/packages/contract-wrappers/generated_docs
|
||||
test-foundry:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
- image: ghcr.io/foundry-rs/foundry:latest
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: forge install
|
||||
- run: forge test
|
||||
test-exchange-ganache:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
@@ -181,6 +193,9 @@ workflows:
|
||||
# - test-contracts-extra-ganache:
|
||||
# requires:
|
||||
# - build
|
||||
- test-foundry:
|
||||
requires:
|
||||
- build
|
||||
- test-contracts-rest-ganache:
|
||||
requires:
|
||||
- build
|
||||
|
9
.gitignore
vendored
9
.gitignore
vendored
@@ -173,6 +173,15 @@ contracts/zero-ex/test/generated-wrappers/
|
||||
contracts/treasury/generated-wrappers/
|
||||
contracts/treasury/test/generated-wrappers/
|
||||
|
||||
# foundry artifacts
|
||||
contracts/zero-ex/foundry-artifacts/
|
||||
|
||||
# foundry cache
|
||||
contracts/zero-ex/foundry-cache/
|
||||
|
||||
# typechain wrappers
|
||||
contracts/zero-ex/typechain-wrappers/
|
||||
|
||||
# Doc README copy
|
||||
packages/*/docs/README.md
|
||||
|
||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "contracts/zero-ex/contracts/deps/forge-std"]
|
||||
path = contracts/zero-ex/contracts/deps/forge-std
|
||||
url = https://github.com/foundry-rs/forge-std
|
@@ -2,6 +2,10 @@
|
||||
|
||||
This package contains contracts for the ZeroEx extensible contract architecture.
|
||||
|
||||
> **_NOTE:_** This repo is undergoing a tooling change. If adding a contract, you will need to
|
||||
> add it to `compiler.json`. You can generate the entire list by running the following:
|
||||
> `find . -type f -name "*.sol" | grep -v foundry | grep -v "contracts/dep" | grep -v "node_modules"`
|
||||
|
||||
## Installation
|
||||
|
||||
**Install**
|
||||
|
@@ -1,6 +1,212 @@
|
||||
{
|
||||
"artifactsDir": "./test/generated-artifacts",
|
||||
"contractsDir": "./contracts",
|
||||
"contracts": [
|
||||
"./contracts/test/TestFixinProtocolFees.sol",
|
||||
"./contracts/test/TestTransformerHost.sol",
|
||||
"./contracts/test/TestFillQuoteTransformerHost.sol",
|
||||
"./contracts/test/TestTransformerDeployerTransformer.sol",
|
||||
"./contracts/test/TestUniswapV3Feature.sol",
|
||||
"./contracts/test/TestBridge.sol",
|
||||
"./contracts/test/TestCallTarget.sol",
|
||||
"./contracts/test/TestNoEthRecipient.sol",
|
||||
"./contracts/test/TestFullMigration.sol",
|
||||
"./contracts/test/TestLibSignature.sol",
|
||||
"./contracts/test/integration/TestUniswapV3Pool.sol",
|
||||
"./contracts/test/integration/TestMooniswap.sol",
|
||||
"./contracts/test/integration/TestUniswapV3Factory.sol",
|
||||
"./contracts/test/integration/TestCurve.sol",
|
||||
"./contracts/test/integration/TestUniswapV2Pool.sol",
|
||||
"./contracts/test/integration/TestUniswapV2Factory.sol",
|
||||
"./contracts/test/integration/TestLiquidityProvider.sol",
|
||||
"./contracts/test/TestMetaTransactionsNativeOrdersFeature.sol",
|
||||
"./contracts/test/TestFeeCollectorController.sol",
|
||||
"./contracts/test/TestNFTOrderPresigner.sol",
|
||||
"./contracts/test/TestMetaTransactionsTransformERC20Feature.sol",
|
||||
"./contracts/test/TestTransformERC20.sol",
|
||||
"./contracts/test/TestFeeRecipient.sol",
|
||||
"./contracts/test/TestPermissionlessTransformerDeployerTransformer.sol",
|
||||
"./contracts/test/TestMigrator.sol",
|
||||
"./contracts/test/TestFixinTokenSpender.sol",
|
||||
"./contracts/test/TestDelegateCaller.sol",
|
||||
"./contracts/test/TestTransformerBase.sol",
|
||||
"./contracts/test/TestZeroExFeature.sol",
|
||||
"./contracts/test/TestLibNativeOrder.sol",
|
||||
"./contracts/test/TestWethTransformerHost.sol",
|
||||
"./contracts/test/TestPropertyValidator.sol",
|
||||
"./contracts/test/TestMintTokenERC20Transformer.sol",
|
||||
"./contracts/test/TestFillQuoteTransformerBridge.sol",
|
||||
"./contracts/test/TestOrderSignerRegistryWithContractWallet.sol",
|
||||
"./contracts/test/TestNativeOrdersFeature.sol",
|
||||
"./contracts/test/TestRfqOriginRegistration.sol",
|
||||
"./contracts/test/TestStaking.sol",
|
||||
"./contracts/test/TestFillQuoteTransformerExchange.sol",
|
||||
"./contracts/test/TestInitialMigration.sol",
|
||||
"./contracts/test/tokens/TestMintableERC721Token.sol",
|
||||
"./contracts/test/tokens/TestTokenSpenderERC20Token.sol",
|
||||
"./contracts/test/tokens/TestWeth.sol",
|
||||
"./contracts/test/tokens/TestMintableERC1155Token.sol",
|
||||
"./contracts/test/tokens/TestMintableERC20Token.sol",
|
||||
"./contracts/test/TestSimpleFunctionRegistryFeatureImpl1.sol",
|
||||
"./contracts/test/ITestSimpleFunctionRegistryFeature.sol",
|
||||
"./contracts/test/TestPermissionlessTransformerDeployerSuicidal.sol",
|
||||
"./contracts/test/TestSimpleFunctionRegistryFeatureImpl2.sol",
|
||||
"./contracts/src/migrations/InitialMigration.sol",
|
||||
"./contracts/src/migrations/LibMigrate.sol",
|
||||
"./contracts/src/migrations/LibBootstrap.sol",
|
||||
"./contracts/src/migrations/FullMigration.sol",
|
||||
"./contracts/src/ZeroExOptimized.sol",
|
||||
"./contracts/src/fixins/FixinERC721Spender.sol",
|
||||
"./contracts/src/fixins/FixinTokenSpender.sol",
|
||||
"./contracts/src/fixins/FixinERC1155Spender.sol",
|
||||
"./contracts/src/fixins/FixinReentrancyGuard.sol",
|
||||
"./contracts/src/fixins/FixinProtocolFees.sol",
|
||||
"./contracts/src/fixins/FixinEIP712.sol",
|
||||
"./contracts/src/fixins/FixinCommon.sol",
|
||||
"./contracts/src/features/BatchFillNativeOrdersFeature.sol",
|
||||
"./contracts/src/features/LiquidityProviderFeature.sol",
|
||||
"./contracts/src/features/ERC165Feature.sol",
|
||||
"./contracts/src/features/MetaTransactionsFeature.sol",
|
||||
"./contracts/src/features/nft_orders/NFTOrders.sol",
|
||||
"./contracts/src/features/nft_orders/ERC1155OrdersFeature.sol",
|
||||
"./contracts/src/features/nft_orders/ERC721OrdersFeature.sol",
|
||||
"./contracts/src/features/TransformERC20Feature.sol",
|
||||
"./contracts/src/features/OwnableFeature.sol",
|
||||
"./contracts/src/features/libs/LibSignature.sol",
|
||||
"./contracts/src/features/libs/LibNativeOrder.sol",
|
||||
"./contracts/src/features/libs/LibNFTOrder.sol",
|
||||
"./contracts/src/features/native_orders/NativeOrdersSettlement.sol",
|
||||
"./contracts/src/features/native_orders/NativeOrdersCancellation.sol",
|
||||
"./contracts/src/features/native_orders/NativeOrdersProtocolFees.sol",
|
||||
"./contracts/src/features/native_orders/NativeOrdersInfo.sol",
|
||||
"./contracts/src/features/UniswapV3Feature.sol",
|
||||
"./contracts/src/features/NativeOrdersFeature.sol",
|
||||
"./contracts/src/features/UniswapFeature.sol",
|
||||
"./contracts/src/features/BootstrapFeature.sol",
|
||||
"./contracts/src/features/multiplex/MultiplexTransformERC20.sol",
|
||||
"./contracts/src/features/multiplex/MultiplexRfq.sol",
|
||||
"./contracts/src/features/multiplex/MultiplexFeature.sol",
|
||||
"./contracts/src/features/multiplex/MultiplexLiquidityProvider.sol",
|
||||
"./contracts/src/features/multiplex/MultiplexOtc.sol",
|
||||
"./contracts/src/features/multiplex/MultiplexUniswapV3.sol",
|
||||
"./contracts/src/features/multiplex/MultiplexUniswapV2.sol",
|
||||
"./contracts/src/features/OtcOrdersFeature.sol",
|
||||
"./contracts/src/features/FundRecoveryFeature.sol",
|
||||
"./contracts/src/features/SimpleFunctionRegistryFeature.sol",
|
||||
"./contracts/src/features/PancakeSwapFeature.sol",
|
||||
"./contracts/src/features/interfaces/IMultiplexFeature.sol",
|
||||
"./contracts/src/features/interfaces/IPancakeSwapFeature.sol",
|
||||
"./contracts/src/features/interfaces/IUniswapV3Feature.sol",
|
||||
"./contracts/src/features/interfaces/INativeOrdersFeature.sol",
|
||||
"./contracts/src/features/interfaces/IOwnableFeature.sol",
|
||||
"./contracts/src/features/interfaces/IERC165Feature.sol",
|
||||
"./contracts/src/features/interfaces/IFundRecoveryFeature.sol",
|
||||
"./contracts/src/features/interfaces/IERC721OrdersFeature.sol",
|
||||
"./contracts/src/features/interfaces/ILiquidityProviderFeature.sol",
|
||||
"./contracts/src/features/interfaces/IFeature.sol",
|
||||
"./contracts/src/features/interfaces/IMetaTransactionsFeature.sol",
|
||||
"./contracts/src/features/interfaces/IBootstrapFeature.sol",
|
||||
"./contracts/src/features/interfaces/IOtcOrdersFeature.sol",
|
||||
"./contracts/src/features/interfaces/IERC1155OrdersFeature.sol",
|
||||
"./contracts/src/features/interfaces/IUniswapFeature.sol",
|
||||
"./contracts/src/features/interfaces/ITokenSpenderFeature.sol",
|
||||
"./contracts/src/features/interfaces/ISimpleFunctionRegistryFeature.sol",
|
||||
"./contracts/src/features/interfaces/ITransformERC20Feature.sol",
|
||||
"./contracts/src/features/interfaces/INativeOrdersEvents.sol",
|
||||
"./contracts/src/features/interfaces/IBatchFillNativeOrdersFeature.sol",
|
||||
"./contracts/src/IZeroEx.sol",
|
||||
"./contracts/src/ZeroEx.sol",
|
||||
"./contracts/src/storage/LibNativeOrdersStorage.sol",
|
||||
"./contracts/src/storage/LibTransformERC20Storage.sol",
|
||||
"./contracts/src/storage/LibOtcOrdersStorage.sol",
|
||||
"./contracts/src/storage/LibSimpleFunctionRegistryStorage.sol",
|
||||
"./contracts/src/storage/LibStorage.sol",
|
||||
"./contracts/src/storage/LibERC721OrdersStorage.sol",
|
||||
"./contracts/src/storage/LibReentrancyGuardStorage.sol",
|
||||
"./contracts/src/storage/LibMetaTransactionsStorage.sol",
|
||||
"./contracts/src/storage/LibProxyStorage.sol",
|
||||
"./contracts/src/storage/LibOwnableStorage.sol",
|
||||
"./contracts/src/storage/LibERC1155OrdersStorage.sol",
|
||||
"./contracts/src/transformers/FillQuoteTransformer.sol",
|
||||
"./contracts/src/transformers/AffiliateFeeTransformer.sol",
|
||||
"./contracts/src/transformers/PositiveSlippageFeeTransformer.sol",
|
||||
"./contracts/src/transformers/Transformer.sol",
|
||||
"./contracts/src/transformers/LibERC20Transformer.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinShell.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinMakerPSM.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinDodoV2.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinMStable.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinBalancerV2.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinCurveV2.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinPlatypus.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinNerve.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinBancor.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinUniswap.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinBalancer.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinCompound.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinBalancerV2Batch.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinLido.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinUniswapV2.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinZeroExBridge.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinUniswapV3.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinBancorV3.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinKyberDmm.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinGMX.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinCurve.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinMooniswap.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinDodo.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinCryptoCom.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinSynthetix.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinAaveV2.sol",
|
||||
"./contracts/src/transformers/bridges/mixins/MixinVelodrome.sol",
|
||||
"./contracts/src/transformers/bridges/CeloBridgeAdapter.sol",
|
||||
"./contracts/src/transformers/bridges/FantomBridgeAdapter.sol",
|
||||
"./contracts/src/transformers/bridges/OptimismBridgeAdapter.sol",
|
||||
"./contracts/src/transformers/bridges/AbstractBridgeAdapter.sol",
|
||||
"./contracts/src/transformers/bridges/EthereumBridgeAdapter.sol",
|
||||
"./contracts/src/transformers/bridges/PolygonBridgeAdapter.sol",
|
||||
"./contracts/src/transformers/bridges/AvalancheBridgeAdapter.sol",
|
||||
"./contracts/src/transformers/bridges/BridgeProtocols.sol",
|
||||
"./contracts/src/transformers/bridges/IBridgeAdapter.sol",
|
||||
"./contracts/src/transformers/bridges/BSCBridgeAdapter.sol",
|
||||
"./contracts/src/transformers/LogMetadataTransformer.sol",
|
||||
"./contracts/src/transformers/IERC20Transformer.sol",
|
||||
"./contracts/src/transformers/PayTakerTransformer.sol",
|
||||
"./contracts/src/transformers/WethTransformer.sol",
|
||||
"./contracts/src/external/PermissionlessTransformerDeployer.sol",
|
||||
"./contracts/src/external/FlashWallet.sol",
|
||||
"./contracts/src/external/FeeCollector.sol",
|
||||
"./contracts/src/external/IFlashWallet.sol",
|
||||
"./contracts/src/external/LiquidityProviderSandbox.sol",
|
||||
"./contracts/src/external/TransformerDeployer.sol",
|
||||
"./contracts/src/external/LibFeeCollector.sol",
|
||||
"./contracts/src/external/FeeCollectorController.sol",
|
||||
"./contracts/src/external/ILiquidityProviderSandbox.sol",
|
||||
"./contracts/src/errors/LibLiquidityProviderRichErrors.sol",
|
||||
"./contracts/src/errors/LibSignatureRichErrors.sol",
|
||||
"./contracts/src/errors/LibWalletRichErrors.sol",
|
||||
"./contracts/src/errors/LibTransformERC20RichErrors.sol",
|
||||
"./contracts/src/errors/LibNativeOrdersRichErrors.sol",
|
||||
"./contracts/src/errors/LibNFTOrdersRichErrors.sol",
|
||||
"./contracts/src/errors/LibMetaTransactionsRichErrors.sol",
|
||||
"./contracts/src/errors/LibCommonRichErrors.sol",
|
||||
"./contracts/src/errors/LibOwnableRichErrors.sol",
|
||||
"./contracts/src/errors/LibProxyRichErrors.sol",
|
||||
"./contracts/src/errors/LibSimpleFunctionRegistryRichErrors.sol",
|
||||
"./contracts/src/liquidity-providers/MooniswapLiquidityProvider.sol",
|
||||
"./contracts/src/liquidity-providers/CurveLiquidityProvider.sol",
|
||||
"./contracts/src/vendor/IMooniswapPool.sol",
|
||||
"./contracts/src/vendor/IFeeRecipient.sol",
|
||||
"./contracts/src/vendor/IERC721Token.sol",
|
||||
"./contracts/src/vendor/IERC1155Token.sol",
|
||||
"./contracts/src/vendor/IPropertyValidator.sol",
|
||||
"./contracts/src/vendor/ITakerCallback.sol",
|
||||
"./contracts/src/vendor/IUniswapV3Pool.sol",
|
||||
"./contracts/src/vendor/v3/IStaking.sol",
|
||||
"./contracts/src/vendor/v3/IERC20Bridge.sol",
|
||||
"./contracts/src/vendor/IUniswapV2Pair.sol",
|
||||
"./contracts/src/vendor/ILiquidityProvider.sol"
|
||||
],
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"shouldSaveStandardInput": true,
|
||||
|
1
contracts/zero-ex/contracts/deps/forge-std
Submodule
1
contracts/zero-ex/contracts/deps/forge-std
Submodule
Submodule contracts/zero-ex/contracts/deps/forge-std added at 1680d7fb3e
30
contracts/zero-ex/contracts/test/foundry/ContractTest.sol
Normal file
30
contracts/zero-ex/contracts/test/foundry/ContractTest.sol
Normal file
@@ -0,0 +1,30 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
|
||||
Copyright 2022 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;
|
||||
|
||||
import "forge-std/Test.sol";
|
||||
|
||||
contract ContractTest is Test {
|
||||
function setUp() public {}
|
||||
|
||||
function testExample() public {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
8
contracts/zero-ex/foundry.toml
Normal file
8
contracts/zero-ex/foundry.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
[default]
|
||||
src = 'contracts/src'
|
||||
out = 'foundry-artifacts'
|
||||
test = 'contracts/test/foundry'
|
||||
libs = ["contracts/deps/", "../utils/contracts/src/"]
|
||||
remappings = ['@0x/contracts-utils/=../utils/', '@0x/contracts-erc20/=../erc20/', 'src/=./contracts/src']
|
||||
cache_path = 'foundry-cache'
|
||||
optimizer_runs = 1000000
|
@@ -38,7 +38,8 @@
|
||||
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES",
|
||||
"publish:private": "yarn build && gitpkg publish",
|
||||
"rollback": "node ./lib/scripts/rollback.js"
|
||||
"rollback": "node ./lib/scripts/rollback.js",
|
||||
"typechain": "typechain --target=ethers-v5 --out-dir='typechain-wrappers' './foundry-artifacts/**/*.json'"
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature,OtcOrdersFeature,IOtcOrdersFeature,AvalancheBridgeAdapter,BSCBridgeAdapter,CeloBridgeAdapter,EthereumBridgeAdapter,FantomBridgeAdapter,OptimismBridgeAdapter,PolygonBridgeAdapter",
|
||||
@@ -65,6 +66,7 @@
|
||||
"@0x/sol-compiler": "^4.8.1",
|
||||
"@0x/ts-doc-gen": "^0.0.28",
|
||||
"@0x/tslint-config": "^4.1.4",
|
||||
"@typechain/ethers-v5": "^10.0.0",
|
||||
"@types/isomorphic-fetch": "^0.0.35",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@@ -78,6 +80,7 @@
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typechain": "^8.0.0",
|
||||
"typedoc": "~0.16.11",
|
||||
"typescript": "4.6.3"
|
||||
},
|
||||
|
@@ -1,4 +1,14 @@
|
||||
[
|
||||
{
|
||||
"version": "16.65.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Use 0x gas api instead of eth gas station api",
|
||||
"pr": 532
|
||||
}
|
||||
],
|
||||
"timestamp": 1659391840
|
||||
},
|
||||
{
|
||||
"version": "16.64.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v16.65.0 - _August 1, 2022_
|
||||
|
||||
* Use 0x gas api instead of eth gas station api (#532)
|
||||
|
||||
## v16.64.0 - _July 27, 2022_
|
||||
|
||||
* Refactor `TokenAdjacency` and `TokenAdjacencyBuilder` (#517)
|
||||
|
@@ -1897,7 +1897,7 @@ ___
|
||||
|
||||
# Interface: SwapQuoteRequestOpts
|
||||
|
||||
slippagePercentage: The percentage buffer to add to account for slippage. Affects max ETH price estimates. Defaults to 0.2 (20%).
|
||||
slippagePercentage: The percentage buffer to add to account for slippage. Affects max ETH price estimates. Defaults to 0.01 (1%).
|
||||
gasPrice: gas price to determine protocolFee amount, default to ethGasStation fast amount
|
||||
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/asset-swapper",
|
||||
"version": "16.64.0",
|
||||
"version": "16.65.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -109,6 +109,7 @@
|
||||
"dirty-chai": "^2.0.1",
|
||||
"gitpkg": "https://github.com/0xProject/gitpkg.git",
|
||||
"mocha": "^6.2.0",
|
||||
"msw": "^0.44.2",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"nyc": "^11.0.1",
|
||||
"shx": "^0.2.2",
|
||||
|
@@ -19,7 +19,7 @@ import {
|
||||
DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID,
|
||||
} from './utils/market_operation_utils/constants';
|
||||
|
||||
const ETH_GAS_STATION_API_URL = 'https://ethgasstation.info/api/ethgasAPI.json';
|
||||
const ZERO_EX_GAS_API_URL = 'https://gas.api.0x.org/source/median';
|
||||
const NULL_BYTES = '0x';
|
||||
const NULL_ERC20_ASSET_DATA = '0xf47261b00000000000000000000000000000000000000000000000000000000000000000';
|
||||
const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
|
||||
@@ -48,7 +48,7 @@ const DEFAULT_SWAP_QUOTER_OPTS: SwapQuoterOpts = {
|
||||
orderRefreshIntervalMs: 10000, // 10 seconds
|
||||
...DEFAULT_ORDER_PRUNER_OPTS,
|
||||
samplerGasLimit: 500e6,
|
||||
ethGasStationUrl: ETH_GAS_STATION_API_URL,
|
||||
zeroExGasApiUrl: ZERO_EX_GAS_API_URL,
|
||||
rfqt: {
|
||||
integratorsWhitelist: [],
|
||||
makerAssetOfferings: {},
|
||||
@@ -95,11 +95,10 @@ export { DEFAULT_FEE_SCHEDULE, DEFAULT_GAS_SCHEDULE } from './utils/market_opera
|
||||
|
||||
export const POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS = new BigNumber(30000);
|
||||
|
||||
// tslint:disable-next-line: custom-no-magic-numbers
|
||||
export const KEEP_ALIVE_TTL = 5 * 60 * ONE_SECOND_MS;
|
||||
|
||||
export const constants = {
|
||||
ETH_GAS_STATION_API_URL,
|
||||
ZERO_EX_GAS_API_URL,
|
||||
PROTOCOL_FEE_MULTIPLIER,
|
||||
POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS,
|
||||
NULL_BYTES,
|
||||
|
@@ -157,8 +157,6 @@ export {
|
||||
GetMarketOrdersRfqOpts,
|
||||
LiquidityProviderFillData,
|
||||
LiquidityProviderRegistry,
|
||||
MarketDepth,
|
||||
MarketDepthSide,
|
||||
MooniswapFillData,
|
||||
MultiHopFillData,
|
||||
NativeRfqOrderFillData,
|
||||
|
@@ -61,7 +61,6 @@ import {
|
||||
requiresTransformERC20,
|
||||
} from './quote_consumer_utils';
|
||||
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
|
||||
const { NULL_ADDRESS, NULL_BYTES, ZERO_AMOUNT } = constants;
|
||||
|
||||
|
@@ -36,9 +36,6 @@ import {
|
||||
FillData,
|
||||
GasSchedule,
|
||||
GetMarketOrdersOpts,
|
||||
MarketDepth,
|
||||
MarketDepthSide,
|
||||
MarketSideLiquidity,
|
||||
OptimizedMarketOrder,
|
||||
OptimizerResultWithReport,
|
||||
} from './utils/market_operation_utils/types';
|
||||
@@ -112,7 +109,7 @@ export class SwapQuoter {
|
||||
};
|
||||
this._protocolFeeUtils = ProtocolFeeUtils.getInstance(
|
||||
constants.PROTOCOL_FEE_UTILS_POLLING_INTERVAL_IN_MS,
|
||||
options.ethGasStationUrl,
|
||||
options.zeroExGasApiUrl,
|
||||
);
|
||||
// Allow the sampler bytecode to be overwritten using geths override functionality
|
||||
const samplerBytecode = _.get(artifacts.ERC20BridgeSampler, 'compilerOutput.evm.deployedBytecode.object');
|
||||
@@ -228,67 +225,6 @@ export class SwapQuoter {
|
||||
return batchSwapQuotes.filter(x => x !== undefined) as MarketBuySwapQuote[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bids and asks liquidity for the entire market.
|
||||
* For certain sources (like AMM's) it is recommended to provide a practical maximum takerAssetAmount.
|
||||
* @param makerTokenAddress The address of the maker asset
|
||||
* @param takerTokenAddress The address of the taker asset
|
||||
* @param takerAssetAmount The amount to sell and buy for the bids and asks.
|
||||
*
|
||||
* @return An object that conforms to MarketDepth that contains all of the samples and liquidity
|
||||
* information for the source.
|
||||
*/
|
||||
public async getBidAskLiquidityForMakerTakerAssetPairAsync(
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerAssetAmount: BigNumber,
|
||||
options: Partial<SwapQuoteRequestOpts> = {},
|
||||
): Promise<MarketDepth> {
|
||||
assert.isString('makerToken', makerToken);
|
||||
assert.isString('takerToken', takerToken);
|
||||
const sourceFilters = new SourceFilters([], options.excludedSources, options.includedSources);
|
||||
|
||||
let [sellOrders, buyOrders] = !sourceFilters.isAllowed(ERC20BridgeSource.Native)
|
||||
? [[], []]
|
||||
: await Promise.all([
|
||||
this.orderbook.getOrdersAsync(makerToken, takerToken),
|
||||
this.orderbook.getOrdersAsync(takerToken, makerToken),
|
||||
]);
|
||||
if (!sellOrders || sellOrders.length === 0) {
|
||||
sellOrders = [createDummyOrder(makerToken, takerToken)];
|
||||
}
|
||||
if (!buyOrders || buyOrders.length === 0) {
|
||||
buyOrders = [createDummyOrder(takerToken, makerToken)];
|
||||
}
|
||||
|
||||
const getMarketDepthSide = (marketSideLiquidity: MarketSideLiquidity): MarketDepthSide => {
|
||||
const { dexQuotes, nativeOrders } = marketSideLiquidity.quotes;
|
||||
const { side } = marketSideLiquidity;
|
||||
|
||||
return [
|
||||
...dexQuotes,
|
||||
nativeOrders.map(o => {
|
||||
return {
|
||||
input: side === MarketOperation.Sell ? o.fillableTakerAmount : o.fillableMakerAmount,
|
||||
output: side === MarketOperation.Sell ? o.fillableMakerAmount : o.fillableTakerAmount,
|
||||
fillData: o,
|
||||
source: ERC20BridgeSource.Native,
|
||||
};
|
||||
}),
|
||||
];
|
||||
};
|
||||
const [bids, asks] = await Promise.all([
|
||||
this._marketOperationUtils.getMarketBuyLiquidityAsync(buyOrders, takerAssetAmount, options),
|
||||
this._marketOperationUtils.getMarketSellLiquidityAsync(sellOrders, takerAssetAmount, options),
|
||||
]);
|
||||
return {
|
||||
bids: getMarketDepthSide(bids),
|
||||
asks: getMarketDepthSide(asks),
|
||||
makerTokenDecimals: asks.makerTokenDecimals,
|
||||
takerTokenDecimals: asks.takerTokenDecimals,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recommended gas price for a fast transaction
|
||||
*/
|
||||
|
@@ -337,7 +337,7 @@ export interface SwapQuoterOpts extends OrderPrunerOpts {
|
||||
contractAddresses?: AssetSwapperContractAddresses;
|
||||
samplerGasLimit?: number;
|
||||
multiBridgeAddress?: string;
|
||||
ethGasStationUrl?: string;
|
||||
zeroExGasApiUrl?: string;
|
||||
rfqt?: SwapQuoterRfqOpts;
|
||||
samplerOverrides?: SamplerOverrides;
|
||||
tokenAdjacencyGraph?: TokenAdjacencyGraph;
|
||||
|
@@ -104,11 +104,9 @@ function parseIndicativeQuoteResponseFromAltMM(
|
||||
takerAmount,
|
||||
// HACK: alt implementation does not return an expiration with indicative quotes
|
||||
// return now + { IMPUTED EXPIRY SECONDS } to have it included after order checks
|
||||
expiry:
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
new BigNumber(Date.now() / 1000)
|
||||
.integerValue(BigNumber.ROUND_DOWN)
|
||||
.plus(constants.ALT_MM_IMPUTED_INDICATIVE_EXPIRY_SECONDS),
|
||||
expiry: new BigNumber(Date.now() / 1000)
|
||||
.integerValue(BigNumber.ROUND_DOWN)
|
||||
.plus(constants.ALT_MM_IMPUTED_INDICATIVE_EXPIRY_SECONDS),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -243,7 +241,6 @@ export async function returnQuoteFromAltMMAsync<ResponseT>(
|
||||
// empty response will get filtered out in validation
|
||||
const emptyResponse = {};
|
||||
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
if (response.status !== SUCCESS_CODE) {
|
||||
const rejectedRequestInfo = {
|
||||
status: response.status,
|
||||
|
@@ -40,7 +40,6 @@ interface Cache {
|
||||
[key: string]: AaveReserve[];
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const RESERVES_REFRESH_INTERVAL_MS = 30 * constants.ONE_MINUTE_MS;
|
||||
|
||||
/**
|
||||
|
@@ -19,7 +19,6 @@ interface Cache {
|
||||
[key: string]: CToken;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const CTOKEN_REFRESH_INTERVAL_MS = 30 * constants.ONE_MINUTE_MS;
|
||||
|
||||
/**
|
||||
|
@@ -37,7 +37,7 @@ import {
|
||||
UniswapV3FillData,
|
||||
} from './types';
|
||||
|
||||
// tslint:disable: custom-no-magic-numbers no-bitwise
|
||||
// tslint:disable: no-bitwise
|
||||
|
||||
export const ERC20_PROXY_ID = '0xf47261b0';
|
||||
export const WALLET_SIGNATURE = '0x04';
|
||||
@@ -2176,7 +2176,6 @@ export const LIDO_INFO_BY_CHAIN = valueByChainId<LidoInfo>(
|
||||
},
|
||||
);
|
||||
|
||||
export const BALANCER_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer';
|
||||
export const BALANCER_TOP_POOLS_FETCHED = 250;
|
||||
export const BALANCER_MAX_POOLS_FETCHED = 3;
|
||||
|
||||
@@ -2473,7 +2472,6 @@ const uniswapV2CloneGasSchedule = (fillData?: FillData) => {
|
||||
* I.e remove the overhead cost of ExchangeProxy (130k) and
|
||||
* the ethereum transaction cost (21k)
|
||||
*/
|
||||
// tslint:disable:custom-no-magic-numbers
|
||||
export const DEFAULT_GAS_SCHEDULE: Required<GasSchedule> = {
|
||||
[ERC20BridgeSource.Native]: fillData => {
|
||||
// TODO jacob re-order imports so there is no circular rependency with SignedNativeOrder
|
||||
@@ -2698,10 +2696,7 @@ export const POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS = new BigNumber(20000);
|
||||
|
||||
export const DEFAULT_FEE_ESTIMATE = { gas: 0, fee: ZERO_AMOUNT };
|
||||
|
||||
// tslint:enable:custom-no-magic-numbers
|
||||
|
||||
export const DEFAULT_GET_MARKET_ORDERS_OPTS: Omit<GetMarketOrdersOpts, 'gasPrice'> = {
|
||||
// tslint:disable-next-line: custom-no-magic-numbers
|
||||
runLimit: 2 ** 15,
|
||||
excludedSources: [],
|
||||
excludedFeeSources: [],
|
||||
|
@@ -862,14 +862,9 @@ export class MarketOperationUtils {
|
||||
}
|
||||
|
||||
private async _refreshPoolCacheIfRequiredAsync(takerToken: string, makerToken: string): Promise<void> {
|
||||
void Promise.all(
|
||||
Object.values(this._sampler.poolsCaches).map(async cache => {
|
||||
if (!cache || cache.isFresh(takerToken, makerToken)) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
return cache.getFreshPoolsForPairAsync(takerToken, makerToken);
|
||||
}),
|
||||
);
|
||||
_.values(this._sampler.poolsCaches)
|
||||
.filter(cache => cache !== undefined && !cache.isFresh(takerToken, makerToken))
|
||||
.forEach(cache => cache?.getFreshPoolsForPairAsync(takerToken, makerToken));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -14,7 +14,7 @@ import { dexSampleToFill, ethToOutputAmount, nativeOrderToFill } from './fills';
|
||||
import { Path, PathPenaltyOpts } from './path';
|
||||
import { DexSample, ERC20BridgeSource, FeeSchedule, Fill, FillAdjustor, FillData, SamplerMetrics } from './types';
|
||||
|
||||
// tslint:disable: prefer-for-of custom-no-magic-numbers completed-docs no-bitwise
|
||||
// tslint:disable: prefer-for-of completed-docs no-bitwise
|
||||
|
||||
// NOTE: The Rust router will panic with less than 3 samples
|
||||
const MIN_NUM_SAMPLE_INPUTS = 3;
|
||||
|
@@ -1,16 +1,19 @@
|
||||
import { ChainId } from '@0x/contract-addresses';
|
||||
import { getPoolsWithTokens, parsePoolData } from 'balancer-labs-sor-v1';
|
||||
import { Pool } from 'balancer-labs-sor-v1/dist/types';
|
||||
import { gql, request } from 'graphql-request';
|
||||
|
||||
import { DEFAULT_WARNING_LOGGER } from '../../../constants';
|
||||
import { LogFunction } from '../../../types';
|
||||
import { BALANCER_MAX_POOLS_FETCHED, BALANCER_SUBGRAPH_URL, BALANCER_TOP_POOLS_FETCHED } from '../constants';
|
||||
import { BALANCER_MAX_POOLS_FETCHED, BALANCER_TOP_POOLS_FETCHED } from '../constants';
|
||||
|
||||
import { CacheValue, PoolsCache } from './pools_cache';
|
||||
import { NoOpPoolsCache } from './no_op_pools_cache';
|
||||
import { AbstractPoolsCache, CacheValue, PoolsCache } from './pools_cache';
|
||||
|
||||
// tslint:disable:custom-no-magic-numbers
|
||||
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
||||
// tslint:enable:custom-no-magic-numbers
|
||||
// tslint:disable: member-ordering
|
||||
|
||||
const BALANCER_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer';
|
||||
|
||||
interface BalancerPoolResponse {
|
||||
id: string;
|
||||
@@ -20,10 +23,18 @@ interface BalancerPoolResponse {
|
||||
totalWeight: string;
|
||||
}
|
||||
|
||||
export class BalancerPoolsCache extends PoolsCache {
|
||||
constructor(
|
||||
export class BalancerPoolsCache extends AbstractPoolsCache {
|
||||
public static create(chainId: ChainId): PoolsCache {
|
||||
if (chainId !== ChainId.Mainnet) {
|
||||
return new NoOpPoolsCache();
|
||||
}
|
||||
|
||||
return new BalancerPoolsCache();
|
||||
}
|
||||
|
||||
private constructor(
|
||||
private readonly _subgraphUrl: string = BALANCER_SUBGRAPH_URL,
|
||||
cache: { [key: string]: CacheValue } = {},
|
||||
cache: Map<string, CacheValue> = new Map(),
|
||||
private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
|
||||
private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED,
|
||||
private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER,
|
||||
|
@@ -9,13 +9,15 @@ import { LogFunction } from '../../../types';
|
||||
import { BALANCER_MAX_POOLS_FETCHED, BALANCER_TOP_POOLS_FETCHED } from '../constants';
|
||||
|
||||
import { parsePoolData } from './balancer_sor_v2';
|
||||
import { CacheValue, PoolsCache } from './pools_cache';
|
||||
import { NoOpPoolsCache } from './no_op_pools_cache';
|
||||
import { AbstractPoolsCache, CacheValue, PoolsCache } from './pools_cache';
|
||||
|
||||
// tslint:disable: member-ordering
|
||||
|
||||
const BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN = new Map<ChainId, string>([
|
||||
[ChainId.Fantom, 'https://api.thegraph.com/subgraphs/name/beethovenxfi/beethovenx'],
|
||||
]);
|
||||
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
||||
|
||||
interface BalancerPoolResponse {
|
||||
@@ -28,11 +30,11 @@ interface BalancerPoolResponse {
|
||||
amp: string | null;
|
||||
}
|
||||
|
||||
export class BalancerV2PoolsCache extends PoolsCache {
|
||||
public static createBeethovenXPoolCache(chainId: ChainId): BalancerV2PoolsCache | undefined {
|
||||
export class BalancerV2PoolsCache extends AbstractPoolsCache {
|
||||
public static createBeethovenXPoolCache(chainId: ChainId): PoolsCache {
|
||||
const subgraphUrl = BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN.get(chainId);
|
||||
if (subgraphUrl === undefined) {
|
||||
return undefined;
|
||||
return new NoOpPoolsCache();
|
||||
}
|
||||
|
||||
return new BalancerV2PoolsCache(subgraphUrl);
|
||||
@@ -58,12 +60,12 @@ export class BalancerV2PoolsCache extends PoolsCache {
|
||||
};
|
||||
}
|
||||
|
||||
constructor(
|
||||
private constructor(
|
||||
private readonly subgraphUrl: string,
|
||||
private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
|
||||
private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED,
|
||||
private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER,
|
||||
cache: { [key: string]: CacheValue } = {},
|
||||
cache: Map<string, CacheValue> = new Map(),
|
||||
) {
|
||||
super(cache);
|
||||
void this._loadTopPoolsAsync();
|
||||
|
@@ -20,7 +20,6 @@ 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 {
|
||||
|
@@ -1,18 +1,20 @@
|
||||
import { ChainId } from '@0x/contract-addresses';
|
||||
import { Pool } from 'balancer-labs-sor-v1/dist/types';
|
||||
import { getPoolsWithTokens, parsePoolData } from 'cream-sor';
|
||||
|
||||
import { BALANCER_MAX_POOLS_FETCHED } from '../constants';
|
||||
|
||||
import { CacheValue, PoolsCache } from './pools_cache';
|
||||
import { NoOpPoolsCache } from './no_op_pools_cache';
|
||||
import { AbstractPoolsCache, CacheValue, PoolsCache } from './pools_cache';
|
||||
|
||||
export class CreamPoolsCache extends PoolsCache {
|
||||
constructor(
|
||||
_cache: { [key: string]: CacheValue } = {},
|
||||
private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
|
||||
) {
|
||||
super(_cache);
|
||||
export class CreamPoolsCache extends AbstractPoolsCache {
|
||||
public static create(chainId: ChainId): PoolsCache {
|
||||
if (chainId !== ChainId.Mainnet) {
|
||||
return new NoOpPoolsCache();
|
||||
}
|
||||
|
||||
return new CreamPoolsCache();
|
||||
}
|
||||
|
||||
protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> {
|
||||
try {
|
||||
const poolData = (await getPoolsWithTokens(takerToken, makerToken)).pools;
|
||||
@@ -25,4 +27,10 @@ export class CreamPoolsCache extends PoolsCache {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
private constructor(
|
||||
_cache: Map<string, CacheValue> = new Map(),
|
||||
private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
|
||||
) {
|
||||
super(_cache);
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
export { BalancerPoolsCache } from './balancer_utils';
|
||||
export { BalancerV2PoolsCache } from './balancer_v2_utils';
|
||||
export { CreamPoolsCache } from './cream_utils';
|
||||
export { PoolsCache } from './pools_cache';
|
||||
export { AbstractPoolsCache, PoolsCache } from './pools_cache';
|
||||
|
@@ -0,0 +1,21 @@
|
||||
import { Pool, PoolsCache } from './pools_cache';
|
||||
|
||||
// tslint:disable:prefer-function-over-method
|
||||
|
||||
export class NoOpPoolsCache implements PoolsCache {
|
||||
public async getFreshPoolsForPairAsync(
|
||||
_takerToken: string,
|
||||
_makerToken: string,
|
||||
_timeoutMs?: number | undefined,
|
||||
): Promise<Pool[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
public getPoolAddressesForPair(_takerToken: string, _makerToken: string): string[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
public isFresh(_takerToken: string, _makerToken: string): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -7,12 +7,10 @@ export interface CacheValue {
|
||||
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.
|
||||
|
@@ -7,18 +7,30 @@ export interface CacheValue {
|
||||
pools: Pool[];
|
||||
}
|
||||
|
||||
// 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 = 1000;
|
||||
// tslint:enable:custom-no-magic-numbers
|
||||
const DEFAULT_TIMEOUT_MS = 3000;
|
||||
|
||||
export abstract class PoolsCache {
|
||||
protected static _isExpired(value: CacheValue): boolean {
|
||||
export interface PoolsCache {
|
||||
getFreshPoolsForPairAsync(takerToken: string, makerToken: string, timeoutMs?: number): Promise<Pool[]>;
|
||||
getPoolAddressesForPair(takerToken: string, makerToken: string): string[];
|
||||
isFresh(takerToken: string, makerToken: string): boolean;
|
||||
}
|
||||
|
||||
export abstract class AbstractPoolsCache implements PoolsCache {
|
||||
protected static _getKey(takerToken: string, makerToken: string): string {
|
||||
return `${takerToken}-${makerToken}`;
|
||||
}
|
||||
|
||||
protected static _isExpired(value: CacheValue | undefined): boolean {
|
||||
if (value === undefined) {
|
||||
return true;
|
||||
}
|
||||
return Date.now() >= value.expiresAt;
|
||||
}
|
||||
|
||||
constructor(
|
||||
protected readonly _cache: { [key: string]: CacheValue },
|
||||
protected readonly _cache: Map<string, CacheValue>,
|
||||
protected readonly _cacheTimeMs: number = DEFAULT_CACHE_TIME_MS,
|
||||
) {}
|
||||
|
||||
@@ -31,47 +43,42 @@ export abstract class PoolsCache {
|
||||
return Promise.race([this._getAndSaveFreshPoolsForPairAsync(takerToken, makerToken), timeout]);
|
||||
}
|
||||
|
||||
public getCachedPoolAddressesForPair(
|
||||
takerToken: string,
|
||||
makerToken: string,
|
||||
ignoreExpired: boolean = true,
|
||||
): string[] | undefined {
|
||||
const key = JSON.stringify([takerToken, makerToken]);
|
||||
const value = this._cache[key];
|
||||
if (ignoreExpired) {
|
||||
return value === undefined ? [] : value.pools.map(pool => pool.id);
|
||||
}
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
if (PoolsCache._isExpired(value)) {
|
||||
return undefined;
|
||||
}
|
||||
return (value || []).pools.map(pool => pool.id);
|
||||
/**
|
||||
* Returns pool addresses (can be stale) for a pair.
|
||||
*
|
||||
* An empty array will be returned if cache does not exist.
|
||||
*/
|
||||
public getPoolAddressesForPair(takerToken: string, makerToken: string): string[] {
|
||||
const value = this._getValue(takerToken, makerToken);
|
||||
return value === undefined ? [] : value.pools.map(pool => pool.id);
|
||||
}
|
||||
|
||||
public isFresh(takerToken: string, makerToken: string): boolean {
|
||||
const cached = this.getCachedPoolAddressesForPair(takerToken, makerToken, false);
|
||||
return cached !== undefined;
|
||||
const value = this._getValue(takerToken, makerToken);
|
||||
return !AbstractPoolsCache._isExpired(value);
|
||||
}
|
||||
|
||||
protected _getValue(takerToken: string, makerToken: string): CacheValue | undefined {
|
||||
const key = AbstractPoolsCache._getKey(takerToken, makerToken);
|
||||
return this._cache.get(key);
|
||||
}
|
||||
|
||||
protected async _getAndSaveFreshPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> {
|
||||
const key = JSON.stringify([takerToken, makerToken]);
|
||||
const value = this._cache[key];
|
||||
if (value === undefined || value.expiresAt >= Date.now()) {
|
||||
const pools = await this._fetchPoolsForPairAsync(takerToken, makerToken);
|
||||
const expiresAt = Date.now() + this._cacheTimeMs;
|
||||
this._cachePoolsForPair(takerToken, makerToken, pools, expiresAt);
|
||||
const key = AbstractPoolsCache._getKey(takerToken, makerToken);
|
||||
const value = this._cache.get(key);
|
||||
if (!AbstractPoolsCache._isExpired(value)) {
|
||||
return value!.pools;
|
||||
}
|
||||
return this._cache[key].pools;
|
||||
|
||||
const pools = await this._fetchPoolsForPairAsync(takerToken, makerToken);
|
||||
const expiresAt = Date.now() + this._cacheTimeMs;
|
||||
this._cachePoolsForPair(takerToken, makerToken, pools, expiresAt);
|
||||
return pools;
|
||||
}
|
||||
|
||||
protected _cachePoolsForPair(takerToken: string, makerToken: string, pools: Pool[], expiresAt: number): void {
|
||||
const key = JSON.stringify([takerToken, makerToken]);
|
||||
this._cache[key] = {
|
||||
pools,
|
||||
expiresAt,
|
||||
};
|
||||
const key = AbstractPoolsCache._getKey(takerToken, makerToken);
|
||||
this._cache.set(key, { pools, expiresAt });
|
||||
}
|
||||
|
||||
protected abstract _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]>;
|
||||
|
@@ -56,7 +56,7 @@ import {
|
||||
} from './constants';
|
||||
import { getGeistInfoForPair } from './geist_utils';
|
||||
import { getLiquidityProvidersForPair } from './liquidity_provider_utils';
|
||||
import { BalancerPoolsCache, BalancerV2PoolsCache, CreamPoolsCache } 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 { SamplerNoOperation } from './sampler_no_operation';
|
||||
@@ -114,10 +114,10 @@ export const TWO_HOP_SOURCE_FILTERS = SourceFilters.all().exclude([
|
||||
export const BATCH_SOURCE_FILTERS = SourceFilters.all().exclude([ERC20BridgeSource.MultiHop, ERC20BridgeSource.Native]);
|
||||
|
||||
export interface PoolsCacheMap {
|
||||
[ERC20BridgeSource.Balancer]: BalancerPoolsCache;
|
||||
[ERC20BridgeSource.Balancer]: PoolsCache;
|
||||
[ERC20BridgeSource.BalancerV2]: BalancerV2SwapInfoCache | undefined;
|
||||
[ERC20BridgeSource.Beethovenx]: BalancerV2PoolsCache | undefined;
|
||||
[ERC20BridgeSource.Cream]: CreamPoolsCache;
|
||||
[ERC20BridgeSource.Beethovenx]: PoolsCache;
|
||||
[ERC20BridgeSource.Cream]: PoolsCache;
|
||||
}
|
||||
|
||||
// tslint:disable:no-inferred-empty-object-type no-unbound-method
|
||||
@@ -156,8 +156,8 @@ export class SamplerOperations {
|
||||
? poolsCaches
|
||||
: {
|
||||
[ERC20BridgeSource.Beethovenx]: BalancerV2PoolsCache.createBeethovenXPoolCache(chainId),
|
||||
[ERC20BridgeSource.Balancer]: new BalancerPoolsCache(),
|
||||
[ERC20BridgeSource.Cream]: new CreamPoolsCache(),
|
||||
[ERC20BridgeSource.Balancer]: BalancerPoolsCache.create(chainId),
|
||||
[ERC20BridgeSource.Cream]: CreamPoolsCache.create(chainId),
|
||||
[ERC20BridgeSource.BalancerV2]:
|
||||
BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[chainId] === NULL_ADDRESS
|
||||
? undefined
|
||||
@@ -1592,20 +1592,17 @@ export class SamplerOperations {
|
||||
),
|
||||
];
|
||||
case ERC20BridgeSource.Balancer:
|
||||
return (
|
||||
this.poolsCaches[ERC20BridgeSource.Balancer].getCachedPoolAddressesForPair(
|
||||
takerToken,
|
||||
makerToken,
|
||||
) || []
|
||||
).map(balancerPool =>
|
||||
this.getBalancerSellQuotes(
|
||||
balancerPool,
|
||||
makerToken,
|
||||
takerToken,
|
||||
takerFillAmounts,
|
||||
ERC20BridgeSource.Balancer,
|
||||
),
|
||||
);
|
||||
return this.poolsCaches[ERC20BridgeSource.Balancer]
|
||||
.getPoolAddressesForPair(takerToken, makerToken)
|
||||
.map(balancerPool =>
|
||||
this.getBalancerSellQuotes(
|
||||
balancerPool,
|
||||
makerToken,
|
||||
takerToken,
|
||||
takerFillAmounts,
|
||||
ERC20BridgeSource.Balancer,
|
||||
),
|
||||
);
|
||||
case ERC20BridgeSource.BalancerV2: {
|
||||
const cache = this.poolsCaches[source];
|
||||
if (!cache) {
|
||||
@@ -1624,18 +1621,14 @@ export class SamplerOperations {
|
||||
}
|
||||
case ERC20BridgeSource.Beethovenx: {
|
||||
const cache = this.poolsCaches[source];
|
||||
if (cache === undefined) {
|
||||
return [];
|
||||
}
|
||||
const poolIds = cache.getCachedPoolAddressesForPair(takerToken, makerToken) || [];
|
||||
|
||||
const poolAddresses = cache.getPoolAddressesForPair(takerToken, makerToken);
|
||||
const vault = BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId];
|
||||
if (vault === NULL_ADDRESS) {
|
||||
return [];
|
||||
}
|
||||
return poolIds.map(poolId =>
|
||||
return poolAddresses.map(poolAddress =>
|
||||
this.getBalancerV2SellQuotes(
|
||||
{ poolId, vault },
|
||||
{ poolId: poolAddress, vault },
|
||||
makerToken,
|
||||
takerToken,
|
||||
takerFillAmounts,
|
||||
@@ -1644,20 +1637,17 @@ export class SamplerOperations {
|
||||
);
|
||||
}
|
||||
case ERC20BridgeSource.Cream:
|
||||
return (
|
||||
this.poolsCaches[ERC20BridgeSource.Cream].getCachedPoolAddressesForPair(
|
||||
takerToken,
|
||||
makerToken,
|
||||
) || []
|
||||
).map(creamPool =>
|
||||
this.getBalancerSellQuotes(
|
||||
creamPool,
|
||||
makerToken,
|
||||
takerToken,
|
||||
takerFillAmounts,
|
||||
ERC20BridgeSource.Cream,
|
||||
),
|
||||
);
|
||||
return this.poolsCaches[ERC20BridgeSource.Cream]
|
||||
.getPoolAddressesForPair(takerToken, makerToken)
|
||||
.map(creamPool =>
|
||||
this.getBalancerSellQuotes(
|
||||
creamPool,
|
||||
makerToken,
|
||||
takerToken,
|
||||
takerFillAmounts,
|
||||
ERC20BridgeSource.Cream,
|
||||
),
|
||||
);
|
||||
case ERC20BridgeSource.Dodo:
|
||||
if (!isValidAddress(DODOV1_CONFIG_BY_CHAIN_ID[this.chainId].registry)) {
|
||||
return [];
|
||||
@@ -1948,20 +1938,17 @@ export class SamplerOperations {
|
||||
),
|
||||
];
|
||||
case ERC20BridgeSource.Balancer:
|
||||
return (
|
||||
this.poolsCaches[ERC20BridgeSource.Balancer].getCachedPoolAddressesForPair(
|
||||
takerToken,
|
||||
makerToken,
|
||||
) || []
|
||||
).map(poolAddress =>
|
||||
this.getBalancerBuyQuotes(
|
||||
poolAddress,
|
||||
makerToken,
|
||||
takerToken,
|
||||
makerFillAmounts,
|
||||
ERC20BridgeSource.Balancer,
|
||||
),
|
||||
);
|
||||
return this.poolsCaches[ERC20BridgeSource.Balancer]
|
||||
.getPoolAddressesForPair(takerToken, makerToken)
|
||||
.map(poolAddress =>
|
||||
this.getBalancerBuyQuotes(
|
||||
poolAddress,
|
||||
makerToken,
|
||||
takerToken,
|
||||
makerFillAmounts,
|
||||
ERC20BridgeSource.Balancer,
|
||||
),
|
||||
);
|
||||
case ERC20BridgeSource.BalancerV2: {
|
||||
const cache = this.poolsCaches[source];
|
||||
if (!cache) {
|
||||
@@ -1986,11 +1973,7 @@ export class SamplerOperations {
|
||||
}
|
||||
case ERC20BridgeSource.Beethovenx: {
|
||||
const cache = this.poolsCaches[source];
|
||||
if (cache === undefined) {
|
||||
return [];
|
||||
}
|
||||
const poolIds = cache.getCachedPoolAddressesForPair(takerToken, makerToken) || [];
|
||||
|
||||
const poolIds = cache.getPoolAddressesForPair(takerToken, makerToken) || [];
|
||||
const vault = BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId];
|
||||
if (vault === NULL_ADDRESS) {
|
||||
return [];
|
||||
@@ -2006,20 +1989,17 @@ export class SamplerOperations {
|
||||
);
|
||||
}
|
||||
case ERC20BridgeSource.Cream:
|
||||
return (
|
||||
this.poolsCaches[ERC20BridgeSource.Cream].getCachedPoolAddressesForPair(
|
||||
takerToken,
|
||||
makerToken,
|
||||
) || []
|
||||
).map(poolAddress =>
|
||||
this.getBalancerBuyQuotes(
|
||||
poolAddress,
|
||||
makerToken,
|
||||
takerToken,
|
||||
makerFillAmounts,
|
||||
ERC20BridgeSource.Cream,
|
||||
),
|
||||
);
|
||||
return this.poolsCaches[ERC20BridgeSource.Cream]
|
||||
.getPoolAddressesForPair(takerToken, makerToken)
|
||||
.map(poolAddress =>
|
||||
this.getBalancerBuyQuotes(
|
||||
poolAddress,
|
||||
makerToken,
|
||||
takerToken,
|
||||
makerFillAmounts,
|
||||
ERC20BridgeSource.Cream,
|
||||
),
|
||||
);
|
||||
case ERC20BridgeSource.Dodo:
|
||||
if (!isValidAddress(DODOV1_CONFIG_BY_CHAIN_ID[this.chainId].registry)) {
|
||||
return [];
|
||||
|
@@ -617,15 +617,6 @@ export interface OptimizerResultWithReport extends OptimizerResult {
|
||||
priceComparisonsReport?: PriceComparisonsReport;
|
||||
}
|
||||
|
||||
export type MarketDepthSide = Array<Array<DexSample<FillData>>>;
|
||||
|
||||
export interface MarketDepth {
|
||||
bids: MarketDepthSide;
|
||||
asks: MarketDepthSide;
|
||||
makerTokenDecimals: number;
|
||||
takerTokenDecimals: number;
|
||||
}
|
||||
|
||||
export interface MarketSideLiquidity {
|
||||
side: MarketOperation;
|
||||
inputAmount: BigNumber;
|
||||
|
@@ -6,28 +6,36 @@ import { SwapQuoterError } from '../types';
|
||||
|
||||
const MAX_ERROR_COUNT = 5;
|
||||
|
||||
interface GasOracleResponse {
|
||||
result: {
|
||||
// gas price in wei
|
||||
fast: number;
|
||||
};
|
||||
}
|
||||
|
||||
export class ProtocolFeeUtils {
|
||||
private static _instance: ProtocolFeeUtils;
|
||||
private readonly _ethGasStationUrl!: string;
|
||||
private readonly _zeroExGasApiUrl: string;
|
||||
private readonly _gasPriceHeart: any;
|
||||
private _gasPriceEstimation: BigNumber = constants.ZERO_AMOUNT;
|
||||
private _errorCount: number = 0;
|
||||
|
||||
public static getInstance(
|
||||
gasPricePollingIntervalInMs: number,
|
||||
ethGasStationUrl: string = constants.ETH_GAS_STATION_API_URL,
|
||||
zeroExGasApiUrl: string = constants.ZERO_EX_GAS_API_URL,
|
||||
initialGasPrice: BigNumber = constants.ZERO_AMOUNT,
|
||||
): ProtocolFeeUtils {
|
||||
if (!ProtocolFeeUtils._instance) {
|
||||
ProtocolFeeUtils._instance = new ProtocolFeeUtils(
|
||||
gasPricePollingIntervalInMs,
|
||||
ethGasStationUrl,
|
||||
zeroExGasApiUrl,
|
||||
initialGasPrice,
|
||||
);
|
||||
}
|
||||
return ProtocolFeeUtils._instance;
|
||||
}
|
||||
|
||||
/** @returns gas price (in wei) */
|
||||
public async getGasPriceEstimationOrThrowAsync(shouldHardRefresh?: boolean): Promise<BigNumber> {
|
||||
if (this._gasPriceEstimation.eq(constants.ZERO_AMOUNT)) {
|
||||
return this._getGasPriceFromGasStationOrThrowAsync();
|
||||
@@ -48,27 +56,21 @@ export class ProtocolFeeUtils {
|
||||
|
||||
private constructor(
|
||||
gasPricePollingIntervalInMs: number,
|
||||
ethGasStationUrl: string = constants.ETH_GAS_STATION_API_URL,
|
||||
zeroExGasApiUrl: string = constants.ZERO_EX_GAS_API_URL,
|
||||
initialGasPrice: BigNumber = constants.ZERO_AMOUNT,
|
||||
) {
|
||||
this._gasPriceHeart = heartbeats.createHeart(gasPricePollingIntervalInMs);
|
||||
this._gasPriceEstimation = initialGasPrice;
|
||||
this._ethGasStationUrl = ethGasStationUrl;
|
||||
this._zeroExGasApiUrl = zeroExGasApiUrl;
|
||||
this._initializeHeartBeat();
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: prefer-function-over-method
|
||||
private async _getGasPriceFromGasStationOrThrowAsync(): Promise<BigNumber> {
|
||||
try {
|
||||
const res = await fetch(this._ethGasStationUrl);
|
||||
const gasInfo = await res.json();
|
||||
// Eth Gas Station result is gwei * 10
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const BASE_TEN = 10;
|
||||
const gasPriceGwei = new BigNumber(gasInfo.fast / BASE_TEN);
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const unit = new BigNumber(BASE_TEN).pow(9);
|
||||
const gasPriceWei = unit.times(gasPriceGwei);
|
||||
const res = await fetch(this._zeroExGasApiUrl);
|
||||
const gasInfo: GasOracleResponse = await res.json();
|
||||
const gasPriceWei = new BigNumber(gasInfo.result.fast);
|
||||
// Reset the error count to 0 once we have a successful response
|
||||
this._errorCount = 0;
|
||||
return gasPriceWei;
|
||||
|
@@ -24,7 +24,7 @@ import {
|
||||
SOURCE_FLAGS,
|
||||
ZERO_AMOUNT,
|
||||
} from '../src/utils/market_operation_utils/constants';
|
||||
import { PoolsCache } from '../src/utils/market_operation_utils/pools_cache';
|
||||
import { AbstractPoolsCache } from '../src/utils/market_operation_utils/pools_cache';
|
||||
import { DexOrderSampler } from '../src/utils/market_operation_utils/sampler';
|
||||
import { BATCH_SOURCE_FILTERS } from '../src/utils/market_operation_utils/sampler_operations';
|
||||
import { SourceFilters } from '../src/utils/market_operation_utils/source_filters';
|
||||
@@ -98,9 +98,9 @@ async function getMarketBuyOrdersAsync(
|
||||
return utils.getOptimizerResultAsync(nativeOrders, makerAmount, MarketOperation.Buy, opts);
|
||||
}
|
||||
|
||||
class MockPoolsCache extends PoolsCache {
|
||||
class MockPoolsCache extends AbstractPoolsCache {
|
||||
constructor(private readonly _handler: (takerToken: string, makerToken: string) => Pool[]) {
|
||||
super({});
|
||||
super(new Map());
|
||||
}
|
||||
protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> {
|
||||
return this._handler(takerToken, makerToken);
|
||||
|
@@ -28,12 +28,12 @@ describe('Pools Caches for Balancer-based sampling', () => {
|
||||
expect(pools.length).greaterThan(0, `Failed to find any pools for ${takerToken} and ${makerToken}`);
|
||||
expect(pools[0]).not.undefined();
|
||||
expect(Object.keys(pools[0])).to.include.members(poolKeys);
|
||||
const cachedPoolIds = cache.getCachedPoolAddressesForPair(takerToken, makerToken);
|
||||
const cachedPoolIds = cache.getPoolAddressesForPair(takerToken, makerToken);
|
||||
expect(cachedPoolIds).to.deep.equal(pools.map(p => p.id));
|
||||
}
|
||||
|
||||
describe('BalancerPoolsCache', () => {
|
||||
const cache = new BalancerPoolsCache();
|
||||
const cache = BalancerPoolsCache.create(ChainId.Mainnet);
|
||||
it('fetches pools', async () => {
|
||||
const pairs = [
|
||||
[usdcAddress, daiAddress],
|
||||
@@ -58,15 +58,14 @@ describe('Pools Caches for Balancer-based sampling', () => {
|
||||
[wftmAddress, fantomWethAddress],
|
||||
];
|
||||
|
||||
expect(cache).not.null();
|
||||
await Promise.all(
|
||||
pairs.map(async ([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache!, takerToken, makerToken)),
|
||||
pairs.map(async ([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('CreamPoolsCache', () => {
|
||||
const cache = new CreamPoolsCache();
|
||||
const cache = CreamPoolsCache.create(ChainId.Mainnet);
|
||||
it('fetches pools', async () => {
|
||||
const pairs = [
|
||||
[usdcAddress, creamAddress],
|
||||
|
45
packages/asset-swapper/test/protocol_fee_utils_test.ts
Normal file
45
packages/asset-swapper/test/protocol_fee_utils_test.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import * as chai from 'chai';
|
||||
import 'mocha';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
|
||||
import { ProtocolFeeUtils } from '../src';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
|
||||
const server = setupServer(
|
||||
rest.get('https://mock-0x-gas-api.org/median', (_req, res, ctx) => {
|
||||
return res(
|
||||
ctx.json({
|
||||
result: {
|
||||
source: 'MEDIAN',
|
||||
timestamp: 1659386474,
|
||||
instant: 22000000000,
|
||||
fast: 18848500000,
|
||||
standard: 14765010000,
|
||||
low: 13265000000,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
describe('ProtocolFeeUtils', () => {
|
||||
describe('getGasPriceEstimationOrThrowAsync', () => {
|
||||
beforeEach(() => {
|
||||
server.listen();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
server.close();
|
||||
});
|
||||
|
||||
it('parses fast gas price response correctly', async () => {
|
||||
const utils = ProtocolFeeUtils.getInstance(420000, 'https://mock-0x-gas-api.org/median');
|
||||
const gasPrice = await utils.getGasPriceEstimationOrThrowAsync();
|
||||
expect(gasPrice.toNumber()).to.eq(18848500000);
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"extends": ["@0x/tslint-config"],
|
||||
"rules": {
|
||||
"custom-no-magic-numbers": false,
|
||||
"max-file-line-count": false,
|
||||
"binary-expression-operand-order": false
|
||||
},
|
||||
|
Reference in New Issue
Block a user