Compare commits

..

6 Commits

Author SHA1 Message Date
Noah Khamliche
4a18c1b0f8 fix rfq/otc encoding logic 2022-07-14 18:09:28 -04:00
Noah Khamliche
3c30c92acf changelog version bumps 2022-07-14 17:41:38 -04:00
Noah Khamliche
cc1cc69ba5 trying to fix tests 2022-07-14 17:20:11 -04:00
Noah Khamliche
4f57736c82 added fill logic for otcOrders in AS, as well as MultiplexBatchFill for otc 2022-07-14 15:43:07 -04:00
Noah Khamliche
f466f8310f added otc orders to quote report generator 2022-07-13 22:01:59 -04:00
Noah Khamliche
8f5e7d7fb5 add new fqt and support for otc orders in asset-swapper exchange proxy swap qutoe consumer 2022-07-13 21:56:50 -04:00
98 changed files with 1129 additions and 3500 deletions

View File

@@ -10,7 +10,6 @@ jobs:
working_directory: ~/repo working_directory: ~/repo
steps: steps:
- checkout - checkout
- run: git submodule update --init --recursive
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV - run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
- run: - run:
name: install-yarn name: install-yarn
@@ -78,17 +77,6 @@ jobs:
keys: keys:
- repo-{{ .Environment.CIRCLE_SHA1 }} - repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn wsrun -p @0x/contracts-multisig -p @0x/contracts-utils -p @0x/contracts-exchange-libs -p @0x/contracts-erc20 -p @0x/contracts-erc721 -p @0x/contracts-erc1155 -p @0x/contracts-asset-proxy -p @0x/contracts-broker -p @0x/contracts-zero-ex -m --serial -c test:circleci - run: yarn wsrun -p @0x/contracts-multisig -p @0x/contracts-utils -p @0x/contracts-exchange-libs -p @0x/contracts-erc20 -p @0x/contracts-erc721 -p @0x/contracts-erc1155 -p @0x/contracts-asset-proxy -p @0x/contracts-broker -p @0x/contracts-zero-ex -m --serial -c test:circleci
test-foundry:
resource_class: medium+
docker:
- image: ghcr.io/foundry-rs/foundry:latest
working_directory: ~/repo/contracts/zero-ex
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
# - run: forge install
- run: forge test
test-publish: test-publish:
resource_class: large resource_class: large
environment: environment:
@@ -193,9 +181,6 @@ workflows:
# - test-contracts-extra-ganache: # - test-contracts-extra-ganache:
# requires: # requires:
# - build # - build
- test-foundry:
requires:
- build
- test-contracts-rest-ganache: - test-contracts-rest-ganache:
requires: requires:
- build - build

9
.gitignore vendored
View File

@@ -173,15 +173,6 @@ contracts/zero-ex/test/generated-wrappers/
contracts/treasury/generated-wrappers/ contracts/treasury/generated-wrappers/
contracts/treasury/test/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 # Doc README copy
packages/*/docs/README.md packages/*/docs/README.md

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "contracts/zero-ex/contracts/deps/forge-std"]
path = contracts/zero-ex/contracts/deps/forge-std
url = https://github.com/foundry-rs/forge-std

View File

@@ -6,15 +6,15 @@
# https://git-scm.com/docs/gitignore#_pattern_format # https://git-scm.com/docs/gitignore#_pattern_format
packages/asset-swapper/ @dekz @dextracker @kyu-c packages/asset-swapper/ @dekz @mzhu25 @dextracker @kh-chang
# Dev tools & setup # Dev tools & setup
.circleci/ @dekz .circleci/ @dekz @mzhu25
packages/contract-addresses/ @dekz @dextracker @kyu-c packages/contract-addresses/ @dekz @mzhu25 @dextracker @kh-chang
packages/contract-artifacts/ @dekz packages/contract-artifacts/ @dekz @mzhu25
packages/protocol-utils/ @dekz packages/protocol-utils/ @dekz @mzhu25
# Protocol/smart contracts # Protocol/smart contracts
contracts/ @dekz @dextracker contracts/ @dekz @mzhu25 @dextracker

View File

@@ -1,40 +1,4 @@
[ [
{
"timestamp": 1660093941,
"version": "3.3.36",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1660073235,
"version": "3.3.35",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1659750766,
"version": "3.3.34",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1658950329,
"version": "3.3.33",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{ {
"timestamp": 1655244958, "timestamp": 1655244958,
"version": "3.3.32", "version": "3.3.32",

View File

@@ -5,22 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v3.3.36 - _August 10, 2022_
* Dependencies updated
## v3.3.35 - _August 9, 2022_
* Dependencies updated
## v3.3.34 - _August 6, 2022_
* Dependencies updated
## v3.3.33 - _July 27, 2022_
* Dependencies updated
## v3.3.32 - _June 14, 2022_ ## v3.3.32 - _June 14, 2022_
* Dependencies updated * Dependencies updated

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contracts-erc20", "name": "@0x/contracts-erc20",
"version": "3.3.36", "version": "3.3.32",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -53,8 +53,8 @@
"devDependencies": { "devDependencies": {
"@0x/abi-gen": "^5.8.0", "@0x/abi-gen": "^5.8.0",
"@0x/contracts-gen": "^2.0.46", "@0x/contracts-gen": "^2.0.46",
"@0x/contracts-test-utils": "^5.4.27", "@0x/contracts-test-utils": "^5.4.23",
"@0x/contracts-utils": "^4.8.17", "@0x/contracts-utils": "^4.8.13",
"@0x/dev-utils": "^4.2.14", "@0x/dev-utils": "^4.2.14",
"@0x/sol-compiler": "^4.8.1", "@0x/sol-compiler": "^4.8.1",
"@0x/ts-doc-gen": "^0.0.28", "@0x/ts-doc-gen": "^0.0.28",

View File

@@ -1,40 +1,4 @@
[ [
{
"timestamp": 1660093941,
"version": "5.4.27",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1660073235,
"version": "5.4.26",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1659750766,
"version": "5.4.25",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1658950329,
"version": "5.4.24",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{ {
"timestamp": 1655244958, "timestamp": 1655244958,
"version": "5.4.23", "version": "5.4.23",

View File

@@ -5,22 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v5.4.27 - _August 10, 2022_
* Dependencies updated
## v5.4.26 - _August 9, 2022_
* Dependencies updated
## v5.4.25 - _August 6, 2022_
* Dependencies updated
## v5.4.24 - _July 27, 2022_
* Dependencies updated
## v5.4.23 - _June 14, 2022_ ## v5.4.23 - _June 14, 2022_
* Dependencies updated * Dependencies updated

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contracts-test-utils", "name": "@0x/contracts-test-utils",
"version": "5.4.27", "version": "5.4.23",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -44,7 +44,7 @@
"dependencies": { "dependencies": {
"@0x/assert": "^3.0.34", "@0x/assert": "^3.0.34",
"@0x/base-contract": "^6.5.0", "@0x/base-contract": "^6.5.0",
"@0x/contract-addresses": "^6.19.2", "@0x/contract-addresses": "^6.16.0",
"@0x/dev-utils": "^4.2.14", "@0x/dev-utils": "^4.2.14",
"@0x/json-schemas": "^6.4.4", "@0x/json-schemas": "^6.4.4",
"@0x/order-utils": "^10.4.28", "@0x/order-utils": "^10.4.28",

View File

@@ -1,40 +1,4 @@
[ [
{
"timestamp": 1660093941,
"version": "1.4.19",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1660073235,
"version": "1.4.18",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1659750766,
"version": "1.4.17",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1658950329,
"version": "1.4.16",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{ {
"timestamp": 1655244958, "timestamp": 1655244958,
"version": "1.4.15", "version": "1.4.15",

View File

@@ -5,22 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v1.4.19 - _August 10, 2022_
* Dependencies updated
## v1.4.18 - _August 9, 2022_
* Dependencies updated
## v1.4.17 - _August 6, 2022_
* Dependencies updated
## v1.4.16 - _July 27, 2022_
* Dependencies updated
## v1.4.15 - _June 14, 2022_ ## v1.4.15 - _June 14, 2022_
* Dependencies updated * Dependencies updated

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contracts-treasury", "name": "@0x/contracts-treasury",
"version": "1.4.19", "version": "1.4.15",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -47,12 +47,12 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury", "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury",
"devDependencies": { "devDependencies": {
"@0x/abi-gen": "^5.8.0", "@0x/abi-gen": "^5.8.0",
"@0x/contract-addresses": "^6.19.2", "@0x/contract-addresses": "^6.16.0",
"@0x/contracts-asset-proxy": "^3.7.19", "@0x/contracts-asset-proxy": "^3.7.19",
"@0x/contracts-erc20": "^3.3.36", "@0x/contracts-erc20": "^3.3.32",
"@0x/contracts-gen": "^2.0.46", "@0x/contracts-gen": "^2.0.46",
"@0x/contracts-staking": "^2.0.45", "@0x/contracts-staking": "^2.0.45",
"@0x/contracts-test-utils": "^5.4.27", "@0x/contracts-test-utils": "^5.4.23",
"@0x/sol-compiler": "^4.8.1", "@0x/sol-compiler": "^4.8.1",
"@0x/ts-doc-gen": "^0.0.28", "@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.4", "@0x/tslint-config": "^4.1.4",
@@ -73,7 +73,7 @@
}, },
"dependencies": { "dependencies": {
"@0x/base-contract": "^6.5.0", "@0x/base-contract": "^6.5.0",
"@0x/protocol-utils": "^11.16.3", "@0x/protocol-utils": "^11.15.0",
"@0x/subproviders": "^6.6.5", "@0x/subproviders": "^6.6.5",
"@0x/types": "^3.3.6", "@0x/types": "^3.3.6",
"@0x/typescript-typings": "^5.3.1", "@0x/typescript-typings": "^5.3.1",

View File

@@ -1,40 +1,4 @@
[ [
{
"timestamp": 1660093941,
"version": "4.8.17",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1660073235,
"version": "4.8.16",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1659750766,
"version": "4.8.15",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1658950329,
"version": "4.8.14",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{ {
"timestamp": 1655244958, "timestamp": 1655244958,
"version": "4.8.13", "version": "4.8.13",

View File

@@ -5,22 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v4.8.17 - _August 10, 2022_
* Dependencies updated
## v4.8.16 - _August 9, 2022_
* Dependencies updated
## v4.8.15 - _August 6, 2022_
* Dependencies updated
## v4.8.14 - _July 27, 2022_
* Dependencies updated
## v4.8.13 - _June 14, 2022_ ## v4.8.13 - _June 14, 2022_
* Dependencies updated * Dependencies updated

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contracts-utils", "name": "@0x/contracts-utils",
"version": "4.8.17", "version": "4.8.13",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -52,7 +52,7 @@
"devDependencies": { "devDependencies": {
"@0x/abi-gen": "^5.8.0", "@0x/abi-gen": "^5.8.0",
"@0x/contracts-gen": "^2.0.46", "@0x/contracts-gen": "^2.0.46",
"@0x/contracts-test-utils": "^5.4.27", "@0x/contracts-test-utils": "^5.4.23",
"@0x/dev-utils": "^4.2.14", "@0x/dev-utils": "^4.2.14",
"@0x/order-utils": "^10.4.28", "@0x/order-utils": "^10.4.28",
"@0x/sol-compiler": "^4.8.1", "@0x/sol-compiler": "^4.8.1",

View File

@@ -1,42 +1,4 @@
[ [
{
"timestamp": 1660093941,
"version": "0.36.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "0.36.2",
"changes": [
{
"note": "Add Foundry support",
"pr": 534
}
],
"timestamp": 1659976271
},
{
"timestamp": 1659750766,
"version": "0.36.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "0.36.0",
"changes": [
{
"note": "Add Synthetix support in Ethereum and Optimism bridge adapters",
"pr": 518
}
],
"timestamp": 1658950329
},
{ {
"version": "0.35.0", "version": "0.35.0",
"changes": [ "changes": [

View File

@@ -5,22 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v0.36.3 - _August 10, 2022_
* Dependencies updated
## v0.36.2 - _August 8, 2022_
* Add Foundry support (#534)
## v0.36.1 - _August 6, 2022_
* Dependencies updated
## v0.36.0 - _July 27, 2022_
* Add Synthetix support in Ethereum and Optimism bridge adapters (#518)
## v0.35.0 - _June 14, 2022_ ## v0.35.0 - _June 14, 2022_
* Adds support for Velodrome OptimismBridgeAdapter (#494) * Adds support for Velodrome OptimismBridgeAdapter (#494)

View File

@@ -2,10 +2,6 @@
This package contains contracts for the ZeroEx extensible contract architecture. 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 ## Installation
**Install** **Install**

View File

@@ -1,212 +1,6 @@
{ {
"artifactsDir": "./test/generated-artifacts", "artifactsDir": "./test/generated-artifacts",
"contractsDir": "./contracts", "contractsDir": "./contracts",
"contracts": [
"./contracts/src/IZeroEx.sol",
"./contracts/src/ZeroEx.sol",
"./contracts/src/ZeroExOptimized.sol",
"./contracts/src/errors/LibCommonRichErrors.sol",
"./contracts/src/errors/LibLiquidityProviderRichErrors.sol",
"./contracts/src/errors/LibMetaTransactionsRichErrors.sol",
"./contracts/src/errors/LibNFTOrdersRichErrors.sol",
"./contracts/src/errors/LibNativeOrdersRichErrors.sol",
"./contracts/src/errors/LibOwnableRichErrors.sol",
"./contracts/src/errors/LibProxyRichErrors.sol",
"./contracts/src/errors/LibSignatureRichErrors.sol",
"./contracts/src/errors/LibSimpleFunctionRegistryRichErrors.sol",
"./contracts/src/errors/LibTransformERC20RichErrors.sol",
"./contracts/src/errors/LibWalletRichErrors.sol",
"./contracts/src/external/FeeCollector.sol",
"./contracts/src/external/FeeCollectorController.sol",
"./contracts/src/external/FlashWallet.sol",
"./contracts/src/external/IFlashWallet.sol",
"./contracts/src/external/ILiquidityProviderSandbox.sol",
"./contracts/src/external/LibFeeCollector.sol",
"./contracts/src/external/LiquidityProviderSandbox.sol",
"./contracts/src/external/PermissionlessTransformerDeployer.sol",
"./contracts/src/external/TransformerDeployer.sol",
"./contracts/src/features/BatchFillNativeOrdersFeature.sol",
"./contracts/src/features/BootstrapFeature.sol",
"./contracts/src/features/ERC165Feature.sol",
"./contracts/src/features/FundRecoveryFeature.sol",
"./contracts/src/features/LiquidityProviderFeature.sol",
"./contracts/src/features/MetaTransactionsFeature.sol",
"./contracts/src/features/NativeOrdersFeature.sol",
"./contracts/src/features/OtcOrdersFeature.sol",
"./contracts/src/features/OwnableFeature.sol",
"./contracts/src/features/PancakeSwapFeature.sol",
"./contracts/src/features/SimpleFunctionRegistryFeature.sol",
"./contracts/src/features/TransformERC20Feature.sol",
"./contracts/src/features/UniswapFeature.sol",
"./contracts/src/features/UniswapV3Feature.sol",
"./contracts/src/features/interfaces/IBatchFillNativeOrdersFeature.sol",
"./contracts/src/features/interfaces/IBootstrapFeature.sol",
"./contracts/src/features/interfaces/IERC1155OrdersFeature.sol",
"./contracts/src/features/interfaces/IERC165Feature.sol",
"./contracts/src/features/interfaces/IERC721OrdersFeature.sol",
"./contracts/src/features/interfaces/IFeature.sol",
"./contracts/src/features/interfaces/IFundRecoveryFeature.sol",
"./contracts/src/features/interfaces/ILiquidityProviderFeature.sol",
"./contracts/src/features/interfaces/IMetaTransactionsFeature.sol",
"./contracts/src/features/interfaces/IMultiplexFeature.sol",
"./contracts/src/features/interfaces/INativeOrdersEvents.sol",
"./contracts/src/features/interfaces/INativeOrdersFeature.sol",
"./contracts/src/features/interfaces/IOtcOrdersFeature.sol",
"./contracts/src/features/interfaces/IOwnableFeature.sol",
"./contracts/src/features/interfaces/IPancakeSwapFeature.sol",
"./contracts/src/features/interfaces/ISimpleFunctionRegistryFeature.sol",
"./contracts/src/features/interfaces/ITokenSpenderFeature.sol",
"./contracts/src/features/interfaces/ITransformERC20Feature.sol",
"./contracts/src/features/interfaces/IUniswapFeature.sol",
"./contracts/src/features/interfaces/IUniswapV3Feature.sol",
"./contracts/src/features/libs/LibNFTOrder.sol",
"./contracts/src/features/libs/LibNativeOrder.sol",
"./contracts/src/features/libs/LibSignature.sol",
"./contracts/src/features/multiplex/MultiplexFeature.sol",
"./contracts/src/features/multiplex/MultiplexLiquidityProvider.sol",
"./contracts/src/features/multiplex/MultiplexOtc.sol",
"./contracts/src/features/multiplex/MultiplexRfq.sol",
"./contracts/src/features/multiplex/MultiplexTransformERC20.sol",
"./contracts/src/features/multiplex/MultiplexUniswapV2.sol",
"./contracts/src/features/multiplex/MultiplexUniswapV3.sol",
"./contracts/src/features/native_orders/NativeOrdersCancellation.sol",
"./contracts/src/features/native_orders/NativeOrdersInfo.sol",
"./contracts/src/features/native_orders/NativeOrdersProtocolFees.sol",
"./contracts/src/features/native_orders/NativeOrdersSettlement.sol",
"./contracts/src/features/nft_orders/ERC1155OrdersFeature.sol",
"./contracts/src/features/nft_orders/ERC721OrdersFeature.sol",
"./contracts/src/features/nft_orders/NFTOrders.sol",
"./contracts/src/fixins/FixinCommon.sol",
"./contracts/src/fixins/FixinEIP712.sol",
"./contracts/src/fixins/FixinERC1155Spender.sol",
"./contracts/src/fixins/FixinERC721Spender.sol",
"./contracts/src/fixins/FixinProtocolFees.sol",
"./contracts/src/fixins/FixinReentrancyGuard.sol",
"./contracts/src/fixins/FixinTokenSpender.sol",
"./contracts/src/liquidity-providers/CurveLiquidityProvider.sol",
"./contracts/src/liquidity-providers/MooniswapLiquidityProvider.sol",
"./contracts/src/migrations/FullMigration.sol",
"./contracts/src/migrations/InitialMigration.sol",
"./contracts/src/migrations/LibBootstrap.sol",
"./contracts/src/migrations/LibMigrate.sol",
"./contracts/src/storage/LibERC1155OrdersStorage.sol",
"./contracts/src/storage/LibERC721OrdersStorage.sol",
"./contracts/src/storage/LibMetaTransactionsStorage.sol",
"./contracts/src/storage/LibNativeOrdersStorage.sol",
"./contracts/src/storage/LibOtcOrdersStorage.sol",
"./contracts/src/storage/LibOwnableStorage.sol",
"./contracts/src/storage/LibProxyStorage.sol",
"./contracts/src/storage/LibReentrancyGuardStorage.sol",
"./contracts/src/storage/LibSimpleFunctionRegistryStorage.sol",
"./contracts/src/storage/LibStorage.sol",
"./contracts/src/storage/LibTransformERC20Storage.sol",
"./contracts/src/transformers/AffiliateFeeTransformer.sol",
"./contracts/src/transformers/FillQuoteTransformer.sol",
"./contracts/src/transformers/IERC20Transformer.sol",
"./contracts/src/transformers/LibERC20Transformer.sol",
"./contracts/src/transformers/LogMetadataTransformer.sol",
"./contracts/src/transformers/PayTakerTransformer.sol",
"./contracts/src/transformers/PositiveSlippageFeeTransformer.sol",
"./contracts/src/transformers/Transformer.sol",
"./contracts/src/transformers/WethTransformer.sol",
"./contracts/src/transformers/bridges/AbstractBridgeAdapter.sol",
"./contracts/src/transformers/bridges/AvalancheBridgeAdapter.sol",
"./contracts/src/transformers/bridges/BSCBridgeAdapter.sol",
"./contracts/src/transformers/bridges/BridgeProtocols.sol",
"./contracts/src/transformers/bridges/CeloBridgeAdapter.sol",
"./contracts/src/transformers/bridges/EthereumBridgeAdapter.sol",
"./contracts/src/transformers/bridges/FantomBridgeAdapter.sol",
"./contracts/src/transformers/bridges/IBridgeAdapter.sol",
"./contracts/src/transformers/bridges/OptimismBridgeAdapter.sol",
"./contracts/src/transformers/bridges/PolygonBridgeAdapter.sol",
"./contracts/src/transformers/bridges/mixins/MixinAaveV2.sol",
"./contracts/src/transformers/bridges/mixins/MixinBalancer.sol",
"./contracts/src/transformers/bridges/mixins/MixinBalancerV2.sol",
"./contracts/src/transformers/bridges/mixins/MixinBalancerV2Batch.sol",
"./contracts/src/transformers/bridges/mixins/MixinBancor.sol",
"./contracts/src/transformers/bridges/mixins/MixinBancorV3.sol",
"./contracts/src/transformers/bridges/mixins/MixinCompound.sol",
"./contracts/src/transformers/bridges/mixins/MixinCryptoCom.sol",
"./contracts/src/transformers/bridges/mixins/MixinCurve.sol",
"./contracts/src/transformers/bridges/mixins/MixinCurveV2.sol",
"./contracts/src/transformers/bridges/mixins/MixinDodo.sol",
"./contracts/src/transformers/bridges/mixins/MixinDodoV2.sol",
"./contracts/src/transformers/bridges/mixins/MixinGMX.sol",
"./contracts/src/transformers/bridges/mixins/MixinKyberDmm.sol",
"./contracts/src/transformers/bridges/mixins/MixinLido.sol",
"./contracts/src/transformers/bridges/mixins/MixinMStable.sol",
"./contracts/src/transformers/bridges/mixins/MixinMakerPSM.sol",
"./contracts/src/transformers/bridges/mixins/MixinMooniswap.sol",
"./contracts/src/transformers/bridges/mixins/MixinNerve.sol",
"./contracts/src/transformers/bridges/mixins/MixinPlatypus.sol",
"./contracts/src/transformers/bridges/mixins/MixinShell.sol",
"./contracts/src/transformers/bridges/mixins/MixinSynthetix.sol",
"./contracts/src/transformers/bridges/mixins/MixinUniswap.sol",
"./contracts/src/transformers/bridges/mixins/MixinUniswapV2.sol",
"./contracts/src/transformers/bridges/mixins/MixinUniswapV3.sol",
"./contracts/src/transformers/bridges/mixins/MixinVelodrome.sol",
"./contracts/src/transformers/bridges/mixins/MixinZeroExBridge.sol",
"./contracts/src/vendor/IERC1155Token.sol",
"./contracts/src/vendor/IERC721Token.sol",
"./contracts/src/vendor/IFeeRecipient.sol",
"./contracts/src/vendor/ILiquidityProvider.sol",
"./contracts/src/vendor/IMooniswapPool.sol",
"./contracts/src/vendor/IPropertyValidator.sol",
"./contracts/src/vendor/ITakerCallback.sol",
"./contracts/src/vendor/IUniswapV2Pair.sol",
"./contracts/src/vendor/IUniswapV3Pool.sol",
"./contracts/src/vendor/v3/IERC20Bridge.sol",
"./contracts/src/vendor/v3/IStaking.sol",
"./contracts/test/ITestSimpleFunctionRegistryFeature.sol",
"./contracts/test/TestBridge.sol",
"./contracts/test/TestCallTarget.sol",
"./contracts/test/TestDelegateCaller.sol",
"./contracts/test/TestFeeCollectorController.sol",
"./contracts/test/TestFeeRecipient.sol",
"./contracts/test/TestFillQuoteTransformerBridge.sol",
"./contracts/test/TestFillQuoteTransformerExchange.sol",
"./contracts/test/TestFillQuoteTransformerHost.sol",
"./contracts/test/TestFixinProtocolFees.sol",
"./contracts/test/TestFixinTokenSpender.sol",
"./contracts/test/TestFullMigration.sol",
"./contracts/test/TestInitialMigration.sol",
"./contracts/test/TestLibNativeOrder.sol",
"./contracts/test/TestLibSignature.sol",
"./contracts/test/TestMetaTransactionsNativeOrdersFeature.sol",
"./contracts/test/TestMetaTransactionsTransformERC20Feature.sol",
"./contracts/test/TestMigrator.sol",
"./contracts/test/TestMintTokenERC20Transformer.sol",
"./contracts/test/TestNFTOrderPresigner.sol",
"./contracts/test/TestNativeOrdersFeature.sol",
"./contracts/test/TestNoEthRecipient.sol",
"./contracts/test/TestOrderSignerRegistryWithContractWallet.sol",
"./contracts/test/TestPermissionlessTransformerDeployerSuicidal.sol",
"./contracts/test/TestPermissionlessTransformerDeployerTransformer.sol",
"./contracts/test/TestPropertyValidator.sol",
"./contracts/test/TestRfqOriginRegistration.sol",
"./contracts/test/TestSimpleFunctionRegistryFeatureImpl1.sol",
"./contracts/test/TestSimpleFunctionRegistryFeatureImpl2.sol",
"./contracts/test/TestStaking.sol",
"./contracts/test/TestTransformERC20.sol",
"./contracts/test/TestTransformerBase.sol",
"./contracts/test/TestTransformerDeployerTransformer.sol",
"./contracts/test/TestTransformerHost.sol",
"./contracts/test/TestUniswapV3Feature.sol",
"./contracts/test/TestWethTransformerHost.sol",
"./contracts/test/TestZeroExFeature.sol",
"./contracts/test/integration/TestCurve.sol",
"./contracts/test/integration/TestLiquidityProvider.sol",
"./contracts/test/integration/TestMooniswap.sol",
"./contracts/test/integration/TestUniswapV2Factory.sol",
"./contracts/test/integration/TestUniswapV2Pool.sol",
"./contracts/test/integration/TestUniswapV3Factory.sol",
"./contracts/test/integration/TestUniswapV3Pool.sol",
"./contracts/test/tokens/TestMintableERC1155Token.sol",
"./contracts/test/tokens/TestMintableERC20Token.sol",
"./contracts/test/tokens/TestMintableERC721Token.sol",
"./contracts/test/tokens/TestTokenSpenderERC20Token.sol",
"./contracts/test/tokens/TestWeth.sol"
],
"useDockerisedSolc": false, "useDockerisedSolc": false,
"isOfflineMode": false, "isOfflineMode": false,
"shouldSaveStandardInput": true, "shouldSaveStandardInput": true,

View File

@@ -31,6 +31,7 @@ import "../features/libs/LibNativeOrder.sol";
import "./bridges/IBridgeAdapter.sol"; import "./bridges/IBridgeAdapter.sol";
import "./Transformer.sol"; import "./Transformer.sol";
import "./LibERC20Transformer.sol"; import "./LibERC20Transformer.sol";
import "../IZeroEx.sol";
/// @dev A transformer that fills an ERC20 market sell/buy quote. /// @dev A transformer that fills an ERC20 market sell/buy quote.
/// This transformer shortcuts bridge orders and fills them directly /// This transformer shortcuts bridge orders and fills them directly
@@ -52,7 +53,8 @@ contract FillQuoteTransformer is
enum OrderType { enum OrderType {
Bridge, Bridge,
Limit, Limit,
Rfq Rfq,
Otc
} }
struct LimitOrderInfo { struct LimitOrderInfo {
@@ -69,6 +71,13 @@ contract FillQuoteTransformer is
uint256 maxTakerTokenFillAmount; uint256 maxTakerTokenFillAmount;
} }
struct OtcOrderInfo {
LibNativeOrder.OtcOrder order;
LibSignature.Signature signature;
// Maximum taker token amount of this limit order to fill.
uint256 maxTakerTokenFillAmount;
}
/// @dev Transform data to ABI-encode and pass into `transform()`. /// @dev Transform data to ABI-encode and pass into `transform()`.
struct TransformData { struct TransformData {
// Whether we are performing a market sell or buy. // Whether we are performing a market sell or buy.
@@ -86,6 +95,8 @@ contract FillQuoteTransformer is
LimitOrderInfo[] limitOrders; LimitOrderInfo[] limitOrders;
// Native RFQ orders. Sorted by fill sequence. // Native RFQ orders. Sorted by fill sequence.
RfqOrderInfo[] rfqOrders; RfqOrderInfo[] rfqOrders;
// Otc orders. Sorted by fill sequence.
OtcOrderInfo[] otcOrders;
// The sequence to fill the orders in. Each item will fill the next // The sequence to fill the orders in. Each item will fill the next
// order of that type in either `bridgeOrders`, `limitOrders`, // order of that type in either `bridgeOrders`, `limitOrders`,
@@ -123,7 +134,7 @@ contract FillQuoteTransformer is
uint256 soldAmount; uint256 soldAmount;
uint256 protocolFee; uint256 protocolFee;
uint256 takerTokenBalanceRemaining; uint256 takerTokenBalanceRemaining;
uint256[3] currentIndices; uint256[4] currentIndices;
OrderType currentOrderType; OrderType currentOrderType;
} }
@@ -147,12 +158,12 @@ contract FillQuoteTransformer is
IBridgeAdapter public immutable bridgeAdapter; IBridgeAdapter public immutable bridgeAdapter;
/// @dev The exchange proxy contract. /// @dev The exchange proxy contract.
INativeOrdersFeature public immutable zeroEx; IZeroEx public immutable zeroEx;
/// @dev Create this contract. /// @dev Create this contract.
/// @param bridgeAdapter_ The bridge adapter contract. /// @param bridgeAdapter_ The bridge adapter contract.
/// @param zeroEx_ The Exchange Proxy contract. /// @param zeroEx_ The Exchange Proxy contract.
constructor(IBridgeAdapter bridgeAdapter_, INativeOrdersFeature zeroEx_) constructor(IBridgeAdapter bridgeAdapter_, IZeroEx zeroEx_)
public public
Transformer() Transformer()
{ {
@@ -183,7 +194,8 @@ contract FillQuoteTransformer is
if (data.bridgeOrders.length if (data.bridgeOrders.length
+ data.limitOrders.length + data.limitOrders.length
+ data.rfqOrders.length != data.fillSequence.length + data.rfqOrders.length
+ data.otcOrders.length != data.fillSequence.length
) { ) {
LibTransformERC20RichErrors.InvalidTransformDataError( LibTransformERC20RichErrors.InvalidTransformDataError(
LibTransformERC20RichErrors.InvalidTransformDataErrorCode.INVALID_ARRAY_LENGTH, LibTransformERC20RichErrors.InvalidTransformDataErrorCode.INVALID_ARRAY_LENGTH,
@@ -198,9 +210,10 @@ contract FillQuoteTransformer is
// Approve the exchange proxy to spend our sell tokens if native orders // Approve the exchange proxy to spend our sell tokens if native orders
// are present. // are present.
if (data.limitOrders.length + data.rfqOrders.length != 0) { if (data.limitOrders.length + data.rfqOrders.length + data.otcOrders.length != 0) {
data.sellToken.approveIfBelow(address(zeroEx), data.fillAmount); data.sellToken.approveIfBelow(address(zeroEx), data.fillAmount);
// Compute the protocol fee if a limit order is present. // Compute the protocol fee if a limit order is present.
if (data.limitOrders.length != 0) { if (data.limitOrders.length != 0) {
state.protocolFee = uint256(zeroEx.getProtocolFeeMultiplier()) state.protocolFee = uint256(zeroEx.getProtocolFeeMultiplier())
.safeMul(tx.gasprice); .safeMul(tx.gasprice);
@@ -222,6 +235,7 @@ contract FillQuoteTransformer is
state.currentOrderType = OrderType(data.fillSequence[i]); state.currentOrderType = OrderType(data.fillSequence[i]);
uint256 orderIndex = state.currentIndices[uint256(state.currentOrderType)]; uint256 orderIndex = state.currentIndices[uint256(state.currentOrderType)];
// Fill the order. // Fill the order.
FillOrderResults memory results; FillOrderResults memory results;
if (state.currentOrderType == OrderType.Bridge) { if (state.currentOrderType == OrderType.Bridge) {
@@ -230,6 +244,8 @@ contract FillQuoteTransformer is
results = _fillLimitOrder(data.limitOrders[orderIndex], data, state); results = _fillLimitOrder(data.limitOrders[orderIndex], data, state);
} else if (state.currentOrderType == OrderType.Rfq) { } else if (state.currentOrderType == OrderType.Rfq) {
results = _fillRfqOrder(data.rfqOrders[orderIndex], data, state); results = _fillRfqOrder(data.rfqOrders[orderIndex], data, state);
} else if (state.currentOrderType == OrderType.Otc) {
results = _fillOtcOrder(data.otcOrders[orderIndex], data, state);
} else { } else {
revert("INVALID_ORDER_TYPE"); revert("INVALID_ORDER_TYPE");
} }
@@ -402,6 +418,41 @@ contract FillQuoteTransformer is
} catch {} } catch {}
} }
// Fill a single RFQ order.
function _fillOtcOrder(
OtcOrderInfo memory orderInfo,
TransformData memory data,
FillState memory state
)
private
returns (FillOrderResults memory results)
{
uint256 takerTokenFillAmount = LibSafeMathV06.min256(
_computeTakerTokenFillAmount(
data,
state,
orderInfo.order.takerAmount,
orderInfo.order.makerAmount,
0
),
orderInfo.maxTakerTokenFillAmount
);
try
zeroEx.fillOtcOrder
(
orderInfo.order,
orderInfo.signature,
takerTokenFillAmount.safeDowncastToUint128()
)
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
{
results.takerTokenSoldAmount = takerTokenFilledAmount;
results.makerTokenBoughtAmount = makerTokenFilledAmount;
} catch {
revert("FillQuoteTransformer/OTC_ORDER_FILL_FAILED");
}
}
// Compute the next taker token fill amount of a generic order. // Compute the next taker token fill amount of a generic order.
function _computeTakerTokenFillAmount( function _computeTakerTokenFillAmount(
TransformData memory data, TransformData memory data,

View File

@@ -30,7 +30,6 @@ import "./mixins/MixinAaveV2.sol";
import "./mixins/MixinNerve.sol"; import "./mixins/MixinNerve.sol";
import "./mixins/MixinPlatypus.sol"; import "./mixins/MixinPlatypus.sol";
import "./mixins/MixinUniswapV2.sol"; import "./mixins/MixinUniswapV2.sol";
import "./mixins/MixinWOOFi.sol";
import "./mixins/MixinZeroExBridge.sol"; import "./mixins/MixinZeroExBridge.sol";
contract AvalancheBridgeAdapter is contract AvalancheBridgeAdapter is
@@ -43,7 +42,6 @@ contract AvalancheBridgeAdapter is
MixinNerve, MixinNerve,
MixinPlatypus, MixinPlatypus,
MixinUniswapV2, MixinUniswapV2,
MixinWOOFi,
MixinZeroExBridge MixinZeroExBridge
{ {
constructor(IEtherTokenV06 weth) constructor(IEtherTokenV06 weth)
@@ -122,14 +120,6 @@ contract AvalancheBridgeAdapter is
sellAmount, sellAmount,
order.bridgeData order.bridgeData
); );
} else if (protocolId == BridgeProtocols.WOOFI) {
if (dryRun) { return (0, true); }
boughtAmount = _tradeWOOFi(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else if (protocolId == BridgeProtocols.UNKNOWN) { } else if (protocolId == BridgeProtocols.UNKNOWN) {
if (dryRun) { return (0, true); } if (dryRun) { return (0, true); }
boughtAmount = _tradeZeroExBridge( boughtAmount = _tradeZeroExBridge(

View File

@@ -29,7 +29,6 @@ import "./mixins/MixinKyberDmm.sol";
import "./mixins/MixinMooniswap.sol"; import "./mixins/MixinMooniswap.sol";
import "./mixins/MixinNerve.sol"; import "./mixins/MixinNerve.sol";
import "./mixins/MixinUniswapV2.sol"; import "./mixins/MixinUniswapV2.sol";
import "./mixins/MixinWOOFi.sol";
import "./mixins/MixinZeroExBridge.sol"; import "./mixins/MixinZeroExBridge.sol";
contract BSCBridgeAdapter is contract BSCBridgeAdapter is
@@ -41,7 +40,6 @@ contract BSCBridgeAdapter is
MixinMooniswap, MixinMooniswap,
MixinNerve, MixinNerve,
MixinUniswapV2, MixinUniswapV2,
MixinWOOFi,
MixinZeroExBridge MixinZeroExBridge
{ {
constructor(IEtherTokenV06 weth) constructor(IEtherTokenV06 weth)
@@ -113,14 +111,6 @@ contract BSCBridgeAdapter is
sellAmount, sellAmount,
order.bridgeData order.bridgeData
); );
} else if (protocolId == BridgeProtocols.WOOFI) {
if (dryRun) { return (0, true); }
boughtAmount = _tradeWOOFi(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else if (protocolId == BridgeProtocols.UNKNOWN) { } else if (protocolId == BridgeProtocols.UNKNOWN) {
if (dryRun) { return (0, true); } if (dryRun) { return (0, true); }
boughtAmount = _tradeZeroExBridge( boughtAmount = _tradeZeroExBridge(

View File

@@ -57,6 +57,4 @@ library BridgeProtocols {
uint128 internal constant PLATYPUS = 27; uint128 internal constant PLATYPUS = 27;
uint128 internal constant BANCORV3 = 28; uint128 internal constant BANCORV3 = 28;
uint128 internal constant VELODROME = 29; uint128 internal constant VELODROME = 29;
uint128 internal constant SYNTHETIX = 30;
uint128 internal constant WOOFI = 31;
} }

View File

@@ -37,10 +37,10 @@ import "./mixins/MixinDodoV2.sol";
import "./mixins/MixinKyberDmm.sol"; import "./mixins/MixinKyberDmm.sol";
import "./mixins/MixinLido.sol"; import "./mixins/MixinLido.sol";
import "./mixins/MixinMakerPSM.sol"; import "./mixins/MixinMakerPSM.sol";
import "./mixins/MixinMooniswap.sol";
import "./mixins/MixinMStable.sol"; import "./mixins/MixinMStable.sol";
import "./mixins/MixinNerve.sol"; import "./mixins/MixinNerve.sol";
import "./mixins/MixinShell.sol"; import "./mixins/MixinShell.sol";
import "./mixins/MixinSynthetix.sol";
import "./mixins/MixinUniswap.sol"; import "./mixins/MixinUniswap.sol";
import "./mixins/MixinUniswapV2.sol"; import "./mixins/MixinUniswapV2.sol";
import "./mixins/MixinUniswapV3.sol"; import "./mixins/MixinUniswapV3.sol";
@@ -63,10 +63,10 @@ contract EthereumBridgeAdapter is
MixinKyberDmm, MixinKyberDmm,
MixinLido, MixinLido,
MixinMakerPSM, MixinMakerPSM,
MixinMooniswap,
MixinMStable, MixinMStable,
MixinNerve, MixinNerve,
MixinShell, MixinShell,
MixinSynthetix,
MixinUniswap, MixinUniswap,
MixinUniswapV2, MixinUniswapV2,
MixinUniswapV3, MixinUniswapV3,
@@ -79,6 +79,7 @@ contract EthereumBridgeAdapter is
MixinCompound(weth) MixinCompound(weth)
MixinCurve(weth) MixinCurve(weth)
MixinLido(weth) MixinLido(weth)
MixinMooniswap(weth)
MixinUniswap(weth) MixinUniswap(weth)
{} {}
@@ -162,6 +163,14 @@ contract EthereumBridgeAdapter is
sellAmount, sellAmount,
order.bridgeData order.bridgeData
); );
} else if (protocolId == BridgeProtocols.MOONISWAP) {
if (dryRun) { return (0, true); }
boughtAmount = _tradeMooniswap(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else if (protocolId == BridgeProtocols.MSTABLE) { } else if (protocolId == BridgeProtocols.MSTABLE) {
if (dryRun) { return (0, true); } if (dryRun) { return (0, true); }
boughtAmount = _tradeMStable( boughtAmount = _tradeMStable(
@@ -251,12 +260,6 @@ contract EthereumBridgeAdapter is
sellAmount, sellAmount,
order.bridgeData order.bridgeData
); );
} else if (protocolId == BridgeProtocols.SYNTHETIX) {
if (dryRun) { return (0, true); }
boughtAmount = _tradeSynthetix(
sellAmount,
order.bridgeData
);
} else if (protocolId == BridgeProtocols.UNKNOWN) { } else if (protocolId == BridgeProtocols.UNKNOWN) {
if (dryRun) { return (0, true); } if (dryRun) { return (0, true); }
boughtAmount = _tradeZeroExBridge( boughtAmount = _tradeZeroExBridge(

View File

@@ -28,7 +28,6 @@ import "./mixins/MixinCurve.sol";
import "./mixins/MixinCurveV2.sol"; import "./mixins/MixinCurveV2.sol";
import "./mixins/MixinNerve.sol"; import "./mixins/MixinNerve.sol";
import "./mixins/MixinUniswapV2.sol"; import "./mixins/MixinUniswapV2.sol";
import "./mixins/MixinWOOFi.sol";
import "./mixins/MixinZeroExBridge.sol"; import "./mixins/MixinZeroExBridge.sol";
contract FantomBridgeAdapter is contract FantomBridgeAdapter is
@@ -39,7 +38,6 @@ contract FantomBridgeAdapter is
MixinCurveV2, MixinCurveV2,
MixinNerve, MixinNerve,
MixinUniswapV2, MixinUniswapV2,
MixinWOOFi,
MixinZeroExBridge MixinZeroExBridge
{ {
constructor(IEtherTokenV06 weth) constructor(IEtherTokenV06 weth)
@@ -105,14 +103,6 @@ contract FantomBridgeAdapter is
sellAmount, sellAmount,
order.bridgeData order.bridgeData
); );
} else if (protocolId == BridgeProtocols.WOOFI) {
if (dryRun) { return (0, true); }
boughtAmount = _tradeWOOFi(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else if (protocolId == BridgeProtocols.UNKNOWN) { } else if (protocolId == BridgeProtocols.UNKNOWN) {
if (dryRun) { return (0, true); } if (dryRun) { return (0, true); }
boughtAmount = _tradeZeroExBridge( boughtAmount = _tradeZeroExBridge(

View File

@@ -25,7 +25,6 @@ import "./BridgeProtocols.sol";
import "./mixins/MixinCurve.sol"; import "./mixins/MixinCurve.sol";
import "./mixins/MixinCurveV2.sol"; import "./mixins/MixinCurveV2.sol";
import "./mixins/MixinNerve.sol"; import "./mixins/MixinNerve.sol";
import "./mixins/MixinSynthetix.sol";
import "./mixins/MixinUniswapV3.sol"; import "./mixins/MixinUniswapV3.sol";
import "./mixins/MixinVelodrome.sol"; import "./mixins/MixinVelodrome.sol";
import "./mixins/MixinZeroExBridge.sol"; import "./mixins/MixinZeroExBridge.sol";
@@ -35,7 +34,6 @@ contract OptimismBridgeAdapter is
MixinCurve, MixinCurve,
MixinCurveV2, MixinCurveV2,
MixinNerve, MixinNerve,
MixinSynthetix,
MixinUniswapV3, MixinUniswapV3,
MixinVelodrome, MixinVelodrome,
MixinZeroExBridge MixinZeroExBridge
@@ -95,12 +93,6 @@ contract OptimismBridgeAdapter is
sellAmount, sellAmount,
order.bridgeData order.bridgeData
); );
} else if (protocolId == BridgeProtocols.SYNTHETIX) {
if (dryRun) { return (0, true); }
boughtAmount = _tradeSynthetix(
sellAmount,
order.bridgeData
);
} else if (protocolId == BridgeProtocols.UNKNOWN) { } else if (protocolId == BridgeProtocols.UNKNOWN) {
if (dryRun) { return (0, true); } if (dryRun) { return (0, true); }
boughtAmount = _tradeZeroExBridge( boughtAmount = _tradeZeroExBridge(

View File

@@ -34,7 +34,6 @@ import "./mixins/MixinMStable.sol";
import "./mixins/MixinNerve.sol"; import "./mixins/MixinNerve.sol";
import "./mixins/MixinUniswapV2.sol"; import "./mixins/MixinUniswapV2.sol";
import "./mixins/MixinUniswapV3.sol"; import "./mixins/MixinUniswapV3.sol";
import "./mixins/MixinWOOFi.sol";
import "./mixins/MixinZeroExBridge.sol"; import "./mixins/MixinZeroExBridge.sol";
contract PolygonBridgeAdapter is contract PolygonBridgeAdapter is
@@ -51,7 +50,6 @@ contract PolygonBridgeAdapter is
MixinNerve, MixinNerve,
MixinUniswapV2, MixinUniswapV2,
MixinUniswapV3, MixinUniswapV3,
MixinWOOFi,
MixinZeroExBridge MixinZeroExBridge
{ {
constructor(IEtherTokenV06 weth) constructor(IEtherTokenV06 weth)
@@ -159,14 +157,6 @@ contract PolygonBridgeAdapter is
sellAmount, sellAmount,
order.bridgeData order.bridgeData
); );
} else if (protocolId == BridgeProtocols.WOOFI) {
if (dryRun) { return (0, true); }
boughtAmount = _tradeWOOFi(
sellToken,
buyToken,
sellAmount,
order.bridgeData
);
} else if (protocolId == BridgeProtocols.UNKNOWN) { } else if (protocolId == BridgeProtocols.UNKNOWN) {
if (dryRun) { return (0, true); } if (dryRun) { return (0, true); }
boughtAmount = _tradeZeroExBridge( boughtAmount = _tradeZeroExBridge(

View File

@@ -1,99 +0,0 @@
// 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.5;
pragma experimental ABIEncoderV2;
interface ISynthetix {
// Ethereum Mainnet
function exchangeAtomically(
bytes32 sourceCurrencyKey,
uint256 sourceAmount,
bytes32 destinationCurrencyKey,
bytes32 trackingCode,
uint256 minAmount
) external returns (uint256 amountReceived);
// Optimism
function exchangeWithTracking(
bytes32 sourceCurrencyKey,
uint256 sourceAmount,
bytes32 destinationCurrencyKey,
address rewardAddress,
bytes32 trackingCode
) external returns (uint256 amountReceived);
}
contract MixinSynthetix {
address private constant rewardAddress =
0x5C80239D97E1eB216b5c3D8fBa5DE5Be5d38e4C9;
bytes32 constant trackingCode =
0x3058000000000000000000000000000000000000000000000000000000000000;
function _tradeSynthetix(uint256 sellAmount, bytes memory bridgeData)
public
returns (uint256 boughtAmount)
{
(
ISynthetix synthetix,
bytes32 sourceCurrencyKey,
bytes32 destinationCurrencyKey
) = abi.decode(
bridgeData,
(ISynthetix, bytes32, bytes32)
);
boughtAmount = exchange(
synthetix,
sourceCurrencyKey,
destinationCurrencyKey,
sellAmount
);
}
function exchange(
ISynthetix synthetix,
bytes32 sourceCurrencyKey,
bytes32 destinationCurrencyKey,
uint256 sellAmount
) internal returns (uint256 boughtAmount) {
uint256 chainId;
assembly {
chainId := chainid()
}
if (chainId == 1) {
boughtAmount = synthetix.exchangeAtomically(
sourceCurrencyKey,
sellAmount,
destinationCurrencyKey,
trackingCode,
0
);
} else {
boughtAmount = synthetix.exchangeWithTracking(
sourceCurrencyKey,
sellAmount,
destinationCurrencyKey,
rewardAddress,
trackingCode
);
}
}
}

View File

@@ -1,136 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "../IBridgeAdapter.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
/// @dev WooFI pool interface.
interface IWooPP {
function quoteToken() external view returns (address);
function sellBase(
address baseToken,
uint256 baseAmount,
uint256 minQuoteAmount,
address to,
address rebateTo
) external returns (uint256 quoteAmount);
function sellQuote(
address baseToken,
uint256 quoteAmount,
uint256 minBaseAmount,
address to,
address rebateTo
) external returns (uint256 baseAmount);
/// @dev Query the amount for selling the base token amount.
/// @param baseToken the base token to sell
/// @param baseAmount the amount to sell
/// @return quoteAmount the swapped quote amount
function querySellBase(
address baseToken,
uint256 baseAmount
) external view returns (uint256 quoteAmount);
}
contract MixinWOOFi{
using LibERC20TokenV06 for IERC20TokenV06;
using LibERC20TokenV06 for IEtherTokenV06;
using LibSafeMathV06 for uint256;
address constant rebateAddress = 0xBfdcBB4C05843163F491C24f9c0019c510786304;
// /// @dev Swaps an exact amount of input tokens for as many output tokens as possible.
// /// @param _amountIn Amount of input tokens to send
// /// @param _minAmountOut The minimum amount of output tokens that must be received for the transaction not to revert.
// /// @param _tokenIn Input token
// /// @param _tokenOut Output token
// /// @param _to recipient of tokens
// /// @param pool WOOFi pool where the swap will happen
function _tradeWOOFi(
IERC20TokenV06 sellToken,
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
)
public
returns (uint256 boughtAmount)
{
(IWooPP _pool) = abi.decode(bridgeData, (IWooPP));
uint256 beforeBalance = buyToken.balanceOf(address(this));
sellToken.approveIfBelow(address(_pool), sellAmount);
_swap(
sellAmount,
address(sellToken),
address(buyToken),
_pool
);
boughtAmount = buyToken.balanceOf(address(this)).safeSub(beforeBalance);
}
function _swap(
uint _amountIn,
address _tokenIn,
address _tokenOut,
IWooPP pool
) internal {
address quoteToken = pool.quoteToken();
if (_tokenIn == quoteToken) {
pool.sellQuote(
_tokenOut,
_amountIn,
1,
address(this),
rebateAddress
);
} else if (_tokenOut == quoteToken) {
pool.sellBase(
_tokenIn,
_amountIn,
1,
address(this),
rebateAddress
);
} else {
uint256 quoteAmount = pool.sellBase(
_tokenIn,
_amountIn,
0,
address(this),
rebateAddress
);
IERC20TokenV06(pool.quoteToken()).approveIfBelow(address(pool), quoteAmount);
pool.sellQuote(
_tokenOut,
quoteAmount,
1,
address(this),
rebateAddress
);
}
}
}

View File

@@ -1,30 +0,0 @@
// 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);
}
}

View File

@@ -1,8 +0,0 @@
[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

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contracts-zero-ex", "name": "@0x/contracts-zero-ex",
"version": "0.36.3", "version": "0.35.0",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -38,13 +38,12 @@
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", "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", "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", "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": { "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", "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",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(AbstractBridgeAdapter|AffiliateFeeTransformer|AvalancheBridgeAdapter|BSCBridgeAdapter|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeProtocols|CeloBridgeAdapter|CurveLiquidityProvider|ERC1155OrdersFeature|ERC165Feature|ERC721OrdersFeature|EthereumBridgeAdapter|FantomBridgeAdapter|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinERC1155Spender|FixinERC721Spender|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC1155OrdersFeature|IERC1155Token|IERC165Feature|IERC20Bridge|IERC20Transformer|IERC721OrdersFeature|IERC721Token|IFeature|IFeeRecipient|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|IPropertyValidator|ISimpleFunctionRegistryFeature|IStaking|ITakerCallback|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC1155OrdersStorage|LibERC20Transformer|LibERC721OrdersStorage|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNFTOrder|LibNFTOrdersRichErrors|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAaveV2|MixinBalancer|MixinBalancerV2|MixinBalancerV2Batch|MixinBancor|MixinBancorV3|MixinCompound|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinGMX|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinPlatypus|MixinShell|MixinSynthetix|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinVelodrome|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NFTOrders|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OptimismBridgeAdapter|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PolygonBridgeAdapter|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/@(AbstractBridgeAdapter|AffiliateFeeTransformer|AvalancheBridgeAdapter|BSCBridgeAdapter|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeProtocols|CeloBridgeAdapter|CurveLiquidityProvider|ERC1155OrdersFeature|ERC165Feature|ERC721OrdersFeature|EthereumBridgeAdapter|FantomBridgeAdapter|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinERC1155Spender|FixinERC721Spender|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC1155OrdersFeature|IERC1155Token|IERC165Feature|IERC20Bridge|IERC20Transformer|IERC721OrdersFeature|IERC721Token|IFeature|IFeeRecipient|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|IPropertyValidator|ISimpleFunctionRegistryFeature|IStaking|ITakerCallback|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC1155OrdersStorage|LibERC20Transformer|LibERC721OrdersStorage|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNFTOrder|LibNFTOrdersRichErrors|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAaveV2|MixinBalancer|MixinBalancerV2|MixinBalancerV2Batch|MixinBancor|MixinBancorV3|MixinCompound|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinGMX|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinPlatypus|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinVelodrome|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NFTOrders|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OptimismBridgeAdapter|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PolygonBridgeAdapter|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFeeRecipient|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC1155Token|TestMintableERC20Token|TestMintableERC721Token|TestMooniswap|TestNFTOrderPresigner|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestPropertyValidator|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -57,16 +56,15 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/zero-ex", "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/zero-ex",
"devDependencies": { "devDependencies": {
"@0x/abi-gen": "^5.8.0", "@0x/abi-gen": "^5.8.0",
"@0x/contract-addresses": "^6.19.2", "@0x/contract-addresses": "^6.16.0",
"@0x/contracts-erc20": "^3.3.36", "@0x/contracts-erc20": "^3.3.32",
"@0x/contracts-gen": "^2.0.46", "@0x/contracts-gen": "^2.0.46",
"@0x/contracts-test-utils": "^5.4.27", "@0x/contracts-test-utils": "^5.4.23",
"@0x/dev-utils": "^4.2.14", "@0x/dev-utils": "^4.2.14",
"@0x/order-utils": "^10.4.28", "@0x/order-utils": "^10.4.28",
"@0x/sol-compiler": "^4.8.1", "@0x/sol-compiler": "^4.8.1",
"@0x/ts-doc-gen": "^0.0.28", "@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.4", "@0x/tslint-config": "^4.1.4",
"@typechain/ethers-v5": "^10.0.0",
"@types/isomorphic-fetch": "^0.0.35", "@types/isomorphic-fetch": "^0.0.35",
"@types/lodash": "4.14.104", "@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7", "@types/mocha": "^5.2.7",
@@ -80,13 +78,12 @@
"solhint": "^1.4.1", "solhint": "^1.4.1",
"truffle": "^5.0.32", "truffle": "^5.0.32",
"tslint": "5.11.0", "tslint": "5.11.0",
"typechain": "^8.0.0",
"typedoc": "~0.16.11", "typedoc": "~0.16.11",
"typescript": "4.6.3" "typescript": "4.6.3"
}, },
"dependencies": { "dependencies": {
"@0x/base-contract": "^6.5.0", "@0x/base-contract": "^6.5.0",
"@0x/protocol-utils": "^11.16.3", "@0x/protocol-utils": "^11.15.0",
"@0x/subproviders": "^6.6.5", "@0x/subproviders": "^6.6.5",
"@0x/types": "^3.3.6", "@0x/types": "^3.3.6",
"@0x/typescript-typings": "^5.3.1", "@0x/typescript-typings": "^5.3.1",

View File

@@ -124,7 +124,6 @@ import * as MixinMStable from '../test/generated-artifacts/MixinMStable.json';
import * as MixinNerve from '../test/generated-artifacts/MixinNerve.json'; import * as MixinNerve from '../test/generated-artifacts/MixinNerve.json';
import * as MixinPlatypus from '../test/generated-artifacts/MixinPlatypus.json'; import * as MixinPlatypus from '../test/generated-artifacts/MixinPlatypus.json';
import * as MixinShell from '../test/generated-artifacts/MixinShell.json'; import * as MixinShell from '../test/generated-artifacts/MixinShell.json';
import * as MixinSynthetix from '../test/generated-artifacts/MixinSynthetix.json';
import * as MixinUniswap from '../test/generated-artifacts/MixinUniswap.json'; import * as MixinUniswap from '../test/generated-artifacts/MixinUniswap.json';
import * as MixinUniswapV2 from '../test/generated-artifacts/MixinUniswapV2.json'; import * as MixinUniswapV2 from '../test/generated-artifacts/MixinUniswapV2.json';
import * as MixinUniswapV3 from '../test/generated-artifacts/MixinUniswapV3.json'; import * as MixinUniswapV3 from '../test/generated-artifacts/MixinUniswapV3.json';
@@ -348,7 +347,6 @@ export const artifacts = {
MixinNerve: MixinNerve as ContractArtifact, MixinNerve: MixinNerve as ContractArtifact,
MixinPlatypus: MixinPlatypus as ContractArtifact, MixinPlatypus: MixinPlatypus as ContractArtifact,
MixinShell: MixinShell as ContractArtifact, MixinShell: MixinShell as ContractArtifact,
MixinSynthetix: MixinSynthetix as ContractArtifact,
MixinUniswap: MixinUniswap as ContractArtifact, MixinUniswap: MixinUniswap as ContractArtifact,
MixinUniswapV2: MixinUniswapV2 as ContractArtifact, MixinUniswapV2: MixinUniswapV2 as ContractArtifact,
MixinUniswapV3: MixinUniswapV3 as ContractArtifact, MixinUniswapV3: MixinUniswapV3 as ContractArtifact,

View File

@@ -12,10 +12,13 @@ import {
FillQuoteTransformerData, FillQuoteTransformerData,
FillQuoteTransformerLimitOrderInfo, FillQuoteTransformerLimitOrderInfo,
FillQuoteTransformerOrderType as OrderType, FillQuoteTransformerOrderType as OrderType,
FillQuoteTransformerOtcOrderInfo,
FillQuoteTransformerRfqOrderInfo, FillQuoteTransformerRfqOrderInfo,
FillQuoteTransformerSide as Side, FillQuoteTransformerSide as Side,
LimitOrder, LimitOrder,
LimitOrderFields, LimitOrderFields,
OtcOrder,
OtcOrderFields,
RfqOrder, RfqOrder,
RfqOrderFields, RfqOrderFields,
Signature, Signature,
@@ -26,7 +29,7 @@ import * as _ from 'lodash';
import { artifacts } from '../artifacts'; import { artifacts } from '../artifacts';
import { TestFillQuoteTransformerBridgeContract } from '../generated-wrappers/test_fill_quote_transformer_bridge'; import { TestFillQuoteTransformerBridgeContract } from '../generated-wrappers/test_fill_quote_transformer_bridge';
import { getRandomLimitOrder, getRandomRfqOrder } from '../utils/orders'; import { getRandomLimitOrder, getRandomOtcOrder, getRandomRfqOrder } from '../utils/orders';
import { import {
EthereumBridgeAdapterContract, EthereumBridgeAdapterContract,
FillQuoteTransformerContract, FillQuoteTransformerContract,
@@ -142,6 +145,18 @@ blockchainTests.resets('FillQuoteTransformer', env => {
}; };
} }
function createOtcOrder(fields: Partial<OtcOrderFields> = {}): OtcOrder {
return getRandomOtcOrder({
makerToken: makerToken.address,
takerToken: takerToken.address,
makerAmount: getRandomInteger('0.1e18', '1e18'),
takerAmount: getRandomInteger('0.1e18', '1e18'),
maker,
taker,
...fields,
});
}
function createOrderSignature(preFilledTakerAmount: Numberish = 0): Signature { function createOrderSignature(preFilledTakerAmount: Numberish = 0): Signature {
return { return {
// The r field of the signature is the pre-filled amount. // The r field of the signature is the pre-filled amount.
@@ -254,6 +269,24 @@ blockchainTests.resets('FillQuoteTransformer', env => {
}; };
} }
function fillOtcOrder(oi: FillQuoteTransformerOtcOrderInfo): FillOrderResults {
const preFilledTakerAmount = orderSignatureToPreFilledTakerAmount(oi.signature);
if (preFilledTakerAmount.gte(oi.order.takerAmount) || preFilledTakerAmount.eq(REVERT_AMOUNT)) {
return EMPTY_FILL_ORDER_RESULTS;
}
const takerTokenFillAmount = BigNumber.min(
computeTakerTokenFillAmount(oi.order.takerAmount, oi.order.makerAmount),
oi.order.takerAmount.minus(preFilledTakerAmount),
oi.maxTakerTokenFillAmount,
);
const fillRatio = takerTokenFillAmount.div(oi.order.takerAmount);
return {
...EMPTY_FILL_ORDER_RESULTS,
takerTokenSoldAmount: takerTokenFillAmount,
makerTokenBoughtAmount: fillRatio.times(oi.order.makerAmount).integerValue(BigNumber.ROUND_DOWN),
};
}
function fillRfqOrder(oi: FillQuoteTransformerRfqOrderInfo): FillOrderResults { function fillRfqOrder(oi: FillQuoteTransformerRfqOrderInfo): FillOrderResults {
const preFilledTakerAmount = orderSignatureToPreFilledTakerAmount(oi.signature); const preFilledTakerAmount = orderSignatureToPreFilledTakerAmount(oi.signature);
if (preFilledTakerAmount.gte(oi.order.takerAmount) || preFilledTakerAmount.eq(REVERT_AMOUNT)) { if (preFilledTakerAmount.gte(oi.order.takerAmount) || preFilledTakerAmount.eq(REVERT_AMOUNT)) {
@@ -296,6 +329,11 @@ blockchainTests.resets('FillQuoteTransformer', env => {
results = fillLimitOrder(data.limitOrders[orderIndices[orderType]]); results = fillLimitOrder(data.limitOrders[orderIndices[orderType]]);
} }
break; break;
case OrderType.Otc:
{
results = fillOtcOrder(data.otcOrders[orderIndices[orderType]]);
}
break;
case OrderType.Rfq: case OrderType.Rfq:
{ {
results = fillRfqOrder(data.rfqOrders[orderIndices[orderType]]); results = fillRfqOrder(data.rfqOrders[orderIndices[orderType]]);
@@ -393,6 +431,7 @@ blockchainTests.resets('FillQuoteTransformer', env => {
buyToken: makerToken.address, buyToken: makerToken.address,
bridgeOrders: [], bridgeOrders: [],
limitOrders: [], limitOrders: [],
otcOrders: [],
rfqOrders: [], rfqOrders: [],
fillSequence: [], fillSequence: [],
fillAmount: MAX_UINT256, fillAmount: MAX_UINT256,
@@ -447,7 +486,7 @@ blockchainTests.resets('FillQuoteTransformer', env => {
} }
describe('sell quotes', () => { describe('sell quotes', () => {
it('can fully sell to a single bridge order with -1 fillAmount', async () => { it.only('can fully sell to a single bridge order with -1 fillAmount', async () => {
const bridgeOrders = [createBridgeOrder()]; const bridgeOrders = [createBridgeOrder()];
const data = createTransformData({ const data = createTransformData({
bridgeOrders, bridgeOrders,
@@ -624,6 +663,24 @@ blockchainTests.resets('FillQuoteTransformer', env => {
return assertFinalBalancesAsync(qfr); return assertFinalBalancesAsync(qfr);
}); });
it('can fully sell to a single OTC order', async () => {
const otcOrders = [createOtcOrder()];
const data = createTransformData({
otcOrders: otcOrders.map(o => ({
order: o,
maxTakerTokenFillAmount: MAX_UINT256,
signature: createOrderSignature(),
})),
fillAmount: BigNumber.sum(...otcOrders.map(o => o.takerAmount)),
fillSequence: otcOrders.map(() => OrderType.Rfq),
});
const qfr = getExpectedQuoteFillResults(data, createSimulationState());
await executeTransformAsync({
data,
takerTokenBalance: qfr.takerTokensSpent,
});
return assertFinalBalancesAsync(qfr);
});
it('can fully sell to a single RFQ order', async () => { it('can fully sell to a single RFQ order', async () => {
const rfqOrders = [createRfqOrder()]; const rfqOrders = [createRfqOrder()];
const data = createTransformData({ const data = createTransformData({
@@ -1117,6 +1174,30 @@ blockchainTests.resets('FillQuoteTransformer', env => {
return assertFinalBalancesAsync(qfr); return assertFinalBalancesAsync(qfr);
}); });
it('can fully buy to a single OTC order', async () => {
const otcOrders = [createOtcOrder()];
const totalTakerTokens = BigNumber.sum(...otcOrders.map(o => o.takerAmount));
const data = createTransformData({
side: Side.Buy,
otcOrders: otcOrders.map(o => ({
order: o,
maxTakerTokenFillAmount: MAX_UINT256,
signature: createOrderSignature(),
})),
fillAmount: BigNumber.sum(...otcOrders.map(o => o.makerAmount)),
fillSequence: otcOrders.map(() => OrderType.Rfq),
});
const qfr = getExpectedQuoteFillResults(
data,
createSimulationState({ takerTokenBalance: totalTakerTokens }),
);
await executeTransformAsync({
data,
takerTokenBalance: qfr.takerTokensSpent,
});
return assertFinalBalancesAsync(qfr);
});
it('can fully buy to a single RFQ order', async () => { it('can fully buy to a single RFQ order', async () => {
const rfqOrders = [createRfqOrder()]; const rfqOrders = [createRfqOrder()];
const totalTakerTokens = BigNumber.sum(...rfqOrders.map(o => o.takerAmount)); const totalTakerTokens = BigNumber.sum(...rfqOrders.map(o => o.takerAmount));

View File

@@ -122,7 +122,6 @@ export * from '../test/generated-wrappers/mixin_mooniswap';
export * from '../test/generated-wrappers/mixin_nerve'; export * from '../test/generated-wrappers/mixin_nerve';
export * from '../test/generated-wrappers/mixin_platypus'; export * from '../test/generated-wrappers/mixin_platypus';
export * from '../test/generated-wrappers/mixin_shell'; export * from '../test/generated-wrappers/mixin_shell';
export * from '../test/generated-wrappers/mixin_synthetix';
export * from '../test/generated-wrappers/mixin_uniswap'; export * from '../test/generated-wrappers/mixin_uniswap';
export * from '../test/generated-wrappers/mixin_uniswap_v2'; export * from '../test/generated-wrappers/mixin_uniswap_v2';
export * from '../test/generated-wrappers/mixin_uniswap_v3'; export * from '../test/generated-wrappers/mixin_uniswap_v3';

View File

@@ -161,7 +161,6 @@
"test/generated-artifacts/MixinNerve.json", "test/generated-artifacts/MixinNerve.json",
"test/generated-artifacts/MixinPlatypus.json", "test/generated-artifacts/MixinPlatypus.json",
"test/generated-artifacts/MixinShell.json", "test/generated-artifacts/MixinShell.json",
"test/generated-artifacts/MixinSynthetix.json",
"test/generated-artifacts/MixinUniswap.json", "test/generated-artifacts/MixinUniswap.json",
"test/generated-artifacts/MixinUniswapV2.json", "test/generated-artifacts/MixinUniswapV2.json",
"test/generated-artifacts/MixinUniswapV3.json", "test/generated-artifacts/MixinUniswapV3.json",

View File

@@ -1,74 +1,12 @@
[ [
{
"timestamp": 1660093941,
"version": "16.66.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "16.66.2",
"changes": [
{
"note": "Upgrade dependency",
"pr": 543
}
],
"timestamp": 1660073235
},
{
"version": "16.66.1",
"changes": [
{
"note": "Upgrade dependency",
"pr": 538
}
],
"timestamp": 1659926840
},
{
"version": "16.66.0",
"changes": [
{
"note": "Add WOOFi support",
"pr": 513
}
],
"timestamp": 1659750766
},
{
"version": "16.65.0",
"changes": [
{
"note": "Use 0x gas api instead of eth gas station api",
"pr": 532
}
],
"timestamp": 1659391840
},
{ {
"version": "16.64.0", "version": "16.64.0",
"changes": [ "changes": [
{ {
"note": "Refactor `TokenAdjacency` and `TokenAdjacencyBuilder`", "note": "Add support for OTC orders in the fillQuoteTransformer",
"pr": 517 "pr": 516
},
{
"note": "Add Synthetix support`",
"pr": 518
},
{
"note": "Replace Beethoven X subgraph URL",
"pr": 519
},
{
"note": "Remove Mooniswap on Ethereum mainnet",
"pr": 529
} }
], ]
"timestamp": 1658950329
}, },
{ {
"version": "16.63.1", "version": "16.63.1",

View File

@@ -5,33 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v16.66.3 - _August 10, 2022_
* Dependencies updated
## v16.66.2 - _August 9, 2022_
* Upgrade dependency (#543)
## v16.66.1 - _August 8, 2022_
* Upgrade dependency (#538)
## v16.66.0 - _August 6, 2022_
* Add WOOFi support (#513)
## 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)
* Add Synthetix support` (#518)
* Replace Beethoven X subgraph URL (#519)
* Remove Mooniswap on Ethereum mainnet (#529)
## v16.63.1 - _July 12, 2022_ ## v16.63.1 - _July 12, 2022_
* Better error handling for balancer cache (#515) * Better error handling for balancer cache (#515)

View File

@@ -39,13 +39,11 @@ import "./MooniswapSampler.sol";
import "./NativeOrderSampler.sol"; import "./NativeOrderSampler.sol";
import "./PlatypusSampler.sol"; import "./PlatypusSampler.sol";
import "./ShellSampler.sol"; import "./ShellSampler.sol";
import "./SynthetixSampler.sol";
import "./TwoHopSampler.sol"; import "./TwoHopSampler.sol";
import "./UniswapSampler.sol"; import "./UniswapSampler.sol";
import "./UniswapV2Sampler.sol"; import "./UniswapV2Sampler.sol";
import "./UniswapV3Sampler.sol"; import "./UniswapV3Sampler.sol";
import "./VelodromeSampler.sol"; import "./VelodromeSampler.sol";
import "./WooPPSampler.sol";
import "./UtilitySampler.sol"; import "./UtilitySampler.sol";
@@ -69,13 +67,11 @@ contract ERC20BridgeSampler is
NativeOrderSampler, NativeOrderSampler,
PlatypusSampler, PlatypusSampler,
ShellSampler, ShellSampler,
SynthetixSampler,
TwoHopSampler, TwoHopSampler,
UniswapSampler, UniswapSampler,
UniswapV2Sampler, UniswapV2Sampler,
UniswapV3Sampler, UniswapV3Sampler,
VelodromeSampler, VelodromeSampler,
WooPPSampler,
UtilitySampler UtilitySampler
{ {

View File

@@ -1,173 +0,0 @@
// 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;
pragma experimental ABIEncoderV2;
interface IReadProxyAddressResolver {
function target() external view returns (address);
}
interface IAddressResolver {
function getAddress(bytes32 name) external view returns (address);
}
interface IExchanger {
// Ethereum Mainnet
function getAmountsForAtomicExchange(
uint256 sourceAmount,
bytes32 sourceCurrencyKey,
bytes32 destinationCurrencyKey
)
external
view
returns (
uint256 amountReceived,
uint256 fee,
uint256 exchangeFeeRate
);
// Optimism
function getAmountsForExchange(
uint256 sourceAmount,
bytes32 sourceCurrencyKey,
bytes32 destinationCurrencyKey
)
external
view
returns (
uint256 amountReceived,
uint256 fee,
uint256 exchangeFeeRate
);
}
contract SynthetixSampler {
/// @dev Sample sell quotes from Synthetix Atomic Swap.
/// @param takerTokenSymbol Symbol (currency key) of the taker token (what to sell).
/// @param makerTokenSymbol Symbol (currency key) of the maker token (what to buy).
/// @param takerTokenAmounts Taker token sell amount for each sample (sorted in ascending order).
/// @return synthetix Synthetix address.
/// @return makerTokenAmounts Maker amounts bought at each taker token amount.
function sampleSellsFromSynthetix(
IReadProxyAddressResolver readProxy,
bytes32 takerTokenSymbol,
bytes32 makerTokenSymbol,
uint256[] memory takerTokenAmounts
) public view returns (address synthetix, uint256[] memory makerTokenAmounts) {
synthetix = getSynthetixAddress(readProxy);
uint256 numSamples = takerTokenAmounts.length;
makerTokenAmounts = new uint256[](numSamples);
if (numSamples == 0) {
return (synthetix, makerTokenAmounts);
}
makerTokenAmounts[0] = exchange(
readProxy,
takerTokenAmounts[0],
takerTokenSymbol,
makerTokenSymbol
);
// Synthetix atomic swap has a fixed rate. Calculate the rest based on the first value (and save gas).
for (uint256 i = 1; i < numSamples; i++) {
makerTokenAmounts[i] =
(makerTokenAmounts[0] * takerTokenAmounts[i]) /
takerTokenAmounts[0];
}
}
/// @dev Sample buy quotes from Synthetix Atomic Swap.
/// @param takerTokenSymbol Symbol (currency key) of the taker token (what to sell).
/// @param makerTokenSymbol Symbol (currency key) of the maker token (what to buy).
/// @param makerTokenAmounts Maker token buy amount for each sample (sorted in ascending order).
/// @return synthetix Synthetix address.
/// @return takerTokenAmounts Taker amounts sold at each maker token amount.
function sampleBuysFromSynthetix(
IReadProxyAddressResolver readProxy,
bytes32 takerTokenSymbol,
bytes32 makerTokenSymbol,
uint256[] memory makerTokenAmounts
) public view returns (address synthetix, uint256[] memory takerTokenAmounts) {
synthetix = getSynthetixAddress(readProxy);
// Since Synthetix atomic have a fixed rate, we can pick any reasonablely size takerTokenAmount (fixed to 1 ether here) and calculate the rest.
uint256 amountReceivedForEther = exchange(
readProxy,
1 ether,
takerTokenSymbol,
makerTokenSymbol
);
uint256 numSamples = makerTokenAmounts.length;
takerTokenAmounts = new uint256[](numSamples);
for (uint256 i = 0; i < numSamples; i++) {
takerTokenAmounts[i] =
(1 ether * makerTokenAmounts[i]) /
amountReceivedForEther;
}
}
function exchange(
IReadProxyAddressResolver readProxy,
uint256 sourceAmount,
bytes32 sourceCurrencyKey,
bytes32 destinationCurrencyKey
) private view returns (uint256 amountReceived) {
IExchanger exchanger = getExchanger(readProxy);
uint256 chainId;
assembly {
chainId := chainid()
}
if (chainId == 1) {
(amountReceived, , ) = exchanger.getAmountsForAtomicExchange(
sourceAmount,
sourceCurrencyKey,
destinationCurrencyKey
);
} else {
(amountReceived, , ) = exchanger.getAmountsForExchange(
sourceAmount,
sourceCurrencyKey,
destinationCurrencyKey
);
}
}
function getSynthetixAddress(IReadProxyAddressResolver readProxy)
private
view
returns (address)
{
return IAddressResolver(readProxy.target()).getAddress("Synthetix");
}
function getExchanger(IReadProxyAddressResolver readProxy)
private
view
returns (IExchanger)
{
return
IExchanger(
IAddressResolver(readProxy.target()).getAddress("Exchanger")
);
}
}

View File

@@ -1,121 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "./SamplerUtils.sol";
import "./ApproximateBuys.sol";
interface IWooPP {
/// @dev get the quote token address (immutable)
/// @return address of quote token
function quoteToken() external view returns (address);
/// @dev Query the amount for selling the base token amount.
/// @param baseToken the base token to sell
/// @param baseAmount the amount to sell
/// @return quoteAmount the swapped quote amount
function querySellBase(address baseToken, uint256 baseAmount) external view returns (uint256 quoteAmount);
/// @dev Query the amount for selling the quote token.
/// @param baseToken the base token to receive (buy)
/// @param quoteAmount the amount to sell
/// @return baseAmount the swapped base token amount
function querySellQuote(address baseToken, uint256 quoteAmount) external view returns (uint256 baseAmount);
}
contract WooPPSampler is SamplerUtils, ApproximateBuys{
function query(
uint amountIn,
address tokenIn,
address tokenOut,
address pool
) internal view returns (uint256 amountOut) {
if (amountIn == 0) {
return 0;
}
address quoteToken = IWooPP(pool).quoteToken();
if (tokenIn == quoteToken) {
amountOut = IWooPP(pool).querySellQuote(tokenOut, amountIn);
} else if (tokenOut == quoteToken) {
amountOut = IWooPP(pool).querySellBase(tokenIn, amountIn);
} else {
uint quoteAmount = IWooPP(pool).querySellBase(tokenIn, amountIn);
amountOut = IWooPP(pool).querySellQuote(tokenOut, quoteAmount);
}
}
/// @dev Sample sell quotes from WooFI.
/// @param pool Address of the pool we are sampling from
/// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy).
/// @param takerTokenAmounts Taker token sell amount for each sample (sorted in ascending order).
/// @return makerTokenAmounts Maker amounts bought at each taker token
/// amount.
function sampleSellsFromWooPP(
address pool,
address takerToken,
address makerToken,
uint256[] memory takerTokenAmounts
)
public
view
returns (uint256[] memory makerTokenAmounts)
{
uint256 numSamples = takerTokenAmounts.length;
makerTokenAmounts = new uint256[](numSamples);
for (uint256 i = 0; i < numSamples; i++) {
makerTokenAmounts[i] = query(takerTokenAmounts[i], takerToken, makerToken, pool);
if (makerTokenAmounts[i] == 0) {
break;
}
}
}
/// @dev Sample buy quotes from WooFI.
/// @param pool Address of the pool we are sampling from
/// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy).
/// @param makerTokenAmounts Maker token sell amount for each sample (sorted in ascending order).
/// @return takerTokenAmounts Taker amounts bought at each taker token
/// amount.
function sampleBuysFromWooPP(
address pool,
address takerToken,
address makerToken,
uint256[] memory makerTokenAmounts
)
public
view
returns (uint256[] memory takerTokenAmounts)
{
uint256 numSamples = makerTokenAmounts.length;
takerTokenAmounts = _sampleApproximateBuys(
ApproximateBuyQuoteOpts({
takerTokenData: abi.encode(pool,takerToken, makerToken),
makerTokenData: abi.encode(pool, makerToken, takerToken),
getSellQuoteCallback: _sampleSellForApproximateBuyFromWoofi
}),
makerTokenAmounts
);
}
function _sampleSellForApproximateBuyFromWoofi(
bytes memory takerTokenData,
bytes memory makerTokenData,
uint256 sellAmount
) internal view returns (uint256) {
(address _pool, address _takerToken, address _makerToken) = abi.decode(takerTokenData, (address, address, address));
(bool success, bytes memory resultData) = address(this).staticcall(abi.encodeWithSelector(
this.sampleSellsFromWooPP.selector,
_pool,
_takerToken,
_makerToken,
_toSingleValueArray(sellAmount)
));
if(!success) {
return 0;
}
return abi.decode(resultData, (uint256[]))[0];
}
}

View File

@@ -1897,7 +1897,7 @@ ___
# Interface: SwapQuoteRequestOpts # Interface: SwapQuoteRequestOpts
slippagePercentage: The percentage buffer to add to account for slippage. Affects max ETH price estimates. Defaults to 0.01 (1%). slippagePercentage: The percentage buffer to add to account for slippage. Affects max ETH price estimates. Defaults to 0.2 (20%).
gasPrice: gas price to determine protocolFee amount, default to ethGasStation fast amount gasPrice: gas price to determine protocolFee amount, default to ethGasStation fast amount

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/asset-swapper", "name": "@0x/asset-swapper",
"version": "16.66.3", "version": "16.63.1",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -40,7 +40,7 @@
"config": { "config": {
"publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker", "publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BalancerV2BatchSampler|BalancerV2Common|BalancerV2Sampler|BancorSampler|BancorV3Sampler|CompoundSampler|CurveSampler|DODOSampler|DODOV2Sampler|ERC20BridgeSampler|FakeTaker|GMXSampler|IBalancer|IBalancerV2Vault|IBancor|IBancorV3|ICurve|IGMX|IMStable|IMooniswap|IMultiBridge|IPlatypus|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberDmmSampler|LidoSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|NativeOrderSampler|PlatypusSampler|SamplerUtils|ShellSampler|SynthetixSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UniswapV3Sampler|UtilitySampler|VelodromeSampler|WooPPSampler).json", "abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BalancerV2BatchSampler|BalancerV2Common|BalancerV2Sampler|BancorSampler|BancorV3Sampler|CompoundSampler|CurveSampler|DODOSampler|DODOV2Sampler|ERC20BridgeSampler|FakeTaker|GMXSampler|IBalancer|IBalancerV2Vault|IBancor|IBancorV3|ICurve|IGMX|IMStable|IMooniswap|IMultiBridge|IPlatypus|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberDmmSampler|LidoSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|NativeOrderSampler|PlatypusSampler|SamplerUtils|ShellSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UniswapV3Sampler|UtilitySampler|VelodromeSampler).json",
"postpublish": { "postpublish": {
"assets": [] "assets": []
} }
@@ -61,17 +61,17 @@
"dependencies": { "dependencies": {
"@0x/assert": "^3.0.34", "@0x/assert": "^3.0.34",
"@0x/base-contract": "^6.5.0", "@0x/base-contract": "^6.5.0",
"@0x/contract-addresses": "^6.19.2", "@0x/contract-addresses": "^6.16.0",
"@0x/contract-wrappers": "^13.20.8", "@0x/contract-wrappers": "^13.20.4",
"@0x/contracts-erc20": "^3.3.36", "@0x/contracts-erc20": "^3.3.32",
"@0x/contracts-zero-ex": "^0.36.3", "@0x/contracts-zero-ex": "^0.35.0",
"@0x/dev-utils": "^4.2.14", "@0x/dev-utils": "^4.2.14",
"@0x/fast-abi": "^0.0.5",
"@0x/json-schemas": "^6.4.4", "@0x/json-schemas": "^6.4.4",
"@0x/neon-router": "^0.3.5", "@0x/neon-router": "^0.3.5",
"@0x/protocol-utils": "^11.16.3", "@0x/protocol-utils": "^11.15.0",
"@0x/quote-server": "^8.0.0", "@0x/quote-server": "^6.0.6",
"@0x/types": "^3.3.6", "@0x/types": "^3.3.6",
"@0x/typescript-typings": "^5.3.1",
"@0x/utils": "^6.5.3", "@0x/utils": "^6.5.3",
"@0x/web3-wrapper": "^7.6.5", "@0x/web3-wrapper": "^7.6.5",
"@balancer-labs/sdk": "0.1.6", "@balancer-labs/sdk": "0.1.6",
@@ -85,22 +85,30 @@
"axios-mock-adapter": "^1.19.0", "axios-mock-adapter": "^1.19.0",
"balancer-labs-sor-v1": "npm:@balancer-labs/sor@0.3.2", "balancer-labs-sor-v1": "npm:@balancer-labs/sor@0.3.2",
"cream-sor": "^0.3.3", "cream-sor": "^0.3.3",
"decimal.js": "^10.2.0",
"ethereum-types": "^3.7.0", "ethereum-types": "^3.7.0",
"ethereumjs-util": "^7.0.10",
"fast-abi": "^0.0.4",
"graphql": "^15.4.0", "graphql": "^15.4.0",
"graphql-request": "^3.4.0", "graphql-request": "^3.4.0",
"heartbeats": "^5.0.1", "heartbeats": "^5.0.1",
"lodash": "^4.17.15", "lodash": "^4.17.11"
"msw": "^0.44.2"
}, },
"devDependencies": { "devDependencies": {
"@0x/abi-gen": "^5.8.0", "@0x/abi-gen": "^5.8.0",
"@0x/contracts-asset-proxy": "^3.7.19",
"@0x/contracts-exchange": "^3.2.38",
"@0x/contracts-exchange-libs": "^4.3.37",
"@0x/contracts-gen": "^2.0.46", "@0x/contracts-gen": "^2.0.46",
"@0x/contracts-test-utils": "^5.4.27", "@0x/contracts-test-utils": "^5.4.23",
"@0x/contracts-utils": "^4.8.13",
"@0x/mesh-rpc-client": "^9.4.2",
"@0x/sol-compiler": "^4.8.1", "@0x/sol-compiler": "^4.8.1",
"@0x/subproviders": "^6.6.5", "@0x/subproviders": "^6.6.5",
"@0x/ts-doc-gen": "^0.0.28", "@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.4", "@0x/tslint-config": "^4.1.4",
"@types/lodash": "4.14.137", "@0x/types": "^3.3.6",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7", "@types/mocha": "^5.2.7",
"@types/node": "12.12.54", "@types/node": "12.12.54",
"chai": "^4.0.1", "chai": "^4.0.1",
@@ -108,11 +116,12 @@
"chai-bignumber": "^3.0.0", "chai-bignumber": "^3.0.0",
"dirty-chai": "^2.0.1", "dirty-chai": "^2.0.1",
"gitpkg": "https://github.com/0xProject/gitpkg.git", "gitpkg": "https://github.com/0xProject/gitpkg.git",
"make-promises-safe": "^1.1.0",
"mocha": "^6.2.0", "mocha": "^6.2.0",
"npm-run-all": "^4.1.2", "npm-run-all": "^4.1.2",
"nyc": "^11.0.1", "nyc": "^11.0.1",
"shx": "^0.2.2", "shx": "^0.2.2",
"tslint": "^6.1.3", "tslint": "5.11.0",
"typedoc": "~0.16.11", "typedoc": "~0.16.11",
"typemoq": "^2.1.0", "typemoq": "^2.1.0",
"typescript": "4.6.3" "typescript": "4.6.3"

View File

@@ -19,7 +19,7 @@ import {
DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID, DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID,
} from './utils/market_operation_utils/constants'; } from './utils/market_operation_utils/constants';
const ZERO_EX_GAS_API_URL = 'https://gas.api.0x.org/source/median'; const ETH_GAS_STATION_API_URL = 'https://ethgasstation.info/api/ethgasAPI.json';
const NULL_BYTES = '0x'; const NULL_BYTES = '0x';
const NULL_ERC20_ASSET_DATA = '0xf47261b00000000000000000000000000000000000000000000000000000000000000000'; const NULL_ERC20_ASSET_DATA = '0xf47261b00000000000000000000000000000000000000000000000000000000000000000';
const NULL_ADDRESS = '0x0000000000000000000000000000000000000000'; const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
@@ -48,7 +48,7 @@ const DEFAULT_SWAP_QUOTER_OPTS: SwapQuoterOpts = {
orderRefreshIntervalMs: 10000, // 10 seconds orderRefreshIntervalMs: 10000, // 10 seconds
...DEFAULT_ORDER_PRUNER_OPTS, ...DEFAULT_ORDER_PRUNER_OPTS,
samplerGasLimit: 500e6, samplerGasLimit: 500e6,
zeroExGasApiUrl: ZERO_EX_GAS_API_URL, ethGasStationUrl: ETH_GAS_STATION_API_URL,
rfqt: { rfqt: {
integratorsWhitelist: [], integratorsWhitelist: [],
makerAssetOfferings: {}, makerAssetOfferings: {},
@@ -95,10 +95,11 @@ export { DEFAULT_FEE_SCHEDULE, DEFAULT_GAS_SCHEDULE } from './utils/market_opera
export const POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS = new BigNumber(30000); 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 KEEP_ALIVE_TTL = 5 * 60 * ONE_SECOND_MS;
export const constants = { export const constants = {
ZERO_EX_GAS_API_URL, ETH_GAS_STATION_API_URL,
PROTOCOL_FEE_MULTIPLIER, PROTOCOL_FEE_MULTIPLIER,
POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS, POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS,
NULL_BYTES, NULL_BYTES,

View File

@@ -157,6 +157,8 @@ export {
GetMarketOrdersRfqOpts, GetMarketOrdersRfqOpts,
LiquidityProviderFillData, LiquidityProviderFillData,
LiquidityProviderRegistry, LiquidityProviderRegistry,
MarketDepth,
MarketDepthSide,
MooniswapFillData, MooniswapFillData,
MultiHopFillData, MultiHopFillData,
NativeRfqOrderFillData, NativeRfqOrderFillData,
@@ -164,10 +166,9 @@ export {
NativeFillData, NativeFillData,
OptimizedMarketOrder, OptimizedMarketOrder,
SourceQuoteOperation, SourceQuoteOperation,
TokenAdjacencyGraph,
UniswapV2FillData, UniswapV2FillData,
} from './utils/market_operation_utils/types'; } from './utils/market_operation_utils/types';
export { TokenAdjacencyGraph, TokenAdjacencyGraphBuilder } from './utils/token_adjacency_graph';
export { IdentityFillAdjustor } from './utils/market_operation_utils/identity_fill_adjustor'; export { IdentityFillAdjustor } from './utils/market_operation_utils/identity_fill_adjustor';
export { ProtocolFeeUtils } from './utils/protocol_fee_utils'; export { ProtocolFeeUtils } from './utils/protocol_fee_utils';
export { export {

View File

@@ -32,13 +32,17 @@ import {
import { assert } from '../utils/assert'; import { assert } from '../utils/assert';
import { import {
CURVE_LIQUIDITY_PROVIDER_BY_CHAIN_ID, CURVE_LIQUIDITY_PROVIDER_BY_CHAIN_ID,
MOONISWAP_LIQUIDITY_PROVIDER_BY_CHAIN_ID,
NATIVE_FEE_TOKEN_BY_CHAIN_ID, NATIVE_FEE_TOKEN_BY_CHAIN_ID,
} from '../utils/market_operation_utils/constants'; } from '../utils/market_operation_utils/constants';
import { poolEncoder } from '../utils/market_operation_utils/orders';
import { import {
CurveFillData, CurveFillData,
ERC20BridgeSource, ERC20BridgeSource,
FinalUniswapV3FillData, FinalUniswapV3FillData,
LiquidityProviderFillData, LiquidityProviderFillData,
MooniswapFillData,
NativeOtcOrderFillData,
NativeRfqOrderFillData, NativeRfqOrderFillData,
OptimizedMarketBridgeOrder, OptimizedMarketBridgeOrder,
OptimizedMarketOrder, OptimizedMarketOrder,
@@ -46,6 +50,7 @@ import {
} from '../utils/market_operation_utils/types'; } from '../utils/market_operation_utils/types';
import { import {
multiplexOtcOrder,
multiplexPlpEncoder, multiplexPlpEncoder,
multiplexRfqEncoder, multiplexRfqEncoder,
MultiplexSubcall, MultiplexSubcall,
@@ -61,6 +66,7 @@ import {
requiresTransformERC20, requiresTransformERC20,
} from './quote_consumer_utils'; } from './quote_consumer_utils';
// tslint:disable-next-line:custom-no-magic-numbers
const MAX_UINT256 = new BigNumber(2).pow(256).minus(1); const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
const { NULL_ADDRESS, NULL_BYTES, ZERO_AMOUNT } = constants; const { NULL_ADDRESS, NULL_BYTES, ZERO_AMOUNT } = constants;
@@ -303,6 +309,30 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
}; };
} }
if (
this.chainId === ChainId.Mainnet &&
isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.Mooniswap])
) {
const fillData = slippedOrders[0].fillData as MooniswapFillData;
return {
calldataHexString: this._exchangeProxy
.sellToLiquidityProvider(
isFromETH ? ETH_TOKEN_ADDRESS : sellToken,
isToETH ? ETH_TOKEN_ADDRESS : buyToken,
MOONISWAP_LIQUIDITY_PROVIDER_BY_CHAIN_ID[this.chainId],
NULL_ADDRESS,
sellAmount,
minBuyAmount,
poolEncoder.encode([fillData.poolAddress]),
)
.getABIEncodedTransactionData(),
ethAmount: isFromETH ? sellAmount : ZERO_AMOUNT,
toAddress: this._exchangeProxy.address,
allowanceTarget: this.contractAddresses.exchangeProxy,
gasOverhead: ZERO_AMOUNT,
};
}
// RFQT VIP // RFQT VIP
if ( if (
[ChainId.Mainnet, ChainId.Polygon].includes(this.chainId) && [ChainId.Mainnet, ChainId.Polygon].includes(this.chainId) &&
@@ -312,18 +342,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
!requiresTransformERC20(optsWithDefaults) !requiresTransformERC20(optsWithDefaults)
) { ) {
const rfqOrdersData = quote.orders.map(o => o.fillData as NativeRfqOrderFillData); const rfqOrdersData = quote.orders.map(o => o.fillData as NativeRfqOrderFillData);
const fillAmountPerOrder = (() => { const fillAmountPerOrder = generateFillAmounts(sellAmount, quote);
// Don't think order taker amounts are clipped to actual sell amount
// (the last one might be too large) so figure them out manually.
let remaining = sellAmount;
const fillAmounts = [];
for (const o of quote.orders) {
const fillAmount = BigNumber.min(o.takerAmount, remaining);
fillAmounts.push(fillAmount);
remaining = remaining.minus(fillAmount);
}
return fillAmounts;
})();
const callData = const callData =
quote.orders.length === 1 quote.orders.length === 1
? this._exchangeProxy ? this._exchangeProxy
@@ -346,6 +365,46 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
}; };
} }
// OTC orders
if (
[ChainId.Mainnet, ChainId.Ropsten].includes(this.chainId) && // @todo goerli and polygon?
quote.orders.every(o => o.type === FillQuoteTransformerOrderType.Otc) &&
!requiresTransformERC20(optsWithDefaults)
) {
const otcOrdersData = quote.orders.map(o => o.fillData as NativeOtcOrderFillData);
const fillAmountPerOrder = generateFillAmounts(sellAmount, quote);
// grab the amount to fill on each OtcOrder (if more than 1, fallback to multiplexBatchFill)
let callData;
// if we have more than one otc order we want to batch fill them,
if (quote.orders.length === 1) {
// if the otc orders takerToken is the native asset
if (isFromETH) {
callData = this._exchangeProxy
.fillOtcOrderWithEth(otcOrdersData[0].order, otcOrdersData[0].signature)
.getABIEncodedTransactionData();
}
// if the otc orders makerToken is the native asset
if (isToETH) {
callData = this._exchangeProxy
.fillOtcOrderForEth(otcOrdersData[0].order, otcOrdersData[0].signature, fillAmountPerOrder[0])
.getABIEncodedTransactionData();
} else {
// if the otc order contains 2 erc20 tokens
callData = this._exchangeProxy
.fillOtcOrder(otcOrdersData[0].order, otcOrdersData[0].signature, fillAmountPerOrder[0])
.getABIEncodedTransactionData();
}
return {
calldataHexString: callData,
ethAmount: isFromETH ? sellAmount : ZERO_AMOUNT,
toAddress: this._exchangeProxy.address,
allowanceTarget: this._exchangeProxy.address,
gasOverhead: ZERO_AMOUNT,
};
}
}
if (this.chainId === ChainId.Mainnet && isMultiplexBatchFillCompatible(quote, optsWithDefaults)) { if (this.chainId === ChainId.Mainnet && isMultiplexBatchFillCompatible(quote, optsWithDefaults)) {
return { return {
calldataHexString: this._encodeMultiplexBatchFillCalldata( calldataHexString: this._encodeMultiplexBatchFillCalldata(
@@ -539,11 +598,12 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
for_loop: for (const [i, order] of quote.orders.entries()) { for_loop: for (const [i, order] of quote.orders.entries()) {
switch_statement: switch (order.source) { switch_statement: switch (order.source) {
case ERC20BridgeSource.Native: case ERC20BridgeSource.Native:
if (order.type !== FillQuoteTransformerOrderType.Rfq) { if (order.type !== FillQuoteTransformerOrderType.Rfq && order.type !== FillQuoteTransformerOrderType.Otc) {
// Should never happen because we check `isMultiplexBatchFillCompatible` // Should never happen because we check `isMultiplexBatchFillCompatible`
// before calling this function. // before calling this function.
throw new Error('Multiplex batch fill only supported for RFQ native orders'); throw new Error('Multiplex batch fill only supported for RFQ native orders and OTC Orders');
} }
if (order.type !== FillQuoteTransformerOrderType.Otc) {
subcalls.push({ subcalls.push({
id: MultiplexSubcall.Rfq, id: MultiplexSubcall.Rfq,
sellAmount: order.takerAmount, sellAmount: order.takerAmount,
@@ -552,6 +612,16 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
signature: order.fillData.signature, signature: order.fillData.signature,
}), }),
}); });
} else {
subcalls.push({
id: MultiplexSubcall.Otc,
sellAmount: order.takerAmount,
data: multiplexOtcOrder.encode({
order: order.fillData.order,
signature: order.fillData.signature,
}),
});
}
break switch_statement; break switch_statement;
case ERC20BridgeSource.UniswapV2: case ERC20BridgeSource.UniswapV2:
case ERC20BridgeSource.SushiSwap: case ERC20BridgeSource.SushiSwap:
@@ -702,6 +772,17 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
} }
} }
function generateFillAmounts(sellAmount: BigNumber, quote: MarketBuySwapQuote | MarketSellSwapQuote): BigNumber[] {
let remaining = sellAmount;
const fillAmounts = [];
for (const o of quote.orders) {
const fillAmount = BigNumber.min(o.takerAmount, remaining);
fillAmounts.push(fillAmount);
remaining = remaining.minus(fillAmount);
}
return fillAmounts;
}
function slipNonNativeOrders(quote: MarketSellSwapQuote | MarketBuySwapQuote): OptimizedMarketOrder[] { function slipNonNativeOrders(quote: MarketSellSwapQuote | MarketBuySwapQuote): OptimizedMarketOrder[] {
const slippage = getMaxQuoteSlippageRate(quote); const slippage = getMaxQuoteSlippageRate(quote);
if (slippage === 0) { if (slippage === 0) {

View File

@@ -1,4 +1,4 @@
import { RfqOrder, SIGNATURE_ABI } from '@0x/protocol-utils'; import { OtcOrder, RfqOrder, SIGNATURE_ABI } from '@0x/protocol-utils';
import { AbiEncoder } from '@0x/utils'; import { AbiEncoder } from '@0x/utils';
export enum MultiplexSubcall { export enum MultiplexSubcall {
@@ -26,6 +26,10 @@ export const multiplexRfqEncoder = AbiEncoder.create([
{ name: 'order', type: 'tuple', components: RfqOrder.STRUCT_ABI }, { name: 'order', type: 'tuple', components: RfqOrder.STRUCT_ABI },
{ name: 'signature', type: 'tuple', components: SIGNATURE_ABI }, { name: 'signature', type: 'tuple', components: SIGNATURE_ABI },
]); ]);
export const multiplexOtcOrder = AbiEncoder.create([
{ name: 'order', type: 'tuple', components: OtcOrder.STRUCT_ABI },
{ name: 'signature', type: 'tuple', components: SIGNATURE_ABI },
]);
export const multiplexUniswapEncoder = AbiEncoder.create([ export const multiplexUniswapEncoder = AbiEncoder.create([
{ name: 'tokens', type: 'address[]' }, { name: 'tokens', type: 'address[]' },
{ name: 'isSushi', type: 'bool' }, { name: 'isSushi', type: 'bool' },

View File

@@ -113,11 +113,15 @@ function isOptimizedRfqOrder(x: OptimizedMarketOrder): x is OptimizedMarketOrder
*/ */
export function getFQTTransformerDataFromOptimizedOrders( export function getFQTTransformerDataFromOptimizedOrders(
orders: OptimizedMarketOrder[], orders: OptimizedMarketOrder[],
): Pick<FillQuoteTransformerData, 'bridgeOrders' | 'limitOrders' | 'rfqOrders' | 'fillSequence'> { ): Pick<FillQuoteTransformerData, 'bridgeOrders' | 'limitOrders' | 'rfqOrders' | 'otcOrders' | 'fillSequence'> {
const fqtData: Pick<FillQuoteTransformerData, 'bridgeOrders' | 'limitOrders' | 'rfqOrders' | 'fillSequence'> = { const fqtData: Pick<
FillQuoteTransformerData,
'bridgeOrders' | 'limitOrders' | 'rfqOrders' | 'otcOrders' | 'fillSequence'
> = {
bridgeOrders: [], bridgeOrders: [],
limitOrders: [], limitOrders: [],
rfqOrders: [], rfqOrders: [],
otcOrders: [],
fillSequence: [], fillSequence: [],
}; };

View File

@@ -1,9 +1,9 @@
import { ChainId, getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; import { ChainId, getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
import { FastABI } from '@0x/fast-abi';
import { FillQuoteTransformerOrderType, LimitOrder } from '@0x/protocol-utils'; import { FillQuoteTransformerOrderType, LimitOrder } from '@0x/protocol-utils';
import { BigNumber, providerUtils } from '@0x/utils'; import { BigNumber, providerUtils } from '@0x/utils';
import Axios, { AxiosInstance } from 'axios'; import Axios, { AxiosInstance } from 'axios';
import { BlockParamLiteral, MethodAbi, SupportedProvider, ZeroExProvider } from 'ethereum-types'; import { BlockParamLiteral, MethodAbi, SupportedProvider, ZeroExProvider } from 'ethereum-types';
import { FastABI } from 'fast-abi';
import { Agent as HttpAgent } from 'http'; import { Agent as HttpAgent } from 'http';
import { Agent as HttpsAgent } from 'https'; import { Agent as HttpsAgent } from 'https';
import * as _ from 'lodash'; import * as _ from 'lodash';
@@ -36,6 +36,9 @@ import {
FillData, FillData,
GasSchedule, GasSchedule,
GetMarketOrdersOpts, GetMarketOrdersOpts,
MarketDepth,
MarketDepthSide,
MarketSideLiquidity,
OptimizedMarketOrder, OptimizedMarketOrder,
OptimizerResultWithReport, OptimizerResultWithReport,
} from './utils/market_operation_utils/types'; } from './utils/market_operation_utils/types';
@@ -109,7 +112,7 @@ export class SwapQuoter {
}; };
this._protocolFeeUtils = ProtocolFeeUtils.getInstance( this._protocolFeeUtils = ProtocolFeeUtils.getInstance(
constants.PROTOCOL_FEE_UTILS_POLLING_INTERVAL_IN_MS, constants.PROTOCOL_FEE_UTILS_POLLING_INTERVAL_IN_MS,
options.zeroExGasApiUrl, options.ethGasStationUrl,
); );
// Allow the sampler bytecode to be overwritten using geths override functionality // Allow the sampler bytecode to be overwritten using geths override functionality
const samplerBytecode = _.get(artifacts.ERC20BridgeSampler, 'compilerOutput.evm.deployedBytecode.object'); const samplerBytecode = _.get(artifacts.ERC20BridgeSampler, 'compilerOutput.evm.deployedBytecode.object');
@@ -225,6 +228,67 @@ export class SwapQuoter {
return batchSwapQuotes.filter(x => x !== undefined) as MarketBuySwapQuote[]; 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 * Returns the recommended gas price for a fast transaction
*/ */

View File

@@ -17,13 +17,11 @@ import {
GetMarketOrdersOpts, GetMarketOrdersOpts,
LiquidityProviderRegistry, LiquidityProviderRegistry,
OptimizedMarketOrder, OptimizedMarketOrder,
TokenAdjacencyGraph,
} from './utils/market_operation_utils/types'; } from './utils/market_operation_utils/types';
export { SamplerMetrics } from './utils/market_operation_utils/types';
import { ExtendedQuoteReportSources, PriceComparisonsReport, QuoteReport } from './utils/quote_report_generator'; import { ExtendedQuoteReportSources, PriceComparisonsReport, QuoteReport } from './utils/quote_report_generator';
import { MetricsProxy } from './utils/quote_requestor'; import { MetricsProxy } from './utils/quote_requestor';
import { TokenAdjacencyGraph } from './utils/token_adjacency_graph';
export { SamplerMetrics } from './utils/market_operation_utils/types';
export type Address = string;
/** /**
* expiryBufferMs: The number of seconds to add when calculating whether an order is expired or not. Defaults to 300s (5m). * expiryBufferMs: The number of seconds to add when calculating whether an order is expired or not. Defaults to 300s (5m).
@@ -337,7 +335,7 @@ export interface SwapQuoterOpts extends OrderPrunerOpts {
contractAddresses?: AssetSwapperContractAddresses; contractAddresses?: AssetSwapperContractAddresses;
samplerGasLimit?: number; samplerGasLimit?: number;
multiBridgeAddress?: string; multiBridgeAddress?: string;
zeroExGasApiUrl?: string; ethGasStationUrl?: string;
rfqt?: SwapQuoterRfqOpts; rfqt?: SwapQuoterRfqOpts;
samplerOverrides?: SamplerOverrides; samplerOverrides?: SamplerOverrides;
tokenAdjacencyGraph?: TokenAdjacencyGraph; tokenAdjacencyGraph?: TokenAdjacencyGraph;

View File

@@ -104,7 +104,9 @@ function parseIndicativeQuoteResponseFromAltMM(
takerAmount, takerAmount,
// HACK: alt implementation does not return an expiration with indicative quotes // HACK: alt implementation does not return an expiration with indicative quotes
// return now + { IMPUTED EXPIRY SECONDS } to have it included after order checks // return now + { IMPUTED EXPIRY SECONDS } to have it included after order checks
expiry: new BigNumber(Date.now() / 1000) expiry:
// tslint:disable-next-line:custom-no-magic-numbers
new BigNumber(Date.now() / 1000)
.integerValue(BigNumber.ROUND_DOWN) .integerValue(BigNumber.ROUND_DOWN)
.plus(constants.ALT_MM_IMPUTED_INDICATIVE_EXPIRY_SECONDS), .plus(constants.ALT_MM_IMPUTED_INDICATIVE_EXPIRY_SECONDS),
}; };
@@ -241,6 +243,7 @@ export async function returnQuoteFromAltMMAsync<ResponseT>(
// empty response will get filtered out in validation // empty response will get filtered out in validation
const emptyResponse = {}; const emptyResponse = {};
// tslint:disable-next-line:custom-no-magic-numbers
if (response.status !== SUCCESS_CODE) { if (response.status !== SUCCESS_CODE) {
const rejectedRequestInfo = { const rejectedRequestInfo = {
status: response.status, status: response.status,

View File

@@ -40,6 +40,7 @@ interface Cache {
[key: string]: AaveReserve[]; [key: string]: AaveReserve[];
} }
// tslint:disable-next-line:custom-no-magic-numbers
const RESERVES_REFRESH_INTERVAL_MS = 30 * constants.ONE_MINUTE_MS; const RESERVES_REFRESH_INTERVAL_MS = 30 * constants.ONE_MINUTE_MS;
/** /**

View File

@@ -33,8 +33,8 @@ import {
MSTABLE_POOLS_BY_CHAIN_ID, MSTABLE_POOLS_BY_CHAIN_ID,
NERVE_BSC_INFOS, NERVE_BSC_INFOS,
NULL_ADDRESS, NULL_ADDRESS,
PANCAKESWAPV2_ROUTER_BY_CHAIN_ID,
PANCAKESWAP_ROUTER_BY_CHAIN_ID, PANCAKESWAP_ROUTER_BY_CHAIN_ID,
PANCAKESWAPV2_ROUTER_BY_CHAIN_ID,
PANGOLIN_ROUTER_BY_CHAIN_ID, PANGOLIN_ROUTER_BY_CHAIN_ID,
PLATYPUS_AVALANCHE_INFOS, PLATYPUS_AVALANCHE_INFOS,
QUICKSWAP_ROUTER_BY_CHAIN_ID, QUICKSWAP_ROUTER_BY_CHAIN_ID,

View File

@@ -19,6 +19,7 @@ interface Cache {
[key: string]: CToken; [key: string]: CToken;
} }
// tslint:disable-next-line:custom-no-magic-numbers
const CTOKEN_REFRESH_INTERVAL_MS = 30 * constants.ONE_MINUTE_MS; const CTOKEN_REFRESH_INTERVAL_MS = 30 * constants.ONE_MINUTE_MS;
/** /**

View File

@@ -1,9 +1,9 @@
import { ChainId, getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; import { ChainId, getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
import { FillQuoteTransformerOrderType } from '@0x/protocol-utils'; import { FillQuoteTransformerOrderType } from '@0x/protocol-utils';
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
import { formatBytes32String, parseBytes32String } from '@ethersproject/strings'; import { formatBytes32String } from '@ethersproject/strings';
import { TokenAdjacencyGraph, TokenAdjacencyGraphBuilder } from '../token_adjacency_graph'; import { TokenAdjacencyGraphBuilder } from '../token_adjacency_graph_builder';
import { IdentityFillAdjustor } from './identity_fill_adjustor'; import { IdentityFillAdjustor } from './identity_fill_adjustor';
import { SourceFilters } from './source_filters'; import { SourceFilters } from './source_filters';
@@ -32,13 +32,12 @@ import {
MultiHopFillData, MultiHopFillData,
PlatypusInfo, PlatypusInfo,
PsmInfo, PsmInfo,
SynthetixFillData, TokenAdjacencyGraph,
UniswapV2FillData, UniswapV2FillData,
UniswapV3FillData, UniswapV3FillData,
WOOFiFillData,
} from './types'; } from './types';
// tslint:disable: no-bitwise // tslint:disable: custom-no-magic-numbers no-bitwise
export const ERC20_PROXY_ID = '0xf47261b0'; export const ERC20_PROXY_ID = '0xf47261b0';
export const WALLET_SIGNATURE = '0x04'; export const WALLET_SIGNATURE = '0x04';
@@ -61,7 +60,6 @@ function valueByChainId<T>(rest: Partial<{ [key in ChainId]: T }>, defaultValue:
[ChainId.Mainnet]: defaultValue, [ChainId.Mainnet]: defaultValue,
[ChainId.Ropsten]: defaultValue, [ChainId.Ropsten]: defaultValue,
[ChainId.Rinkeby]: defaultValue, [ChainId.Rinkeby]: defaultValue,
[ChainId.Goerli]: defaultValue,
[ChainId.Kovan]: defaultValue, [ChainId.Kovan]: defaultValue,
[ChainId.Ganache]: defaultValue, [ChainId.Ganache]: defaultValue,
[ChainId.BSC]: defaultValue, [ChainId.BSC]: defaultValue,
@@ -90,6 +88,7 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.Bancor, ERC20BridgeSource.Bancor,
ERC20BridgeSource.BancorV3, ERC20BridgeSource.BancorV3,
ERC20BridgeSource.MStable, ERC20BridgeSource.MStable,
ERC20BridgeSource.Mooniswap,
ERC20BridgeSource.SushiSwap, ERC20BridgeSource.SushiSwap,
ERC20BridgeSource.Shell, ERC20BridgeSource.Shell,
ERC20BridgeSource.MultiHop, ERC20BridgeSource.MultiHop,
@@ -108,7 +107,6 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.CurveV2, ERC20BridgeSource.CurveV2,
ERC20BridgeSource.ShibaSwap, ERC20BridgeSource.ShibaSwap,
ERC20BridgeSource.Synapse, ERC20BridgeSource.Synapse,
ERC20BridgeSource.Synthetix,
// TODO: enable after FQT has been redeployed on Ethereum mainnet // TODO: enable after FQT has been redeployed on Ethereum mainnet
// ERC20BridgeSource.AaveV2, // ERC20BridgeSource.AaveV2,
// ERC20BridgeSource.Compound, // ERC20BridgeSource.Compound,
@@ -120,17 +118,10 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.UniswapV2, ERC20BridgeSource.UniswapV2,
ERC20BridgeSource.UniswapV3, ERC20BridgeSource.UniswapV3,
ERC20BridgeSource.Curve, ERC20BridgeSource.Curve,
ERC20BridgeSource.Mooniswap,
]), ]),
[ChainId.Rinkeby]: new SourceFilters([ERC20BridgeSource.Native]), [ChainId.Rinkeby]: new SourceFilters([ERC20BridgeSource.Native]),
[ChainId.Kovan]: new SourceFilters([ERC20BridgeSource.Native]), [ChainId.Kovan]: new SourceFilters([ERC20BridgeSource.Native]),
[ChainId.Goerli]: new SourceFilters([
ERC20BridgeSource.Native,
ERC20BridgeSource.SushiSwap,
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
ERC20BridgeSource.UniswapV3,
]),
[ChainId.PolygonMumbai]: new SourceFilters([ERC20BridgeSource.Native, ERC20BridgeSource.UniswapV3]),
[ChainId.Ganache]: new SourceFilters([ERC20BridgeSource.Native]), [ChainId.Ganache]: new SourceFilters([ERC20BridgeSource.Native]),
[ChainId.BSC]: new SourceFilters([ [ChainId.BSC]: new SourceFilters([
ERC20BridgeSource.BakerySwap, ERC20BridgeSource.BakerySwap,
@@ -155,7 +146,6 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.BiSwap, ERC20BridgeSource.BiSwap,
ERC20BridgeSource.MDex, ERC20BridgeSource.MDex,
ERC20BridgeSource.KnightSwap, ERC20BridgeSource.KnightSwap,
ERC20BridgeSource.WOOFi,
]), ]),
[ChainId.Polygon]: new SourceFilters([ [ChainId.Polygon]: new SourceFilters([
ERC20BridgeSource.SushiSwap, ERC20BridgeSource.SushiSwap,
@@ -178,7 +168,6 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.UniswapV3, ERC20BridgeSource.UniswapV3,
ERC20BridgeSource.Synapse, ERC20BridgeSource.Synapse,
ERC20BridgeSource.MeshSwap, ERC20BridgeSource.MeshSwap,
ERC20BridgeSource.WOOFi,
]), ]),
[ChainId.Avalanche]: new SourceFilters([ [ChainId.Avalanche]: new SourceFilters([
ERC20BridgeSource.MultiHop, ERC20BridgeSource.MultiHop,
@@ -192,7 +181,6 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.Synapse, ERC20BridgeSource.Synapse,
ERC20BridgeSource.GMX, ERC20BridgeSource.GMX,
ERC20BridgeSource.Platypus, ERC20BridgeSource.Platypus,
ERC20BridgeSource.WOOFi,
]), ]),
[ChainId.Fantom]: new SourceFilters([ [ChainId.Fantom]: new SourceFilters([
ERC20BridgeSource.MultiHop, ERC20BridgeSource.MultiHop,
@@ -206,7 +194,6 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.SushiSwap, ERC20BridgeSource.SushiSwap,
ERC20BridgeSource.Synapse, ERC20BridgeSource.Synapse,
ERC20BridgeSource.Yoshi, ERC20BridgeSource.Yoshi,
ERC20BridgeSource.WOOFi,
]), ]),
[ChainId.Celo]: new SourceFilters([ [ChainId.Celo]: new SourceFilters([
ERC20BridgeSource.UbeSwap, ERC20BridgeSource.UbeSwap,
@@ -221,7 +208,6 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.CurveV2, ERC20BridgeSource.CurveV2,
ERC20BridgeSource.MultiHop, ERC20BridgeSource.MultiHop,
ERC20BridgeSource.Velodrome, ERC20BridgeSource.Velodrome,
ERC20BridgeSource.Synthetix,
]), ]),
}, },
new SourceFilters([]), new SourceFilters([]),
@@ -242,6 +228,7 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
// ERC20BridgeSource.Bancor, // FIXME: Bancor Buys not implemented in Sampler // ERC20BridgeSource.Bancor, // FIXME: Bancor Buys not implemented in Sampler
ERC20BridgeSource.BancorV3, ERC20BridgeSource.BancorV3,
ERC20BridgeSource.MStable, ERC20BridgeSource.MStable,
ERC20BridgeSource.Mooniswap,
ERC20BridgeSource.Shell, ERC20BridgeSource.Shell,
ERC20BridgeSource.SushiSwap, ERC20BridgeSource.SushiSwap,
ERC20BridgeSource.MultiHop, ERC20BridgeSource.MultiHop,
@@ -260,7 +247,6 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.CurveV2, ERC20BridgeSource.CurveV2,
ERC20BridgeSource.ShibaSwap, ERC20BridgeSource.ShibaSwap,
ERC20BridgeSource.Synapse, ERC20BridgeSource.Synapse,
ERC20BridgeSource.Synthetix,
// TODO: enable after FQT has been redeployed on Ethereum mainnet // TODO: enable after FQT has been redeployed on Ethereum mainnet
// ERC20BridgeSource.AaveV2, // ERC20BridgeSource.AaveV2,
// ERC20BridgeSource.Compound, // ERC20BridgeSource.Compound,
@@ -272,15 +258,8 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.UniswapV2, ERC20BridgeSource.UniswapV2,
ERC20BridgeSource.UniswapV3, ERC20BridgeSource.UniswapV3,
ERC20BridgeSource.Curve, ERC20BridgeSource.Curve,
ERC20BridgeSource.Mooniswap,
]), ]),
[ChainId.Goerli]: new SourceFilters([
ERC20BridgeSource.Native,
ERC20BridgeSource.SushiSwap,
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
ERC20BridgeSource.UniswapV3,
]),
[ChainId.PolygonMumbai]: new SourceFilters([ERC20BridgeSource.Native, ERC20BridgeSource.UniswapV3]),
[ChainId.Rinkeby]: new SourceFilters([ERC20BridgeSource.Native]), [ChainId.Rinkeby]: new SourceFilters([ERC20BridgeSource.Native]),
[ChainId.Kovan]: new SourceFilters([ERC20BridgeSource.Native]), [ChainId.Kovan]: new SourceFilters([ERC20BridgeSource.Native]),
[ChainId.Ganache]: new SourceFilters([ERC20BridgeSource.Native]), [ChainId.Ganache]: new SourceFilters([ERC20BridgeSource.Native]),
@@ -307,7 +286,6 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.BiSwap, ERC20BridgeSource.BiSwap,
ERC20BridgeSource.MDex, ERC20BridgeSource.MDex,
ERC20BridgeSource.KnightSwap, ERC20BridgeSource.KnightSwap,
ERC20BridgeSource.WOOFi,
]), ]),
[ChainId.Polygon]: new SourceFilters([ [ChainId.Polygon]: new SourceFilters([
ERC20BridgeSource.SushiSwap, ERC20BridgeSource.SushiSwap,
@@ -330,7 +308,6 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.UniswapV3, ERC20BridgeSource.UniswapV3,
ERC20BridgeSource.Synapse, ERC20BridgeSource.Synapse,
ERC20BridgeSource.MeshSwap, ERC20BridgeSource.MeshSwap,
ERC20BridgeSource.WOOFi,
]), ]),
[ChainId.Avalanche]: new SourceFilters([ [ChainId.Avalanche]: new SourceFilters([
ERC20BridgeSource.MultiHop, ERC20BridgeSource.MultiHop,
@@ -344,7 +321,6 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.Synapse, ERC20BridgeSource.Synapse,
ERC20BridgeSource.GMX, ERC20BridgeSource.GMX,
ERC20BridgeSource.Platypus, ERC20BridgeSource.Platypus,
ERC20BridgeSource.WOOFi,
]), ]),
[ChainId.Fantom]: new SourceFilters([ [ChainId.Fantom]: new SourceFilters([
ERC20BridgeSource.MultiHop, ERC20BridgeSource.MultiHop,
@@ -358,7 +334,6 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.SushiSwap, ERC20BridgeSource.SushiSwap,
ERC20BridgeSource.Synapse, ERC20BridgeSource.Synapse,
ERC20BridgeSource.Yoshi, ERC20BridgeSource.Yoshi,
ERC20BridgeSource.WOOFi,
]), ]),
[ChainId.Celo]: new SourceFilters([ [ChainId.Celo]: new SourceFilters([
ERC20BridgeSource.UbeSwap, ERC20BridgeSource.UbeSwap,
@@ -373,7 +348,6 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.CurveV2, ERC20BridgeSource.CurveV2,
ERC20BridgeSource.MultiHop, ERC20BridgeSource.MultiHop,
ERC20BridgeSource.Velodrome, ERC20BridgeSource.Velodrome,
ERC20BridgeSource.Synthetix,
]), ]),
}, },
new SourceFilters([]), new SourceFilters([]),
@@ -392,8 +366,6 @@ export const FEE_QUOTE_SOURCES_BY_CHAIN_ID = valueByChainId<ERC20BridgeSource[]>
[ChainId.Mainnet]: [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap, ERC20BridgeSource.UniswapV3], [ChainId.Mainnet]: [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap, ERC20BridgeSource.UniswapV3],
[ChainId.BSC]: [ERC20BridgeSource.PancakeSwap, ERC20BridgeSource.Mooniswap, ERC20BridgeSource.SushiSwap], [ChainId.BSC]: [ERC20BridgeSource.PancakeSwap, ERC20BridgeSource.Mooniswap, ERC20BridgeSource.SushiSwap],
[ChainId.Ropsten]: [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap], [ChainId.Ropsten]: [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap],
[ChainId.Goerli]: [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap],
[ChainId.PolygonMumbai]: [ERC20BridgeSource.UniswapV3],
[ChainId.Polygon]: [ERC20BridgeSource.QuickSwap, ERC20BridgeSource.SushiSwap, ERC20BridgeSource.UniswapV3], [ChainId.Polygon]: [ERC20BridgeSource.QuickSwap, ERC20BridgeSource.SushiSwap, ERC20BridgeSource.UniswapV3],
[ChainId.Avalanche]: [ERC20BridgeSource.Pangolin, ERC20BridgeSource.TraderJoe, ERC20BridgeSource.SushiSwap], [ChainId.Avalanche]: [ERC20BridgeSource.Pangolin, ERC20BridgeSource.TraderJoe, ERC20BridgeSource.SushiSwap],
[ChainId.Fantom]: [ERC20BridgeSource.SpiritSwap, ERC20BridgeSource.SpookySwap, ERC20BridgeSource.SushiSwap], [ChainId.Fantom]: [ERC20BridgeSource.SpiritSwap, ERC20BridgeSource.SpookySwap, ERC20BridgeSource.SushiSwap],
@@ -415,6 +387,23 @@ export const SOURCE_FLAGS: { [key in ERC20BridgeSource]: bigint } & {
})), })),
); );
const MIRROR_WRAPPED_TOKENS = {
mAAPL: '0xd36932143f6ebdedd872d5fb0651f4b72fd15a84',
mSLV: '0x9d1555d8cb3c846bb4f7d5b1b1080872c3166676',
mIAU: '0x1d350417d9787e000cc1b95d70e9536dcd91f373',
mAMZN: '0x0cae9e4d663793c2a2a0b211c1cf4bbca2b9caa7',
mGOOGL: '0x4b70ccd1cf9905be1faed025eadbd3ab124efe9a',
mTSLA: '0x21ca39943e91d704678f5d00b6616650f066fd63',
mQQQ: '0x13b02c8de71680e71f0820c996e4be43c2f57d15',
mTWTR: '0xedb0414627e6f1e3f082de65cd4f9c693d78cca9',
mMSFT: '0x41bbedd7286daab5910a1f15d12cbda839852bd7',
mNFLX: '0xc8d674114bac90148d11d3c1d33c61835a0f9dcd',
mBABA: '0x676ce85f66adb8d7b8323aeefe17087a3b8cb363',
mUSO: '0x31c63146a635eb7465e5853020b39713ac356991',
mVIXY: '0xf72fcd9dcf0190923fadd44811e240ef4533fc86',
mLUNA: '0xd2877702675e6ceb975b4a1dff9fb7baf4c91ea9',
};
// Mainnet tokens // Mainnet tokens
// Not an exhaustive list, just enough so we don't repeat ourselves // Not an exhaustive list, just enough so we don't repeat ourselves
export const MAINNET_TOKENS = { export const MAINNET_TOKENS = {
@@ -453,11 +442,6 @@ export const MAINNET_TOKENS = {
EURS: '0xdb25f211ab05b1c97d595516f45794528a807ad8', EURS: '0xdb25f211ab05b1c97d595516f45794528a807ad8',
sEUR: '0xd71ecff9342a5ced620049e616c5035f1db98620', sEUR: '0xd71ecff9342a5ced620049e616c5035f1db98620',
sETH: '0x5e74c9036fb86bd7ecdcb084a0673efc32ea31cb', sETH: '0x5e74c9036fb86bd7ecdcb084a0673efc32ea31cb',
sJPY: '0xf6b1c627e95bfc3c1b4c9b825a032ff0fbf3e07d',
sGBP: '0x97fe22e7341a0cd8db6f6c021a24dc8f4dad855f',
sAUD: '0xf48e200eaf9906362bb1442fca31e0835773b8b4',
sKRW: '0x269895a3df4d73b077fc823dd6da1b95f72aaf9b',
sCHF: '0x0f83287ff768d1c1e17a42f44d644d7f22e8ee1d',
stETH: '0xae7ab96520de3a18e5e111b5eaab095312d7fe84', stETH: '0xae7ab96520de3a18e5e111b5eaab095312d7fe84',
wstETH: '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0', wstETH: '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0',
LINK: '0x514910771af9ca656af840dff83e8264ecf986ca', LINK: '0x514910771af9ca656af840dff83e8264ecf986ca',
@@ -478,7 +462,10 @@ export const MAINNET_TOKENS = {
vETH: '0x898bad2774eb97cf6b94605677f43b41871410b1', vETH: '0x898bad2774eb97cf6b94605677f43b41871410b1',
alETH: '0x0100546f2cd4c9d97f798ffc9755e47865ff7ee6', alETH: '0x0100546f2cd4c9d97f798ffc9755e47865ff7ee6',
HT: '0x6f259637dcD74C767781E37Bc6133cd6A68aa161', HT: '0x6f259637dcD74C767781E37Bc6133cd6A68aa161',
// Mirror Protocol
UST: '0xa47c8bf37f92abed4a126bda807a7b7498661acd', UST: '0xa47c8bf37f92abed4a126bda807a7b7498661acd',
MIR: '0x09a3ecafa817268f77be1283176b946c4ff2e608',
...MIRROR_WRAPPED_TOKENS,
// StableSwap "open pools" (crv.finance) // StableSwap "open pools" (crv.finance)
STABLEx: '0xcd91538b91b4ba7797d39a2f66e63810b50a33d0', STABLEx: '0xcd91538b91b4ba7797d39a2f66e63810b50a33d0',
alUSD: '0xbc6da0fe9ad5f3b0d58160288917aa56653660e9', alUSD: '0xbc6da0fe9ad5f3b0d58160288917aa56653660e9',
@@ -531,7 +518,6 @@ export const BSC_TOKENS = {
pBTC: '0xed28a457a5a76596ac48d87c0f577020f6ea1c4c', pBTC: '0xed28a457a5a76596ac48d87c0f577020f6ea1c4c',
nUSD: '0x23b891e5c62e0955ae2bd185990103928ab817b3', nUSD: '0x23b891e5c62e0955ae2bd185990103928ab817b3',
BSW: '0x965F527D9159dCe6288a2219DB51fc6Eef120dD1', BSW: '0x965F527D9159dCe6288a2219DB51fc6Eef120dD1',
WOO: '0x4691937a7508860f876c9c0a2a617e7d9e945d4b',
}; };
export const POLYGON_TOKENS = { export const POLYGON_TOKENS = {
@@ -551,7 +537,6 @@ export const POLYGON_TOKENS = {
WEXPOLY: '0x4c4bf319237d98a30a929a96112effa8da3510eb', WEXPOLY: '0x4c4bf319237d98a30a929a96112effa8da3510eb',
nUSD: '0xb6c473756050de474286bed418b77aeac39b02af', nUSD: '0xb6c473756050de474286bed418b77aeac39b02af',
ANY: '0x6aB6d61428fde76768D7b45D8BFeec19c6eF91A8', ANY: '0x6aB6d61428fde76768D7b45D8BFeec19c6eF91A8',
WOO: '0x1b815d120b3ef02039ee11dc2d33de7aa4a8c603',
}; };
export const AVALANCHE_TOKENS = { export const AVALANCHE_TOKENS = {
@@ -578,7 +563,6 @@ export const AVALANCHE_TOKENS = {
UST: '0xb599c3590f42f8f995ecfa0f85d2980b76862fc1', UST: '0xb599c3590f42f8f995ecfa0f85d2980b76862fc1',
FRAX: '0xd24c2ad096400b6fbcd2ad8b24e7acbc21a1da64', FRAX: '0xd24c2ad096400b6fbcd2ad8b24e7acbc21a1da64',
YUSD: '0x111111111111ed1d73f860f57b2798b683f2d325', YUSD: '0x111111111111ed1d73f860f57b2798b683f2d325',
WOO: '0xabc9547b534519ff73921b1fba6e672b5f58d083',
}; };
export const CELO_TOKENS = { export const CELO_TOKENS = {
@@ -638,7 +622,10 @@ export const FANTOM_TOKENS = {
gWBTC: '0x38aca5484b8603373acc6961ecd57a6a594510a3', gWBTC: '0x38aca5484b8603373acc6961ecd57a6a594510a3',
gCRV: '0x690754a168b022331caa2467207c61919b3f8a98', gCRV: '0x690754a168b022331caa2467207c61919b3f8a98',
gMIM: '0xc664fc7b8487a3e10824cda768c1d239f2403bbe', gMIM: '0xc664fc7b8487a3e10824cda768c1d239f2403bbe',
WOO: '0x6626c47c00f1d87902fc13eecfac3ed06d5e8d8a', };
export const GEIST_FANTOM_POOLS = {
lendingPool: '0x9fad24f572045c7869117160a571b2e50b10d068',
}; };
export const OPTIMISM_TOKENS = { export const OPTIMISM_TOKENS = {
@@ -649,21 +636,6 @@ export const OPTIMISM_TOKENS = {
WBTC: '0x68f180fcce6836688e9084f035309e29bf0a2095', WBTC: '0x68f180fcce6836688e9084f035309e29bf0a2095',
nETH: '0x809dc529f07651bd43a172e8db6f4a7a0d771036', nETH: '0x809dc529f07651bd43a172e8db6f4a7a0d771036',
sWETH: '0x121ab82b49b2bc4c7901ca46b8277962b4350204', sWETH: '0x121ab82b49b2bc4c7901ca46b8277962b4350204',
// Synthetix synths:
sAAVE: '0x00b8d5a5e1ac97cb4341c4bc4367443c8776e8d9',
sAVAX: '0xb2b42b231c68cbb0b4bf2ffebf57782fd97d3da4',
sBTC: '0x298b9b95708152ff6968aafd889c6586e9169f1d',
sETH: '0xe405de8f52ba7559f9df3c368500b6e6ae6cee49',
sEUR: '0xfbc4198702e81ae77c06d58f81b629bdf36f0a71',
sLINK: '0xc5db22719a06418028a40a9b5e9a7c02959d0d08',
sMATIC: '0x81ddfac111913d3d5218dea999216323b7cd6356',
sSOL: '0x8b2f7ae8ca8ee8428b6d76de88326bb413db2766',
sUNI: '0xf5a6115aa582fd1beea22bc93b7dc7a785f60d03',
sUSD: '0x8c6f28f2f1a3c87f0f938b96d27520d9751ec8d9',
};
export const GEIST_FANTOM_POOLS = {
lendingPool: '0x9fad24f572045c7869117160a571b2e50b10d068',
}; };
export const CURVE_POOLS = { export const CURVE_POOLS = {
@@ -715,6 +687,8 @@ export const CURVE_POOLS = {
eurt: '0xfd5db7463a3ab53fd211b4af195c5bccc1a03890', eurt: '0xfd5db7463a3ab53fd211b4af195c5bccc1a03890',
ethcrv: '0x8301ae4fc9c624d1d396cbdaa1ed877821d7c511', ethcrv: '0x8301ae4fc9c624d1d396cbdaa1ed877821d7c511',
ethcvx: '0xb576491f1e6e5e62f1d8f26062ee822b40b0e0d4', ethcvx: '0xb576491f1e6e5e62f1d8f26062ee822b40b0e0d4',
mimust: '0x55a8a39bc9694714e2874c1ce77aa1e599461e18',
usttri_wormhole: '0xceaf7747579696a2f0bb206a14210e3c9e6fb269',
fei_tri: '0x06cb22615ba53e60d67bf6c341a0fd5e718e1655', fei_tri: '0x06cb22615ba53e60d67bf6c341a0fd5e718e1655',
rai_tri: '0x618788357d0ebd8a37e763adab3bc575d54c2c7d', rai_tri: '0x618788357d0ebd8a37e763adab3bc575d54c2c7d',
DOLA_tri: '0xaa5a67c256e27a5d80712c51971408db3370927d', DOLA_tri: '0xaa5a67c256e27a5d80712c51971408db3370927d',
@@ -855,39 +829,6 @@ export const PLATYPUS_AVALANCHE_POOLS = {
sAVAX: '0x4658ea7e9960d6158a261104aaa160cc953bb6ba', sAVAX: '0x4658ea7e9960d6158a261104aaa160cc953bb6ba',
}; };
export const WOOFI_POOL_BY_CHAIN_ID = valueByChainId<string>(
{
[ChainId.BSC]: '0xbf365ce9cfcb2d5855521985e351ba3bcf77fd3f',
[ChainId.Fantom]: '0x9503e7517d3c5bc4f9e4a1c6ae4f8b33ac2546f2',
[ChainId.Avalanche]: '0x1df3009c57a8b143c6246149f00b090bce3b8f88',
[ChainId.Polygon]: '0x7400b665c8f4f3a951a99f1ee9872efb8778723d',
},
NULL_ADDRESS,
);
export const WOOFI_SUPPORTED_TOKENS = new Set([
BSC_TOKENS.USDT,
BSC_TOKENS.WBNB,
BSC_TOKENS.WOO,
BSC_TOKENS.WETH,
BSC_TOKENS.BTCB,
AVALANCHE_TOKENS.nUSDC,
AVALANCHE_TOKENS.WAVAX,
AVALANCHE_TOKENS.WBTC,
AVALANCHE_TOKENS.WETH,
AVALANCHE_TOKENS.WOO,
FANTOM_TOKENS.USDC,
FANTOM_TOKENS.WFTM,
FANTOM_TOKENS.WETH,
FANTOM_TOKENS.WBTC,
FANTOM_TOKENS.WOO,
POLYGON_TOKENS.USDC,
POLYGON_TOKENS.WMATIC,
POLYGON_TOKENS.WBTC,
POLYGON_TOKENS.WETH,
POLYGON_TOKENS.WOO,
]);
export const DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID = valueByChainId<string[]>( export const DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID = valueByChainId<string[]>(
{ {
[ChainId.Mainnet]: [ [ChainId.Mainnet]: [
@@ -911,15 +852,6 @@ export const DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID = valueByChainId<string[]>(
'0xad6d458402f60fd3bd25163575031acdce07538d', // DAI '0xad6d458402f60fd3bd25163575031acdce07538d', // DAI
'0x07865c6e87b9f70255377e024ace6630c1eaa37f', // USDC '0x07865c6e87b9f70255377e024ace6630c1eaa37f', // USDC
], ],
[ChainId.Goerli]: [
getContractAddressesForChainOrThrow(ChainId.Goerli).etherToken,
'0x11fE4B6AE13d2a6055C8D9cF65c55bac32B5d844', // DAI
'0x07865c6E87B9F70255377e024ace6630C1Eaa37F', // USDC
],
[ChainId.PolygonMumbai]: [
getContractAddressesForChainOrThrow(ChainId.PolygonMumbai).etherToken,
'0xe6b8a5CF854791412c1f6EFC7CAf629f5Df1c747', // USDC
],
[ChainId.Polygon]: [ [ChainId.Polygon]: [
POLYGON_TOKENS.WMATIC, POLYGON_TOKENS.WMATIC,
POLYGON_TOKENS.WETH, POLYGON_TOKENS.WETH,
@@ -971,72 +903,65 @@ export const DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID = valueByChainId<string[]>(
// attaching to a default intermediary token (stables or ETH etc) can have a large impact // attaching to a default intermediary token (stables or ETH etc) can have a large impact
export const DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID = valueByChainId<TokenAdjacencyGraph>( export const DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID = valueByChainId<TokenAdjacencyGraph>(
{ {
[ChainId.Mainnet]: new TokenAdjacencyGraphBuilder(DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Mainnet]) [ChainId.Mainnet]: new TokenAdjacencyGraphBuilder({
default: DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Mainnet],
})
.tap(builder => { .tap(builder => {
// Mirror Protocol
builder.add(MAINNET_TOKENS.MIR, MAINNET_TOKENS.UST);
// Convex and Curve // Convex and Curve
builder.addBidirectional(MAINNET_TOKENS.cvxCRV, MAINNET_TOKENS.CRV); builder.add(MAINNET_TOKENS.cvxCRV, MAINNET_TOKENS.CRV).add(MAINNET_TOKENS.CRV, MAINNET_TOKENS.cvxCRV);
// Convex and FXS // Convex and FXS
builder.addBidirectional(MAINNET_TOKENS.cvxFXS, MAINNET_TOKENS.FXS); builder.add(MAINNET_TOKENS.cvxFXS, MAINNET_TOKENS.FXS).add(MAINNET_TOKENS.FXS, MAINNET_TOKENS.cvxFXS);
// FEI TRIBE liquid in UniV2 // FEI TRIBE liquid in UniV2
builder.addBidirectional(MAINNET_TOKENS.FEI, MAINNET_TOKENS.TRIBE); builder.add(MAINNET_TOKENS.FEI, MAINNET_TOKENS.TRIBE).add(MAINNET_TOKENS.TRIBE, MAINNET_TOKENS.FEI);
// FRAX ecosystem // FRAX ecosystem
builder.addBidirectional(MAINNET_TOKENS.FRAX, MAINNET_TOKENS.FXS); builder.add(MAINNET_TOKENS.FRAX, MAINNET_TOKENS.FXS).add(MAINNET_TOKENS.FXS, MAINNET_TOKENS.FRAX);
builder.addBidirectional(MAINNET_TOKENS.FRAX, MAINNET_TOKENS.OHM); builder.add(MAINNET_TOKENS.FRAX, MAINNET_TOKENS.OHM).add(MAINNET_TOKENS.OHM, MAINNET_TOKENS.FRAX);
// REDACTED CARTEL // REDACTED CARTEL
builder.addBidirectional(MAINNET_TOKENS.OHMV2, MAINNET_TOKENS.BTRFLY); builder
.add(MAINNET_TOKENS.OHMV2, MAINNET_TOKENS.BTRFLY)
.add(MAINNET_TOKENS.BTRFLY, MAINNET_TOKENS.OHMV2);
// Lido // Lido
builder.addBidirectional(MAINNET_TOKENS.stETH, MAINNET_TOKENS.wstETH); builder
// Synthetix Atomic Swap .add(MAINNET_TOKENS.stETH, MAINNET_TOKENS.wstETH)
builder.addCompleteSubgraph([ .add(MAINNET_TOKENS.wstETH, MAINNET_TOKENS.stETH);
MAINNET_TOKENS.sBTC,
MAINNET_TOKENS.sETH,
MAINNET_TOKENS.sUSD,
MAINNET_TOKENS.sEUR,
MAINNET_TOKENS.sJPY,
MAINNET_TOKENS.sGBP,
MAINNET_TOKENS.sAUD,
MAINNET_TOKENS.sKRW,
MAINNET_TOKENS.sCHF,
]);
}) })
// Build
.build(), .build(),
[ChainId.BSC]: new TokenAdjacencyGraphBuilder(DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.BSC]).build(), [ChainId.BSC]: new TokenAdjacencyGraphBuilder({
[ChainId.Polygon]: new TokenAdjacencyGraphBuilder(DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Polygon]) default: DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.BSC],
}).build(),
[ChainId.Polygon]: new TokenAdjacencyGraphBuilder({
default: DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Polygon],
})
.tap(builder => { .tap(builder => {
builder.addBidirectional(POLYGON_TOKENS.QUICK, POLYGON_TOKENS.ANY); builder.add(POLYGON_TOKENS.QUICK, POLYGON_TOKENS.ANY).add(POLYGON_TOKENS.ANY, POLYGON_TOKENS.QUICK);
}) })
.build(), .build(),
[ChainId.Avalanche]: new TokenAdjacencyGraphBuilder(DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Avalanche]) [ChainId.Avalanche]: new TokenAdjacencyGraphBuilder({
default: DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Avalanche],
})
.tap(builder => { .tap(builder => {
// Synapse nETH/aWETH pool // Synapse nETH/aWETH pool
builder.addBidirectional(AVALANCHE_TOKENS.aWETH, AVALANCHE_TOKENS.nETH); builder
.add(AVALANCHE_TOKENS.aWETH, AVALANCHE_TOKENS.nETH)
.add(AVALANCHE_TOKENS.nETH, AVALANCHE_TOKENS.aWETH);
// Trader Joe MAG/MIM pool // Trader Joe MAG/MIM pool
builder.addBidirectional(AVALANCHE_TOKENS.MIM, AVALANCHE_TOKENS.MAG); builder.add(AVALANCHE_TOKENS.MIM, AVALANCHE_TOKENS.MAG).add(AVALANCHE_TOKENS.MAG, AVALANCHE_TOKENS.MIM);
})
.build(),
[ChainId.Fantom]: new TokenAdjacencyGraphBuilder(
DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Fantom],
).build(),
[ChainId.Celo]: new TokenAdjacencyGraphBuilder(DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Celo]).build(),
[ChainId.Optimism]: new TokenAdjacencyGraphBuilder(DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Optimism])
.tap(builder => {
// Synthetix Atomic Swap
builder.addCompleteSubgraph([
OPTIMISM_TOKENS.sAAVE,
OPTIMISM_TOKENS.sAVAX,
OPTIMISM_TOKENS.sBTC,
OPTIMISM_TOKENS.sETH,
OPTIMISM_TOKENS.sEUR,
OPTIMISM_TOKENS.sLINK,
OPTIMISM_TOKENS.sMATIC,
OPTIMISM_TOKENS.sSOL,
OPTIMISM_TOKENS.sUNI,
OPTIMISM_TOKENS.sUSD,
]);
}) })
.build(), .build(),
[ChainId.Fantom]: new TokenAdjacencyGraphBuilder({
default: DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Fantom],
}).build(),
[ChainId.Celo]: new TokenAdjacencyGraphBuilder({
default: DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Celo],
}).build(),
[ChainId.Optimism]: new TokenAdjacencyGraphBuilder({
default: DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Optimism],
}).build(),
}, },
TokenAdjacencyGraph.getEmptyGraph(), new TokenAdjacencyGraphBuilder({ default: [] }).build(),
); );
export const NATIVE_FEE_TOKEN_BY_CHAIN_ID = valueByChainId<string>( export const NATIVE_FEE_TOKEN_BY_CHAIN_ID = valueByChainId<string>(
@@ -1045,8 +970,6 @@ export const NATIVE_FEE_TOKEN_BY_CHAIN_ID = valueByChainId<string>(
[ChainId.BSC]: getContractAddressesForChainOrThrow(ChainId.BSC).etherToken, [ChainId.BSC]: getContractAddressesForChainOrThrow(ChainId.BSC).etherToken,
[ChainId.Ganache]: getContractAddressesForChainOrThrow(ChainId.Ganache).etherToken, [ChainId.Ganache]: getContractAddressesForChainOrThrow(ChainId.Ganache).etherToken,
[ChainId.Ropsten]: getContractAddressesForChainOrThrow(ChainId.Ropsten).etherToken, [ChainId.Ropsten]: getContractAddressesForChainOrThrow(ChainId.Ropsten).etherToken,
[ChainId.Goerli]: getContractAddressesForChainOrThrow(ChainId.Goerli).etherToken,
[ChainId.PolygonMumbai]: getContractAddressesForChainOrThrow(ChainId.PolygonMumbai).etherToken,
[ChainId.Rinkeby]: getContractAddressesForChainOrThrow(ChainId.Rinkeby).etherToken, [ChainId.Rinkeby]: getContractAddressesForChainOrThrow(ChainId.Rinkeby).etherToken,
[ChainId.Kovan]: getContractAddressesForChainOrThrow(ChainId.Kovan).etherToken, [ChainId.Kovan]: getContractAddressesForChainOrThrow(ChainId.Kovan).etherToken,
[ChainId.Polygon]: getContractAddressesForChainOrThrow(ChainId.Polygon).etherToken, [ChainId.Polygon]: getContractAddressesForChainOrThrow(ChainId.Polygon).etherToken,
@@ -1380,6 +1303,16 @@ export const CURVE_MAINNET_INFOS: { [name: string]: CurveInfo } = {
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_uint256, sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_uint256,
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying_uint256, exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying_uint256,
}, },
[CURVE_POOLS.mimust]: createCurveExchangePool({
tokens: [MAINNET_TOKENS.MIM, MAINNET_TOKENS.UST],
pool: CURVE_POOLS.mimust,
gasSchedule: 105e3,
}),
[CURVE_POOLS.usttri_wormhole]: createCurveMetaTriPool({
tokens: [MAINNET_TOKENS.UST_WORMHOLE],
pool: CURVE_POOLS.usttri_wormhole,
gasSchedule: 340e3,
}),
[CURVE_POOLS.fei_tri]: createCurveMetaTriPool({ [CURVE_POOLS.fei_tri]: createCurveMetaTriPool({
tokens: [MAINNET_TOKENS.FEI], tokens: [MAINNET_TOKENS.FEI],
pool: CURVE_POOLS.fei_tri, pool: CURVE_POOLS.fei_tri,
@@ -1900,7 +1833,6 @@ export const UNISWAPV1_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
{ {
[ChainId.Mainnet]: '0xc0a47dfe034b400b47bdad5fecda2621de6c4d95', [ChainId.Mainnet]: '0xc0a47dfe034b400b47bdad5fecda2621de6c4d95',
[ChainId.Ropsten]: '0x9c83dce8ca20e9aaf9d3efc003b2ea62abc08351', [ChainId.Ropsten]: '0x9c83dce8ca20e9aaf9d3efc003b2ea62abc08351',
[ChainId.Goerli]: '0x6Ce570d02D73d4c384b46135E87f8C592A8c86dA',
}, },
NULL_ADDRESS, NULL_ADDRESS,
); );
@@ -1909,7 +1841,6 @@ export const UNISWAPV2_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
{ {
[ChainId.Mainnet]: '0xf164fc0ec4e93095b804a4795bbe1e041497b92a', [ChainId.Mainnet]: '0xf164fc0ec4e93095b804a4795bbe1e041497b92a',
[ChainId.Ropsten]: '0xf164fc0ec4e93095b804a4795bbe1e041497b92a', [ChainId.Ropsten]: '0xf164fc0ec4e93095b804a4795bbe1e041497b92a',
[ChainId.Goerli]: '0xf164fc0ec4e93095b804a4795bbe1e041497b92a',
}, },
NULL_ADDRESS, NULL_ADDRESS,
); );
@@ -1919,7 +1850,6 @@ export const SUSHISWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
[ChainId.Mainnet]: '0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f', [ChainId.Mainnet]: '0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f',
[ChainId.BSC]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506', [ChainId.BSC]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506',
[ChainId.Ropsten]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506', [ChainId.Ropsten]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506',
[ChainId.Goerli]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506',
[ChainId.Polygon]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506', [ChainId.Polygon]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506',
[ChainId.Avalanche]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506', [ChainId.Avalanche]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506',
[ChainId.Fantom]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506', [ChainId.Fantom]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506',
@@ -2011,6 +1941,7 @@ export const KNIGHTSWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
export const MOONISWAP_REGISTRIES_BY_CHAIN_ID = valueByChainId( export const MOONISWAP_REGISTRIES_BY_CHAIN_ID = valueByChainId(
{ {
[ChainId.Mainnet]: ['0xbaf9a5d4b0052359326a6cdab54babaa3a3a9643'],
[ChainId.BSC]: ['0xd41b24bba51fac0e4827b6f94c0d6ddeb183cd64'], [ChainId.BSC]: ['0xd41b24bba51fac0e4827b6f94c0d6ddeb183cd64'],
}, },
[] as string[], [] as string[],
@@ -2080,6 +2011,14 @@ export const MAKER_PSM_INFO_BY_CHAIN_ID = valueByChainId<PsmInfo>(
}, },
); );
export const MOONISWAP_LIQUIDITY_PROVIDER_BY_CHAIN_ID = valueByChainId<string>(
{
[ChainId.Mainnet]: '0xa2033d6ba88756ce6a87584d69dc87bda9a4f889',
[ChainId.Ropsten]: '0x87e0393aee0fb8c10b8653c6507c182264fe5a34',
},
NULL_ADDRESS,
);
export const BANCOR_REGISTRY_BY_CHAIN_ID = valueByChainId<string>( export const BANCOR_REGISTRY_BY_CHAIN_ID = valueByChainId<string>(
{ {
[ChainId.Mainnet]: '0x52Ae12ABe5D8BD778BD5397F99cA900624CfADD4', [ChainId.Mainnet]: '0x52Ae12ABe5D8BD778BD5397F99cA900624CfADD4',
@@ -2188,6 +2127,7 @@ 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_TOP_POOLS_FETCHED = 250;
export const BALANCER_MAX_POOLS_FETCHED = 3; export const BALANCER_MAX_POOLS_FETCHED = 3;
@@ -2199,6 +2139,13 @@ export const BALANCER_V2_SUBGRAPH_URL_BY_CHAIN = valueByChainId(
null, null,
); );
export const BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN = valueByChainId<string>(
{
[ChainId.Fantom]: 'https://graph-node.beets-ftm-node.com/subgraphs/name/beethovenx',
},
'https://graph-node.beets-ftm-node.com/subgraphs/name/beethovenx',
);
export const UNISWAPV3_CONFIG_BY_CHAIN_ID = valueByChainId( export const UNISWAPV3_CONFIG_BY_CHAIN_ID = valueByChainId(
{ {
[ChainId.Mainnet]: { [ChainId.Mainnet]: {
@@ -2209,14 +2156,6 @@ export const UNISWAPV3_CONFIG_BY_CHAIN_ID = valueByChainId(
quoter: '0x61ffe014ba17989e743c5f6cb21bf9697530b21e', quoter: '0x61ffe014ba17989e743c5f6cb21bf9697530b21e',
router: '0xe592427a0aece92de3edee1f18e0157c05861564', router: '0xe592427a0aece92de3edee1f18e0157c05861564',
}, },
[ChainId.Goerli]: {
quoter: '0x61ffe014ba17989e743c5f6cb21bf9697530b21e',
router: '0xe592427a0aece92de3edee1f18e0157c05861564',
},
[ChainId.PolygonMumbai]: {
quoter: '0x61ffe014ba17989e743c5f6cb21bf9697530b21e',
router: '0xe592427a0aece92de3edee1f18e0157c05861564',
},
[ChainId.Polygon]: { [ChainId.Polygon]: {
quoter: '0x61ffe014ba17989e743c5f6cb21bf9697530b21e', quoter: '0x61ffe014ba17989e743c5f6cb21bf9697530b21e',
router: '0xe592427a0aece92de3edee1f18e0157c05861564', router: '0xe592427a0aece92de3edee1f18e0157c05861564',
@@ -2402,47 +2341,6 @@ export const VELODROME_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
NULL_ADDRESS, NULL_ADDRESS,
); );
export const SYNTHETIX_READ_PROXY_BY_CHAIN_ID = valueByChainId<string>(
{
[ChainId.Mainnet]: '0x4e3b31eb0e5cb73641ee1e65e7dcefe520ba3ef2',
[ChainId.Optimism]: '0x1cb059b7e74fd21665968c908806143e744d5f30',
},
NULL_ADDRESS,
);
export const SYNTHETIX_CURRENCY_KEYS_BY_CHAIN_ID = valueByChainId<Map<string, string>>(
{
// There is no easy way to find out what synths are supported on mainnet.
// The below list is based on https://sips.synthetix.io/sccp/sccp-190.
[ChainId.Mainnet]: new Map([
[MAINNET_TOKENS.sAUD, 'sAUD'],
[MAINNET_TOKENS.sBTC, 'sBTC'],
[MAINNET_TOKENS.sCHF, 'sCHF'],
[MAINNET_TOKENS.sETH, 'sETH'],
[MAINNET_TOKENS.sEUR, 'sEUR'],
[MAINNET_TOKENS.sGBP, 'sGBP'],
[MAINNET_TOKENS.sJPY, 'sJPY'],
[MAINNET_TOKENS.sKRW, 'sKRW'],
[MAINNET_TOKENS.sUSD, 'sUSD'],
]),
// Supported assets can be find through SynthUtil::synthsRates.
// Low liquidity tokens can be excluded.
[ChainId.Optimism]: new Map([
[OPTIMISM_TOKENS.sAAVE, 'sAAVE'],
[OPTIMISM_TOKENS.sAVAX, 'sAVAX'],
[OPTIMISM_TOKENS.sBTC, 'sBTC'],
[OPTIMISM_TOKENS.sETH, 'sETH'],
[OPTIMISM_TOKENS.sEUR, 'sEUR'],
[OPTIMISM_TOKENS.sLINK, 'sLINK'],
[OPTIMISM_TOKENS.sMATIC, 'sMATIC'],
[OPTIMISM_TOKENS.sSOL, 'sSOL'],
[OPTIMISM_TOKENS.sUNI, 'sUNI'],
[OPTIMISM_TOKENS.sUSD, 'sUSD'],
]),
},
new Map(),
);
export const VIP_ERC20_BRIDGE_SOURCES_BY_CHAIN_ID = valueByChainId<ERC20BridgeSource[]>( export const VIP_ERC20_BRIDGE_SOURCES_BY_CHAIN_ID = valueByChainId<ERC20BridgeSource[]>(
{ {
[ChainId.Mainnet]: [ [ChainId.Mainnet]: [
@@ -2484,6 +2382,7 @@ const uniswapV2CloneGasSchedule = (fillData?: FillData) => {
* I.e remove the overhead cost of ExchangeProxy (130k) and * I.e remove the overhead cost of ExchangeProxy (130k) and
* the ethereum transaction cost (21k) * the ethereum transaction cost (21k)
*/ */
// tslint:disable:custom-no-magic-numbers
export const DEFAULT_GAS_SCHEDULE: Required<GasSchedule> = { export const DEFAULT_GAS_SCHEDULE: Required<GasSchedule> = {
[ERC20BridgeSource.Native]: fillData => { [ERC20BridgeSource.Native]: fillData => {
// TODO jacob re-order imports so there is no circular rependency with SignedNativeOrder // TODO jacob re-order imports so there is no circular rependency with SignedNativeOrder
@@ -2625,28 +2524,7 @@ export const DEFAULT_GAS_SCHEDULE: Required<GasSchedule> = {
return compoundFillData.takerToken === wethAddress ? 210e3 : 250e3; return compoundFillData.takerToken === wethAddress ? 210e3 : 250e3;
} }
}, },
[ERC20BridgeSource.Synthetix]: (fillData?: FillData) => {
const { chainId, makerTokenSymbolBytes32, takerTokenSymbolBytes32 } = fillData as SynthetixFillData;
const makerTokenSymbol = parseBytes32String(makerTokenSymbolBytes32);
const takerTokenSymbol = parseBytes32String(takerTokenSymbolBytes32);
// Gas cost widely varies by token on mainnet.
if (chainId === ChainId.Mainnet) {
if (takerTokenSymbol === 'sBTC' || makerTokenSymbol === 'sBTC') {
return 800e3;
}
if (takerTokenSymbol === 'sETH' || makerTokenSymbol === 'sETH') {
return 700e3;
}
return 580e3;
}
// Optimism
if (takerTokenSymbol === 'sUSD' || makerTokenSymbol === 'sUSD') {
return 480e3;
}
return 580e3;
},
// //
// BSC // BSC
// //
@@ -2657,19 +2535,7 @@ export const DEFAULT_GAS_SCHEDULE: Required<GasSchedule> = {
[ERC20BridgeSource.CheeseSwap]: uniswapV2CloneGasSchedule, [ERC20BridgeSource.CheeseSwap]: uniswapV2CloneGasSchedule,
[ERC20BridgeSource.WaultSwap]: uniswapV2CloneGasSchedule, [ERC20BridgeSource.WaultSwap]: uniswapV2CloneGasSchedule,
[ERC20BridgeSource.ACryptos]: fillData => (fillData as CurveFillData).pool.gasSchedule, [ERC20BridgeSource.ACryptos]: fillData => (fillData as CurveFillData).pool.gasSchedule,
[ERC20BridgeSource.WOOFi]: (fillData?: FillData) => {
const woofiFillData = fillData as WOOFiFillData;
const quoteTokenAddresses = [BSC_TOKENS.USDT, AVALANCHE_TOKENS.nUSDC, FANTOM_TOKENS.USDC, POLYGON_TOKENS.USDC];
if (
quoteTokenAddresses.includes(woofiFillData.takerToken) ||
quoteTokenAddresses.includes(woofiFillData.makerToken)
) {
return 500e3;
} else {
return 100e4;
}
},
// //
// Polygon // Polygon
// //
@@ -2720,7 +2586,10 @@ export const POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS = new BigNumber(20000);
export const DEFAULT_FEE_ESTIMATE = { gas: 0, fee: ZERO_AMOUNT }; 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'> = { export const DEFAULT_GET_MARKET_ORDERS_OPTS: Omit<GetMarketOrdersOpts, 'gasPrice'> = {
// tslint:disable-next-line: custom-no-magic-numbers
runLimit: 2 ** 15, runLimit: 2 ** 15,
excludedSources: [], excludedSources: [],
excludedFeeSources: [], excludedFeeSources: [],
@@ -2735,7 +2604,7 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: Omit<GetMarketOrdersOpts, 'gasPrice
allowFallback: true, allowFallback: true,
shouldGenerateQuoteReport: true, shouldGenerateQuoteReport: true,
shouldIncludePriceComparisonsReport: false, shouldIncludePriceComparisonsReport: false,
tokenAdjacencyGraph: TokenAdjacencyGraph.getEmptyGraph(), tokenAdjacencyGraph: { default: [] },
neonRouterNumSamples: 14, neonRouterNumSamples: 14,
fillAdjustor: new IdentityFillAdjustor(), fillAdjustor: new IdentityFillAdjustor(),
}; };

View File

@@ -29,6 +29,7 @@ import {
PriceComparisonsReport, PriceComparisonsReport,
QuoteReport, QuoteReport,
} from './../quote_report_generator'; } from './../quote_report_generator';
import { getComparisonPrices } from './comparison_price'; import { getComparisonPrices } from './comparison_price';
import { import {
BUY_SOURCE_FILTER_BY_CHAIN_ID, BUY_SOURCE_FILTER_BY_CHAIN_ID,
@@ -861,9 +862,14 @@ export class MarketOperationUtils {
} }
private async _refreshPoolCacheIfRequiredAsync(takerToken: string, makerToken: string): Promise<void> { private async _refreshPoolCacheIfRequiredAsync(takerToken: string, makerToken: string): Promise<void> {
_.values(this._sampler.poolsCaches) void Promise.all(
.filter(cache => cache !== undefined && !cache.isFresh(takerToken, makerToken)) Object.values(this._sampler.poolsCaches).map(async cache => {
.forEach(cache => cache?.getFreshPoolsForPairAsync(takerToken, makerToken)); if (!cache || cache.isFresh(takerToken, makerToken)) {
return Promise.resolve([]);
}
return cache.getFreshPoolsForPairAsync(takerToken, makerToken);
}),
);
} }
} }

View File

@@ -12,8 +12,26 @@ import {
FillAdjustor, FillAdjustor,
MarketSideLiquidity, MarketSideLiquidity,
MultiHopFillData, MultiHopFillData,
TokenAdjacencyGraph,
} from './types'; } from './types';
/**
* Given a token pair, returns the intermediate tokens to consider for two-hop routes.
*/
export function getIntermediateTokens(
makerToken: string,
takerToken: string,
tokenAdjacencyGraph: TokenAdjacencyGraph,
): string[] {
const intermediateTokens = _.union(
_.get(tokenAdjacencyGraph, takerToken, tokenAdjacencyGraph.default),
_.get(tokenAdjacencyGraph, makerToken, tokenAdjacencyGraph.default),
);
return _.uniqBy(intermediateTokens, a => a.toLowerCase()).filter(
token => token.toLowerCase() !== makerToken.toLowerCase() && token.toLowerCase() !== takerToken.toLowerCase(),
);
}
/** /**
* Returns the best two-hop quote and the fee-adjusted rate of that quote. * Returns the best two-hop quote and the fee-adjusted rate of that quote.
*/ */

View File

@@ -38,12 +38,10 @@ import {
OrderDomain, OrderDomain,
PlatypusFillData, PlatypusFillData,
ShellFillData, ShellFillData,
SynthetixFillData,
UniswapV2FillData, UniswapV2FillData,
UniswapV3FillData, UniswapV3FillData,
UniswapV3PathAmount, UniswapV3PathAmount,
VelodromeFillData, VelodromeFillData,
WOOFiFillData,
} from './types'; } from './types';
// tslint:disable completed-docs // tslint:disable completed-docs
@@ -212,10 +210,6 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s
return encodeBridgeSourceId(BridgeProtocol.BancorV3, 'BancorV3'); return encodeBridgeSourceId(BridgeProtocol.BancorV3, 'BancorV3');
case ERC20BridgeSource.Velodrome: case ERC20BridgeSource.Velodrome:
return encodeBridgeSourceId(BridgeProtocol.Velodrome, 'Velodrome'); return encodeBridgeSourceId(BridgeProtocol.Velodrome, 'Velodrome');
case ERC20BridgeSource.Synthetix:
return encodeBridgeSourceId(BridgeProtocol.Synthetix, 'Synthetix');
case ERC20BridgeSource.WOOFi:
return encodeBridgeSourceId(BridgeProtocol.WOOFi, 'WOOFi');
default: default:
throw new Error(AggregationError.NoBridgeForSource); throw new Error(AggregationError.NoBridgeForSource);
} }
@@ -397,18 +391,6 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
const velodromeFillData = (order as OptimizedMarketBridgeOrder<VelodromeFillData>).fillData; const velodromeFillData = (order as OptimizedMarketBridgeOrder<VelodromeFillData>).fillData;
bridgeData = encoder.encode([velodromeFillData.router, velodromeFillData.stable]); bridgeData = encoder.encode([velodromeFillData.router, velodromeFillData.stable]);
break; break;
case ERC20BridgeSource.Synthetix:
const fillData = (order as OptimizedMarketBridgeOrder<SynthetixFillData>).fillData;
bridgeData = encoder.encode([
fillData.synthetix,
fillData.takerTokenSymbolBytes32,
fillData.makerTokenSymbolBytes32,
]);
break;
case ERC20BridgeSource.WOOFi:
const woofiFillData = (order as OptimizedMarketBridgeOrder<WOOFiFillData>).fillData;
bridgeData = encoder.encode([woofiFillData.poolAddress]);
break;
default: default:
throw new Error(AggregationError.NoBridgeForSource); throw new Error(AggregationError.NoBridgeForSource);
} }
@@ -535,8 +517,6 @@ export const BRIDGE_ENCODERS: {
[ERC20BridgeSource.Compound]: AbiEncoder.create('(address)'), [ERC20BridgeSource.Compound]: AbiEncoder.create('(address)'),
[ERC20BridgeSource.Geist]: AbiEncoder.create('(address,address)'), [ERC20BridgeSource.Geist]: AbiEncoder.create('(address,address)'),
[ERC20BridgeSource.Velodrome]: AbiEncoder.create('(address,bool)'), [ERC20BridgeSource.Velodrome]: AbiEncoder.create('(address,bool)'),
[ERC20BridgeSource.Synthetix]: AbiEncoder.create('(address,bytes32,bytes32)'),
[ERC20BridgeSource.WOOFi]: AbiEncoder.create('(address)'),
}; };
function getFillTokenAmounts(fill: Fill, side: MarketOperation): [BigNumber, BigNumber] { function getFillTokenAmounts(fill: Fill, side: MarketOperation): [BigNumber, BigNumber] {

View File

@@ -14,7 +14,7 @@ import { dexSampleToFill, ethToOutputAmount, nativeOrderToFill } from './fills';
import { Path, PathPenaltyOpts } from './path'; import { Path, PathPenaltyOpts } from './path';
import { DexSample, ERC20BridgeSource, FeeSchedule, Fill, FillAdjustor, FillData, SamplerMetrics } from './types'; import { DexSample, ERC20BridgeSource, FeeSchedule, Fill, FillAdjustor, FillData, SamplerMetrics } from './types';
// tslint:disable: prefer-for-of completed-docs no-bitwise // tslint:disable: prefer-for-of custom-no-magic-numbers completed-docs no-bitwise
// NOTE: The Rust router will panic with less than 3 samples // NOTE: The Rust router will panic with less than 3 samples
const MIN_NUM_SAMPLE_INPUTS = 3; const MIN_NUM_SAMPLE_INPUTS = 3;

View File

@@ -1,19 +1,16 @@
import { ChainId } from '@0x/contract-addresses';
import { getPoolsWithTokens, parsePoolData } from 'balancer-labs-sor-v1'; import { getPoolsWithTokens, parsePoolData } from 'balancer-labs-sor-v1';
import { Pool } from 'balancer-labs-sor-v1/dist/types'; import { Pool } from 'balancer-labs-sor-v1/dist/types';
import { gql, request } from 'graphql-request'; import { gql, request } from 'graphql-request';
import { DEFAULT_WARNING_LOGGER } from '../../../constants'; import { DEFAULT_WARNING_LOGGER } from '../../../constants';
import { LogFunction } from '../../../types'; import { LogFunction } from '../../../types';
import { BALANCER_MAX_POOLS_FETCHED, BALANCER_TOP_POOLS_FETCHED } from '../constants'; import { BALANCER_MAX_POOLS_FETCHED, BALANCER_SUBGRAPH_URL, BALANCER_TOP_POOLS_FETCHED } from '../constants';
import { NoOpPoolsCache } from './no_op_pools_cache'; import { CacheValue, PoolsCache } from './pools_cache';
import { AbstractPoolsCache, CacheValue, PoolsCache } from './pools_cache';
// tslint:disable:custom-no-magic-numbers
const ONE_DAY_MS = 24 * 60 * 60 * 1000; const ONE_DAY_MS = 24 * 60 * 60 * 1000;
// tslint:disable: member-ordering // tslint:enable:custom-no-magic-numbers
const BALANCER_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer';
interface BalancerPoolResponse { interface BalancerPoolResponse {
id: string; id: string;
@@ -23,18 +20,10 @@ interface BalancerPoolResponse {
totalWeight: string; totalWeight: string;
} }
export class BalancerPoolsCache extends AbstractPoolsCache { export class BalancerPoolsCache extends PoolsCache {
public static create(chainId: ChainId): PoolsCache { constructor(
if (chainId !== ChainId.Mainnet) {
return new NoOpPoolsCache();
}
return new BalancerPoolsCache();
}
private constructor(
private readonly _subgraphUrl: string = BALANCER_SUBGRAPH_URL, private readonly _subgraphUrl: string = BALANCER_SUBGRAPH_URL,
cache: Map<string, CacheValue> = new Map(), cache: { [key: string]: CacheValue } = {},
private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED, private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED, private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED,
private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER, private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER,

View File

@@ -6,18 +6,16 @@ import { gql, request } from 'graphql-request';
import { DEFAULT_WARNING_LOGGER } from '../../../constants'; import { DEFAULT_WARNING_LOGGER } from '../../../constants';
import { LogFunction } from '../../../types'; import { LogFunction } from '../../../types';
import { BALANCER_MAX_POOLS_FETCHED, BALANCER_TOP_POOLS_FETCHED } from '../constants'; import {
BALANCER_MAX_POOLS_FETCHED,
BALANCER_TOP_POOLS_FETCHED,
BALANCER_V2_SUBGRAPH_URL_BY_CHAIN,
} from '../constants';
import { parsePoolData } from './balancer_sor_v2'; import { parsePoolData } from './balancer_sor_v2';
import { NoOpPoolsCache } from './no_op_pools_cache'; import { CacheValue, PoolsCache } from './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; const ONE_DAY_MS = 24 * 60 * 60 * 1000;
interface BalancerPoolResponse { interface BalancerPoolResponse {
@@ -30,16 +28,7 @@ interface BalancerPoolResponse {
amp: string | null; amp: string | null;
} }
export class BalancerV2PoolsCache extends AbstractPoolsCache { export class BalancerV2PoolsCache extends PoolsCache {
public static createBeethovenXPoolCache(chainId: ChainId): PoolsCache {
const subgraphUrl = BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN.get(chainId);
if (subgraphUrl === undefined) {
return new NoOpPoolsCache();
}
return new BalancerV2PoolsCache(subgraphUrl);
}
private static _parseSubgraphPoolData(pool: any, takerToken: string, makerToken: string): Pool { private static _parseSubgraphPoolData(pool: any, takerToken: string, makerToken: string): Pool {
const tToken = pool.tokens.find((t: any) => t.address === takerToken); const tToken = pool.tokens.find((t: any) => t.address === takerToken);
const mToken = pool.tokens.find((t: any) => t.address === makerToken); const mToken = pool.tokens.find((t: any) => t.address === makerToken);
@@ -60,12 +49,13 @@ export class BalancerV2PoolsCache extends AbstractPoolsCache {
}; };
} }
private constructor( constructor(
private readonly subgraphUrl: string, chainId: ChainId,
private readonly subgraphUrl: string = BALANCER_V2_SUBGRAPH_URL_BY_CHAIN[chainId]!,
private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED, private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED, private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED,
private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER, private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER,
cache: Map<string, CacheValue> = new Map(), cache: { [key: string]: CacheValue } = {},
) { ) {
super(cache); super(cache);
void this._loadTopPoolsAsync(); void this._loadTopPoolsAsync();
@@ -73,6 +63,19 @@ export class BalancerV2PoolsCache extends AbstractPoolsCache {
setInterval(async () => void this._loadTopPoolsAsync(), ONE_DAY_MS / 2); setInterval(async () => void this._loadTopPoolsAsync(), ONE_DAY_MS / 2);
} }
// protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> {
// try {
// const poolData = (await getPoolsWithTokens(takerToken, makerToken)).pools;
// // Sort by maker token balance (descending)
// const pools = parsePoolData(poolData, takerToken, makerToken).sort((a, b) =>
// b.balanceOut.minus(a.balanceOut).toNumber(),
// );
// return pools.length > this.maxPoolsFetched ? pools.slice(0, this.maxPoolsFetched) : pools;
// } catch (err) {
// return [];
// }
// }
protected async _fetchTopPoolsAsync(): Promise<BalancerPoolResponse[]> { protected async _fetchTopPoolsAsync(): Promise<BalancerPoolResponse[]> {
const query = gql` const query = gql`
query fetchTopPools($topPoolsFetched: Int!) { query fetchTopPools($topPoolsFetched: Int!) {

View File

@@ -20,6 +20,7 @@ import { BalancerSwapInfo, BalancerSwaps } from '../types';
import { CacheValue, EMPTY_BALANCER_SWAPS, SwapInfoCache } from './pair_swaps_cache'; import { CacheValue, EMPTY_BALANCER_SWAPS, SwapInfoCache } from './pair_swaps_cache';
import { SubgraphPoolDataService } from './sgPoolDataService'; import { SubgraphPoolDataService } from './sgPoolDataService';
// tslint:disable-next-line:custom-no-magic-numbers
const ONE_DAY_MS = 24 * 60 * 60 * ONE_SECOND_MS; const ONE_DAY_MS = 24 * 60 * 60 * ONE_SECOND_MS;
export interface BalancerPoolResponse { export interface BalancerPoolResponse {

View File

@@ -1,20 +1,18 @@
import { ChainId } from '@0x/contract-addresses';
import { Pool } from 'balancer-labs-sor-v1/dist/types'; import { Pool } from 'balancer-labs-sor-v1/dist/types';
import { getPoolsWithTokens, parsePoolData } from 'cream-sor'; import { getPoolsWithTokens, parsePoolData } from 'cream-sor';
import { BALANCER_MAX_POOLS_FETCHED } from '../constants'; import { BALANCER_MAX_POOLS_FETCHED } from '../constants';
import { NoOpPoolsCache } from './no_op_pools_cache'; import { CacheValue, PoolsCache } from './pools_cache';
import { AbstractPoolsCache, CacheValue, PoolsCache } from './pools_cache';
export class CreamPoolsCache extends AbstractPoolsCache { export class CreamPoolsCache extends PoolsCache {
public static create(chainId: ChainId): PoolsCache { constructor(
if (chainId !== ChainId.Mainnet) { _cache: { [key: string]: CacheValue } = {},
return new NoOpPoolsCache(); private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
) {
super(_cache);
} }
return new CreamPoolsCache();
}
protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> { protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> {
try { try {
const poolData = (await getPoolsWithTokens(takerToken, makerToken)).pools; const poolData = (await getPoolsWithTokens(takerToken, makerToken)).pools;
@@ -27,10 +25,4 @@ export class CreamPoolsCache extends AbstractPoolsCache {
return []; return [];
} }
} }
private constructor(
_cache: Map<string, CacheValue> = new Map(),
private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
) {
super(_cache);
}
} }

View File

@@ -1,4 +1,4 @@
export { BalancerPoolsCache } from './balancer_pools_cache'; export { BalancerPoolsCache } from './balancer_utils';
export { BalancerV2PoolsCache } from './balancer_v2_pools_cache'; export { BalancerV2PoolsCache } from './balancer_v2_utils';
export { CreamPoolsCache } from './cream_pools_cache'; export { CreamPoolsCache } from './cream_utils';
export { AbstractPoolsCache, PoolsCache } from './pools_cache'; export { PoolsCache } from './pools_cache';

View File

@@ -1,21 +0,0 @@
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;
}
}

View File

@@ -1,15 +1,18 @@
import { ONE_HOUR_IN_SECONDS, ONE_SECOND_MS } from '../constants';
import { BalancerSwaps } from '../types'; import { BalancerSwaps } from '../types';
import { ONE_HOUR_IN_SECONDS, ONE_SECOND_MS } from '../constants';
export interface CacheValue { export interface CacheValue {
expiresAt: number; expiresAt: number;
balancerSwaps: BalancerSwaps; balancerSwaps: BalancerSwaps;
} }
// tslint:disable:custom-no-magic-numbers
// Cache results for 30mins // Cache results for 30mins
const DEFAULT_CACHE_TIME_MS = (ONE_HOUR_IN_SECONDS / 2) * ONE_SECOND_MS; const DEFAULT_CACHE_TIME_MS = (ONE_HOUR_IN_SECONDS / 2) * ONE_SECOND_MS;
const DEFAULT_TIMEOUT_MS = ONE_SECOND_MS; const DEFAULT_TIMEOUT_MS = ONE_SECOND_MS;
export const EMPTY_BALANCER_SWAPS = { swapInfoExactIn: [], swapInfoExactOut: [] }; export const EMPTY_BALANCER_SWAPS = { swapInfoExactIn: [], swapInfoExactOut: [] };
// tslint:enable:custom-no-magic-numbers
/** /**
* Caches SwapInfo for a pair of tokens. * Caches SwapInfo for a pair of tokens.

View File

@@ -7,30 +7,18 @@ export interface CacheValue {
pools: Pool[]; pools: Pool[];
} }
// tslint:disable:custom-no-magic-numbers
// Cache results for 30mins // Cache results for 30mins
const DEFAULT_CACHE_TIME_MS = (ONE_HOUR_IN_SECONDS / 2) * ONE_SECOND_MS; const DEFAULT_CACHE_TIME_MS = (ONE_HOUR_IN_SECONDS / 2) * ONE_SECOND_MS;
const DEFAULT_TIMEOUT_MS = 3000; const DEFAULT_TIMEOUT_MS = 1000;
// tslint:enable:custom-no-magic-numbers
export interface PoolsCache { export abstract class PoolsCache {
getFreshPoolsForPairAsync(takerToken: string, makerToken: string, timeoutMs?: number): Promise<Pool[]>; protected static _isExpired(value: CacheValue): boolean {
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; return Date.now() >= value.expiresAt;
} }
constructor( constructor(
protected readonly _cache: Map<string, CacheValue>, protected readonly _cache: { [key: string]: CacheValue },
protected readonly _cacheTimeMs: number = DEFAULT_CACHE_TIME_MS, protected readonly _cacheTimeMs: number = DEFAULT_CACHE_TIME_MS,
) {} ) {}
@@ -43,42 +31,47 @@ export abstract class AbstractPoolsCache implements PoolsCache {
return Promise.race([this._getAndSaveFreshPoolsForPairAsync(takerToken, makerToken), timeout]); return Promise.race([this._getAndSaveFreshPoolsForPairAsync(takerToken, makerToken), timeout]);
} }
/** public getCachedPoolAddressesForPair(
* Returns pool addresses (can be stale) for a pair. takerToken: string,
* makerToken: string,
* An empty array will be returned if cache does not exist. ignoreExpired: boolean = true,
*/ ): string[] | undefined {
public getPoolAddressesForPair(takerToken: string, makerToken: string): string[] { const key = JSON.stringify([takerToken, makerToken]);
const value = this._getValue(takerToken, makerToken); const value = this._cache[key];
if (ignoreExpired) {
return value === undefined ? [] : value.pools.map(pool => pool.id); 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);
}
public isFresh(takerToken: string, makerToken: string): boolean { public isFresh(takerToken: string, makerToken: string): boolean {
const value = this._getValue(takerToken, makerToken); const cached = this.getCachedPoolAddressesForPair(takerToken, makerToken, false);
return !AbstractPoolsCache._isExpired(value); return cached !== undefined;
}
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[]> { protected async _getAndSaveFreshPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> {
const key = AbstractPoolsCache._getKey(takerToken, makerToken); const key = JSON.stringify([takerToken, makerToken]);
const value = this._cache.get(key); const value = this._cache[key];
if (!AbstractPoolsCache._isExpired(value)) { if (value === undefined || value.expiresAt >= Date.now()) {
return value!.pools;
}
const pools = await this._fetchPoolsForPairAsync(takerToken, makerToken); const pools = await this._fetchPoolsForPairAsync(takerToken, makerToken);
const expiresAt = Date.now() + this._cacheTimeMs; const expiresAt = Date.now() + this._cacheTimeMs;
this._cachePoolsForPair(takerToken, makerToken, pools, expiresAt); this._cachePoolsForPair(takerToken, makerToken, pools, expiresAt);
return pools; }
return this._cache[key].pools;
} }
protected _cachePoolsForPair(takerToken: string, makerToken: string, pools: Pool[], expiresAt: number): void { protected _cachePoolsForPair(takerToken: string, makerToken: string, pools: Pool[], expiresAt: number): void {
const key = AbstractPoolsCache._getKey(takerToken, makerToken); const key = JSON.stringify([takerToken, makerToken]);
this._cache.set(key, { pools, expiresAt }); this._cache[key] = {
pools,
expiresAt,
};
} }
protected abstract _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]>; protected abstract _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]>;

View File

@@ -3,11 +3,10 @@ import { BigNumber, NULL_BYTES } from '@0x/utils';
import { SamplerOverrides } from '../../types'; import { SamplerOverrides } from '../../types';
import { ERC20BridgeSamplerContract } from '../../wrappers'; import { ERC20BridgeSamplerContract } from '../../wrappers';
import { TokenAdjacencyGraph } from '../token_adjacency_graph';
import { BancorService } from './bancor_service'; import { BancorService } from './bancor_service';
import { PoolsCacheMap, SamplerOperations } from './sampler_operations'; import { PoolsCacheMap, SamplerOperations } from './sampler_operations';
import { BatchedOperation, LiquidityProviderRegistry } from './types'; import { BatchedOperation, LiquidityProviderRegistry, TokenAdjacencyGraph } from './types';
/** /**
* Generate sample amounts up to `maxFillAmount`. * Generate sample amounts up to `maxFillAmount`.

View File

@@ -1,14 +1,12 @@
import { ChainId } from '@0x/contract-addresses'; import { ChainId } from '@0x/contract-addresses';
import { LimitOrderFields } from '@0x/protocol-utils'; import { LimitOrderFields } from '@0x/protocol-utils';
import { BigNumber, logUtils } from '@0x/utils'; import { BigNumber, logUtils } from '@0x/utils';
import { formatBytes32String } from '@ethersproject/strings';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { AaveV2Sampler } from '../../noop_samplers/AaveV2Sampler'; import { AaveV2Sampler } from '../../noop_samplers/AaveV2Sampler';
import { GeistSampler } from '../../noop_samplers/GeistSampler'; import { GeistSampler } from '../../noop_samplers/GeistSampler';
import { SamplerCallResult, SignedNativeOrder } from '../../types'; import { SamplerCallResult, SignedNativeOrder } from '../../types';
import { ERC20BridgeSamplerContract } from '../../wrappers'; import { ERC20BridgeSamplerContract } from '../../wrappers';
import { TokenAdjacencyGraph } from '../token_adjacency_graph';
import { AaveV2ReservesCache } from './aave_reserves_cache'; import { AaveV2ReservesCache } from './aave_reserves_cache';
import { BancorService } from './bancor_service'; import { BancorService } from './bancor_service';
@@ -26,9 +24,10 @@ import {
AAVE_V2_SUBGRAPH_URL_BY_CHAIN_ID, AAVE_V2_SUBGRAPH_URL_BY_CHAIN_ID,
AVALANCHE_TOKENS, AVALANCHE_TOKENS,
BALANCER_V2_VAULT_ADDRESS_BY_CHAIN, BALANCER_V2_VAULT_ADDRESS_BY_CHAIN,
BANCOR_REGISTRY_BY_CHAIN_ID,
BANCORV3_NETWORK_BY_CHAIN_ID, BANCORV3_NETWORK_BY_CHAIN_ID,
BANCORV3_NETWORK_INFO_BY_CHAIN_ID, BANCORV3_NETWORK_INFO_BY_CHAIN_ID,
BANCOR_REGISTRY_BY_CHAIN_ID, BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN,
BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN, BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN,
COMPOUND_API_URL_BY_CHAIN_ID, COMPOUND_API_URL_BY_CHAIN_ID,
DODOV1_CONFIG_BY_CHAIN_ID, DODOV1_CONFIG_BY_CHAIN_ID,
@@ -47,19 +46,16 @@ import {
NULL_ADDRESS, NULL_ADDRESS,
PLATYPUS_ROUTER_BY_CHAIN_ID, PLATYPUS_ROUTER_BY_CHAIN_ID,
SELL_SOURCE_FILTER_BY_CHAIN_ID, SELL_SOURCE_FILTER_BY_CHAIN_ID,
SYNTHETIX_CURRENCY_KEYS_BY_CHAIN_ID,
SYNTHETIX_READ_PROXY_BY_CHAIN_ID,
UNISWAPV1_ROUTER_BY_CHAIN_ID, UNISWAPV1_ROUTER_BY_CHAIN_ID,
UNISWAPV3_CONFIG_BY_CHAIN_ID, UNISWAPV3_CONFIG_BY_CHAIN_ID,
VELODROME_ROUTER_BY_CHAIN_ID, VELODROME_ROUTER_BY_CHAIN_ID,
WOOFI_POOL_BY_CHAIN_ID,
WOOFI_SUPPORTED_TOKENS,
ZERO_AMOUNT, ZERO_AMOUNT,
} from './constants'; } from './constants';
import { getGeistInfoForPair } from './geist_utils'; import { getGeistInfoForPair } from './geist_utils';
import { getLiquidityProvidersForPair } from './liquidity_provider_utils'; import { getLiquidityProvidersForPair } from './liquidity_provider_utils';
import { getIntermediateTokens } from './multihop_utils';
import { BalancerPoolsCache, BalancerV2PoolsCache, CreamPoolsCache, PoolsCache } from './pools_cache'; import { BalancerPoolsCache, BalancerV2PoolsCache, CreamPoolsCache, PoolsCache } from './pools_cache';
import { BalancerV2SwapInfoCache } from './pools_cache/balancer_v2_swap_info_cache'; import { BalancerV2SwapInfoCache } from './pools_cache/balancer_v2_utils_new';
import { SamplerContractOperation } from './sampler_contract_operation'; import { SamplerContractOperation } from './sampler_contract_operation';
import { SamplerNoOperation } from './sampler_no_operation'; import { SamplerNoOperation } from './sampler_no_operation';
import { SourceFilters } from './source_filters'; import { SourceFilters } from './source_filters';
@@ -97,11 +93,11 @@ import {
PsmInfo, PsmInfo,
ShellFillData, ShellFillData,
SourceQuoteOperation, SourceQuoteOperation,
SynthetixFillData, SourcesWithPoolsCache,
TokenAdjacencyGraph,
UniswapV2FillData, UniswapV2FillData,
UniswapV3FillData, UniswapV3FillData,
VelodromeFillData, VelodromeFillData,
WOOFiFillData,
} from './types'; } from './types';
/** /**
@@ -116,12 +112,9 @@ export const TWO_HOP_SOURCE_FILTERS = SourceFilters.all().exclude([
*/ */
export const BATCH_SOURCE_FILTERS = SourceFilters.all().exclude([ERC20BridgeSource.MultiHop, ERC20BridgeSource.Native]); export const BATCH_SOURCE_FILTERS = SourceFilters.all().exclude([ERC20BridgeSource.MultiHop, ERC20BridgeSource.Native]);
export interface PoolsCacheMap { export type PoolsCacheMap = { [key in Exclude<SourcesWithPoolsCache, ERC20BridgeSource.BalancerV2>]: PoolsCache } & {
[ERC20BridgeSource.Balancer]: PoolsCache;
[ERC20BridgeSource.BalancerV2]: BalancerV2SwapInfoCache | undefined; [ERC20BridgeSource.BalancerV2]: BalancerV2SwapInfoCache | undefined;
[ERC20BridgeSource.Beethovenx]: PoolsCache; };
[ERC20BridgeSource.Cream]: PoolsCache;
}
// tslint:disable:no-inferred-empty-object-type no-unbound-method // tslint:disable:no-inferred-empty-object-type no-unbound-method
@@ -147,7 +140,7 @@ export class SamplerOperations {
public readonly chainId: ChainId, public readonly chainId: ChainId,
protected readonly _samplerContract: ERC20BridgeSamplerContract, protected readonly _samplerContract: ERC20BridgeSamplerContract,
poolsCaches?: PoolsCacheMap, poolsCaches?: PoolsCacheMap,
protected readonly tokenAdjacencyGraph: TokenAdjacencyGraph = TokenAdjacencyGraph.getEmptyGraph(), protected readonly tokenAdjacencyGraph: TokenAdjacencyGraph = { default: [] },
liquidityProviderRegistry: LiquidityProviderRegistry = {}, liquidityProviderRegistry: LiquidityProviderRegistry = {},
bancorServiceFn: () => Promise<BancorService | undefined> = async () => undefined, bancorServiceFn: () => Promise<BancorService | undefined> = async () => undefined,
) { ) {
@@ -158,9 +151,12 @@ export class SamplerOperations {
this.poolsCaches = poolsCaches this.poolsCaches = poolsCaches
? poolsCaches ? poolsCaches
: { : {
[ERC20BridgeSource.Beethovenx]: BalancerV2PoolsCache.createBeethovenXPoolCache(chainId), [ERC20BridgeSource.Beethovenx]: new BalancerV2PoolsCache(
[ERC20BridgeSource.Balancer]: BalancerPoolsCache.create(chainId), chainId,
[ERC20BridgeSource.Cream]: CreamPoolsCache.create(chainId), BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN[chainId],
),
[ERC20BridgeSource.Balancer]: new BalancerPoolsCache(),
[ERC20BridgeSource.Cream]: new CreamPoolsCache(),
[ERC20BridgeSource.BalancerV2]: [ERC20BridgeSource.BalancerV2]:
BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[chainId] === NULL_ADDRESS BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[chainId] === NULL_ADDRESS
? undefined ? undefined
@@ -814,7 +810,7 @@ export class SamplerOperations {
if (_sources.length === 0) { if (_sources.length === 0) {
return SamplerOperations.constant([]); return SamplerOperations.constant([]);
} }
const intermediateTokens = this.tokenAdjacencyGraph.getIntermediateTokens(makerToken, takerToken); const intermediateTokens = getIntermediateTokens(makerToken, takerToken, this.tokenAdjacencyGraph);
const subOps = intermediateTokens.map(intermediateToken => { const subOps = intermediateTokens.map(intermediateToken => {
const firstHopOps = this._getSellQuoteOperations(_sources, intermediateToken, takerToken, [ZERO_AMOUNT]); const firstHopOps = this._getSellQuoteOperations(_sources, intermediateToken, takerToken, [ZERO_AMOUNT]);
const secondHopOps = this._getSellQuoteOperations(_sources, makerToken, intermediateToken, [ZERO_AMOUNT]); const secondHopOps = this._getSellQuoteOperations(_sources, makerToken, intermediateToken, [ZERO_AMOUNT]);
@@ -869,7 +865,7 @@ export class SamplerOperations {
if (_sources.length === 0) { if (_sources.length === 0) {
return SamplerOperations.constant([]); return SamplerOperations.constant([]);
} }
const intermediateTokens = this.tokenAdjacencyGraph.getIntermediateTokens(makerToken, takerToken); const intermediateTokens = getIntermediateTokens(makerToken, takerToken, this.tokenAdjacencyGraph);
const subOps = intermediateTokens.map(intermediateToken => { const subOps = intermediateTokens.map(intermediateToken => {
const firstHopOps = this._getBuyQuoteOperations(_sources, intermediateToken, takerToken, [ const firstHopOps = this._getBuyQuoteOperations(_sources, intermediateToken, takerToken, [
new BigNumber(0), new BigNumber(0),
@@ -1314,89 +1310,6 @@ export class SamplerOperations {
}); });
} }
public getSynthetixSellQuotes(
readProxy: string,
takerTokenSymbol: string,
makerTokenSymbol: string,
takerFillAmounts: BigNumber[],
): SourceQuoteOperation<SynthetixFillData> {
const takerTokenSymbolBytes32 = formatBytes32String(takerTokenSymbol);
const makerTokenSymbolBytes32 = formatBytes32String(makerTokenSymbol);
return new SamplerContractOperation({
source: ERC20BridgeSource.Synthetix,
contract: this._samplerContract,
function: this._samplerContract.sampleSellsFromSynthetix,
params: [readProxy, takerTokenSymbolBytes32, makerTokenSymbolBytes32, takerFillAmounts],
callback: (callResults: string, fillData: SynthetixFillData): BigNumber[] => {
const [synthetix, samples] = this._samplerContract.getABIDecodedReturnData<[string, BigNumber[]]>(
'sampleSellsFromSynthetix',
callResults,
);
fillData.synthetix = synthetix;
fillData.takerTokenSymbolBytes32 = takerTokenSymbolBytes32;
fillData.makerTokenSymbolBytes32 = makerTokenSymbolBytes32;
fillData.chainId = this.chainId;
return samples;
},
});
}
public getSynthetixBuyQuotes(
readProxy: string,
takerTokenSymbol: string,
makerTokenSymbol: string,
makerFillAmounts: BigNumber[],
): SourceQuoteOperation<SynthetixFillData> {
const takerTokenSymbolBytes32 = formatBytes32String(takerTokenSymbol);
const makerTokenSymbolBytes32 = formatBytes32String(makerTokenSymbol);
return new SamplerContractOperation({
source: ERC20BridgeSource.Synthetix,
contract: this._samplerContract,
function: this._samplerContract.sampleBuysFromSynthetix,
params: [readProxy, takerTokenSymbolBytes32, makerTokenSymbolBytes32, makerFillAmounts],
callback: (callResults: string, fillData: SynthetixFillData): BigNumber[] => {
const [synthetix, samples] = this._samplerContract.getABIDecodedReturnData<[string, BigNumber[]]>(
'sampleBuysFromSynthetix',
callResults,
);
fillData.synthetix = synthetix;
fillData.takerTokenSymbolBytes32 = takerTokenSymbolBytes32;
fillData.makerTokenSymbolBytes32 = makerTokenSymbolBytes32;
fillData.chainId = this.chainId;
return samples;
},
});
}
public getWOOFiSellQuotes(
poolAddress: string,
takerToken: string,
makerToken: string,
makerFillAmounts: BigNumber[],
): SourceQuoteOperation<WOOFiFillData> {
return new SamplerContractOperation({
fillData: { poolAddress, takerToken, makerToken },
source: ERC20BridgeSource.WOOFi,
contract: this._samplerContract,
function: this._samplerContract.sampleSellsFromWooPP,
params: [poolAddress, takerToken, makerToken, makerFillAmounts],
});
}
public getWOOFiBuyQuotes(
poolAddress: string,
takerToken: string,
makerToken: string,
makerFillAmounts: BigNumber[],
): SourceQuoteOperation<WOOFiFillData> {
return new SamplerContractOperation({
fillData: { poolAddress, takerToken, makerToken },
source: ERC20BridgeSource.WOOFi,
contract: this._samplerContract,
function: this._samplerContract.sampleBuysFromWooPP,
params: [poolAddress, takerToken, makerToken, makerFillAmounts],
});
}
/** /**
* Returns the best price for the native token * Returns the best price for the native token
* Best is calculated according to the fee schedule, so the price of the * Best is calculated according to the fee schedule, so the price of the
@@ -1412,13 +1325,9 @@ export class SamplerOperations {
if (makerToken.toLowerCase() === nativeToken.toLowerCase()) { if (makerToken.toLowerCase() === nativeToken.toLowerCase()) {
return SamplerOperations.constant(new BigNumber(1)); return SamplerOperations.constant(new BigNumber(1));
} }
const subOps = this._getSellQuoteOperations( const subOps = this._getSellQuoteOperations(sources, makerToken, nativeToken, [nativeFillAmount], {
sources, default: [],
makerToken, });
nativeToken,
[nativeFillAmount],
TokenAdjacencyGraph.getEmptyGraph(),
);
return this._createBatch( return this._createBatch(
subOps, subOps,
(samples: BigNumber[][]) => { (samples: BigNumber[][]) => {
@@ -1514,7 +1423,7 @@ export class SamplerOperations {
): SourceQuoteOperation[] { ): SourceQuoteOperation[] {
// Find the adjacent tokens in the provided token adjacency graph, // Find the adjacent tokens in the provided token adjacency graph,
// e.g if this is DAI->USDC we may check for DAI->WETH->USDC // e.g if this is DAI->USDC we may check for DAI->WETH->USDC
const intermediateTokens = tokenAdjacencyGraph.getIntermediateTokens(makerToken, takerToken); const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph);
// Drop out MultiHop and Native as we do not query those here. // Drop out MultiHop and Native as we do not query those here.
const _sources = SELL_SOURCE_FILTER_BY_CHAIN_ID[this.chainId] const _sources = SELL_SOURCE_FILTER_BY_CHAIN_ID[this.chainId]
.exclude([ERC20BridgeSource.MultiHop, ERC20BridgeSource.Native]) .exclude([ERC20BridgeSource.MultiHop, ERC20BridgeSource.Native])
@@ -1624,9 +1533,12 @@ export class SamplerOperations {
), ),
]; ];
case ERC20BridgeSource.Balancer: case ERC20BridgeSource.Balancer:
return this.poolsCaches[ERC20BridgeSource.Balancer] return (
.getPoolAddressesForPair(takerToken, makerToken) this.poolsCaches[ERC20BridgeSource.Balancer].getCachedPoolAddressesForPair(
.map(balancerPool => takerToken,
makerToken,
) || []
).map(balancerPool =>
this.getBalancerSellQuotes( this.getBalancerSellQuotes(
balancerPool, balancerPool,
makerToken, makerToken,
@@ -1652,15 +1564,16 @@ export class SamplerOperations {
); );
} }
case ERC20BridgeSource.Beethovenx: { case ERC20BridgeSource.Beethovenx: {
const cache = this.poolsCaches[source]; const poolIds =
const poolAddresses = cache.getPoolAddressesForPair(takerToken, makerToken); this.poolsCaches[source].getCachedPoolAddressesForPair(takerToken, makerToken) || [];
const vault = BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId]; const vault = BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId];
if (vault === NULL_ADDRESS) { if (vault === NULL_ADDRESS) {
return []; return [];
} }
return poolAddresses.map(poolAddress => return poolIds.map(poolId =>
this.getBalancerV2SellQuotes( this.getBalancerV2SellQuotes(
{ poolId: poolAddress, vault }, { poolId, vault },
makerToken, makerToken,
takerToken, takerToken,
takerFillAmounts, takerFillAmounts,
@@ -1669,9 +1582,12 @@ export class SamplerOperations {
); );
} }
case ERC20BridgeSource.Cream: case ERC20BridgeSource.Cream:
return this.poolsCaches[ERC20BridgeSource.Cream] return (
.getPoolAddressesForPair(takerToken, makerToken) this.poolsCaches[ERC20BridgeSource.Cream].getCachedPoolAddressesForPair(
.map(creamPool => takerToken,
makerToken,
) || []
).map(creamPool =>
this.getBalancerSellQuotes( this.getBalancerSellQuotes(
creamPool, creamPool,
makerToken, makerToken,
@@ -1779,8 +1695,8 @@ export class SamplerOperations {
); );
} }
case ERC20BridgeSource.GMX: { case ERC20BridgeSource.GMX: {
// MIM has no liquidity. // low liquidity mim pool dont quote
if (takerToken === AVALANCHE_TOKENS.MIM || makerToken === AVALANCHE_TOKENS.MIM) { if (takerToken === AVALANCHE_TOKENS.MIM || makerToken === 'AVALANCHE_TOKENS.MIM') {
return []; return [];
} }
return this.getGMXSellQuotes( return this.getGMXSellQuotes(
@@ -1817,32 +1733,6 @@ export class SamplerOperations {
takerFillAmounts, takerFillAmounts,
); );
} }
case ERC20BridgeSource.Synthetix: {
const readProxy = SYNTHETIX_READ_PROXY_BY_CHAIN_ID[this.chainId];
const currencyKeyMap = SYNTHETIX_CURRENCY_KEYS_BY_CHAIN_ID[this.chainId];
const takerTokenSymbol = currencyKeyMap.get(takerToken.toLowerCase());
const makerTokenSymbol = currencyKeyMap.get(makerToken.toLowerCase());
if (takerTokenSymbol === undefined || makerTokenSymbol === undefined) {
return [];
}
return this.getSynthetixSellQuotes(
readProxy,
takerTokenSymbol,
makerTokenSymbol,
takerFillAmounts,
);
}
case ERC20BridgeSource.WOOFi: {
if (!(WOOFI_SUPPORTED_TOKENS.has(takerToken) && WOOFI_SUPPORTED_TOKENS.has(makerToken))) {
return [];
}
return this.getWOOFiSellQuotes(
WOOFI_POOL_BY_CHAIN_ID[this.chainId],
takerToken,
makerToken,
takerFillAmounts,
);
}
default: default:
throw new Error(`Unsupported sell sample source: ${source}`); throw new Error(`Unsupported sell sample source: ${source}`);
} }
@@ -1877,7 +1767,7 @@ export class SamplerOperations {
): SourceQuoteOperation[] { ): SourceQuoteOperation[] {
// Find the adjacent tokens in the provided token adjacency graph, // Find the adjacent tokens in the provided token adjacency graph,
// e.g if this is DAI->USDC we may check for DAI->WETH->USDC // e.g if this is DAI->USDC we may check for DAI->WETH->USDC
const intermediateTokens = this.tokenAdjacencyGraph.getIntermediateTokens(makerToken, takerToken); const intermediateTokens = getIntermediateTokens(makerToken, takerToken, this.tokenAdjacencyGraph);
const _sources = BATCH_SOURCE_FILTERS.getAllowed(sources); const _sources = BATCH_SOURCE_FILTERS.getAllowed(sources);
return _.flatten( return _.flatten(
_sources.map((source): SourceQuoteOperation | SourceQuoteOperation[] => { _sources.map((source): SourceQuoteOperation | SourceQuoteOperation[] => {
@@ -1981,9 +1871,12 @@ export class SamplerOperations {
), ),
]; ];
case ERC20BridgeSource.Balancer: case ERC20BridgeSource.Balancer:
return this.poolsCaches[ERC20BridgeSource.Balancer] return (
.getPoolAddressesForPair(takerToken, makerToken) this.poolsCaches[ERC20BridgeSource.Balancer].getCachedPoolAddressesForPair(
.map(poolAddress => takerToken,
makerToken,
) || []
).map(poolAddress =>
this.getBalancerBuyQuotes( this.getBalancerBuyQuotes(
poolAddress, poolAddress,
makerToken, makerToken,
@@ -2015,8 +1908,9 @@ export class SamplerOperations {
); );
} }
case ERC20BridgeSource.Beethovenx: { case ERC20BridgeSource.Beethovenx: {
const cache = this.poolsCaches[source]; const poolIds =
const poolIds = cache.getPoolAddressesForPair(takerToken, makerToken) || []; this.poolsCaches[source].getCachedPoolAddressesForPair(takerToken, makerToken) || [];
const vault = BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId]; const vault = BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId];
if (vault === NULL_ADDRESS) { if (vault === NULL_ADDRESS) {
return []; return [];
@@ -2032,9 +1926,12 @@ export class SamplerOperations {
); );
} }
case ERC20BridgeSource.Cream: case ERC20BridgeSource.Cream:
return this.poolsCaches[ERC20BridgeSource.Cream] return (
.getPoolAddressesForPair(takerToken, makerToken) this.poolsCaches[ERC20BridgeSource.Cream].getCachedPoolAddressesForPair(
.map(poolAddress => takerToken,
makerToken,
) || []
).map(poolAddress =>
this.getBalancerBuyQuotes( this.getBalancerBuyQuotes(
poolAddress, poolAddress,
makerToken, makerToken,
@@ -2130,8 +2027,8 @@ export class SamplerOperations {
return this.getCompoundBuyQuotes(cToken.tokenAddress, makerToken, takerToken, makerFillAmounts); return this.getCompoundBuyQuotes(cToken.tokenAddress, makerToken, takerToken, makerFillAmounts);
} }
case ERC20BridgeSource.GMX: { case ERC20BridgeSource.GMX: {
// MIM has no liquidity. // bad mim pool dont quote
if (takerToken === AVALANCHE_TOKENS.MIM || makerToken === AVALANCHE_TOKENS.MIM) { if (takerToken === 'AVALANCHE_TOKENS.MIM' || makerToken === 'AVALANCHE_TOKENS.MIM') {
return []; return [];
} }
return this.getGMXBuyQuotes( return this.getGMXBuyQuotes(
@@ -2168,32 +2065,6 @@ export class SamplerOperations {
makerFillAmounts, makerFillAmounts,
); );
} }
case ERC20BridgeSource.Synthetix: {
const readProxy = SYNTHETIX_READ_PROXY_BY_CHAIN_ID[this.chainId];
const currencyKeyMap = SYNTHETIX_CURRENCY_KEYS_BY_CHAIN_ID[this.chainId];
const takerTokenSymbol = currencyKeyMap.get(takerToken.toLowerCase());
const makerTokenSymbol = currencyKeyMap.get(makerToken.toLowerCase());
if (takerTokenSymbol === undefined || makerTokenSymbol === undefined) {
return [];
}
return this.getSynthetixBuyQuotes(
readProxy,
takerTokenSymbol,
makerTokenSymbol,
makerFillAmounts,
);
}
case ERC20BridgeSource.WOOFi: {
if (!(WOOFI_SUPPORTED_TOKENS.has(takerToken) && WOOFI_SUPPORTED_TOKENS.has(makerToken))) {
return [];
}
return this.getWOOFiBuyQuotes(
WOOFI_POOL_BY_CHAIN_ID[this.chainId],
takerToken,
makerToken,
makerFillAmounts,
);
}
default: default:
throw new Error(`Unsupported buy sample source: ${source}`); throw new Error(`Unsupported buy sample source: ${source}`);
} }

View File

@@ -1,7 +1,7 @@
import { ChainId } from '@0x/contract-addresses';
import { import {
FillQuoteTransformerLimitOrderInfo, FillQuoteTransformerLimitOrderInfo,
FillQuoteTransformerOrderType, FillQuoteTransformerOrderType,
FillQuoteTransformerOtcOrderInfo,
FillQuoteTransformerRfqOrderInfo, FillQuoteTransformerRfqOrderInfo,
} from '@0x/protocol-utils'; } from '@0x/protocol-utils';
import { MarketOperation } from '@0x/types'; import { MarketOperation } from '@0x/types';
@@ -11,7 +11,6 @@ import { NativeOrderWithFillableAmounts, RfqFirmQuoteValidator, RfqRequestOpts }
import { QuoteRequestor, V4RFQIndicativeQuoteMM } from '../../utils/quote_requestor'; import { QuoteRequestor, V4RFQIndicativeQuoteMM } from '../../utils/quote_requestor';
import { IRfqClient } from '../irfq_client'; import { IRfqClient } from '../irfq_client';
import { ExtendedQuoteReportSources, PriceComparisonsReport, QuoteReport } from '../quote_report_generator'; import { ExtendedQuoteReportSources, PriceComparisonsReport, QuoteReport } from '../quote_report_generator';
import { TokenAdjacencyGraph } from '../token_adjacency_graph';
import { SourceFilters } from './source_filters'; import { SourceFilters } from './source_filters';
@@ -68,8 +67,6 @@ export enum ERC20BridgeSource {
Compound = 'Compound', Compound = 'Compound',
Synapse = 'Synapse', Synapse = 'Synapse',
BancorV3 = 'BancorV3', BancorV3 = 'BancorV3',
Synthetix = 'Synthetix',
WOOFi = 'WOOFi',
// BSC only // BSC only
PancakeSwap = 'PancakeSwap', PancakeSwap = 'PancakeSwap',
PancakeSwapV2 = 'PancakeSwap_V2', PancakeSwapV2 = 'PancakeSwap_V2',
@@ -109,6 +106,11 @@ export enum ERC20BridgeSource {
// Optimism // Optimism
Velodrome = 'Velodrome', Velodrome = 'Velodrome',
} }
export type SourcesWithPoolsCache =
| ERC20BridgeSource.Balancer
| ERC20BridgeSource.BalancerV2
| ERC20BridgeSource.Beethovenx
| ERC20BridgeSource.Cream;
// tslint:disable: enum-naming // tslint:disable: enum-naming
/** /**
@@ -195,7 +197,8 @@ export interface FillData {}
// `FillData` for native fills. Represents a single native order // `FillData` for native fills. Represents a single native order
export type NativeRfqOrderFillData = FillQuoteTransformerRfqOrderInfo; export type NativeRfqOrderFillData = FillQuoteTransformerRfqOrderInfo;
export type NativeLimitOrderFillData = FillQuoteTransformerLimitOrderInfo; export type NativeLimitOrderFillData = FillQuoteTransformerLimitOrderInfo;
export type NativeFillData = NativeRfqOrderFillData | NativeLimitOrderFillData; export type NativeOtcOrderFillData = FillQuoteTransformerOtcOrderInfo;
export type NativeFillData = NativeRfqOrderFillData | NativeLimitOrderFillData | NativeOtcOrderFillData;
// Represents an individual DEX sample from the sampler contract // Represents an individual DEX sample from the sampler contract
export interface DexSample<TFillData extends FillData = FillData> { export interface DexSample<TFillData extends FillData = FillData> {
@@ -374,25 +377,11 @@ export interface PlatypusFillData extends FillData {
tokenAddressPath: string[]; tokenAddressPath: string[];
} }
export interface WOOFiFillData extends FillData {
poolAddress: string;
takerToken: string;
makerToken: string;
}
export interface VelodromeFillData extends FillData { export interface VelodromeFillData extends FillData {
router: string; router: string;
stable: boolean; stable: boolean;
} }
export interface SynthetixFillData extends FillData {
synthetix: string;
takerTokenSymbolBytes32: string;
makerTokenSymbolBytes32: string;
// Only needed for gas estimation.
chainId: ChainId;
}
/** /**
* Represents a node on a fill path. * Represents a node on a fill path.
*/ */
@@ -449,7 +438,8 @@ export interface OptimizedRfqOrder extends OptimizedMarketOrderBase<NativeRfqOrd
export type OptimizedMarketOrder = export type OptimizedMarketOrder =
| OptimizedMarketBridgeOrder<FillData> | OptimizedMarketBridgeOrder<FillData>
| OptimizedMarketOrderBase<NativeLimitOrderFillData> | OptimizedMarketOrderBase<NativeLimitOrderFillData>
| OptimizedMarketOrderBase<NativeRfqOrderFillData>; | OptimizedMarketOrderBase<NativeRfqOrderFillData>
| OptimizedMarketOrderBase<NativeOtcOrderFillData>;
export interface GetMarketOrdersRfqOpts extends RfqRequestOpts { export interface GetMarketOrdersRfqOpts extends RfqRequestOpts {
rfqClient?: IRfqClient; rfqClient?: IRfqClient;
@@ -624,6 +614,15 @@ export interface OptimizerResultWithReport extends OptimizerResult {
priceComparisonsReport?: PriceComparisonsReport; priceComparisonsReport?: PriceComparisonsReport;
} }
export type MarketDepthSide = Array<Array<DexSample<FillData>>>;
export interface MarketDepth {
bids: MarketDepthSide;
asks: MarketDepthSide;
makerTokenDecimals: number;
takerTokenDecimals: number;
}
export interface MarketSideLiquidity { export interface MarketSideLiquidity {
side: MarketOperation; side: MarketOperation;
inputAmount: BigNumber; inputAmount: BigNumber;
@@ -646,6 +645,11 @@ export interface RawQuotes {
dexQuotes: Array<Array<DexSample<FillData>>>; dexQuotes: Array<Array<DexSample<FillData>>>;
} }
export interface TokenAdjacencyGraph {
[token: string]: string[];
default: string[];
}
export interface LiquidityProviderRegistry { export interface LiquidityProviderRegistry {
[address: string]: { [address: string]: {
tokens: string[]; tokens: string[];

View File

@@ -6,36 +6,28 @@ import { SwapQuoterError } from '../types';
const MAX_ERROR_COUNT = 5; const MAX_ERROR_COUNT = 5;
interface GasOracleResponse {
result: {
// gas price in wei
fast: number;
};
}
export class ProtocolFeeUtils { export class ProtocolFeeUtils {
private static _instance: ProtocolFeeUtils; private static _instance: ProtocolFeeUtils;
private readonly _zeroExGasApiUrl: string; private readonly _ethGasStationUrl!: string;
private readonly _gasPriceHeart: any; private readonly _gasPriceHeart: any;
private _gasPriceEstimation: BigNumber = constants.ZERO_AMOUNT; private _gasPriceEstimation: BigNumber = constants.ZERO_AMOUNT;
private _errorCount: number = 0; private _errorCount: number = 0;
public static getInstance( public static getInstance(
gasPricePollingIntervalInMs: number, gasPricePollingIntervalInMs: number,
zeroExGasApiUrl: string = constants.ZERO_EX_GAS_API_URL, ethGasStationUrl: string = constants.ETH_GAS_STATION_API_URL,
initialGasPrice: BigNumber = constants.ZERO_AMOUNT, initialGasPrice: BigNumber = constants.ZERO_AMOUNT,
): ProtocolFeeUtils { ): ProtocolFeeUtils {
if (!ProtocolFeeUtils._instance) { if (!ProtocolFeeUtils._instance) {
ProtocolFeeUtils._instance = new ProtocolFeeUtils( ProtocolFeeUtils._instance = new ProtocolFeeUtils(
gasPricePollingIntervalInMs, gasPricePollingIntervalInMs,
zeroExGasApiUrl, ethGasStationUrl,
initialGasPrice, initialGasPrice,
); );
} }
return ProtocolFeeUtils._instance; return ProtocolFeeUtils._instance;
} }
/** @returns gas price (in wei) */
public async getGasPriceEstimationOrThrowAsync(shouldHardRefresh?: boolean): Promise<BigNumber> { public async getGasPriceEstimationOrThrowAsync(shouldHardRefresh?: boolean): Promise<BigNumber> {
if (this._gasPriceEstimation.eq(constants.ZERO_AMOUNT)) { if (this._gasPriceEstimation.eq(constants.ZERO_AMOUNT)) {
return this._getGasPriceFromGasStationOrThrowAsync(); return this._getGasPriceFromGasStationOrThrowAsync();
@@ -56,21 +48,27 @@ export class ProtocolFeeUtils {
private constructor( private constructor(
gasPricePollingIntervalInMs: number, gasPricePollingIntervalInMs: number,
zeroExGasApiUrl: string = constants.ZERO_EX_GAS_API_URL, ethGasStationUrl: string = constants.ETH_GAS_STATION_API_URL,
initialGasPrice: BigNumber = constants.ZERO_AMOUNT, initialGasPrice: BigNumber = constants.ZERO_AMOUNT,
) { ) {
this._gasPriceHeart = heartbeats.createHeart(gasPricePollingIntervalInMs); this._gasPriceHeart = heartbeats.createHeart(gasPricePollingIntervalInMs);
this._gasPriceEstimation = initialGasPrice; this._gasPriceEstimation = initialGasPrice;
this._zeroExGasApiUrl = zeroExGasApiUrl; this._ethGasStationUrl = ethGasStationUrl;
this._initializeHeartBeat(); this._initializeHeartBeat();
} }
// tslint:disable-next-line: prefer-function-over-method // tslint:disable-next-line: prefer-function-over-method
private async _getGasPriceFromGasStationOrThrowAsync(): Promise<BigNumber> { private async _getGasPriceFromGasStationOrThrowAsync(): Promise<BigNumber> {
try { try {
const res = await fetch(this._zeroExGasApiUrl); const res = await fetch(this._ethGasStationUrl);
const gasInfo: GasOracleResponse = await res.json(); const gasInfo = await res.json();
const gasPriceWei = new BigNumber(gasInfo.result.fast); // 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);
// Reset the error count to 0 once we have a successful response // Reset the error count to 0 once we have a successful response
this._errorCount = 0; this._errorCount = 0;
return gasPriceWei; return gasPriceWei;

View File

@@ -11,8 +11,6 @@ import {
FillData, FillData,
MultiHopFillData, MultiHopFillData,
NativeFillData, NativeFillData,
NativeLimitOrderFillData,
NativeRfqOrderFillData,
RawQuotes, RawQuotes,
} from './market_operation_utils/types'; } from './market_operation_utils/types';
import { QuoteRequestor, V4RFQIndicativeQuoteMM } from './quote_requestor'; import { QuoteRequestor, V4RFQIndicativeQuoteMM } from './quote_requestor';
@@ -353,7 +351,7 @@ function _isNativeOrderFromCollapsedFill(cf: Fill): cf is Fill<NativeFillData> {
*/ */
export function nativeOrderToReportEntry( export function nativeOrderToReportEntry(
type: FillQuoteTransformerOrderType, type: FillQuoteTransformerOrderType,
fillData: NativeLimitOrderFillData | NativeRfqOrderFillData, fillData: NativeFillData,
fillableAmount: BigNumber, fillableAmount: BigNumber,
comparisonPrice?: BigNumber | undefined, comparisonPrice?: BigNumber | undefined,
quoteRequestor?: QuoteRequestor, quoteRequestor?: QuoteRequestor,

View File

@@ -1,84 +0,0 @@
import * as _ from 'lodash';
import { Address } from '../types';
export class TokenAdjacencyGraph {
private readonly _graph: Map<Address, Address[]>;
private readonly _defaultTokens: readonly Address[];
public static getEmptyGraph(): TokenAdjacencyGraph {
return new TokenAdjacencyGraphBuilder().build();
}
/** Prefer using {@link TokenAdjacencyGraphBuilder}. */
constructor(graph: Map<Address, Address[]>, defaultTokens: readonly Address[]) {
this._graph = graph;
this._defaultTokens = defaultTokens;
}
public getAdjacentTokens(fromToken: Address): readonly Address[] {
return this._graph.get(fromToken.toLowerCase()) || this._defaultTokens;
}
/** Given a token pair, returns the intermediate tokens to consider for two-hop routes. */
public getIntermediateTokens(takerToken: Address, makerToken: Address): Address[] {
// NOTE: it seems it should be a union of `to` tokens of `takerToken` and `from` tokens of `makerToken`,
// leaving it as same as the initial implementation for now.
return _.union(this.getAdjacentTokens(takerToken), this.getAdjacentTokens(makerToken)).filter(
token => token !== takerToken.toLowerCase() && token !== makerToken.toLowerCase(),
);
}
}
// tslint:disable-next-line: max-classes-per-file
export class TokenAdjacencyGraphBuilder {
private readonly _graph: Map<Address, Address[]>;
private readonly _defaultTokens: readonly Address[];
constructor(defaultTokens: readonly string[] = []) {
this._graph = new Map();
this._defaultTokens = defaultTokens.map(addr => addr.toLowerCase());
}
public add(fromToken: Address, toToken: Address): TokenAdjacencyGraphBuilder {
const fromLower = fromToken.toLowerCase();
const toLower = toToken.toLowerCase();
if (fromLower === toLower) {
throw new Error(`from token (${fromToken}) must be different from to token (${toToken})`);
}
if (!this._graph.has(fromLower)) {
this._graph.set(fromLower, [...this._defaultTokens]);
}
const toTokens = this._graph.get(fromLower)!;
if (!toTokens.includes(toLower)) {
toTokens.push(toLower);
}
return this;
}
public addBidirectional(tokenA: Address, tokenB: Address): TokenAdjacencyGraphBuilder {
return this.add(tokenA, tokenB).add(tokenB, tokenA);
}
public addCompleteSubgraph(tokens: Address[]): TokenAdjacencyGraphBuilder {
for (let i = 0; i < tokens.length; i++) {
for (let j = i + 1; j < tokens.length; j++) {
this.addBidirectional(tokens[i], tokens[j]);
}
}
return this;
}
public tap(cb: (graph: TokenAdjacencyGraphBuilder) => void): TokenAdjacencyGraphBuilder {
cb(this);
return this;
}
public build(): TokenAdjacencyGraph {
return new TokenAdjacencyGraph(this._graph, this._defaultTokens);
}
}

View File

@@ -0,0 +1,25 @@
import _ = require('lodash');
import { TokenAdjacencyGraph } from './market_operation_utils/types';
export class TokenAdjacencyGraphBuilder {
constructor(private readonly tokenAdjacency: TokenAdjacencyGraph) {}
public add(from: string, to: string | string[]): TokenAdjacencyGraphBuilder {
if (!this.tokenAdjacency[from]) {
this.tokenAdjacency[from] = [...this.tokenAdjacency.default];
}
this.tokenAdjacency[from] = [...(Array.isArray(to) ? to : [to]), ...this.tokenAdjacency[from]];
this.tokenAdjacency[from] = _.uniqBy(this.tokenAdjacency[from], a => a.toLowerCase());
return this;
}
public tap(cb: (builder: TokenAdjacencyGraphBuilder) => void): TokenAdjacencyGraphBuilder {
cb(this);
return this;
}
public build(): TokenAdjacencyGraph {
return this.tokenAdjacency;
}
}

View File

@@ -43,7 +43,6 @@ import * as NativeOrderSampler from '../test/generated-artifacts/NativeOrderSamp
import * as PlatypusSampler from '../test/generated-artifacts/PlatypusSampler.json'; import * as PlatypusSampler from '../test/generated-artifacts/PlatypusSampler.json';
import * as SamplerUtils from '../test/generated-artifacts/SamplerUtils.json'; import * as SamplerUtils from '../test/generated-artifacts/SamplerUtils.json';
import * as ShellSampler from '../test/generated-artifacts/ShellSampler.json'; import * as ShellSampler from '../test/generated-artifacts/ShellSampler.json';
import * as SynthetixSampler from '../test/generated-artifacts/SynthetixSampler.json';
import * as TestNativeOrderSampler from '../test/generated-artifacts/TestNativeOrderSampler.json'; import * as TestNativeOrderSampler from '../test/generated-artifacts/TestNativeOrderSampler.json';
import * as TwoHopSampler from '../test/generated-artifacts/TwoHopSampler.json'; import * as TwoHopSampler from '../test/generated-artifacts/TwoHopSampler.json';
import * as UniswapSampler from '../test/generated-artifacts/UniswapSampler.json'; import * as UniswapSampler from '../test/generated-artifacts/UniswapSampler.json';
@@ -51,7 +50,6 @@ import * as UniswapV2Sampler from '../test/generated-artifacts/UniswapV2Sampler.
import * as UniswapV3Sampler from '../test/generated-artifacts/UniswapV3Sampler.json'; import * as UniswapV3Sampler from '../test/generated-artifacts/UniswapV3Sampler.json';
import * as UtilitySampler from '../test/generated-artifacts/UtilitySampler.json'; import * as UtilitySampler from '../test/generated-artifacts/UtilitySampler.json';
import * as VelodromeSampler from '../test/generated-artifacts/VelodromeSampler.json'; import * as VelodromeSampler from '../test/generated-artifacts/VelodromeSampler.json';
import * as WooPPSampler from '../test/generated-artifacts/WooPPSampler.json';
export const artifacts = { export const artifacts = {
ApproximateBuys: ApproximateBuys as ContractArtifact, ApproximateBuys: ApproximateBuys as ContractArtifact,
BalanceChecker: BalanceChecker as ContractArtifact, BalanceChecker: BalanceChecker as ContractArtifact,
@@ -78,14 +76,12 @@ export const artifacts = {
PlatypusSampler: PlatypusSampler as ContractArtifact, PlatypusSampler: PlatypusSampler as ContractArtifact,
SamplerUtils: SamplerUtils as ContractArtifact, SamplerUtils: SamplerUtils as ContractArtifact,
ShellSampler: ShellSampler as ContractArtifact, ShellSampler: ShellSampler as ContractArtifact,
SynthetixSampler: SynthetixSampler as ContractArtifact,
TwoHopSampler: TwoHopSampler as ContractArtifact, TwoHopSampler: TwoHopSampler as ContractArtifact,
UniswapSampler: UniswapSampler as ContractArtifact, UniswapSampler: UniswapSampler as ContractArtifact,
UniswapV2Sampler: UniswapV2Sampler as ContractArtifact, UniswapV2Sampler: UniswapV2Sampler as ContractArtifact,
UniswapV3Sampler: UniswapV3Sampler as ContractArtifact, UniswapV3Sampler: UniswapV3Sampler as ContractArtifact,
UtilitySampler: UtilitySampler as ContractArtifact, UtilitySampler: UtilitySampler as ContractArtifact,
VelodromeSampler: VelodromeSampler as ContractArtifact, VelodromeSampler: VelodromeSampler as ContractArtifact,
WooPPSampler: WooPPSampler as ContractArtifact,
IBalancer: IBalancer as ContractArtifact, IBalancer: IBalancer as ContractArtifact,
IBalancerV2Vault: IBalancerV2Vault as ContractArtifact, IBalancerV2Vault: IBalancerV2Vault as ContractArtifact,
IBancor: IBancor as ContractArtifact, IBancor: IBancor as ContractArtifact,

View File

@@ -13,8 +13,7 @@ import * as _ from 'lodash';
import { SignedOrder } from '../src/types'; import { SignedOrder } from '../src/types';
import { DexOrderSampler, getSampleAmounts } from '../src/utils/market_operation_utils/sampler'; import { DexOrderSampler, getSampleAmounts } from '../src/utils/market_operation_utils/sampler';
import { ERC20BridgeSource } from '../src/utils/market_operation_utils/types'; import { ERC20BridgeSource, TokenAdjacencyGraph } from '../src/utils/market_operation_utils/types';
import { TokenAdjacencyGraphBuilder } from '../src/utils/token_adjacency_graph';
import { MockSamplerContract } from './utils/mock_sampler_contract'; import { MockSamplerContract } from './utils/mock_sampler_contract';
import { generatePseudoRandomSalt } from './utils/utils'; import { generatePseudoRandomSalt } from './utils/utils';
@@ -30,7 +29,7 @@ describe('DexSampler tests', () => {
const wethAddress = getContractAddressesForChainOrThrow(CHAIN_ID).etherToken; const wethAddress = getContractAddressesForChainOrThrow(CHAIN_ID).etherToken;
const exchangeProxyAddress = getContractAddressesForChainOrThrow(CHAIN_ID).exchangeProxy; const exchangeProxyAddress = getContractAddressesForChainOrThrow(CHAIN_ID).exchangeProxy;
const tokenAdjacencyGraph = new TokenAdjacencyGraphBuilder([wethAddress]).build(); const tokenAdjacencyGraph: TokenAdjacencyGraph = { default: [wethAddress] };
describe('getSampleAmounts()', () => { describe('getSampleAmounts()', () => {
const FILL_AMOUNT = getRandomInteger(1, 1e18); const FILL_AMOUNT = getRandomInteger(1, 1e18);

View File

@@ -15,7 +15,7 @@ import { Pool } from 'balancer-labs-sor-v1/dist/types';
import * as _ from 'lodash'; import * as _ from 'lodash';
import * as TypeMoq from 'typemoq'; import * as TypeMoq from 'typemoq';
import { MarketOperation, QuoteRequestor, RfqRequestOpts, SignedNativeOrder, TokenAdjacencyGraph } from '../src'; import { MarketOperation, QuoteRequestor, RfqRequestOpts, SignedNativeOrder } from '../src';
import { Integrator } from '../src/types'; import { Integrator } from '../src/types';
import { MarketOperationUtils } from '../src/utils/market_operation_utils/'; import { MarketOperationUtils } from '../src/utils/market_operation_utils/';
import { import {
@@ -24,7 +24,7 @@ import {
SOURCE_FLAGS, SOURCE_FLAGS,
ZERO_AMOUNT, ZERO_AMOUNT,
} from '../src/utils/market_operation_utils/constants'; } from '../src/utils/market_operation_utils/constants';
import { AbstractPoolsCache } from '../src/utils/market_operation_utils/pools_cache'; import { PoolsCache } from '../src/utils/market_operation_utils/pools_cache';
import { DexOrderSampler } from '../src/utils/market_operation_utils/sampler'; import { DexOrderSampler } from '../src/utils/market_operation_utils/sampler';
import { BATCH_SOURCE_FILTERS } from '../src/utils/market_operation_utils/sampler_operations'; import { BATCH_SOURCE_FILTERS } from '../src/utils/market_operation_utils/sampler_operations';
import { SourceFilters } from '../src/utils/market_operation_utils/source_filters'; import { SourceFilters } from '../src/utils/market_operation_utils/source_filters';
@@ -39,6 +39,7 @@ import {
MarketSideLiquidity, MarketSideLiquidity,
OptimizedMarketBridgeOrder, OptimizedMarketBridgeOrder,
OptimizerResultWithReport, OptimizerResultWithReport,
TokenAdjacencyGraph,
} from '../src/utils/market_operation_utils/types'; } from '../src/utils/market_operation_utils/types';
const MAKER_TOKEN = randomAddress(); const MAKER_TOKEN = randomAddress();
@@ -56,7 +57,7 @@ const DEFAULT_EXCLUDED = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].sources
); );
const BUY_SOURCES = BUY_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].sources; const BUY_SOURCES = BUY_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].sources;
const SELL_SOURCES = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].sources; const SELL_SOURCES = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].sources;
const TOKEN_ADJACENCY_GRAPH = TokenAdjacencyGraph.getEmptyGraph(); const TOKEN_ADJACENCY_GRAPH: TokenAdjacencyGraph = { default: [] };
const SIGNATURE = { v: 1, r: NULL_BYTES, s: NULL_BYTES, signatureType: SignatureType.EthSign }; const SIGNATURE = { v: 1, r: NULL_BYTES, s: NULL_BYTES, signatureType: SignatureType.EthSign };
const FOO_INTEGRATOR: Integrator = { const FOO_INTEGRATOR: Integrator = {
@@ -98,9 +99,9 @@ async function getMarketBuyOrdersAsync(
return utils.getOptimizerResultAsync(nativeOrders, makerAmount, MarketOperation.Buy, opts); return utils.getOptimizerResultAsync(nativeOrders, makerAmount, MarketOperation.Buy, opts);
} }
class MockPoolsCache extends AbstractPoolsCache { class MockPoolsCache extends PoolsCache {
constructor(private readonly _handler: (takerToken: string, makerToken: string) => Pool[]) { constructor(private readonly _handler: (takerToken: string, makerToken: string) => Pool[]) {
super(new Map()); super({});
} }
protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> { protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> {
return this._handler(takerToken, makerToken); return this._handler(takerToken, makerToken);

View File

@@ -17,6 +17,8 @@ const expect = chai.expect;
const usdcAddress = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'; const usdcAddress = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48';
const daiAddress = '0x6b175474e89094c44da98b954eedeac495271d0f'; const daiAddress = '0x6b175474e89094c44da98b954eedeac495271d0f';
const wethAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'; const wethAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
const wbtcAddress = '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599';
const balAddress = '0xba100000625a3754423978a60c9317c58a424e3d';
const creamAddress = '0x2ba592f78db6436527729929aaf6c908497cb200'; const creamAddress = '0x2ba592f78db6436527729929aaf6c908497cb200';
const timeoutMs = 5000; const timeoutMs = 5000;
@@ -28,12 +30,12 @@ describe('Pools Caches for Balancer-based sampling', () => {
expect(pools.length).greaterThan(0, `Failed to find any pools for ${takerToken} and ${makerToken}`); expect(pools.length).greaterThan(0, `Failed to find any pools for ${takerToken} and ${makerToken}`);
expect(pools[0]).not.undefined(); expect(pools[0]).not.undefined();
expect(Object.keys(pools[0])).to.include.members(poolKeys); expect(Object.keys(pools[0])).to.include.members(poolKeys);
const cachedPoolIds = cache.getPoolAddressesForPair(takerToken, makerToken); const cachedPoolIds = cache.getCachedPoolAddressesForPair(takerToken, makerToken);
expect(cachedPoolIds).to.deep.equal(pools.map(p => p.id)); expect(cachedPoolIds).to.deep.equal(pools.map(p => p.id));
} }
describe('BalancerPoolsCache', () => { describe('BalancerPoolsCache', () => {
const cache = BalancerPoolsCache.create(ChainId.Mainnet); const cache = new BalancerPoolsCache();
it('fetches pools', async () => { it('fetches pools', async () => {
const pairs = [ const pairs = [
[usdcAddress, daiAddress], [usdcAddress, daiAddress],
@@ -41,38 +43,36 @@ describe('Pools Caches for Balancer-based sampling', () => {
[daiAddress, wethAddress], [daiAddress, wethAddress],
]; ];
await Promise.all( await Promise.all(
pairs.map(async ([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)), // tslint:disable-next-line:promise-function-async
pairs.map(([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)),
); );
}); });
}); });
describe('BalancerV2PoolsCache', () => { describe('BalancerV2PoolsCache', () => {
it('fetches pools (Beethoven X - Fantom)', async () => { const cache = new BalancerV2PoolsCache(ChainId.Mainnet);
const cache = BalancerV2PoolsCache.createBeethovenXPoolCache(ChainId.Fantom); it('fetches pools', async () => {
const wftmAddress = '0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83';
const beetsAddress = '0xf24bcf4d1e507740041c9cfd2dddb29585adce1e';
const fantomWethAddress = '0x74b23882a30290451a17c44f4f05243b6b58c76d';
const pairs = [ const pairs = [
[wftmAddress, beetsAddress], [wethAddress, wbtcAddress],
[wftmAddress, fantomWethAddress], [wethAddress, balAddress],
]; ];
await Promise.all( await Promise.all(
pairs.map(async ([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)), // tslint:disable-next-line:promise-function-async
pairs.map(([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)),
); );
}); });
}); });
describe('CreamPoolsCache', () => { describe('CreamPoolsCache', () => {
const cache = CreamPoolsCache.create(ChainId.Mainnet); const cache = new CreamPoolsCache();
it('fetches pools', async () => { it('fetches pools', async () => {
const pairs = [ const pairs = [
[usdcAddress, creamAddress], [usdcAddress, creamAddress],
[creamAddress, wethAddress], [creamAddress, wethAddress],
]; ];
await Promise.all( await Promise.all(
pairs.map(async ([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)), // tslint:disable-next-line:promise-function-async
pairs.map(([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)),
); );
}); });
}); });

View File

@@ -1,45 +0,0 @@
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);
});
});
});

View File

@@ -1,108 +0,0 @@
import * as chai from 'chai';
import 'mocha';
import { TokenAdjacencyGraphBuilder } from '../src/utils/token_adjacency_graph';
import { chaiSetup } from './utils/chai_setup';
chaiSetup.configure();
const expect = chai.expect;
describe('TokenAdjacencyGraphBuilder and TokenAdjacencyGraph', () => {
describe('constructor', () => {
it('sanitizes passed default tokens to lower case', async () => {
const graph = new TokenAdjacencyGraphBuilder(['DEFAULT_1', 'DEFAULT_2']).build();
expect(graph.getAdjacentTokens('random_token')).to.deep.eq(['default_1', 'default_2']);
});
});
describe('add', () => {
it('adds a new token path to the graph', async () => {
const graph = new TokenAdjacencyGraphBuilder(['default_1', 'default_2']).add('token_a', 'token_b').build();
expect(graph.getAdjacentTokens('token_a')).to.deep.eq(['default_1', 'default_2', 'token_b']);
});
it('adds lower-cased token path to the graph', async () => {
const graph = new TokenAdjacencyGraphBuilder(['default_1', 'default_2']).add('TOKEN_A', 'TOKEN_B').build();
expect(graph.getAdjacentTokens('token_a')).to.deep.eq(['default_1', 'default_2', 'token_b']);
});
it('ignores an existing to token', async () => {
const graph = new TokenAdjacencyGraphBuilder()
.add('token_a', 'token_b')
.add('token_a', 'token_b')
.build();
expect(graph.getAdjacentTokens('token_a')).to.deep.eq(['token_b']);
});
});
describe('addBidirectional', () => {
it('adds a bidirectional path to the graph', async () => {
const graph = new TokenAdjacencyGraphBuilder(['default_1']).addBidirectional('token_a', 'token_b').build();
expect(graph.getAdjacentTokens('token_a')).to.deep.eq(['default_1', 'token_b']);
expect(graph.getAdjacentTokens('token_b')).to.deep.eq(['default_1', 'token_a']);
});
});
describe('addCompleteSubgraph', () => {
it('adds a complete subgraph to the graph', async () => {
const graph = new TokenAdjacencyGraphBuilder(['default_1'])
.addCompleteSubgraph(['token_a', 'token_b', 'token_c', 'token_d'])
.build();
expect(graph.getAdjacentTokens('token_a')).to.deep.eq(['default_1', 'token_b', 'token_c', 'token_d']);
expect(graph.getAdjacentTokens('token_b')).to.deep.eq(['default_1', 'token_a', 'token_c', 'token_d']);
expect(graph.getAdjacentTokens('token_c')).to.deep.eq(['default_1', 'token_a', 'token_b', 'token_d']);
expect(graph.getAdjacentTokens('token_d')).to.deep.eq(['default_1', 'token_a', 'token_b', 'token_c']);
});
});
describe('tap', () => {
it('applies callback correctly', async () => {
const graph = new TokenAdjacencyGraphBuilder(['default_1'])
.tap(g => {
g.add('token_a', 'token_b');
g.add('token_c', 'token_d');
})
.build();
expect(graph.getAdjacentTokens('token_a')).to.deep.eq(['default_1', 'token_b']);
expect(graph.getAdjacentTokens('token_c')).to.deep.eq(['default_1', 'token_d']);
});
});
describe('getIntermediateTokens', () => {
it('returns intermediate tokens without a duplicate ', async () => {
const graph = new TokenAdjacencyGraphBuilder(['default_1'])
.add('token_a', 'token_b')
.add('token_c', 'token_b')
.build();
expect(graph.getIntermediateTokens('token_a', 'token_c')).to.deep.eq(['default_1', 'token_b']);
});
it('returns intermediate tokens after lower-casing taker and maker tokens', async () => {
const graph = new TokenAdjacencyGraphBuilder(['default_1'])
.add('token_a', 'token_b')
.add('token_c', 'token_d')
.build();
expect(graph.getIntermediateTokens('TOKEN_a', 'token_C')).to.deep.eq(['default_1', 'token_b', 'token_d']);
});
it('returns intermediate tokens excluding taker token or maker token ', async () => {
const graph = new TokenAdjacencyGraphBuilder(['default_1'])
.addBidirectional('token_a', 'token_b')
.addBidirectional('token_b', 'token_c')
.addBidirectional('token_c', 'token_a')
.build();
expect(graph.getIntermediateTokens('token_a', 'token_c')).to.deep.eq(['default_1', 'token_b']);
});
});
});

View File

@@ -41,7 +41,6 @@ export * from '../test/generated-wrappers/native_order_sampler';
export * from '../test/generated-wrappers/platypus_sampler'; export * from '../test/generated-wrappers/platypus_sampler';
export * from '../test/generated-wrappers/sampler_utils'; export * from '../test/generated-wrappers/sampler_utils';
export * from '../test/generated-wrappers/shell_sampler'; export * from '../test/generated-wrappers/shell_sampler';
export * from '../test/generated-wrappers/synthetix_sampler';
export * from '../test/generated-wrappers/test_native_order_sampler'; export * from '../test/generated-wrappers/test_native_order_sampler';
export * from '../test/generated-wrappers/two_hop_sampler'; export * from '../test/generated-wrappers/two_hop_sampler';
export * from '../test/generated-wrappers/uniswap_sampler'; export * from '../test/generated-wrappers/uniswap_sampler';
@@ -49,4 +48,3 @@ export * from '../test/generated-wrappers/uniswap_v2_sampler';
export * from '../test/generated-wrappers/uniswap_v3_sampler'; export * from '../test/generated-wrappers/uniswap_v3_sampler';
export * from '../test/generated-wrappers/utility_sampler'; export * from '../test/generated-wrappers/utility_sampler';
export * from '../test/generated-wrappers/velodrome_sampler'; export * from '../test/generated-wrappers/velodrome_sampler';
export * from '../test/generated-wrappers/woo_p_p_sampler';

View File

@@ -44,14 +44,12 @@
"test/generated-artifacts/PlatypusSampler.json", "test/generated-artifacts/PlatypusSampler.json",
"test/generated-artifacts/SamplerUtils.json", "test/generated-artifacts/SamplerUtils.json",
"test/generated-artifacts/ShellSampler.json", "test/generated-artifacts/ShellSampler.json",
"test/generated-artifacts/SynthetixSampler.json",
"test/generated-artifacts/TestNativeOrderSampler.json", "test/generated-artifacts/TestNativeOrderSampler.json",
"test/generated-artifacts/TwoHopSampler.json", "test/generated-artifacts/TwoHopSampler.json",
"test/generated-artifacts/UniswapSampler.json", "test/generated-artifacts/UniswapSampler.json",
"test/generated-artifacts/UniswapV2Sampler.json", "test/generated-artifacts/UniswapV2Sampler.json",
"test/generated-artifacts/UniswapV3Sampler.json", "test/generated-artifacts/UniswapV3Sampler.json",
"test/generated-artifacts/UtilitySampler.json", "test/generated-artifacts/UtilitySampler.json",
"test/generated-artifacts/VelodromeSampler.json", "test/generated-artifacts/VelodromeSampler.json"
"test/generated-artifacts/WooPPSampler.json"
] ]
} }

View File

@@ -1,8 +1,6 @@
{ {
"extends": ["@0x/tslint-config"], "extends": ["@0x/tslint-config"],
"rules": { "rules": {
"array-type": false,
"custom-no-magic-numbers": false,
"max-file-line-count": false, "max-file-line-count": false,
"binary-expression-operand-order": false "binary-expression-operand-order": false
}, },

View File

@@ -1,46 +1,4 @@
[ [
{
"timestamp": 1660093941,
"version": "6.19.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "6.19.1",
"changes": [
{
"note": "Fix lowercase addresses",
"pr": 543
}
],
"timestamp": 1660073235
},
{
"version": "6.19.0",
"changes": [
{
"note": "Goerli and Mumbai updated verified contracts addresses",
"pr": 537
}
],
"timestamp": 1659750766
},
{
"version": "6.17.0",
"changes": [
{
"note": "Goerli and Mumbai"
},
{
"note": "Redeploy FQT on Mainnet and Optimism",
"pr": 530
}
],
"timestamp": 1658950329
},
{ {
"version": "6.16.0", "version": "6.16.0",
"changes": [ "changes": [

View File

@@ -5,23 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v6.19.2 - _August 10, 2022_
* Dependencies updated
## v6.19.1 - _August 9, 2022_
* Fix lowercase addresses (#543)
## v6.19.0 - _August 6, 2022_
* Goerli and Mumbai updated verified contracts addresses (#537)
## v6.17.0 - _July 27, 2022_
* Goerli and Mumbai
* Redeploy FQT on Mainnet and Optimism (#530)
## v6.16.0 - _June 14, 2022_ ## v6.16.0 - _June 14, 2022_
* Redeploy FQT on Mainnet and Optimism * Redeploy FQT on Mainnet and Optimism

View File

@@ -37,7 +37,7 @@
"wethTransformer": "0xb2bc06a4efb20fc6553a69dbfa49b7be938034a7", "wethTransformer": "0xb2bc06a4efb20fc6553a69dbfa49b7be938034a7",
"payTakerTransformer": "0x4638a7ebe75b911b995d0ec73a81e4f85f41f24e", "payTakerTransformer": "0x4638a7ebe75b911b995d0ec73a81e4f85f41f24e",
"affiliateFeeTransformer": "0xda6d9fc5998f550a094585cf9171f0e8ee3ac59f", "affiliateFeeTransformer": "0xda6d9fc5998f550a094585cf9171f0e8ee3ac59f",
"fillQuoteTransformer": "0xd75a9019a2a1782ea670e4f4a55f04b43514ed53", "fillQuoteTransformer": "0x26b2d9ea76f24206805d17565a5e0efcf787e0ae",
"positiveSlippageFeeTransformer": "0xa9416ce1dbde8d331210c07b5c253d94ee4cc3fd" "positiveSlippageFeeTransformer": "0xa9416ce1dbde8d331210c07b5c253d94ee4cc3fd"
} }
}, },
@@ -125,48 +125,6 @@
"positiveSlippageFeeTransformer": "0x0000000000000000000000000000000000000000" "positiveSlippageFeeTransformer": "0x0000000000000000000000000000000000000000"
} }
}, },
"5": {
"erc20Proxy": "0x0000000000000000000000000000000000000000",
"erc721Proxy": "0x0000000000000000000000000000000000000000",
"zrxToken": "0x0000000000000000000000000000000000000000",
"etherToken": "0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6",
"exchangeV2": "0x0000000000000000000000000000000000000000",
"exchange": "0x0000000000000000000000000000000000000000",
"assetProxyOwner": "0x0000000000000000000000000000000000000000",
"zeroExGovernor": "0x0000000000000000000000000000000000000000",
"forwarder": "0x0000000000000000000000000000000000000000",
"coordinatorRegistry": "0x0000000000000000000000000000000000000000",
"coordinator": "0x0000000000000000000000000000000000000000",
"multiAssetProxy": "0x0000000000000000000000000000000000000000",
"staticCallProxy": "0x0000000000000000000000000000000000000000",
"erc1155Proxy": "0x0000000000000000000000000000000000000000",
"devUtils": "0x0000000000000000000000000000000000000000",
"zrxVault": "0x0000000000000000000000000000000000000000",
"staking": "0x0000000000000000000000000000000000000000",
"stakingProxy": "0x0000000000000000000000000000000000000000",
"erc20BridgeProxy": "0x0000000000000000000000000000000000000000",
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
"chaiBridge": "0x0000000000000000000000000000000000000000",
"dydxBridge": "0x0000000000000000000000000000000000000000",
"godsUnchainedValidator": "0x0000000000000000000000000000000000000000",
"broker": "0x0000000000000000000000000000000000000000",
"chainlinkStopLimit": "0x0000000000000000000000000000000000000000",
"maximumGasPrice": "0x0000000000000000000000000000000000000000",
"dexForwarderBridge": "0x0000000000000000000000000000000000000000",
"exchangeProxyGovernor": "0xf289f8a9d26f9a32ecc8602e92e634d71a91d490",
"exchangeProxy": "0xf91bb752490473b8342a3e964e855b9f9a2a668e",
"exchangeProxyTransformerDeployer": "0x7b4f0063cc0097c19c6b8cc74ecaf630621e2be6",
"exchangeProxyFlashWallet": "0xf15469c80a1965f5f90be5651fcb6c6f3392b2a1",
"exchangeProxyLiquidityProviderSandbox": "0x0000000000000000000000000000000000000000",
"zrxTreasury": "0x0000000000000000000000000000000000000000",
"transformers": {
"wethTransformer": "0x5e485f1ab8aa2a71d533f2bc15af64dd10fa44e9",
"payTakerTransformer": "0x0c59ced2ffce5fceb40f665def2146f76c576f34",
"affiliateFeeTransformer": "0x6f4d30df1ecaed54239af95efa2964f9252fd0a3",
"fillQuoteTransformer": "0x841b18c263a290c41ac41b6afbf4c1d31b0c6b36",
"positiveSlippageFeeTransformer": "0x5d6ab5729a08775c69035730bcfbad65759c4f4d"
}
},
"42": { "42": {
"erc20Proxy": "0xaa460127562482faa5df42f2c39a025cd4a1cc0a", "erc20Proxy": "0xaa460127562482faa5df42f2c39a025cd4a1cc0a",
"erc721Proxy": "0x7b70a148e20b348c320208df84fdd642aab49fd0", "erc721Proxy": "0x7b70a148e20b348c320208df84fdd642aab49fd0",
@@ -247,7 +205,7 @@
"wethTransformer": "0xac3d95668c092e895cd83a9cbafe9c7d9906471f", "wethTransformer": "0xac3d95668c092e895cd83a9cbafe9c7d9906471f",
"payTakerTransformer": "0x4f5e8ca2cadecd4a467ae441e4b03de4278a4574", "payTakerTransformer": "0x4f5e8ca2cadecd4a467ae441e4b03de4278a4574",
"affiliateFeeTransformer": "0x1be34ab9b2acb5c4ddd89454bdce637967e65230", "affiliateFeeTransformer": "0x1be34ab9b2acb5c4ddd89454bdce637967e65230",
"fillQuoteTransformer": "0xbd7fd6e116fc8589bb658fba3a2cc6273050bcf2", "fillQuoteTransformer": "0x0b72d55485e8d877f73cc8b14ea3e010b3e804fd",
"positiveSlippageFeeTransformer": "0x7f5c79ad1788573b1145f4651a248523c54f5d1f" "positiveSlippageFeeTransformer": "0x7f5c79ad1788573b1145f4651a248523c54f5d1f"
} }
}, },
@@ -331,7 +289,7 @@
"wethTransformer": "0xe309d011cc6f189a3e8dcba85922715a019fed38", "wethTransformer": "0xe309d011cc6f189a3e8dcba85922715a019fed38",
"payTakerTransformer": "0x5ba7b9be86cda01cfbf56e0fb97184783be9dda1", "payTakerTransformer": "0x5ba7b9be86cda01cfbf56e0fb97184783be9dda1",
"affiliateFeeTransformer": "0xbed27284b42e5684e987169cf1da09c5d6c49fa8", "affiliateFeeTransformer": "0xbed27284b42e5684e987169cf1da09c5d6c49fa8",
"fillQuoteTransformer": "0x01c082e47c8dc6dedd01e3fcb07bfd3eb72e044d", "fillQuoteTransformer": "0xd4a518760030dae1adbde9496f8a3b478e83932a",
"positiveSlippageFeeTransformer": "0x4cd8f1c0df4d40fcc1e073845d5f6f4ed5cc8dab" "positiveSlippageFeeTransformer": "0x4cd8f1c0df4d40fcc1e073845d5f6f4ed5cc8dab"
} }
}, },
@@ -363,18 +321,18 @@
"chainlinkStopLimit": "0x0000000000000000000000000000000000000000", "chainlinkStopLimit": "0x0000000000000000000000000000000000000000",
"maximumGasPrice": "0x0000000000000000000000000000000000000000", "maximumGasPrice": "0x0000000000000000000000000000000000000000",
"dexForwarderBridge": "0x0000000000000000000000000000000000000000", "dexForwarderBridge": "0x0000000000000000000000000000000000000000",
"exchangeProxyGovernor": "0x30186b2e187aeddabf019089f9375a8dc53138e4", "exchangeProxyGovernor": "0x4cf19577bcb5e784f315e952f97a6dc247f03140",
"exchangeProxy": "0xf471d32cb40837bf24529fcf17418fc1a4807626", "exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
"exchangeProxyTransformerDeployer": "0x05481589f447a0767def2b0ed98a04ea5f5eba50", "exchangeProxyTransformerDeployer": "0xa8220408bcb5b327875fd82145d379a83dfd7d61",
"exchangeProxyFlashWallet": "0x64254cf2f3abd765bee46f8445b76e2bb0af5a2c", "exchangeProxyFlashWallet": "0xdb6f1920a889355780af7570773609bd8cb1f498",
"exchangeProxyLiquidityProviderSandbox": "0x0000000000000000000000000000000000000000", "exchangeProxyLiquidityProviderSandbox": "0xe6f76f5090f8d64015113841a0c9bc5d14755d6f",
"zrxTreasury": "0x0000000000000000000000000000000000000000", "zrxTreasury": "0x0000000000000000000000000000000000000000",
"transformers": { "transformers": {
"wethTransformer": "0x445af2e5791cc9a72f81c49a3dc90cf3b03d2a62", "wethTransformer": "0x44a65ee6b33f70eda7b854abe8d81e925984c932",
"payTakerTransformer": "0xe3e8652fb306873f9dc87222423ffd51b967f014", "payTakerTransformer": "0x2f4868ed9cae9a4cdba063818dce19f411be4e75",
"affiliateFeeTransformer": "0xbd901aff2ce18355537594a17ebb0a38ca44d8b6", "affiliateFeeTransformer": "0x843c0ac5b1b373be51800c8f1caffe54cc29dd22",
"fillQuoteTransformer": "0xbfac39aea3c0a6222266cef674ec39c3b5387852", "fillQuoteTransformer": "0x750cb81ee6d64e29e1e358ba155925000bf044d4",
"positiveSlippageFeeTransformer": "0x33ab86b46d84d30538a9b35c7ece4d5673caa778" "positiveSlippageFeeTransformer": "0x30aebc4c68effa70e21612b39b94299a8778d0cb"
} }
}, },
"43114": { "43114": {
@@ -415,7 +373,7 @@
"wethTransformer": "0x9b8b52391071d71cd4ad1e61d7f273268fa34c6c", "wethTransformer": "0x9b8b52391071d71cd4ad1e61d7f273268fa34c6c",
"payTakerTransformer": "0x898c6fde239d646c73f0a57e3570b6f86a3d62a3", "payTakerTransformer": "0x898c6fde239d646c73f0a57e3570b6f86a3d62a3",
"affiliateFeeTransformer": "0x34617b855411e52fbc05899435f44cbd0503022c", "affiliateFeeTransformer": "0x34617b855411e52fbc05899435f44cbd0503022c",
"fillQuoteTransformer": "0xcee9118bc14e1fe740c54c754b901629b322ee4f", "fillQuoteTransformer": "0xb6c9c52ce7094fc96d8bd5d3ecd0c6feeafe3457",
"positiveSlippageFeeTransformer": "0x470ba89da18a6db6e8a0567b3c9214b960861857" "positiveSlippageFeeTransformer": "0x470ba89da18a6db6e8a0567b3c9214b960861857"
} }
}, },
@@ -457,7 +415,7 @@
"wethTransformer": "0x9b6aa8f26a92108e7d1f66373d757bb955112703", "wethTransformer": "0x9b6aa8f26a92108e7d1f66373d757bb955112703",
"payTakerTransformer": "0x32df54951d33d7460e15fa59b1fcc262183ce4c2", "payTakerTransformer": "0x32df54951d33d7460e15fa59b1fcc262183ce4c2",
"affiliateFeeTransformer": "0x67efa679a4b56c38713d478e649c88247f4f8e88", "affiliateFeeTransformer": "0x67efa679a4b56c38713d478e649c88247f4f8e88",
"fillQuoteTransformer": "0xe40f81ef6e9c95ba04c659b8d032eab73152aafd", "fillQuoteTransformer": "0x641efe8a57ad39353fe22f77d211ef6b17b0590b",
"positiveSlippageFeeTransformer": "0xe87d69b285005cc82b53b844322652c49ed64600" "positiveSlippageFeeTransformer": "0xe87d69b285005cc82b53b844322652c49ed64600"
} }
}, },
@@ -541,7 +499,7 @@
"wethTransformer": "0x02ce7af6520e2862f961f5d7eda746642865179c", "wethTransformer": "0x02ce7af6520e2862f961f5d7eda746642865179c",
"payTakerTransformer": "0x085d10a34f14f6a631ea8ff7d016782ee3ffaa11", "payTakerTransformer": "0x085d10a34f14f6a631ea8ff7d016782ee3ffaa11",
"affiliateFeeTransformer": "0x55cf1d7535250db75bf0190493f55781ee583553", "affiliateFeeTransformer": "0x55cf1d7535250db75bf0190493f55781ee583553",
"fillQuoteTransformer": "0x96499c097efc56ba5cf6b2a474392db17790ce96", "fillQuoteTransformer": "0xfae0ce3841afbf5625a15f0c73e03ba6660e575f",
"positiveSlippageFeeTransformer": "0xb11e14565dfbeb702dea9bc0cb47f1a8b32f4783" "positiveSlippageFeeTransformer": "0xb11e14565dfbeb702dea9bc0cb47f1a8b32f4783"
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contract-addresses", "name": "@0x/contract-addresses",
"version": "6.19.2", "version": "6.16.0",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },

View File

@@ -47,7 +47,6 @@ export enum ChainId {
Mainnet = 1, Mainnet = 1,
Ropsten = 3, Ropsten = 3,
Rinkeby = 4, Rinkeby = 4,
Goerli = 5,
Kovan = 42, Kovan = 42,
Ganache = 1337, Ganache = 1337,
BSC = 56, BSC = 56,
@@ -56,7 +55,6 @@ export enum ChainId {
Avalanche = 43114, Avalanche = 43114,
Fantom = 250, Fantom = 250,
Celo = 42220, Celo = 42220,
// Arbitrum = 42161,
Optimism = 10, Optimism = 10,
} }

View File

@@ -1,40 +1,4 @@
[ [
{
"timestamp": 1660093941,
"version": "13.20.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1660073235,
"version": "13.20.7",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1659750766,
"version": "13.20.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1658950329,
"version": "13.20.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{ {
"timestamp": 1655244958, "timestamp": 1655244958,
"version": "13.20.4", "version": "13.20.4",

View File

@@ -5,22 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v13.20.8 - _August 10, 2022_
* Dependencies updated
## v13.20.7 - _August 9, 2022_
* Dependencies updated
## v13.20.6 - _August 6, 2022_
* Dependencies updated
## v13.20.5 - _July 27, 2022_
* Dependencies updated
## v13.20.4 - _June 14, 2022_ ## v13.20.4 - _June 14, 2022_
* Dependencies updated * Dependencies updated

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/contract-wrappers", "name": "@0x/contract-wrappers",
"version": "13.20.8", "version": "13.20.4",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -57,7 +57,7 @@
"dependencies": { "dependencies": {
"@0x/assert": "^3.0.34", "@0x/assert": "^3.0.34",
"@0x/base-contract": "^6.5.0", "@0x/base-contract": "^6.5.0",
"@0x/contract-addresses": "^6.19.2", "@0x/contract-addresses": "^6.16.0",
"@0x/json-schemas": "^6.4.4", "@0x/json-schemas": "^6.4.4",
"@0x/types": "^3.3.6", "@0x/types": "^3.3.6",
"@0x/utils": "^6.5.3", "@0x/utils": "^6.5.3",

View File

@@ -1,40 +1,12 @@
[ [
{
"timestamp": 1660093941,
"version": "11.16.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1660073235,
"version": "11.16.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1659750766,
"version": "11.16.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{ {
"version": "11.16.0", "version": "11.16.0",
"changes": [ "changes": [
{ {
"note": "Add Synthetix support`", "note": "Add Otc order support to the fillQuoteTransformer",
"pr": 518 "pr": 516
} }
], ]
"timestamp": 1658950329
}, },
{ {
"version": "11.15.0", "version": "11.15.0",

View File

@@ -5,22 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG CHANGELOG
## v11.16.3 - _August 10, 2022_
* Dependencies updated
## v11.16.2 - _August 9, 2022_
* Dependencies updated
## v11.16.1 - _August 6, 2022_
* Dependencies updated
## v11.16.0 - _July 27, 2022_
* Add Synthetix support` (#518)
## v11.15.0 - _June 14, 2022_ ## v11.15.0 - _June 14, 2022_
* Add Velodrome support (#494) * Add Velodrome support (#494)

View File

@@ -1,6 +1,6 @@
{ {
"name": "@0x/protocol-utils", "name": "@0x/protocol-utils",
"version": "11.16.3", "version": "11.15.0",
"engines": { "engines": {
"node": ">=6.12" "node": ">=6.12"
}, },
@@ -63,8 +63,8 @@
}, },
"dependencies": { "dependencies": {
"@0x/assert": "^3.0.34", "@0x/assert": "^3.0.34",
"@0x/contract-addresses": "^6.19.2", "@0x/contract-addresses": "^6.16.0",
"@0x/contract-wrappers": "^13.20.8", "@0x/contract-wrappers": "^13.20.4",
"@0x/json-schemas": "^6.4.4", "@0x/json-schemas": "^6.4.4",
"@0x/subproviders": "^6.6.5", "@0x/subproviders": "^6.6.5",
"@0x/utils": "^6.5.3", "@0x/utils": "^6.5.3",

View File

@@ -1,7 +1,7 @@
import { AbiEncoder, BigNumber, hexUtils, NULL_ADDRESS } from '@0x/utils'; import { AbiEncoder, BigNumber, hexUtils, NULL_ADDRESS } from '@0x/utils';
import * as ethjs from 'ethereumjs-util'; import * as ethjs from 'ethereumjs-util';
import { LimitOrder, LimitOrderFields, RfqOrder, RfqOrderFields } from './orders'; import { LimitOrder, LimitOrderFields, OtcOrder, OtcOrderFields, RfqOrder, RfqOrderFields } from './orders';
import { Signature, SIGNATURE_ABI } from './signature_utils'; import { Signature, SIGNATURE_ABI } from './signature_utils';
const BRIDGE_ORDER_ABI_COMPONENTS = [ const BRIDGE_ORDER_ABI_COMPONENTS = [
@@ -39,6 +39,20 @@ const RFQ_ORDER_INFO_ABI_COMPONENTS = [
{ name: 'maxTakerTokenFillAmount', type: 'uint256' }, { name: 'maxTakerTokenFillAmount', type: 'uint256' },
]; ];
const OTC_ORDER_INFO_ABI_COMPONENTS = [
{
name: 'order',
type: 'tuple',
components: OtcOrder.STRUCT_ABI,
},
{
name: 'signature',
type: 'tuple',
components: SIGNATURE_ABI,
},
{ name: 'maxTakerTokenFillAmount', type: 'uint256' },
];
/** /**
* ABI encoder for `FillQuoteTransformer.TransformData` * ABI encoder for `FillQuoteTransformer.TransformData`
*/ */
@@ -60,6 +74,11 @@ export const fillQuoteTransformerDataEncoder = AbiEncoder.create([
type: 'tuple[]', type: 'tuple[]',
components: LIMIT_ORDER_INFO_ABI_COMPONENTS, components: LIMIT_ORDER_INFO_ABI_COMPONENTS,
}, },
{
name: 'otcOrders',
type: 'tuple[]',
components: OTC_ORDER_INFO_ABI_COMPONENTS,
},
{ {
name: 'rfqOrders', name: 'rfqOrders',
type: 'tuple[]', type: 'tuple[]',
@@ -87,6 +106,7 @@ export enum FillQuoteTransformerOrderType {
Bridge, Bridge,
Limit, Limit,
Rfq, Rfq,
Otc,
} }
/** /**
@@ -99,6 +119,7 @@ export interface FillQuoteTransformerData {
bridgeOrders: FillQuoteTransformerBridgeOrder[]; bridgeOrders: FillQuoteTransformerBridgeOrder[];
limitOrders: FillQuoteTransformerLimitOrderInfo[]; limitOrders: FillQuoteTransformerLimitOrderInfo[];
rfqOrders: FillQuoteTransformerRfqOrderInfo[]; rfqOrders: FillQuoteTransformerRfqOrderInfo[];
otcOrders: FillQuoteTransformerOtcOrderInfo[];
fillSequence: FillQuoteTransformerOrderType[]; fillSequence: FillQuoteTransformerOrderType[];
fillAmount: BigNumber; fillAmount: BigNumber;
refundReceiver: string; refundReceiver: string;
@@ -140,8 +161,6 @@ export enum BridgeProtocol {
Platypus, Platypus,
BancorV3, BancorV3,
Velodrome, Velodrome,
Synthetix,
WOOFi,
} }
// tslint:enable: enum-naming // tslint:enable: enum-naming
@@ -178,6 +197,11 @@ export type FillQuoteTransformerLimitOrderInfo = FillQuoteTransformerNativeOrder
*/ */
export type FillQuoteTransformerRfqOrderInfo = FillQuoteTransformerNativeOrderInfo<RfqOrderFields>; export type FillQuoteTransformerRfqOrderInfo = FillQuoteTransformerNativeOrderInfo<RfqOrderFields>;
/**
* `FillQuoteTransformer.OtcOrderInfo`
*/
export type FillQuoteTransformerOtcOrderInfo = FillQuoteTransformerNativeOrderInfo<OtcOrderFields>;
/** /**
* ABI-encode a `FillQuoteTransformer.TransformData` type. * ABI-encode a `FillQuoteTransformer.TransformData` type.
*/ */

1308
yarn.lock

File diff suppressed because it is too large Load Diff