Compare commits
	
		
			96 Commits
		
	
	
		
			@0x/contra
			...
			feat/1155-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | b6b90e30d8 | ||
|  | 7bf1b0750e | ||
|  | 2005054ec8 | ||
|  | cc70ad9d3c | ||
|  | db07fad051 | ||
|  | 91bfce9145 | ||
|  | 5fc608ed2f | ||
|  | 9b626ee37a | ||
|  | 4ae56d5876 | ||
|  | fd5d549c43 | ||
|  | 180110de50 | ||
|  | d186cddc29 | ||
|  | fbabd2f264 | ||
|  | 35f375a525 | ||
|  | 29892db0fd | ||
|  | 2cbb107380 | ||
|  | 599d590fbc | ||
|  | 9651b41264 | ||
|  | b6f118ef32 | ||
|  | 2cc11c87d1 | ||
|  | 7fa2eb4c2a | ||
|  | 35d839c651 | ||
|  | a009779a88 | ||
|  | 9aa7945bc4 | ||
|  | e7d198ef16 | ||
|  | 4e7e6eb634 | ||
|  | f745023625 | ||
|  | 2fdca24d4e | ||
|  | 42ec0b144e | ||
|  | 3f6ce78b46 | ||
|  | c1300c1068 | ||
|  | 9a641cfab6 | ||
|  | 60345d4465 | ||
|  | 11dfea47a6 | ||
|  | 55e9dd39a2 | ||
|  | 1993929bed | ||
|  | e1d81de517 | ||
|  | a6b3a21635 | ||
|  | fd59cdc2db | ||
|  | 98e11b5189 | ||
|  | 3bebc7cd62 | ||
|  | 56dab6ae8c | ||
|  | 285f98e9e9 | ||
|  | 8ae9f59f20 | ||
|  | 4c341c5ca3 | ||
|  | a3c912c2af | ||
|  | 5e72eb9af9 | ||
|  | 9b08b73c06 | ||
|  | 76c7eb7c3e | ||
|  | 9b2e5a3adb | ||
|  | 813d703d12 | ||
|  | 83005d0f3d | ||
|  | d07ffd2688 | ||
|  | 4170f970d0 | ||
|  | dcde12dd70 | ||
|  | 84a60ec982 | ||
|  | 9615570dc6 | ||
|  | 880a9c3da0 | ||
|  | c44bd9d42d | ||
|  | 90b441330b | ||
|  | e12ed1eddf | ||
|  | ac94023ab3 | ||
|  | 281e6acca5 | ||
|  | 2f1b520409 | ||
|  | 21b4eb3d26 | ||
|  | 644f6c7d28 | ||
|  | 0647b9e4f8 | ||
|  | 82d42eeede | ||
|  | 6ef4d95043 | ||
|  | 6044140f86 | ||
|  | 4da1ef0f56 | ||
|  | 8c668a3918 | ||
|  | f1ff1cde39 | ||
|  | 1668a24e31 | ||
|  | 4b7c376d96 | ||
|  | bb4a9c656c | ||
|  | 6ab07b6304 | ||
|  | 8903f1ab01 | ||
|  | 415535612a | ||
|  | 5248a135c3 | ||
|  | 602290925c | ||
|  | 01813746e8 | ||
|  | 7d668d8801 | ||
|  | 797a00a33a | ||
|  | 4b3d98f43c | ||
|  | 9ff77c1cd5 | ||
|  | 18a8351671 | ||
|  | 9a994dfcd3 | ||
|  | b7adc5a889 | ||
|  | 10b0d7f363 | ||
|  | e2c905a15f | ||
|  | 8589ba728c | ||
|  | 43512fd07a | ||
|  | c090608d99 | ||
|  | 89817428ed | ||
|  | fce3664258 | 
| @@ -1,4 +1,40 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1640364306, | ||||
|         "version": "3.3.25", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1638390144, | ||||
|         "version": "3.3.24", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1637102971, | ||||
|         "version": "3.3.23", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1635903615, | ||||
|         "version": "3.3.22", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1634668033, | ||||
|         "version": "3.3.21", | ||||
|   | ||||
| @@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v3.3.25 - _December 24, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.3.24 - _December 1, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.3.23 - _November 16, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.3.22 - _November 3, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.3.21 - _October 19, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-erc20", | ||||
|     "version": "3.3.21", | ||||
|     "version": "3.3.25", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -53,8 +53,8 @@ | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.6.2", | ||||
|         "@0x/contracts-gen": "^2.0.40", | ||||
|         "@0x/contracts-test-utils": "^5.4.12", | ||||
|         "@0x/contracts-utils": "^4.8.2", | ||||
|         "@0x/contracts-test-utils": "^5.4.16", | ||||
|         "@0x/contracts-utils": "^4.8.6", | ||||
|         "@0x/dev-utils": "^4.2.9", | ||||
|         "@0x/sol-compiler": "^4.7.5", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|   | ||||
| @@ -1,4 +1,40 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1640364306, | ||||
|         "version": "5.4.16", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1638390144, | ||||
|         "version": "5.4.15", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1637102971, | ||||
|         "version": "5.4.14", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1635903615, | ||||
|         "version": "5.4.13", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1634668033, | ||||
|         "version": "5.4.12", | ||||
|   | ||||
| @@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v5.4.16 - _December 24, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v5.4.15 - _December 1, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v5.4.14 - _November 16, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v5.4.13 - _November 3, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v5.4.12 - _October 19, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-test-utils", | ||||
|     "version": "5.4.12", | ||||
|     "version": "5.4.16", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -44,7 +44,7 @@ | ||||
|     "dependencies": { | ||||
|         "@0x/assert": "^3.0.29", | ||||
|         "@0x/base-contract": "^6.4.2", | ||||
|         "@0x/contract-addresses": "^6.8.0", | ||||
|         "@0x/contract-addresses": "^6.11.0", | ||||
|         "@0x/dev-utils": "^4.2.9", | ||||
|         "@0x/json-schemas": "^6.3.0", | ||||
|         "@0x/order-utils": "^10.4.28", | ||||
|   | ||||
| @@ -1,4 +1,40 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1640364306, | ||||
|         "version": "1.4.8", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1638390144, | ||||
|         "version": "1.4.7", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1637102971, | ||||
|         "version": "1.4.6", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1635903615, | ||||
|         "version": "1.4.5", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1634668033, | ||||
|         "version": "1.4.4", | ||||
|   | ||||
| @@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v1.4.8 - _December 24, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.4.7 - _December 1, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.4.6 - _November 16, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.4.5 - _November 3, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.4.4 - _October 19, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-treasury", | ||||
|     "version": "1.4.4", | ||||
|     "version": "1.4.8", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -47,12 +47,12 @@ | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.6.2", | ||||
|         "@0x/contract-addresses": "^6.8.0", | ||||
|         "@0x/contract-addresses": "^6.11.0", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.19", | ||||
|         "@0x/contracts-erc20": "^3.3.21", | ||||
|         "@0x/contracts-erc20": "^3.3.25", | ||||
|         "@0x/contracts-gen": "^2.0.40", | ||||
|         "@0x/contracts-staking": "^2.0.45", | ||||
|         "@0x/contracts-test-utils": "^5.4.12", | ||||
|         "@0x/contracts-test-utils": "^5.4.16", | ||||
|         "@0x/sol-compiler": "^4.7.5", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
| @@ -73,7 +73,7 @@ | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.4.2", | ||||
|         "@0x/protocol-utils": "^1.9.3", | ||||
|         "@0x/protocol-utils": "^1.10.1", | ||||
|         "@0x/subproviders": "^6.6.0", | ||||
|         "@0x/types": "^3.3.4", | ||||
|         "@0x/typescript-typings": "^5.2.1", | ||||
|   | ||||
| @@ -1,4 +1,40 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1640364306, | ||||
|         "version": "4.8.6", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1638390144, | ||||
|         "version": "4.8.5", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1637102971, | ||||
|         "version": "4.8.4", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1635903615, | ||||
|         "version": "4.8.3", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1634668033, | ||||
|         "version": "4.8.2", | ||||
|   | ||||
| @@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v4.8.6 - _December 24, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v4.8.5 - _December 1, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v4.8.4 - _November 16, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v4.8.3 - _November 3, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v4.8.2 - _October 19, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-utils", | ||||
|     "version": "4.8.2", | ||||
|     "version": "4.8.6", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -52,7 +52,7 @@ | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.6.2", | ||||
|         "@0x/contracts-gen": "^2.0.40", | ||||
|         "@0x/contracts-test-utils": "^5.4.12", | ||||
|         "@0x/contracts-test-utils": "^5.4.16", | ||||
|         "@0x/dev-utils": "^4.2.9", | ||||
|         "@0x/order-utils": "^10.4.28", | ||||
|         "@0x/sol-compiler": "^4.7.5", | ||||
|   | ||||
| @@ -1,4 +1,56 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1640364306, | ||||
|         "version": "0.30.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "0.30.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add `AaveV2` and `Compound` deposit/withdrawal liquidity source", | ||||
|                 "pr": 321 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1638390144 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1637102971, | ||||
|         "version": "0.29.5", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "0.29.4", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Prevent EP ETH balance from reducing when executin mtxs", | ||||
|                 "pr": 365 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1637065617 | ||||
|     }, | ||||
|     { | ||||
|         "version": "0.29.3", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Register transformERC20() and remove transformERC20Staging()", | ||||
|                 "pr": 355 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add OtcOrders to FullMigration", | ||||
|                 "pr": 350 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1635903615 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1634668033, | ||||
|         "version": "0.29.2", | ||||
|   | ||||
| @@ -5,6 +5,27 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v0.30.1 - _December 24, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v0.30.0 - _December 1, 2021_ | ||||
|  | ||||
|     * Add `AaveV2` and `Compound` deposit/withdrawal liquidity source (#321) | ||||
|  | ||||
| ## v0.29.5 - _November 16, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v0.29.4 - _November 16, 2021_ | ||||
|  | ||||
|     * Prevent EP ETH balance from reducing when executin mtxs (#365) | ||||
|  | ||||
| ## v0.29.3 - _November 3, 2021_ | ||||
|  | ||||
|     * Register transformERC20() and remove transformERC20Staging() (#355) | ||||
|     * Add OtcOrders to FullMigration (#350) | ||||
|  | ||||
| ## v0.29.2 - _October 19, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -34,6 +34,7 @@ import "./features/interfaces/IBatchFillNativeOrdersFeature.sol"; | ||||
| import "./features/interfaces/IMultiplexFeature.sol"; | ||||
| import "./features/interfaces/IOtcOrdersFeature.sol"; | ||||
| import "./features/interfaces/IFundRecoveryFeature.sol"; | ||||
| import "./features/interfaces/IERC721OrdersFeature.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev Interface for a fully featured Exchange Proxy. | ||||
| @@ -50,7 +51,8 @@ interface IZeroEx is | ||||
|     IBatchFillNativeOrdersFeature, | ||||
|     IMultiplexFeature, | ||||
|     IOtcOrdersFeature, | ||||
|     IFundRecoveryFeature | ||||
|     IFundRecoveryFeature, | ||||
|     IERC721OrdersFeature | ||||
| { | ||||
|     // solhint-disable state-visibility | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,184 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
|  | ||||
|  | ||||
| library LibERC1155OrdersRichErrors { | ||||
|  | ||||
|     // solhint-disable func-name-mixedcase | ||||
|  | ||||
|     function OverspentEthError( | ||||
|         uint256 ethSpent, | ||||
|         uint256 msgValue | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("OverspentEthError(uint256,uint256)")), | ||||
|             ethSpent, | ||||
|             msgValue | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function InsufficientEthError( | ||||
|         uint256 ethAvailable, | ||||
|         uint256 orderAmount | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("InsufficientEthError(uint256,uint256)")), | ||||
|             ethAvailable, | ||||
|             orderAmount | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function ERC1155TokenMismatchError( | ||||
|         address token1, | ||||
|         address token2 | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("ERC1155TokenMismatchError(address,address)")), | ||||
|             token1, | ||||
|             token2 | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function ERC20TokenMismatchError( | ||||
|         address token1, | ||||
|         address token2 | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("ERC20TokenMismatchError(address,address)")), | ||||
|             token1, | ||||
|             token2 | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function OnlyTakerError( | ||||
|         address sender, | ||||
|         address taker | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("OnlyTakerError(address,address)")), | ||||
|             sender, | ||||
|             taker | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function InvalidSignerError( | ||||
|         address maker, | ||||
|         address signer | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("InvalidSignerError(address,address)")), | ||||
|             maker, | ||||
|             signer | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function OrderNotFillableError( | ||||
|         address maker, | ||||
|         uint256 nonce, | ||||
|         uint8 orderStatus | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("OrderNotFillableError(address,uint256,uint8)")), | ||||
|             maker, | ||||
|             nonce, | ||||
|             orderStatus | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function ERC1155TokenIdMismatchError( | ||||
|         uint256 tokenId, | ||||
|         uint256 orderTokenId | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("ERC1155TokenIdMismatchError(uint256,uint256)")), | ||||
|             tokenId, | ||||
|             orderTokenId | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function PropertyValidationFailedError( | ||||
|         address propertyValidator, | ||||
|         address erc1155Token, | ||||
|         uint256 erc1155TokenId, | ||||
|         bytes memory propertyData, | ||||
|         bytes memory errorData | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("PropertyValidationFailedError(address,address,uint256,bytes,bytes)")), | ||||
|             propertyValidator, | ||||
|             erc1155Token, | ||||
|             erc1155TokenId, | ||||
|             propertyData, | ||||
|             errorData | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function ExceedsRemainingOrderAmount( | ||||
|         uint128 remainingOrderAmount, | ||||
|         uint128 erc1155FillAmount | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("ExceedsRemainingOrderAmount(uint128,uint128)")), | ||||
|             remainingOrderAmount, | ||||
|             erc1155FillAmount | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,200 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
|  | ||||
|  | ||||
| library LibERC721OrdersRichErrors { | ||||
|  | ||||
|     // solhint-disable func-name-mixedcase | ||||
|  | ||||
|     function OverspentEthError( | ||||
|         uint256 ethSpent, | ||||
|         uint256 msgValue | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("OverspentEthError(uint256,uint256)")), | ||||
|             ethSpent, | ||||
|             msgValue | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function InsufficientEthError( | ||||
|         uint256 ethAvailable, | ||||
|         uint256 orderAmount | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("InsufficientEthError(uint256,uint256)")), | ||||
|             ethAvailable, | ||||
|             orderAmount | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function ERC721TokenMismatchError( | ||||
|         address token1, | ||||
|         address token2 | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("ERC721TokenMismatchError(address,address)")), | ||||
|             token1, | ||||
|             token2 | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function ERC20TokenMismatchError( | ||||
|         address token1, | ||||
|         address token2 | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("ERC20TokenMismatchError(address,address)")), | ||||
|             token1, | ||||
|             token2 | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function NegativeSpreadError( | ||||
|         uint256 sellOrderAmount, | ||||
|         uint256 buyOrderAmount | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("NegativeSpreadError(uint256,uint256)")), | ||||
|             sellOrderAmount, | ||||
|             buyOrderAmount | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function SellOrderFeesExceedSpreadError( | ||||
|         uint256 sellOrderFees, | ||||
|         uint256 spread | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("SellOrderFeesExceedSpreadError(uint256,uint256)")), | ||||
|             sellOrderFees, | ||||
|             spread | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function OnlyTakerError( | ||||
|         address sender, | ||||
|         address taker | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("OnlyTakerError(address,address)")), | ||||
|             sender, | ||||
|             taker | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function InvalidSignerError( | ||||
|         address maker, | ||||
|         address signer | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("InvalidSignerError(address,address)")), | ||||
|             maker, | ||||
|             signer | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function OrderNotFillableError( | ||||
|         address maker, | ||||
|         uint256 nonce, | ||||
|         uint8 orderStatus | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("OrderNotFillableError(address,uint256,uint8)")), | ||||
|             maker, | ||||
|             nonce, | ||||
|             orderStatus | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function ERC721TokenIdMismatchError( | ||||
|         uint256 tokenId, | ||||
|         uint256 orderTokenId | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("ERC721TokenIdMismatchError(uint256,uint256)")), | ||||
|             tokenId, | ||||
|             orderTokenId | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     function PropertyValidationFailedError( | ||||
|         address propertyValidator, | ||||
|         address erc721Token, | ||||
|         uint256 erc721TokenId, | ||||
|         bytes memory propertyData, | ||||
|         bytes memory errorData | ||||
|     ) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes memory) | ||||
|     { | ||||
|         return abi.encodeWithSelector( | ||||
|             bytes4(keccak256("PropertyValidationFailedError(address,address,uint256,bytes,bytes)")), | ||||
|             propertyValidator, | ||||
|             erc721Token, | ||||
|             erc721TokenId, | ||||
|             propertyData, | ||||
|             errorData | ||||
|         ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1003
									
								
								contracts/zero-ex/contracts/src/features/ERC1155OrdersFeature.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1003
									
								
								contracts/zero-ex/contracts/src/features/ERC1155OrdersFeature.sol
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1138
									
								
								contracts/zero-ex/contracts/src/features/ERC721OrdersFeature.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1138
									
								
								contracts/zero-ex/contracts/src/features/ERC721OrdersFeature.sol
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -78,7 +78,7 @@ contract MetaTransactionsFeature is | ||||
|     /// @dev Name of this feature. | ||||
|     string public constant override FEATURE_NAME = "MetaTransactions"; | ||||
|     /// @dev Version of this feature. | ||||
|     uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 2, 0); | ||||
|     uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 2, 1); | ||||
|     /// @dev EIP712 typehash of the `MetaTransactionData` struct. | ||||
|     bytes32 public immutable MTX_EIP712_TYPEHASH = keccak256( | ||||
|         "MetaTransactionData(" | ||||
| @@ -105,6 +105,17 @@ contract MetaTransactionsFeature is | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @dev Ensures that the ETH balance of `this` does not go below the | ||||
|     ///      initial ETH balance before the call (excluding ETH attached to the call). | ||||
|     modifier doesNotReduceEthBalance() { | ||||
|         uint256 initialBalance = address(this).balance - msg.value; | ||||
|         _; | ||||
|         require( | ||||
|             initialBalance <= address(this).balance, | ||||
|             "MetaTransactionsFeature/ETH_LEAK" | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     constructor(address zeroExAddress) | ||||
|         public | ||||
|         FixinCommon() | ||||
| @@ -140,6 +151,7 @@ contract MetaTransactionsFeature is | ||||
|         payable | ||||
|         override | ||||
|         nonReentrant(REENTRANCY_MTX) | ||||
|         doesNotReduceEthBalance | ||||
|         refundsAttachedEth | ||||
|         returns (bytes memory returnResult) | ||||
|     { | ||||
| @@ -164,6 +176,7 @@ contract MetaTransactionsFeature is | ||||
|         payable | ||||
|         override | ||||
|         nonReentrant(REENTRANCY_MTX) | ||||
|         doesNotReduceEthBalance | ||||
|         refundsAttachedEth | ||||
|         returns (bytes[] memory returnResults) | ||||
|     { | ||||
|   | ||||
| @@ -311,7 +311,7 @@ contract OtcOrdersFeature is | ||||
|         // Unwrap WETH | ||||
|         WETH.withdraw(order.makerAmount); | ||||
|         // Transfer ETH to taker | ||||
|         _transferEth(taker, order.makerAmount); | ||||
|         _transferEth(payable(taker), order.makerAmount); | ||||
|  | ||||
|         emit OtcOrderFilled( | ||||
|             orderInfo.orderHash, | ||||
| @@ -622,16 +622,4 @@ contract OtcOrdersFeature is | ||||
|             [txOrigin] | ||||
|             [nonceBucket]; | ||||
|     } | ||||
|  | ||||
|     function _transferEth(address recipient, uint256 amount) | ||||
|         private | ||||
|     { | ||||
|         // Transfer ETH to recipient | ||||
|         (bool success, bytes memory revertData) = | ||||
|             recipient.call{value: amount}(""); | ||||
|         // Revert on failure | ||||
|         if (!success) { | ||||
|             revertData.rrevert(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -75,7 +75,7 @@ contract TransformERC20Feature is | ||||
|         _registerFeatureFunction(this.setTransformerDeployer.selector); | ||||
|         _registerFeatureFunction(this.setQuoteSigner.selector); | ||||
|         _registerFeatureFunction(this.getQuoteSigner.selector); | ||||
|         _registerFeatureFunction(this.transformERC20Staging.selector); | ||||
|         _registerFeatureFunction(this.transformERC20.selector); | ||||
|         _registerFeatureFunction(this._transformERC20.selector); | ||||
|         if (this.getTransformWallet() == IFlashWallet(address(0))) { | ||||
|             // Create the transform wallet if it doesn't exist. | ||||
| @@ -145,44 +145,6 @@ contract TransformERC20Feature is | ||||
|         LibTransformERC20Storage.getStorage().wallet = wallet; | ||||
|     } | ||||
|  | ||||
|     /// @dev Wrapper for `transformERC20`. This selector will be temporarily | ||||
|     ///      registered to the Exchange Proxy so that we can migrate 0x API | ||||
|     ///      with no downtime. Once 0x API has been updated to point to this | ||||
|     ///      function, we can safely re-register `transformERC20`, point  | ||||
|     ///      0x API back to `transformERC20`, and deregister this function. | ||||
|     /// @param inputToken The token being provided by the sender. | ||||
|     ///        If `0xeee...`, ETH is implied and should be provided with the call.` | ||||
|     /// @param outputToken The token to be acquired by the sender. | ||||
|     ///        `0xeee...` implies ETH. | ||||
|     /// @param inputTokenAmount The amount of `inputToken` to take from the sender. | ||||
|     ///        If set to `uint256(-1)`, the entire spendable balance of the taker | ||||
|     ///        will be solt. | ||||
|     /// @param minOutputTokenAmount The minimum amount of `outputToken` the sender | ||||
|     ///        must receive for the entire transformation to succeed. If set to zero, | ||||
|     ///        the minimum output token transfer will not be asserted. | ||||
|     /// @param transformations The transformations to execute on the token balance(s) | ||||
|     ///        in sequence. | ||||
|     /// @return outputTokenAmount The amount of `outputToken` received by the sender. | ||||
|     function transformERC20Staging( | ||||
|         IERC20TokenV06 inputToken, | ||||
|         IERC20TokenV06 outputToken, | ||||
|         uint256 inputTokenAmount, | ||||
|         uint256 minOutputTokenAmount, | ||||
|         Transformation[] memory transformations | ||||
|     ) | ||||
|         public | ||||
|         payable | ||||
|         returns (uint256 outputTokenAmount) | ||||
|     { | ||||
|         return transformERC20( | ||||
|             inputToken,  | ||||
|             outputToken,  | ||||
|             inputTokenAmount,  | ||||
|             minOutputTokenAmount,  | ||||
|             transformations | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Executes a series of transformations to convert an ERC20 `inputToken` | ||||
|     ///      to an ERC20 `outputToken`. | ||||
|     /// @param inputToken The token being provided by the sender. | ||||
| @@ -283,8 +245,8 @@ contract TransformERC20Feature is | ||||
|             } | ||||
|             // Transfer output tokens from wallet to recipient | ||||
|             outputTokenAmount = _executeOutputTokenTransfer( | ||||
|                 args.outputToken,  | ||||
|                 state.wallet,  | ||||
|                 args.outputToken, | ||||
|                 state.wallet, | ||||
|                 args.recipient | ||||
|             ); | ||||
|         } | ||||
|   | ||||
| @@ -0,0 +1,236 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "../libs/LibERC1155Order.sol"; | ||||
| import "../libs/LibSignature.sol"; | ||||
| import "../../vendor/IERC1155Token.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev Feature for interacting with ERC1155 orders. | ||||
| interface IERC1155OrdersFeature { | ||||
|  | ||||
|     /// @dev Emitted whenever an `ERC1155Order` is filled. | ||||
|     /// @param direction Whether the order is selling or | ||||
|     ///        buying the ERC1155 token. | ||||
|     /// @param erc20Token The address of the ERC20 token. | ||||
|     /// @param erc20FillAmount The amount of ERC20 token filled. | ||||
|     /// @param erc1155Token The address of the ERC1155 token. | ||||
|     /// @param erc1155TokenId The ID of the ERC1155 asset. | ||||
|     /// @param erc1155FillAmount The amount of ERC1155 asset filled. | ||||
|     /// @param maker The maker of the order. | ||||
|     /// @param taker The taker of the order. | ||||
|     /// @param nonce The unique maker nonce in the order. | ||||
|     /// @param matcher Currently unused. | ||||
|     event ERC1155OrderFilled( | ||||
|         LibERC1155Order.TradeDirection direction, | ||||
|         IERC20TokenV06 erc20Token, | ||||
|         uint256 erc20FillAmount, | ||||
|         IERC1155Token erc1155Token, | ||||
|         uint256 erc1155TokenId, | ||||
|         uint128 erc1155FillAmount, | ||||
|         address maker, | ||||
|         address taker, | ||||
|         uint256 nonce, | ||||
|         address matcher | ||||
|     ); | ||||
|  | ||||
|     /// @dev Emitted whenever an `ERC1155Order` is cancelled. | ||||
|     /// @param orderHash The hash the order. | ||||
|     /// @param maker The maker of the order. | ||||
|     event ERC1155OrderCancelled( | ||||
|         bytes32 orderHash, | ||||
|         address maker | ||||
|     ); | ||||
|  | ||||
|     /// @dev Emitted when an `ERC1155Order` is pre-signed. | ||||
|     ///      Contains all the fields of the order. | ||||
|     event ERC1155OrderPreSigned( | ||||
|         LibERC1155Order.TradeDirection direction, | ||||
|         IERC20TokenV06 erc20Token, | ||||
|         uint256 erc20TokenAmount, | ||||
|         IERC1155Token erc1155Token, | ||||
|         uint256 erc1155TokenId, | ||||
|         uint128 erc1155TokenAmount, | ||||
|         LibERC1155Order.Property[] erc1155TokenProperties, | ||||
|         LibERC1155Order.Fee[] fees, | ||||
|         address maker, | ||||
|         address taker, | ||||
|         uint256 expiry, | ||||
|         uint256 nonce | ||||
|     ); | ||||
|  | ||||
|     /// @dev Sells an ERC1155 asset to fill the given order. | ||||
|     /// @param buyOrder The ERC1155 buy order. | ||||
|     /// @param signature The order signature from the maker. | ||||
|     /// @param erc1155TokenId The ID of the ERC1155 asset being | ||||
|     ///        sold. If the given order specifies properties, | ||||
|     ///        the asset must satisfy those properties. Otherwise, | ||||
|     ///        it must equal the tokenId in the order. | ||||
|     /// @param erc1155SellAmount The amount of the ERC1155 asset | ||||
|     ///        to sell. | ||||
|     /// @param unwrapNativeToken If this parameter is true and the | ||||
|     ///        ERC20 token of the order is e.g. WETH, unwraps the | ||||
|     ///        token before transferring it to the taker. | ||||
|     /// @param callbackData If this parameter is non-zero, invokes | ||||
|     ///        `zeroExERC1155OrderCallback` on `msg.sender` after | ||||
|     ///        the ERC20 tokens have been transferred to `msg.sender` | ||||
|     ///        but before transferring the ERC1155 asset to the buyer. | ||||
|     function sellERC1155( | ||||
|         LibERC1155Order.ERC1155Order calldata buyOrder, | ||||
|         LibSignature.Signature calldata signature, | ||||
|         uint256 erc1155TokenId, | ||||
|         uint128 erc1155SellAmount, | ||||
|         bool unwrapNativeToken, | ||||
|         bytes calldata callbackData | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Buys an ERC1155 asset by filling the given order. | ||||
|     /// @param sellOrder The ERC1155 sell order. | ||||
|     /// @param signature The order signature. | ||||
|     /// @param erc1155BuyAmount The amount of the ERC1155 asset | ||||
|     ///        to buy. | ||||
|     /// @param callbackData If this parameter is non-zero, invokes | ||||
|     ///        `zeroExERC1155OrderCallback` on `msg.sender` after | ||||
|     ///        the ERC1155 asset has been transferred to `msg.sender` | ||||
|     ///        but before transferring the ERC20 tokens to the seller. | ||||
|     ///        Native tokens acquired during the callback can be used | ||||
|     ///        to fill the order. | ||||
|     function buyERC1155( | ||||
|         LibERC1155Order.ERC1155Order calldata sellOrder, | ||||
|         LibSignature.Signature calldata signature, | ||||
|         uint128 erc1155BuyAmount, | ||||
|         bytes calldata callbackData | ||||
|     ) | ||||
|         external | ||||
|         payable; | ||||
|  | ||||
|     /// @dev Cancel a single ERC1155 order. The caller should be the | ||||
|     ///      maker of the order. Silently succeeds if the order has | ||||
|     ///      already been filled or cancelled. | ||||
|     /// @param order The order to cancel. | ||||
|     function cancelERC1155Order(LibERC1155Order.ERC1155Order calldata order) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Cancel multiple ERC1155 orders. The caller should be the | ||||
|     ///      maker of the orders. Silently succeeds if an order has | ||||
|     ///      already been filled or cancelled. | ||||
|     /// @param orders The orders to cancel. | ||||
|     function batchCancelERC1155Orders(LibERC1155Order.ERC1155Order[] calldata orders) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Buys multiple ERC1155 assets by filling the | ||||
|     ///      given orders. | ||||
|     /// @param sellOrders The ERC1155 sell orders. | ||||
|     /// @param signatures The order signatures. | ||||
|     /// @param erc1155TokenAmounts The amounts of the ERC1155 assets | ||||
|     ///        to buy for each order. | ||||
|     /// @param revertIfIncomplete If true, reverts if this | ||||
|     ///        function fails to fill any individual order. | ||||
|     /// @return successes An array of booleans corresponding to whether | ||||
|     ///         each order in `orders` was successfully filled. | ||||
|     function batchBuyERC1155s( | ||||
|         LibERC1155Order.ERC1155Order[] calldata sellOrders, | ||||
|         LibSignature.Signature[] calldata signatures, | ||||
|         uint256[] calldata erc1155TokenAmounts, | ||||
|         bool revertIfIncomplete | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|         returns (bool[] memory successes); | ||||
|  | ||||
|     /// @dev Callback for the ERC1155 `safeTransferFrom` function. | ||||
|     ///      This callback can be used to sell an ERC1155 asset if | ||||
|     ///      a valid ERC1155 order, signature and `unwrapNativeToken` | ||||
|     ///      are encoded in `data`. This allows takers to sell their | ||||
|     ///      ERC1155 asset without first calling `setApprovalForAll`. | ||||
|     /// @param operator The address which called `safeTransferFrom`. | ||||
|     /// @param from The address which previously owned the token. | ||||
|     /// @param tokenId The ID of the asset being transferred. | ||||
|     /// @param value The amount being transferred. | ||||
|     /// @param data Additional data with no specified format. If a | ||||
|     ///        valid ERC1155 order, signature and `unwrapNativeToken` | ||||
|     ///        are encoded in `data`, this function will try to fill | ||||
|     ///        the order using the received asset. | ||||
|     /// @return success The selector of this function (0xf23a6e61), | ||||
|     ///         indicating that the callback succeeded. | ||||
|     function onERC1155Received( | ||||
|         address operator, | ||||
|         address from, | ||||
|         uint256 tokenId, | ||||
|         uint256 value, | ||||
|         bytes calldata data | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4 success); | ||||
|  | ||||
|     /// @dev Approves an ERC1155 order on-chain. After pre-signing | ||||
|     ///      the order, the `PRESIGNED` signature type will become | ||||
|     ///      valid for that order and signer. | ||||
|     /// @param order An ERC1155 order. | ||||
|     function preSignERC1155Order(LibERC1155Order.ERC1155Order calldata order) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Checks whether the given signature is valid for the | ||||
|     ///      the given ERC1155 order. Reverts if not. | ||||
|     /// @param order The ERC1155 order. | ||||
|     /// @param signature The signature to validate. | ||||
|     function validateERC1155OrderSignature( | ||||
|         LibERC1155Order.ERC1155Order calldata order, | ||||
|         LibSignature.Signature calldata signature | ||||
|     ) | ||||
|         external | ||||
|         view; | ||||
|  | ||||
|     /// @dev If the given order is buying an ERC1155 asset, checks | ||||
|     ///      whether or not the given token ID satisfies the required | ||||
|     ///      properties specified in the order. If the order does not | ||||
|     ///      specify any properties, this function instead checks | ||||
|     ///      whether the given token ID matches the ID in the order. | ||||
|     ///      Reverts if any checks fail, or if the order is selling | ||||
|     ///      an ERC1155 asset. | ||||
|     /// @param order The ERC1155 order. | ||||
|     /// @param erc1155TokenId The ID of the ERC1155 asset. | ||||
|     function validateERC1155OrderProperties( | ||||
|         LibERC1155Order.ERC1155Order calldata order, | ||||
|         uint256 erc1155TokenId | ||||
|     ) | ||||
|         external | ||||
|         view; | ||||
|  | ||||
|     /// @dev Get the order info for an ERC1155 order. | ||||
|     /// @param order The ERC1155 order. | ||||
|     /// @return orderInfo Infor about the order. | ||||
|     function getERC1155OrderInfo(LibERC1155Order.ERC1155Order calldata order) | ||||
|         external | ||||
|         view | ||||
|         returns (LibERC1155Order.OrderInfo memory orderInfo); | ||||
|  | ||||
|     /// @dev Get the canonical hash of an ERC1155 order. | ||||
|     /// @param order The ERC1155 order. | ||||
|     /// @return orderHash The order hash. | ||||
|     function getERC1155OrderHash(LibERC1155Order.ERC1155Order calldata order) | ||||
|         external | ||||
|         view | ||||
|         returns (bytes32 orderHash); | ||||
| } | ||||
| @@ -0,0 +1,282 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "../libs/LibERC721Order.sol"; | ||||
| import "../libs/LibSignature.sol"; | ||||
| import "../../vendor/IERC721Token.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev Feature for interacting with ERC721 orders. | ||||
| interface IERC721OrdersFeature { | ||||
|  | ||||
|     /// @dev Emitted whenever an `ERC721Order` is filled. | ||||
|     /// @param direction Whether the order is selling or | ||||
|     ///        buying the ERC721 token. | ||||
|     /// @param erc20Token The address of the ERC20 token. | ||||
|     /// @param erc20TokenAmount The amount of ERC20 token | ||||
|     ///        to sell or buy. | ||||
|     /// @param erc721Token The address of the ERC721 token. | ||||
|     /// @param erc721TokenId The ID of the ERC721 asset. | ||||
|     /// @param maker The maker of the order. | ||||
|     /// @param taker The taker of the order. | ||||
|     /// @param nonce The unique maker nonce in the order. | ||||
|     /// @param matcher If this order was matched with another using `matchERC721Orders()`, | ||||
|     ///                this will be the address of the caller. If not, this will be `address(0)`. | ||||
|     event ERC721OrderFilled( | ||||
|         LibERC721Order.TradeDirection direction, | ||||
|         IERC20TokenV06 erc20Token, | ||||
|         uint256 erc20TokenAmount, | ||||
|         IERC721Token erc721Token, | ||||
|         uint256 erc721TokenId, | ||||
|         address maker, | ||||
|         address taker, | ||||
|         uint256 nonce, | ||||
|         address matcher | ||||
|     ); | ||||
|  | ||||
|     /// @dev Emitted whenever an `ERC721Order` is cancelled. | ||||
|     /// @param maker The maker of the order. | ||||
|     /// @param nonce The nonce of the order that was cancelled. | ||||
|     event ERC721OrderCancelled( | ||||
|         address maker, | ||||
|         uint256 nonce | ||||
|     ); | ||||
|  | ||||
|     /// @dev Emitted when an `ERC721Order` is pre-signed. | ||||
|     ///      Contains all the fields of the order. | ||||
|     event ERC721OrderPreSigned( | ||||
|         LibERC721Order.TradeDirection direction, | ||||
|         IERC20TokenV06 erc20Token, | ||||
|         uint256 erc20TokenAmount, | ||||
|         IERC721Token erc721Token, | ||||
|         uint256 erc721TokenId, | ||||
|         LibERC721Order.Property[] erc721TokenProperties, | ||||
|         LibERC721Order.Fee[] fees, | ||||
|         address maker, | ||||
|         address taker, | ||||
|         uint256 expiry, | ||||
|         uint256 nonce | ||||
|     ); | ||||
|  | ||||
|     /// @dev Sells an ERC721 asset to fill the given order. | ||||
|     /// @param buyOrder The ERC721 buy order. | ||||
|     /// @param signature The order signature from the maker. | ||||
|     /// @param erc721TokenId The ID of the ERC721 asset being | ||||
|     ///        sold. If the given order specifies properties, | ||||
|     ///        the asset must satisfy those properties. Otherwise, | ||||
|     ///        it must equal the tokenId in the order. | ||||
|     /// @param unwrapNativeToken If this parameter is true and the | ||||
|     ///        ERC20 token of the order is e.g. WETH, unwraps the | ||||
|     ///        token before transferring it to the taker. | ||||
|     /// @param callbackData If this parameter is non-zero, invokes | ||||
|     ///        `zeroExERC721OrderCallback` on `msg.sender` after | ||||
|     ///        the ERC20 tokens have been transferred to `msg.sender` | ||||
|     ///        but before transferring the ERC721 asset to the buyer. | ||||
|     function sellERC721( | ||||
|         LibERC721Order.ERC721Order calldata buyOrder, | ||||
|         LibSignature.Signature calldata signature, | ||||
|         uint256 erc721TokenId, | ||||
|         bool unwrapNativeToken, | ||||
|         bytes calldata callbackData | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Buys an ERC721 asset by filling the given order. | ||||
|     /// @param sellOrder The ERC721 sell order. | ||||
|     /// @param signature The order signature. | ||||
|     /// @param callbackData If this parameter is non-zero, invokes | ||||
|     ///        `zeroExERC721OrderCallback` on `msg.sender` after | ||||
|     ///        the ERC721 asset has been transferred to `msg.sender` | ||||
|     ///        but before transferring the ERC20 tokens to the seller. | ||||
|     ///        Native tokens acquired during the callback can be used | ||||
|     ///        to fill the order. | ||||
|     function buyERC721( | ||||
|         LibERC721Order.ERC721Order calldata sellOrder, | ||||
|         LibSignature.Signature calldata signature, | ||||
|         bytes calldata callbackData | ||||
|     ) | ||||
|         external | ||||
|         payable; | ||||
|  | ||||
|     /// @dev Cancel a single ERC721 order by its nonce. The caller | ||||
|     ///      should be the maker of the order. Silently succeeds if | ||||
|     ///      an order with the same nonce has already been filled or | ||||
|     ///      cancelled. | ||||
|     /// @param orderNonce The order nonce. | ||||
|     function cancelERC721Order(uint256 orderNonce) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Cancel multiple ERC721 orders by their nonces. The caller | ||||
|     ///      should be the maker of the orders. Silently succeeds if | ||||
|     ///      an order with the same nonce has already been filled or | ||||
|     ///      cancelled. | ||||
|     /// @param orderNonces The order nonces. | ||||
|     function batchCancelERC721Orders(uint256[] calldata orderNonces) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Buys multiple ERC721 assets by filling the | ||||
|     ///      given orders. | ||||
|     /// @param sellOrders The ERC721 sell orders. | ||||
|     /// @param signatures The order signatures. | ||||
|     /// @param revertIfIncomplete If true, reverts if this | ||||
|     ///        function fails to fill any individual order. | ||||
|     /// @return successes An array of booleans corresponding to whether | ||||
|     ///         each order in `orders` was successfully filled. | ||||
|     function batchBuyERC721s( | ||||
|         LibERC721Order.ERC721Order[] calldata sellOrders, | ||||
|         LibSignature.Signature[] calldata signatures, | ||||
|         bool revertIfIncomplete | ||||
|     ) | ||||
|         external | ||||
|         payable | ||||
|         returns (bool[] memory successes); | ||||
|  | ||||
|     /// @dev Matches a pair of complementary orders that have | ||||
|     ///      a non-negative spread. Each order is filled at | ||||
|     ///      their respective price, and the matcher receives | ||||
|     ///      a profit denominated in the ERC20 token. | ||||
|     /// @param sellOrder Order selling an ERC721 asset. | ||||
|     /// @param buyOrder Order buying an ERC721 asset. | ||||
|     /// @param sellOrderSignature Signature for the sell order. | ||||
|     /// @param buyOrderSignature Signature for the buy order. | ||||
|     /// @return profit The amount of profit earned by the caller | ||||
|     ///         of this function (denominated in the ERC20 token | ||||
|     ///         of the matched orders). | ||||
|     function matchERC721Orders( | ||||
|         LibERC721Order.ERC721Order calldata sellOrder, | ||||
|         LibERC721Order.ERC721Order calldata buyOrder, | ||||
|         LibSignature.Signature calldata sellOrderSignature, | ||||
|         LibSignature.Signature calldata buyOrderSignature | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256 profit); | ||||
|  | ||||
|     /// @dev Matches pairs of complementary orders that have | ||||
|     ///      non-negative spreads. Each order is filled at | ||||
|     ///      their respective price, and the matcher receives | ||||
|     ///      a profit denominated in the ERC20 token. | ||||
|     /// @param sellOrders Orders selling ERC721 assets. | ||||
|     /// @param buyOrders Orders buying ERC721 assets. | ||||
|     /// @param sellOrderSignatures Signatures for the sell orders. | ||||
|     /// @param buyOrderSignatures Signatures for the buy orders. | ||||
|     /// @return profits The amount of profit earned by the caller | ||||
|     ///         of this function for each pair of matched orders | ||||
|     ///         (denominated in the ERC20 token of the order pair). | ||||
|     /// @return successes An array of booleans corresponding to | ||||
|     ///         whether each pair of orders was successfully matched. | ||||
|     function batchMatchERC721Orders( | ||||
|         LibERC721Order.ERC721Order[] calldata sellOrders, | ||||
|         LibERC721Order.ERC721Order[] calldata buyOrders, | ||||
|         LibSignature.Signature[] calldata sellOrderSignatures, | ||||
|         LibSignature.Signature[] calldata buyOrderSignatures | ||||
|     ) | ||||
|         external | ||||
|         returns (uint256[] memory profits, bool[] memory successes); | ||||
|  | ||||
|     /// @dev Callback for the ERC721 `safeTransferFrom` function. | ||||
|     ///      This callback can be used to sell an ERC721 asset if | ||||
|     ///      a valid ERC721 order, signature and `unwrapNativeToken` | ||||
|     ///      are encoded in `data`. This allows takers to sell their | ||||
|     ///      ERC721 asset without first calling `setApprovalForAll`. | ||||
|     /// @param operator The address which called `safeTransferFrom`. | ||||
|     /// @param from The address which previously owned the token. | ||||
|     /// @param tokenId The ID of the asset being transferred. | ||||
|     /// @param data Additional data with no specified format. If a | ||||
|     ///        valid ERC721 order, signature and `unwrapNativeToken` | ||||
|     ///        are encoded in `data`, this function will try to fill | ||||
|     ///        the order using the received asset. | ||||
|     /// @return success The selector of this function (0x150b7a02), | ||||
|     ///         indicating that the callback succeeded. | ||||
|     function onERC721Received( | ||||
|         address operator, | ||||
|         address from, | ||||
|         uint256 tokenId, | ||||
|         bytes calldata data | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4 success); | ||||
|  | ||||
|     /// @dev Approves an ERC721 order on-chain. After pre-signing | ||||
|     ///      the order, the `PRESIGNED` signature type will become | ||||
|     ///      valid for that order and signer. | ||||
|     /// @param order An ERC721 order. | ||||
|     function preSignERC721Order(LibERC721Order.ERC721Order calldata order) | ||||
|         external; | ||||
|  | ||||
|     /// @dev Checks whether the given signature is valid for the | ||||
|     ///      the given ERC721 order. Reverts if not. | ||||
|     /// @param order The ERC721 order. | ||||
|     /// @param signature The signature to validate. | ||||
|     function validateERC721OrderSignature( | ||||
|         LibERC721Order.ERC721Order calldata order, | ||||
|         LibSignature.Signature calldata signature | ||||
|     ) | ||||
|         external | ||||
|         view; | ||||
|  | ||||
|     /// @dev If the given order is buying an ERC721 asset, checks | ||||
|     ///      whether or not the given token ID satisfies the required | ||||
|     ///      properties specified in the order. If the order does not | ||||
|     ///      specify any properties, this function instead checks | ||||
|     ///      whether the given token ID matches the ID in the order. | ||||
|     ///      Reverts if any checks fail, or if the order is selling | ||||
|     ///      an ERC721 asset. | ||||
|     /// @param order The ERC721 order. | ||||
|     /// @param erc721TokenId The ID of the ERC721 asset. | ||||
|     function validateERC721OrderProperties( | ||||
|         LibERC721Order.ERC721Order calldata order, | ||||
|         uint256 erc721TokenId | ||||
|     ) | ||||
|         external | ||||
|         view; | ||||
|  | ||||
|     /// @dev Get the current status of an ERC721 order. | ||||
|     /// @param order The ERC721 order. | ||||
|     /// @return status The status of the order. | ||||
|     function getERC721OrderStatus(LibERC721Order.ERC721Order calldata order) | ||||
|         external | ||||
|         view | ||||
|         returns (LibERC721Order.OrderStatus status); | ||||
|  | ||||
|     /// @dev Get the canonical hash of an ERC721 order. | ||||
|     /// @param order The ERC721 order. | ||||
|     /// @return orderHash The order hash. | ||||
|     function getERC721OrderHash(LibERC721Order.ERC721Order calldata order) | ||||
|         external | ||||
|         view | ||||
|         returns (bytes32 orderHash); | ||||
|  | ||||
|     /// @dev Get the order status bit vector for the given | ||||
|     ///      maker address and nonce range. | ||||
|     /// @param maker The maker of the order. | ||||
|     /// @param nonceRange Order status bit vectors are indexed | ||||
|     ///        by maker address and the upper 248 bits of the | ||||
|     ///        order nonce. We define `nonceRange` to be these | ||||
|     ///        248 bits. | ||||
|     /// @return bitVector The order status bit vector for the | ||||
|     ///         given maker and nonce range. | ||||
|     function getERC721OrderStatusBitVector(address maker, uint248 nonceRange) | ||||
|         external | ||||
|         view | ||||
|         returns (uint256 bitVector); | ||||
| } | ||||
| @@ -0,0 +1,277 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; | ||||
| import "../../vendor/IERC1155Token.sol"; | ||||
| import "../../vendor/IPropertyValidator.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev A library for common ERC1155 order operations. | ||||
| library LibERC1155Order { | ||||
|     using LibSafeMathV06 for uint256; | ||||
|     using LibRichErrorsV06 for bytes; | ||||
|  | ||||
|     enum OrderStatus { | ||||
|         INVALID, | ||||
|         FILLABLE, | ||||
|         CANCELLED, | ||||
|         EXPIRED, | ||||
|         FILLED | ||||
|     } | ||||
|  | ||||
|     enum TradeDirection { | ||||
|         SELL_1155, | ||||
|         BUY_1155 | ||||
|     } | ||||
|  | ||||
|     struct Property { | ||||
|         IPropertyValidator propertyValidator; | ||||
|         bytes propertyData; | ||||
|     } | ||||
|  | ||||
|     struct Fee { | ||||
|         address recipient; | ||||
|         uint256 amount; | ||||
|         bytes feeData; | ||||
|     } | ||||
|  | ||||
|     /// @dev An ERC1155<>ERC20 limit order. | ||||
|     struct ERC1155Order { | ||||
|         TradeDirection direction; | ||||
|         IERC20TokenV06 erc20Token; | ||||
|         uint256 erc20TokenAmount; | ||||
|         IERC1155Token erc1155Token; | ||||
|         uint256 erc1155TokenId; | ||||
|         uint128 erc1155TokenAmount; | ||||
|         Property[] erc1155TokenProperties; | ||||
|         Fee[] fees; | ||||
|         address maker; | ||||
|         address taker; | ||||
|         uint256 expiry; | ||||
|         uint256 nonce; | ||||
|     } | ||||
|  | ||||
|     struct OrderInfo { | ||||
|         bytes32 orderHash; | ||||
|         OrderStatus status; | ||||
|         uint128 remainingERC1155FillableAmount; | ||||
|     } | ||||
|  | ||||
|     // The type hash for ERC1155 orders, which is: | ||||
|     // keccak256(abi.encodePacked( | ||||
|     //     "ERC1155Order(", | ||||
|     //       "uint8 direction,", | ||||
|     //       "address erc20Token,", | ||||
|     //       "uint256 erc20TokenAmount,", | ||||
|     //       "address erc1155Token,", | ||||
|     //       "uint256 erc1155TokenId,", | ||||
|     //       "uint128 erc1155TokenAmount,", | ||||
|     //       "Property[] erc1155TokenProperties,", | ||||
|     //       "Fee[] fees,", | ||||
|     //       "address maker,", | ||||
|     //       "address taker,", | ||||
|     //       "uint256 expiry,", | ||||
|     //       "uint256 nonce", | ||||
|     //     ")", | ||||
|     //     "Fee(", | ||||
|     //       "address recipient,", | ||||
|     //       "uint256 amount,", | ||||
|     //       "bytes feeData", | ||||
|     //     ")", | ||||
|     //     "Property(", | ||||
|     //       "address propertyValidator,", | ||||
|     //       "bytes propertyData", | ||||
|     //     ")" | ||||
|     // )) | ||||
|     uint256 private constant _ERC_1155_ORDER_TYPEHASH = | ||||
|         0xa3eda4c7db3c9b6e39713fae70a50e840b420b920eff22c4c6abc8e940cfac3b; | ||||
|  | ||||
|     // keccak256(abi.encodePacked( | ||||
|     //     "Fee(", | ||||
|     //       "address recipient,", | ||||
|     //       "uint256 amount,", | ||||
|     //       "bytes feeData", | ||||
|     //     ")" | ||||
|     // )) | ||||
|     uint256 private constant _FEE_TYPEHASH = | ||||
|         0xe68c29f1b4e8cce0bbcac76eb1334bdc1dc1f293a517c90e9e532340e1e94115; | ||||
|  | ||||
|     // keccak256(abi.encodePacked( | ||||
|     //     "Property(", | ||||
|     //       "address propertyValidator,", | ||||
|     //       "bytes propertyData", | ||||
|     //     ")" | ||||
|     // )) | ||||
|     uint256 private constant _PROPERTY_TYPEHASH = | ||||
|         0x6292cf854241cb36887e639065eca63b3af9f7f70270cebeda4c29b6d3bc65e8; | ||||
|  | ||||
|     // keccak256(""); | ||||
|     bytes32 private constant _EMPTY_ARRAY_KECCAK256 = | ||||
|         0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; | ||||
|  | ||||
|     // keccak256(abi.encodePacked(keccak256(abi.encode( | ||||
|     //     _PROPERTY_TYPEHASH, | ||||
|     //     address(0), | ||||
|     //     keccak256("") | ||||
|     // )))); | ||||
|     bytes32 private constant _NULL_PROPERTY_STRUCT_HASH = | ||||
|         0x720ee400a9024f6a49768142c339bf09d2dd9056ab52d20fbe7165faba6e142d; | ||||
|  | ||||
|     uint256 private constant ADDRESS_MASK = (1 << 160) - 1; | ||||
|  | ||||
|     /// @dev Get the struct hash of an ERC1155 order. | ||||
|     /// @param order The ERC1155 order. | ||||
|     /// @return structHash The struct hash of the order. | ||||
|     function getERC1155OrderStructHash(ERC1155Order memory order) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes32 structHash) | ||||
|     { | ||||
|         // We give `order.erc1155TokenProperties.length == 0` and | ||||
|         // `order.erc1155TokenProperties.length == 1` special treatment | ||||
|         // because we expect these to be the most common. | ||||
|         bytes32 propertiesHash; | ||||
|         if (order.erc1155TokenProperties.length == 0) { | ||||
|             propertiesHash = _EMPTY_ARRAY_KECCAK256; | ||||
|         } else if (order.erc1155TokenProperties.length == 1) { | ||||
|             Property memory property = order | ||||
|                 .erc1155TokenProperties[0]; | ||||
|             if ( | ||||
|                 address(property.propertyValidator) == address(0) && | ||||
|                 property.propertyData.length == 0 | ||||
|             ) { | ||||
|                 propertiesHash = _NULL_PROPERTY_STRUCT_HASH; | ||||
|             } else { | ||||
|                 // propertiesHash = keccak256(abi.encodePacked(keccak256(abi.encode( | ||||
|                 //     _PROPERTY_TYPEHASH, | ||||
|                 //     order.erc1155TokenProperties[0].propertyValidator, | ||||
|                 //     keccak256(order.erc1155TokenProperties[0].propertyData) | ||||
|                 // )))); | ||||
|                 bytes32 dataHash = keccak256(property.propertyData); | ||||
|                 assembly { | ||||
|                     // Load free memory pointer | ||||
|                     let mem := mload(64) | ||||
|                     mstore(mem, _PROPERTY_TYPEHASH) | ||||
|                     // property.propertyValidator | ||||
|                     mstore(add(mem, 32), and(ADDRESS_MASK, mload(property))) | ||||
|                     // keccak256(property.propertyData) | ||||
|                     mstore(add(mem, 64), dataHash) | ||||
|                     mstore(mem, keccak256(mem, 96)) | ||||
|                     propertiesHash := keccak256(mem, 32) | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             bytes32[] memory propertyStructHashArray = new bytes32[]( | ||||
|                 order.erc1155TokenProperties.length | ||||
|             ); | ||||
|             for (uint256 i = 0; i < order.erc1155TokenProperties.length; i++) { | ||||
|                 propertyStructHashArray[i] = keccak256(abi.encode( | ||||
|                     _PROPERTY_TYPEHASH, | ||||
|                     order.erc1155TokenProperties[i].propertyValidator, | ||||
|                     keccak256(order.erc1155TokenProperties[i].propertyData) | ||||
|                 )); | ||||
|             } | ||||
|             propertiesHash = keccak256(abi.encodePacked(propertyStructHashArray)); | ||||
|         } | ||||
|  | ||||
|         // We give `order.fees.length == 0` and | ||||
|         // `order.fees.length == 1` special treatment | ||||
|         // because we expect these to be the most common. | ||||
|         bytes32 feesHash; | ||||
|         if (order.fees.length == 0) { | ||||
|             feesHash = _EMPTY_ARRAY_KECCAK256; | ||||
|         } else if (order.fees.length == 1) { | ||||
|             // feesHash = keccak256(abi.encodePacked(keccak256(abi.encode( | ||||
|             //     _FEE_TYPEHASH, | ||||
|             //     order.fees[0].recipient, | ||||
|             //     order.fees[0].amount, | ||||
|             //     keccak256(order.fees[0].feeData) | ||||
|             // )))); | ||||
|             Fee memory fee = order.fees[0]; | ||||
|             bytes32 dataHash = keccak256(fee.feeData); | ||||
|             assembly { | ||||
|                 // Load free memory pointer | ||||
|                 let mem := mload(64) | ||||
|                 mstore(mem, _FEE_TYPEHASH) | ||||
|                 // fee.recipient | ||||
|                 mstore(add(mem, 32), and(ADDRESS_MASK, mload(fee))) | ||||
|                 // fee.amount | ||||
|                 mstore(add(mem, 64), mload(add(fee, 32))) | ||||
|                 // keccak256(fee.feeData) | ||||
|                 mstore(add(mem, 96), dataHash) | ||||
|                 mstore(mem, keccak256(mem, 128)) | ||||
|                 feesHash := keccak256(mem, 32) | ||||
|             } | ||||
|         } else { | ||||
|             bytes32[] memory feeStructHashArray = new bytes32[](order.fees.length); | ||||
|             for (uint256 i = 0; i < order.fees.length; i++) { | ||||
|                 feeStructHashArray[i] = keccak256(abi.encode( | ||||
|                     _FEE_TYPEHASH, | ||||
|                     order.fees[i].recipient, | ||||
|                     order.fees[i].amount, | ||||
|                     keccak256(order.fees[i].feeData) | ||||
|                 )); | ||||
|             } | ||||
|             feesHash = keccak256(abi.encodePacked(feeStructHashArray)); | ||||
|         } | ||||
|  | ||||
|         // Hash in place, equivalent to: | ||||
|         // return keccak256(abi.encode( | ||||
|         //     _ERC_1155_ORDER_TYPEHASH, | ||||
|         //     order.direction, | ||||
|         //     order.erc20Token, | ||||
|         //     order.erc20TokenAmount, | ||||
|         //     order.erc1155Token, | ||||
|         //     order.erc1155TokenId, | ||||
|         //     order.erc1155TokenAmount, | ||||
|         //     propertiesHash, | ||||
|         //     feesHash, | ||||
|         //     order.maker, | ||||
|         //     order.taker, | ||||
|         //     order.expiry, | ||||
|         //     order.nonce | ||||
|         // )); | ||||
|         assembly { | ||||
|             if lt(order, 32) { invalid() } // Don't underflow memory. | ||||
|  | ||||
|             let typeHashPos := sub(order, 32) // order + (32 * -1) | ||||
|             let propertiesHashPos := add(order, 192) // order + (32 * 6) | ||||
|             let feesHashPos := add(order, 224) // order + (32 * 7) | ||||
|  | ||||
|             let temp1 := mload(typeHashPos) | ||||
|             let temp2 := mload(propertiesHashPos) | ||||
|             let temp3 := mload(feesHashPos) | ||||
|  | ||||
|             mstore(typeHashPos, _ERC_1155_ORDER_TYPEHASH) | ||||
|             mstore(propertiesHashPos, propertiesHash) | ||||
|             mstore(feesHashPos, feesHash) | ||||
|             structHash := keccak256(typeHashPos, 416 /* 32 * 12 */ ) | ||||
|  | ||||
|             mstore(typeHashPos, temp1) | ||||
|             mstore(propertiesHashPos, temp2) | ||||
|             mstore(feesHashPos, temp3) | ||||
|         } | ||||
|         return structHash; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										267
									
								
								contracts/zero-ex/contracts/src/features/libs/LibERC721Order.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										267
									
								
								contracts/zero-ex/contracts/src/features/libs/LibERC721Order.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,267 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; | ||||
| import "../../vendor/IERC721Token.sol"; | ||||
| import "../../vendor/IPropertyValidator.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev A library for common ERC721 order operations. | ||||
| library LibERC721Order { | ||||
|     using LibSafeMathV06 for uint256; | ||||
|     using LibRichErrorsV06 for bytes; | ||||
|  | ||||
|     enum OrderStatus { | ||||
|         INVALID, | ||||
|         FILLABLE, | ||||
|         UNFILLABLE, | ||||
|         EXPIRED | ||||
|     } | ||||
|  | ||||
|     enum TradeDirection { | ||||
|         SELL_721, | ||||
|         BUY_721 | ||||
|     } | ||||
|  | ||||
|     struct Property { | ||||
|         IPropertyValidator propertyValidator; | ||||
|         bytes propertyData; | ||||
|     } | ||||
|  | ||||
|     struct Fee { | ||||
|         address recipient; | ||||
|         uint256 amount; | ||||
|         bytes feeData; | ||||
|     } | ||||
|  | ||||
|     /// @dev An ERC721<>ERC20 limit order. | ||||
|     struct ERC721Order { | ||||
|         TradeDirection direction; | ||||
|         IERC20TokenV06 erc20Token; | ||||
|         uint256 erc20TokenAmount; | ||||
|         IERC721Token erc721Token; | ||||
|         uint256 erc721TokenId; | ||||
|         Property[] erc721TokenProperties; | ||||
|         Fee[] fees; | ||||
|         address maker; | ||||
|         address taker; | ||||
|         uint256 expiry; | ||||
|         uint256 nonce; | ||||
|     } | ||||
|  | ||||
|     // The type hash for ERC721 orders, which is: | ||||
|     // keccak256(abi.encodePacked( | ||||
|     //     "ERC721Order(", | ||||
|     //       "uint8 direction,", | ||||
|     //       "address erc20Token,", | ||||
|     //       "uint256 erc20TokenAmount,", | ||||
|     //       "address erc721Token,", | ||||
|     //       "uint256 erc721TokenId,", | ||||
|     //       "Property[] erc721TokenProperties,", | ||||
|     //       "Fee[] fees,", | ||||
|     //       "address maker,", | ||||
|     //       "address taker,", | ||||
|     //       "uint256 expiry,", | ||||
|     //       "uint256 nonce", | ||||
|     //     ")", | ||||
|     //     "Fee(", | ||||
|     //       "address recipient,", | ||||
|     //       "uint256 amount,", | ||||
|     //       "bytes feeData", | ||||
|     //     ")", | ||||
|     //     "Property(", | ||||
|     //       "address propertyValidator,", | ||||
|     //       "bytes propertyData", | ||||
|     //     ")" | ||||
|     // )) | ||||
|     uint256 private constant _ERC_721_ORDER_TYPEHASH = | ||||
|         0x7af652c2504c5c7d806f4f25edc3762dd8478099f694981f8802db656a9ba9d8; | ||||
|  | ||||
|     // keccak256(abi.encodePacked( | ||||
|     //     "Fee(", | ||||
|     //       "address recipient,", | ||||
|     //       "uint256 amount,", | ||||
|     //       "bytes feeData", | ||||
|     //     ")" | ||||
|     // )) | ||||
|     uint256 private constant _FEE_TYPEHASH = | ||||
|         0xe68c29f1b4e8cce0bbcac76eb1334bdc1dc1f293a517c90e9e532340e1e94115; | ||||
|  | ||||
|     // keccak256(abi.encodePacked( | ||||
|     //     "Property(", | ||||
|     //       "address propertyValidator,", | ||||
|     //       "bytes propertyData", | ||||
|     //     ")" | ||||
|     // )) | ||||
|     uint256 private constant _PROPERTY_TYPEHASH = | ||||
|         0x6292cf854241cb36887e639065eca63b3af9f7f70270cebeda4c29b6d3bc65e8; | ||||
|  | ||||
|     // keccak256(""); | ||||
|     bytes32 private constant _EMPTY_ARRAY_KECCAK256 = | ||||
|         0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; | ||||
|  | ||||
|     // keccak256(abi.encodePacked(keccak256(abi.encode( | ||||
|     //     _PROPERTY_TYPEHASH, | ||||
|     //     address(0), | ||||
|     //     keccak256("") | ||||
|     // )))); | ||||
|     bytes32 private constant _NULL_PROPERTY_STRUCT_HASH = | ||||
|         0x720ee400a9024f6a49768142c339bf09d2dd9056ab52d20fbe7165faba6e142d; | ||||
|  | ||||
|     uint256 private constant ADDRESS_MASK = (1 << 160) - 1; | ||||
|  | ||||
|     /// @dev Get the struct hash of an ERC721 order. | ||||
|     /// @param order The ERC721 order. | ||||
|     /// @return structHash The struct hash of the order. | ||||
|     function getERC721OrderStructHash(ERC721Order memory order) | ||||
|         internal | ||||
|         pure | ||||
|         returns (bytes32 structHash) | ||||
|     { | ||||
|         // We give `order.erc721TokenProperties.length == 0` and | ||||
|         // `order.erc721TokenProperties.length == 1` special treatment | ||||
|         // because we expect these to be the most common. | ||||
|         bytes32 propertiesHash; | ||||
|         if (order.erc721TokenProperties.length == 0) { | ||||
|             propertiesHash = _EMPTY_ARRAY_KECCAK256; | ||||
|         } else if (order.erc721TokenProperties.length == 1) { | ||||
|             Property memory property = order | ||||
|                 .erc721TokenProperties[0]; | ||||
|             if ( | ||||
|                 address(property.propertyValidator) == address(0) && | ||||
|                 property.propertyData.length == 0 | ||||
|             ) { | ||||
|                 propertiesHash = _NULL_PROPERTY_STRUCT_HASH; | ||||
|             } else { | ||||
|                 // propertiesHash = keccak256(abi.encodePacked(keccak256(abi.encode( | ||||
|                 //     _PROPERTY_TYPEHASH, | ||||
|                 //     order.erc721TokenProperties[0].propertyValidator, | ||||
|                 //     keccak256(order.erc721TokenProperties[0].propertyData) | ||||
|                 // )))); | ||||
|                 bytes32 dataHash = keccak256(property.propertyData); | ||||
|                 assembly { | ||||
|                     // Load free memory pointer | ||||
|                     let mem := mload(64) | ||||
|                     mstore(mem, _PROPERTY_TYPEHASH) | ||||
|                     // property.propertyValidator | ||||
|                     mstore(add(mem, 32), and(ADDRESS_MASK, mload(property))) | ||||
|                     // keccak256(property.propertyData) | ||||
|                     mstore(add(mem, 64), dataHash) | ||||
|                     mstore(mem, keccak256(mem, 96)) | ||||
|                     propertiesHash := keccak256(mem, 32) | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             bytes32[] memory propertyStructHashArray = new bytes32[]( | ||||
|                 order.erc721TokenProperties.length | ||||
|             ); | ||||
|             for (uint256 i = 0; i < order.erc721TokenProperties.length; i++) { | ||||
|                 propertyStructHashArray[i] = keccak256(abi.encode( | ||||
|                     _PROPERTY_TYPEHASH, | ||||
|                     order.erc721TokenProperties[i].propertyValidator, | ||||
|                     keccak256(order.erc721TokenProperties[i].propertyData) | ||||
|                 )); | ||||
|             } | ||||
|             propertiesHash = keccak256(abi.encodePacked(propertyStructHashArray)); | ||||
|         } | ||||
|  | ||||
|         // We give `order.fees.length == 0` and | ||||
|         // `order.fees.length == 1` special treatment | ||||
|         // because we expect these to be the most common. | ||||
|         bytes32 feesHash; | ||||
|         if (order.fees.length == 0) { | ||||
|             feesHash = _EMPTY_ARRAY_KECCAK256; | ||||
|         } else if (order.fees.length == 1) { | ||||
|             // feesHash = keccak256(abi.encodePacked(keccak256(abi.encode( | ||||
|             //     _FEE_TYPEHASH, | ||||
|             //     order.fees[0].recipient, | ||||
|             //     order.fees[0].amount, | ||||
|             //     keccak256(order.fees[0].feeData) | ||||
|             // )))); | ||||
|             Fee memory fee = order.fees[0]; | ||||
|             bytes32 dataHash = keccak256(fee.feeData); | ||||
|             assembly { | ||||
|                 // Load free memory pointer | ||||
|                 let mem := mload(64) | ||||
|                 mstore(mem, _FEE_TYPEHASH) | ||||
|                 // fee.recipient | ||||
|                 mstore(add(mem, 32), and(ADDRESS_MASK, mload(fee))) | ||||
|                 // fee.amount | ||||
|                 mstore(add(mem, 64), mload(add(fee, 32))) | ||||
|                 // keccak256(fee.feeData) | ||||
|                 mstore(add(mem, 96), dataHash) | ||||
|                 mstore(mem, keccak256(mem, 128)) | ||||
|                 feesHash := keccak256(mem, 32) | ||||
|             } | ||||
|         } else { | ||||
|             bytes32[] memory feeStructHashArray = new bytes32[](order.fees.length); | ||||
|             for (uint256 i = 0; i < order.fees.length; i++) { | ||||
|                 feeStructHashArray[i] = keccak256(abi.encode( | ||||
|                     _FEE_TYPEHASH, | ||||
|                     order.fees[i].recipient, | ||||
|                     order.fees[i].amount, | ||||
|                     keccak256(order.fees[i].feeData) | ||||
|                 )); | ||||
|             } | ||||
|             feesHash = keccak256(abi.encodePacked(feeStructHashArray)); | ||||
|         } | ||||
|  | ||||
|         // Hash in place, equivalent to: | ||||
|         // return keccak256(abi.encode( | ||||
|         //     _ERC_721_ORDER_TYPEHASH, | ||||
|         //     order.direction, | ||||
|         //     order.erc20Token, | ||||
|         //     order.erc20TokenAmount, | ||||
|         //     order.erc721Token, | ||||
|         //     order.erc721TokenId, | ||||
|         //     propertiesHash, | ||||
|         //     feesHash, | ||||
|         //     order.maker, | ||||
|         //     order.taker, | ||||
|         //     order.expiry, | ||||
|         //     order.nonce | ||||
|         // )); | ||||
|         assembly { | ||||
|             if lt(order, 32) { invalid() } // Don't underflow memory. | ||||
|  | ||||
|             let typeHashPos := sub(order, 32) // order + (32 * -1) | ||||
|             let propertiesHashPos := add(order, 160) // order + (32 * 5) | ||||
|             let feesHashPos := add(order, 192) // order + (32 * 6) | ||||
|  | ||||
|             let temp1 := mload(typeHashPos) | ||||
|             let temp2 := mload(propertiesHashPos) | ||||
|             let temp3 := mload(feesHashPos) | ||||
|  | ||||
|             mstore(typeHashPos, _ERC_721_ORDER_TYPEHASH) | ||||
|             mstore(propertiesHashPos, propertiesHash) | ||||
|             mstore(feesHashPos, feesHash) | ||||
|             structHash := keccak256(typeHashPos, 384 /* 32 * 12 */ ) | ||||
|  | ||||
|             mstore(typeHashPos, temp1) | ||||
|             mstore(propertiesHashPos, temp2) | ||||
|             mstore(feesHashPos, temp3) | ||||
|         } | ||||
|         return structHash; | ||||
|     } | ||||
| } | ||||
| @@ -44,7 +44,8 @@ library LibSignature { | ||||
|         ILLEGAL, | ||||
|         INVALID, | ||||
|         EIP712, | ||||
|         ETHSIGN | ||||
|         ETHSIGN, | ||||
|         PRESIGNED | ||||
|     } | ||||
|  | ||||
|     /// @dev Encoded EC signature. | ||||
| @@ -146,6 +147,15 @@ library LibSignature { | ||||
|             ).rrevert(); | ||||
|         } | ||||
|  | ||||
|         // If a feature supports pre-signing, it wouldn't use  | ||||
|         // `getSignerOfHash` on a pre-signed order. | ||||
|         if (signature.signatureType == SignatureType.PRESIGNED) { | ||||
|             LibSignatureRichErrors.SignatureValidationError( | ||||
|                 LibSignatureRichErrors.SignatureValidationErrorCodes.UNSUPPORTED, | ||||
|                 hash | ||||
|             ).rrevert(); | ||||
|         } | ||||
|  | ||||
|         // Solidity should check that the signature type is within enum range for us | ||||
|         // when abi-decoding. | ||||
|     } | ||||
|   | ||||
| @@ -622,15 +622,6 @@ contract MultiplexFeature is | ||||
|             _executeBatchSell(batchSellParams).boughtAmount; | ||||
|     } | ||||
|  | ||||
|     // Transfers some amount of ETH to the given recipient and | ||||
|     // reverts if the transfer fails. | ||||
|     function _transferEth(address payable recipient, uint256 amount) | ||||
|         private | ||||
|     { | ||||
|         (bool success,) = recipient.call{value: amount}(""); | ||||
|         require(success, "MultiplexFeature::_transferEth/TRANSFER_FAILED"); | ||||
|     } | ||||
|  | ||||
|     // This function computes the "target" address of hop index `i` within | ||||
|     // a multi-hop sell. | ||||
|     // If `i == 0`, the target is the address which should hold the input | ||||
|   | ||||
| @@ -0,0 +1,77 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2020 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; | ||||
| import "../vendor/IERC1155Token.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev Helpers for moving ERC1155 assets around. | ||||
| abstract contract FixinERC1155Spender { | ||||
|  | ||||
|     // Mask of the lower 20 bytes of a bytes32. | ||||
|     uint256 constant private ADDRESS_MASK = 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff; | ||||
|  | ||||
|     /// @dev Transfers an ERC1155 asset from `owner` to `to`. | ||||
|     /// @param token The address of the ERC1155 token contract. | ||||
|     /// @param owner The owner of the asset. | ||||
|     /// @param to The recipient of the asset. | ||||
|     /// @param tokenId The token ID of the asset to transfer. | ||||
|     /// @param amount The amount of the asset to transfer. | ||||
|     function _transferERC1155AssetFrom( | ||||
|         IERC1155Token token, | ||||
|         address owner, | ||||
|         address to, | ||||
|         uint256 tokenId, | ||||
|         uint256 amount | ||||
|     ) | ||||
|         internal | ||||
|     { | ||||
|         require(address(token) != address(this), "FixinERC1155Spender/CANNOT_INVOKE_SELF"); | ||||
|  | ||||
|         assembly { | ||||
|             let ptr := mload(0x40) // free memory pointer | ||||
|  | ||||
|             // selector for transferFrom(address,address,uint256,uin256) | ||||
|             mstore(ptr, 0x2716439b00000000000000000000000000000000000000000000000000000000) | ||||
|             mstore(add(ptr, 0x04), and(owner, ADDRESS_MASK)) | ||||
|             mstore(add(ptr, 0x24), and(to, ADDRESS_MASK)) | ||||
|             mstore(add(ptr, 0x44), tokenId) | ||||
|             mstore(add(ptr, 0x64), amount) | ||||
|  | ||||
|             let success := call( | ||||
|                 gas(), | ||||
|                 and(token, ADDRESS_MASK), | ||||
|                 0, | ||||
|                 ptr, | ||||
|                 0x84, | ||||
|                 0, | ||||
|                 0 | ||||
|             ) | ||||
|  | ||||
|             if iszero(success) { | ||||
|                 let rdsize := returndatasize() | ||||
|                 returndatacopy(ptr, 0, rdsize) | ||||
|                 revert(ptr, rdsize) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,74 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2020 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; | ||||
| import "../vendor/IERC721Token.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev Helpers for moving ERC721 assets around. | ||||
| abstract contract FixinERC721Spender { | ||||
|  | ||||
|     // Mask of the lower 20 bytes of a bytes32. | ||||
|     uint256 constant private ADDRESS_MASK = 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff; | ||||
|  | ||||
|     /// @dev Transfers an ERC721 asset from `owner` to `to`. | ||||
|     /// @param token The address of the ERC721 token contract. | ||||
|     /// @param owner The owner of the asset. | ||||
|     /// @param to The recipient of the asset. | ||||
|     /// @param tokenId The token ID of the asset to transfer. | ||||
|     function _transferERC721AssetFrom( | ||||
|         IERC721Token token, | ||||
|         address owner, | ||||
|         address to, | ||||
|         uint256 tokenId | ||||
|     ) | ||||
|         internal | ||||
|     { | ||||
|         require(address(token) != address(this), "FixinERC721Spender/CANNOT_INVOKE_SELF"); | ||||
|  | ||||
|         assembly { | ||||
|             let ptr := mload(0x40) // free memory pointer | ||||
|  | ||||
|             // selector for transferFrom(address,address,uint256) | ||||
|             mstore(ptr, 0x23b872dd00000000000000000000000000000000000000000000000000000000) | ||||
|             mstore(add(ptr, 0x04), and(owner, ADDRESS_MASK)) | ||||
|             mstore(add(ptr, 0x24), and(to, ADDRESS_MASK)) | ||||
|             mstore(add(ptr, 0x44), tokenId) | ||||
|  | ||||
|             let success := call( | ||||
|                 gas(), | ||||
|                 and(token, ADDRESS_MASK), | ||||
|                 0, | ||||
|                 ptr, | ||||
|                 0x64, | ||||
|                 0, | ||||
|                 0 | ||||
|             ) | ||||
|  | ||||
|             if iszero(success) { | ||||
|                 let rdsize := returndatasize() | ||||
|                 returndatacopy(ptr, 0, rdsize) | ||||
|                 revert(ptr, rdsize) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -20,7 +20,7 @@ | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; | ||||
|  | ||||
|  | ||||
| @@ -141,6 +141,20 @@ abstract contract FixinTokenSpender { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// @dev Transfers some amount of ETH to the given recipient and | ||||
|     ///      reverts if the transfer fails. | ||||
|     /// @param recipient The recipient of the ETH. | ||||
|     /// @param amount The amount of ETH to transfer. | ||||
|     function _transferEth(address payable recipient, uint256 amount) | ||||
|         internal | ||||
|     { | ||||
|         if (amount > 0) { | ||||
|             (bool success,) = recipient.call{value: amount}(""); | ||||
|             require(success, "FixinTokenSpender::_transferEth/TRANSFER_FAILED"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @dev Gets the maximum amount of an ERC20 token `token` that can be | ||||
|     ///      pulled from `owner` by this address. | ||||
|     /// @param token The token to spend. | ||||
|   | ||||
| @@ -25,6 +25,7 @@ import "../features/interfaces/IOwnableFeature.sol"; | ||||
| import "../features/TransformERC20Feature.sol"; | ||||
| import "../features/MetaTransactionsFeature.sol"; | ||||
| import "../features/NativeOrdersFeature.sol"; | ||||
| import "../features/OtcOrdersFeature.sol"; | ||||
| import "./InitialMigration.sol"; | ||||
|  | ||||
|  | ||||
| @@ -40,6 +41,7 @@ contract FullMigration { | ||||
|         TransformERC20Feature transformERC20; | ||||
|         MetaTransactionsFeature metaTransactions; | ||||
|         NativeOrdersFeature nativeOrders; | ||||
|         OtcOrdersFeature otcOrders; | ||||
|     } | ||||
|  | ||||
|     /// @dev Parameters needed to initialize features. | ||||
| @@ -173,5 +175,16 @@ contract FullMigration { | ||||
|                 address(this) | ||||
|             ); | ||||
|         } | ||||
|         // OtcOrdersFeature | ||||
|         { | ||||
|             // Register the feature. | ||||
|             ownable.migrate( | ||||
|                 address(features.otcOrders), | ||||
|                 abi.encodeWithSelector( | ||||
|                     OtcOrdersFeature.migrate.selector | ||||
|                 ), | ||||
|                 address(this) | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,47 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2020 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "./LibStorage.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev Storage helpers for `ERC1155OrdersFeature`. | ||||
| library LibERC1155OrdersStorage { | ||||
|  | ||||
|     /// @dev Storage bucket for this feature. | ||||
|     struct Storage { | ||||
|         // The lower `uint128` is the taker token fill amount. | ||||
|         // The highest bit will be `1` if the order was cancelled. | ||||
|         // The second-highest bit will be `1` if the order was pre-signed. | ||||
|         mapping(bytes32 => uint256) orderState; | ||||
|     } | ||||
|  | ||||
|     /// @dev Get the storage bucket for this contract. | ||||
|     function getStorage() internal pure returns (Storage storage stor) { | ||||
|         uint256 storageSlot = LibStorage.getStorageSlot( | ||||
|             LibStorage.StorageId.ERC1155Orders | ||||
|         ); | ||||
|         // Dip into assembly to change the slot pointed to by the local | ||||
|         // variable `stor`. | ||||
|         // See https://solidity.readthedocs.io/en/v0.6.8/assembly.html?highlight=slot#access-to-external-variables-functions-and-libraries | ||||
|         assembly { stor_slot := storageSlot } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,47 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2020 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "./LibStorage.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev Storage helpers for `ERC721OrdersFeature`. | ||||
| library LibERC721OrdersStorage { | ||||
|  | ||||
|     /// @dev Storage bucket for this feature. | ||||
|     struct Storage { | ||||
|         // maker => nonce range => order status bit vector | ||||
|         mapping(address => mapping(uint248 => uint256)) orderStatusByMaker; | ||||
|         // order hash => maker => isSigned | ||||
|         mapping(bytes32 => mapping(address => bool)) preSigned; | ||||
|     } | ||||
|  | ||||
|     /// @dev Get the storage bucket for this contract. | ||||
|     function getStorage() internal pure returns (Storage storage stor) { | ||||
|         uint256 storageSlot = LibStorage.getStorageSlot( | ||||
|             LibStorage.StorageId.ERC721Orders | ||||
|         ); | ||||
|         // Dip into assembly to change the slot pointed to by the local | ||||
|         // variable `stor`. | ||||
|         // See https://solidity.readthedocs.io/en/v0.6.8/assembly.html?highlight=slot#access-to-external-variables-functions-and-libraries | ||||
|         assembly { stor_slot := storageSlot } | ||||
|     } | ||||
| } | ||||
| @@ -39,7 +39,9 @@ library LibStorage { | ||||
|         MetaTransactions, | ||||
|         ReentrancyGuard, | ||||
|         NativeOrders, | ||||
|         OtcOrders | ||||
|         OtcOrders, | ||||
|         ERC721Orders, | ||||
|         ERC1155Orders | ||||
|     } | ||||
|  | ||||
|     /// @dev Get the storage slot given a storage ID. We assign unique, well-spaced | ||||
|   | ||||
| @@ -22,10 +22,12 @@ pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "./IBridgeAdapter.sol"; | ||||
| import "./BridgeProtocols.sol"; | ||||
| import "./mixins/MixinAaveV2.sol"; | ||||
| import "./mixins/MixinBalancer.sol"; | ||||
| import "./mixins/MixinBalancerV2.sol"; | ||||
| import "./mixins/MixinBancor.sol"; | ||||
| import "./mixins/MixinCoFiX.sol"; | ||||
| import "./mixins/MixinCompound.sol"; | ||||
| import "./mixins/MixinCurve.sol"; | ||||
| import "./mixins/MixinCurveV2.sol"; | ||||
| import "./mixins/MixinCryptoCom.sol"; | ||||
| @@ -47,10 +49,12 @@ import "./mixins/MixinZeroExBridge.sol"; | ||||
|  | ||||
| contract BridgeAdapter is | ||||
|     IBridgeAdapter, | ||||
|     MixinAaveV2, | ||||
|     MixinBalancer, | ||||
|     MixinBalancerV2, | ||||
|     MixinBancor, | ||||
|     MixinCoFiX, | ||||
|     MixinCompound, | ||||
|     MixinCurve, | ||||
|     MixinCurveV2, | ||||
|     MixinCryptoCom, | ||||
| @@ -72,10 +76,12 @@ contract BridgeAdapter is | ||||
| { | ||||
|     constructor(IEtherTokenV06 weth) | ||||
|         public | ||||
|         MixinAaveV2() | ||||
|         MixinBalancer() | ||||
|         MixinBalancerV2() | ||||
|         MixinBancor(weth) | ||||
|         MixinCoFiX() | ||||
|         MixinCompound(weth) | ||||
|         MixinCurve(weth) | ||||
|         MixinCurveV2() | ||||
|         MixinCryptoCom() | ||||
| @@ -245,6 +251,20 @@ contract BridgeAdapter is | ||||
|                 sellAmount, | ||||
|                 order.bridgeData | ||||
|             ); | ||||
|         } else if (protocolId == BridgeProtocols.AAVEV2) { | ||||
|             boughtAmount = _tradeAaveV2( | ||||
|                 sellToken, | ||||
|                 buyToken, | ||||
|                 sellAmount, | ||||
|                 order.bridgeData | ||||
|             ); | ||||
|         } else if (protocolId == BridgeProtocols.COMPOUND) { | ||||
|             boughtAmount = _tradeCompound( | ||||
|                 sellToken, | ||||
|                 buyToken, | ||||
|                 sellAmount, | ||||
|                 order.bridgeData | ||||
|             ); | ||||
|         } else { | ||||
|             boughtAmount = _tradeZeroExBridge( | ||||
|                 sellToken, | ||||
|   | ||||
| @@ -50,4 +50,6 @@ library BridgeProtocols { | ||||
|     uint128 internal constant CURVEV2     = 20; | ||||
|     uint128 internal constant LIDO        = 21; | ||||
|     uint128 internal constant CLIPPER     = 22; // Not used: Clipper is now using PLP interface | ||||
|     uint128 internal constant AAVEV2      = 23; | ||||
|     uint128 internal constant COMPOUND    = 24; | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,93 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
|  | ||||
| // Minimal Aave V2 LendingPool interface | ||||
| interface ILendingPool { | ||||
|     /** | ||||
|    * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. | ||||
|    * - E.g. User deposits 100 USDC and gets in return 100 aUSDC | ||||
|    * @param asset The address of the underlying asset to deposit | ||||
|    * @param amount The amount to be deposited | ||||
|    * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user | ||||
|    *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens | ||||
|    *   is a different wallet | ||||
|    * @param referralCode Code used to register the integrator originating the operation, for potential rewards. | ||||
|    *   0 if the action is executed directly by the user, without any middle-man | ||||
|    **/ | ||||
|   function deposit( | ||||
|     address asset, | ||||
|     uint256 amount, | ||||
|     address onBehalfOf, | ||||
|     uint16 referralCode | ||||
|   ) external; | ||||
|  | ||||
|   /** | ||||
|    * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned | ||||
|    * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC | ||||
|    * @param asset The address of the underlying asset to withdraw | ||||
|    * @param amount The underlying amount to be withdrawn | ||||
|    *   - Send the value type(uint256).max in order to withdraw the whole aToken balance | ||||
|    * @param to Address that will receive the underlying, same as msg.sender if the user | ||||
|    *   wants to receive it on his own wallet, or a different address if the beneficiary is a | ||||
|    *   different wallet | ||||
|    * @return The final amount withdrawn | ||||
|    **/ | ||||
|   function withdraw( | ||||
|     address asset, | ||||
|     uint256 amount, | ||||
|     address to | ||||
|   ) external returns (uint256); | ||||
| } | ||||
|  | ||||
| contract MixinAaveV2 { | ||||
|     using LibERC20TokenV06 for IERC20TokenV06; | ||||
|  | ||||
|     function _tradeAaveV2( | ||||
|         IERC20TokenV06 sellToken, | ||||
|         IERC20TokenV06 buyToken, | ||||
|         uint256 sellAmount, | ||||
|         bytes memory bridgeData | ||||
|     ) | ||||
|         internal | ||||
|         returns (uint256) | ||||
|     { | ||||
|         (ILendingPool lendingPool, address aToken) = abi.decode(bridgeData, (ILendingPool, address)); | ||||
|  | ||||
|           sellToken.approveIfBelow( | ||||
|               address(lendingPool), | ||||
|               sellAmount | ||||
|           ); | ||||
|  | ||||
|         if (address(buyToken) == aToken) { | ||||
|             lendingPool.deposit(address(sellToken), sellAmount, address(this), 0); | ||||
|             // 1:1 mapping token -> aToken and have the same number of decimals as the underlying token | ||||
|             return sellAmount; | ||||
|         } else if (address(sellToken) == aToken) { | ||||
|             return lendingPool.withdraw(address(buyToken), sellAmount, address(this)); | ||||
|         } | ||||
|  | ||||
|         revert("MixinAaveV2/UNSUPPORTED_TOKEN_PAIR"); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,110 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev Minimal CToken interface | ||||
| interface ICToken { | ||||
|     /// @dev deposits specified amount underlying tokens and mints cToken for the sender | ||||
|     /// @param mintAmountInUnderlying amount of underlying tokens to deposit to mint cTokens | ||||
|     /// @return status code of whether the mint was successful or not | ||||
|     function mint(uint256 mintAmountInUnderlying) external returns (uint256); | ||||
|     /// @dev redeems specified amount of cTokens and returns the underlying token to the sender | ||||
|     /// @param redeemTokensInCtokens amount of cTokens to redeem for underlying collateral | ||||
|     /// @return status code of whether the redemption was successful or not | ||||
|     function redeem(uint256 redeemTokensInCtokens) external returns (uint256); | ||||
| } | ||||
| /// @dev Minimal CEther interface | ||||
| interface ICEther { | ||||
|     /// @dev deposits the amount of Ether sent as value and return mints cEther for the sender | ||||
|     function mint() payable external; | ||||
|     /// @dev redeems specified amount of cETH and returns the underlying ether to the sender | ||||
|     /// @dev redeemTokensInCEther amount of cETH to redeem for underlying ether | ||||
|     /// @return status code of whether the redemption was successful or not | ||||
|     function redeem(uint256 redeemTokensInCEther) external returns (uint256); | ||||
| } | ||||
|  | ||||
| contract MixinCompound { | ||||
|     using LibERC20TokenV06 for IERC20TokenV06; | ||||
|     using LibSafeMathV06 for uint256; | ||||
|  | ||||
|     IEtherTokenV06 private immutable WETH; | ||||
|  | ||||
|     constructor(IEtherTokenV06 weth) | ||||
|         public | ||||
|     { | ||||
|         WETH = weth; | ||||
|     } | ||||
|  | ||||
|     uint256 constant private COMPOUND_SUCCESS_CODE = 0; | ||||
|  | ||||
|     function _tradeCompound( | ||||
|         IERC20TokenV06 sellToken, | ||||
|         IERC20TokenV06 buyToken, | ||||
|         uint256 sellAmount, | ||||
|         bytes memory bridgeData | ||||
|     ) | ||||
|         internal | ||||
|         returns (uint256) | ||||
|     { | ||||
|         (address cTokenAddress) = abi.decode(bridgeData, (address)); | ||||
|         uint256 beforeBalance = buyToken.balanceOf(address(this)); | ||||
|  | ||||
|         if (address(buyToken) == cTokenAddress) { | ||||
|             if (address(sellToken) == address(WETH)) { | ||||
|                 // ETH/WETH -> cETH | ||||
|                 ICEther cETH = ICEther(cTokenAddress); | ||||
|                 // Compound expects ETH to be sent with mint call | ||||
|                 WETH.withdraw(sellAmount); | ||||
|                 // NOTE: cETH mint will revert on failure instead of returning a status code | ||||
|                 cETH.mint{value: sellAmount}(); | ||||
|             } else { | ||||
|                 sellToken.approveIfBelow( | ||||
|                     cTokenAddress, | ||||
|                     sellAmount | ||||
|                 ); | ||||
|                 // Token -> cToken | ||||
|                 ICToken cToken = ICToken(cTokenAddress); | ||||
|                 require(cToken.mint(sellAmount) == COMPOUND_SUCCESS_CODE, "MixinCompound/FAILED_TO_MINT_CTOKEN"); | ||||
|             } | ||||
|         } else if (address(sellToken) == cTokenAddress) { | ||||
|             if (address(buyToken) == address(WETH)) { | ||||
|                 // cETH -> ETH/WETH | ||||
|                 uint256 etherBalanceBefore = address(this).balance; | ||||
|                 ICEther cETH = ICEther(cTokenAddress); | ||||
|                 require(cETH.redeem(sellAmount) == COMPOUND_SUCCESS_CODE, "MixinCompound/FAILED_TO_REDEEM_CETHER"); | ||||
|                 uint256 etherBalanceAfter = address(this).balance; | ||||
|                 uint256 receivedEtherBalance = etherBalanceAfter.safeSub(etherBalanceBefore); | ||||
|                 WETH.deposit{value: receivedEtherBalance}(); | ||||
|             } else { | ||||
|                 ICToken cToken = ICToken(cTokenAddress); | ||||
|                 require(cToken.redeem(sellAmount) == COMPOUND_SUCCESS_CODE, "MixinCompound/FAILED_TO_REDEEM_CTOKEN"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return buyToken.balanceOf(address(this)).safeSub(beforeBalance); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								contracts/zero-ex/contracts/src/vendor/IERC1155OrderCallback.sol
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								contracts/zero-ex/contracts/src/vendor/IERC1155OrderCallback.sol
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| interface IERC1155OrderCallback { | ||||
|  | ||||
|     /// @dev A taker callback function invoked in the ERC1155Feature between | ||||
|     ///      the maker -> taker transfer and the taker -> maker transfer. | ||||
|     /// @param callbackData Arbitrary data used by this callback. | ||||
|     /// @return success The selector of this function (0x0ea5ba79), | ||||
|     ///         indicating that the callback succeeded. | ||||
|     function zeroExERC1155OrderCallback(bytes calldata callbackData) | ||||
|         external | ||||
|         returns (bytes4 success); | ||||
| } | ||||
							
								
								
									
										151
									
								
								contracts/zero-ex/contracts/src/vendor/IERC1155Token.sol
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								contracts/zero-ex/contracts/src/vendor/IERC1155Token.sol
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | ||||
| // 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 IERC1155Token { | ||||
|  | ||||
|     /// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, | ||||
|     ///      including zero value transfers as well as minting or burning. | ||||
|     /// Operator will always be msg.sender. | ||||
|     /// Either event from address `0x0` signifies a minting operation. | ||||
|     /// An event to address `0x0` signifies a burning or melting operation. | ||||
|     /// The total value transferred from address 0x0 minus the total value transferred to 0x0 may | ||||
|     /// be used by clients and exchanges to be added to the "circulating supply" for a given token ID. | ||||
|     /// To define a token ID with no initial balance, the contract SHOULD emit the TransferSingle event | ||||
|     /// from `0x0` to `0x0`, with the token creator as `_operator`. | ||||
|     event TransferSingle( | ||||
|         address indexed operator, | ||||
|         address indexed from, | ||||
|         address indexed to, | ||||
|         uint256 id, | ||||
|         uint256 value | ||||
|     ); | ||||
|  | ||||
|     /// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, | ||||
|     ///      including zero value transfers as well as minting or burning. | ||||
|     ///Operator will always be msg.sender. | ||||
|     /// Either event from address `0x0` signifies a minting operation. | ||||
|     /// An event to address `0x0` signifies a burning or melting operation. | ||||
|     /// The total value transferred from address 0x0 minus the total value transferred to 0x0 may | ||||
|     /// be used by clients and exchanges to be added to the "circulating supply" for a given token ID. | ||||
|     /// To define multiple token IDs with no initial balance, this SHOULD emit the TransferBatch event | ||||
|     /// from `0x0` to `0x0`, with the token creator as `_operator`. | ||||
|     event TransferBatch( | ||||
|         address indexed operator, | ||||
|         address indexed from, | ||||
|         address indexed to, | ||||
|         uint256[] ids, | ||||
|         uint256[] values | ||||
|     ); | ||||
|  | ||||
|     /// @dev MUST emit when an approval is updated. | ||||
|     event ApprovalForAll( | ||||
|         address indexed owner, | ||||
|         address indexed operator, | ||||
|         bool approved | ||||
|     ); | ||||
|  | ||||
|     /// @dev MUST emit when the URI is updated for a token ID. | ||||
|     /// URIs are defined in RFC 3986. | ||||
|     /// The URI MUST point a JSON file that conforms to the "ERC-1155 Metadata JSON Schema". | ||||
|     event URI( | ||||
|         string value, | ||||
|         uint256 indexed id | ||||
|     ); | ||||
|  | ||||
|     /// @notice Transfers value amount of an _id from the _from address to the _to address specified. | ||||
|     /// @dev MUST emit TransferSingle event on success. | ||||
|     /// Caller must be approved to manage the _from account's tokens (see isApprovedForAll). | ||||
|     /// MUST throw if `_to` is the zero address. | ||||
|     /// MUST throw if balance of sender for token `_id` is lower than the `_value` sent. | ||||
|     /// MUST throw on any other error. | ||||
|     /// When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0). | ||||
|     /// If so, it MUST call `onERC1155Received` on `_to` and revert if the return value | ||||
|     /// is not `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`. | ||||
|     /// @param from    Source address | ||||
|     /// @param to      Target address | ||||
|     /// @param id      ID of the token type | ||||
|     /// @param value   Transfer amount | ||||
|     /// @param data    Additional data with no specified format, sent in call to `_to` | ||||
|     function safeTransferFrom( | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256 id, | ||||
|         uint256 value, | ||||
|         bytes calldata data | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @notice Send multiple types of Tokens from a 3rd party in one transfer (with safety call). | ||||
|     /// @dev MUST emit TransferBatch event on success. | ||||
|     /// Caller must be approved to manage the _from account's tokens (see isApprovedForAll). | ||||
|     /// MUST throw if `_to` is the zero address. | ||||
|     /// MUST throw if length of `_ids` is not the same as length of `_values`. | ||||
|     ///  MUST throw if any of the balance of sender for token `_ids` is lower than the respective `_values` sent. | ||||
|     /// MUST throw on any other error. | ||||
|     /// When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0). | ||||
|     /// If so, it MUST call `onERC1155BatchReceived` on `_to` and revert if the return value | ||||
|     /// is not `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`. | ||||
|     /// @param from    Source addresses | ||||
|     /// @param to      Target addresses | ||||
|     /// @param ids     IDs of each token type | ||||
|     /// @param values  Transfer amounts per token type | ||||
|     /// @param data    Additional data with no specified format, sent in call to `_to` | ||||
|     function safeBatchTransferFrom( | ||||
|         address from, | ||||
|         address to, | ||||
|         uint256[] calldata ids, | ||||
|         uint256[] calldata values, | ||||
|         bytes calldata data | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. | ||||
|     /// @dev MUST emit the ApprovalForAll event on success. | ||||
|     /// @param operator  Address to add to the set of authorized operators | ||||
|     /// @param approved  True if the operator is approved, false to revoke approval | ||||
|     function setApprovalForAll(address operator, bool approved) external; | ||||
|  | ||||
|     /// @notice Queries the approval status of an operator for a given owner. | ||||
|     /// @param owner        The owner of the Tokens | ||||
|     /// @param operator     Address of authorized operator | ||||
|     /// @return isApproved  True if the operator is approved, false if not | ||||
|     function isApprovedForAll(address owner, address operator) external view returns (bool isApproved); | ||||
|  | ||||
|     /// @notice Get the balance of an account's Tokens. | ||||
|     /// @param owner     The address of the token holder | ||||
|     /// @param id        ID of the Token | ||||
|     /// @return balance  The _owner's balance of the Token type requested | ||||
|     function balanceOf(address owner, uint256 id) external view returns (uint256 balance); | ||||
|  | ||||
|     /// @notice Get the balance of multiple account/token pairs | ||||
|     /// @param owners      The addresses of the token holders | ||||
|     /// @param ids         ID of the Tokens | ||||
|     /// @return balances_  The _owner's balance of the Token types requested | ||||
|     function balanceOfBatch( | ||||
|         address[] calldata owners, | ||||
|         uint256[] calldata ids | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|         returns (uint256[] memory balances_); | ||||
| } | ||||
							
								
								
									
										34
									
								
								contracts/zero-ex/contracts/src/vendor/IERC721OrderCallback.sol
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								contracts/zero-ex/contracts/src/vendor/IERC721OrderCallback.sol
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| interface IERC721OrderCallback { | ||||
|  | ||||
|     /// @dev A taker callback function invoked in the ERC721Feature between  | ||||
|     ///      the maker -> taker transfer and the taker -> maker transfer. | ||||
|     /// @param callbackData Arbitrary data used by this callback. | ||||
|     /// @return success The selector of this function (0x6d46db51),  | ||||
|     ///         indicating that the callback succeeded. | ||||
|     function zeroExERC721OrderCallback(bytes calldata callbackData) | ||||
|         external | ||||
|         returns (bytes4 success); | ||||
| } | ||||
							
								
								
									
										159
									
								
								contracts/zero-ex/contracts/src/vendor/IERC721Token.sol
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								contracts/zero-ex/contracts/src/vendor/IERC721Token.sol
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,159 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
|  | ||||
|  | ||||
| interface IERC721Token { | ||||
|  | ||||
|     /// @dev This emits when ownership of any NFT changes by any mechanism. | ||||
|     ///      This event emits when NFTs are created (`from` == 0) and destroyed | ||||
|     ///      (`to` == 0). Exception: during contract creation, any number of NFTs | ||||
|     ///      may be created and assigned without emitting Transfer. At the time of | ||||
|     ///      any transfer, the approved address for that NFT (if any) is reset to none. | ||||
|     event Transfer( | ||||
|         address indexed _from, | ||||
|         address indexed _to, | ||||
|         uint256 indexed _tokenId | ||||
|     ); | ||||
|  | ||||
|     /// @dev This emits when the approved address for an NFT is changed or | ||||
|     ///      reaffirmed. The zero address indicates there is no approved address. | ||||
|     ///      When a Transfer event emits, this also indicates that the approved | ||||
|     ///      address for that NFT (if any) is reset to none. | ||||
|     event Approval( | ||||
|         address indexed _owner, | ||||
|         address indexed _approved, | ||||
|         uint256 indexed _tokenId | ||||
|     ); | ||||
|  | ||||
|     /// @dev This emits when an operator is enabled or disabled for an owner. | ||||
|     ///      The operator can manage all NFTs of the owner. | ||||
|     event ApprovalForAll( | ||||
|         address indexed _owner, | ||||
|         address indexed _operator, | ||||
|         bool _approved | ||||
|     ); | ||||
|  | ||||
|     /// @notice Transfers the ownership of an NFT from one address to another address | ||||
|     /// @dev Throws unless `msg.sender` is the current owner, an authorized | ||||
|     ///      perator, or the approved address for this NFT. Throws if `_from` is | ||||
|     ///      not the current owner. Throws if `_to` is the zero address. Throws if | ||||
|     ///      `_tokenId` is not a valid NFT. When transfer is complete, this function | ||||
|     ///      checks if `_to` is a smart contract (code size > 0). If so, it calls | ||||
|     ///      `onERC721Received` on `_to` and throws if the return value is not | ||||
|     ///      `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. | ||||
|     /// @param _from The current owner of the NFT | ||||
|     /// @param _to The new owner | ||||
|     /// @param _tokenId The NFT to transfer | ||||
|     /// @param _data Additional data with no specified format, sent in call to `_to` | ||||
|     function safeTransferFrom( | ||||
|         address _from, | ||||
|         address _to, | ||||
|         uint256 _tokenId, | ||||
|         bytes calldata _data | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @notice Transfers the ownership of an NFT from one address to another address | ||||
|     /// @dev This works identically to the other function with an extra data parameter, | ||||
|     ///      except this function just sets data to "". | ||||
|     /// @param _from The current owner of the NFT | ||||
|     /// @param _to The new owner | ||||
|     /// @param _tokenId The NFT to transfer | ||||
|     function safeTransferFrom( | ||||
|         address _from, | ||||
|         address _to, | ||||
|         uint256 _tokenId | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @notice Change or reaffirm the approved address for an NFT | ||||
|     /// @dev The zero address indicates there is no approved address. | ||||
|     ///      Throws unless `msg.sender` is the current NFT owner, or an authorized | ||||
|     ///      operator of the current owner. | ||||
|     /// @param _approved The new approved NFT controller | ||||
|     /// @param _tokenId The NFT to approve | ||||
|     function approve(address _approved, uint256 _tokenId) | ||||
|         external; | ||||
|  | ||||
|     /// @notice Enable or disable approval for a third party ("operator") to manage | ||||
|     ///         all of `msg.sender`'s assets | ||||
|     /// @dev Emits the ApprovalForAll event. The contract MUST allow | ||||
|     ///      multiple operators per owner. | ||||
|     /// @param _operator Address to add to the set of authorized operators | ||||
|     /// @param _approved True if the operator is approved, false to revoke approval | ||||
|     function setApprovalForAll(address _operator, bool _approved) | ||||
|         external; | ||||
|  | ||||
|     /// @notice Count all NFTs assigned to an owner | ||||
|     /// @dev NFTs assigned to the zero address are considered invalid, and this | ||||
|     ///      function throws for queries about the zero address. | ||||
|     /// @param _owner An address for whom to query the balance | ||||
|     /// @return The number of NFTs owned by `_owner`, possibly zero | ||||
|     function balanceOf(address _owner) | ||||
|         external | ||||
|         view | ||||
|         returns (uint256); | ||||
|  | ||||
|     /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE | ||||
|     ///         TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE | ||||
|     ///         THEY MAY BE PERMANENTLY LOST | ||||
|     /// @dev Throws unless `msg.sender` is the current owner, an authorized | ||||
|     ///      operator, or the approved address for this NFT. Throws if `_from` is | ||||
|     ///      not the current owner. Throws if `_to` is the zero address. Throws if | ||||
|     ///      `_tokenId` is not a valid NFT. | ||||
|     /// @param _from The current owner of the NFT | ||||
|     /// @param _to The new owner | ||||
|     /// @param _tokenId The NFT to transfer | ||||
|     function transferFrom( | ||||
|         address _from, | ||||
|         address _to, | ||||
|         uint256 _tokenId | ||||
|     ) | ||||
|         external; | ||||
|  | ||||
|     /// @notice Find the owner of an NFT | ||||
|     /// @dev NFTs assigned to zero address are considered invalid, and queries | ||||
|     ///      about them do throw. | ||||
|     /// @param _tokenId The identifier for an NFT | ||||
|     /// @return The address of the owner of the NFT | ||||
|     function ownerOf(uint256 _tokenId) | ||||
|         external | ||||
|         view | ||||
|         returns (address); | ||||
|  | ||||
|     /// @notice Get the approved address for a single NFT | ||||
|     /// @dev Throws if `_tokenId` is not a valid NFT. | ||||
|     /// @param _tokenId The NFT to find the approved address for | ||||
|     /// @return The approved address for this NFT, or the zero address if there is none | ||||
|     function getApproved(uint256 _tokenId)  | ||||
|         external | ||||
|         view | ||||
|         returns (address); | ||||
|      | ||||
|     /// @notice Query if an address is an authorized operator for another address | ||||
|     /// @param _owner The address that owns the NFTs | ||||
|     /// @param _operator The address that acts on behalf of the owner | ||||
|     /// @return True if `_operator` is an approved operator for `_owner`, false otherwise | ||||
|     function isApprovedForAll(address _owner, address _operator) | ||||
|         external | ||||
|         view | ||||
|         returns (bool); | ||||
| } | ||||
							
								
								
									
										44
									
								
								contracts/zero-ex/contracts/src/vendor/IFeeRecipient.sol
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								contracts/zero-ex/contracts/src/vendor/IFeeRecipient.sol
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| interface IFeeRecipient { | ||||
|  | ||||
|     /// @dev A callback function invoked in the ERC721Feature for each ERC721 | ||||
|     ///      order fee that get paid. Integrators can make use of this callback | ||||
|     ///      to implement arbitrary fee-handling logic, e.g. splitting the fee | ||||
|     ///      between multiple parties. | ||||
|     /// @param tokenAddress The address of the token in which the received fee is | ||||
|     ///        denominated. `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` indicates | ||||
|     ///        that the fee was paid in the native token (e.g. ETH). | ||||
|     /// @param amount The amount of the given token received. | ||||
|     /// @param feeData Arbitrary data encoded in the `Fee` used by this callback. | ||||
|     /// @return success The selector of this function (0x0190805e), | ||||
|     ///         indicating that the callback succeeded. | ||||
|     function receiveZeroExFeeCallback( | ||||
|         address tokenAddress, | ||||
|         uint256 amount, | ||||
|         bytes calldata feeData | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4 success); | ||||
| } | ||||
							
								
								
									
										38
									
								
								contracts/zero-ex/contracts/src/vendor/IPropertyValidator.sol
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								contracts/zero-ex/contracts/src/vendor/IPropertyValidator.sol
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| interface IPropertyValidator { | ||||
|  | ||||
|     /// @dev Checks that the given ERC721/ERC1155 asset satisfies the properties encoded in `propertyData`. | ||||
|     ///      Should revert if the asset does not satisfy the specified properties. | ||||
|     /// @param tokenAddress The ERC721/ERC1155 token contract address. | ||||
|     /// @param tokenId The ERC721/ERC1155 tokenId of the asset to check. | ||||
|     /// @param propertyData Encoded properties or auxiliary data needed to perform the check. | ||||
|     function validateProperty( | ||||
|         address tokenAddress, | ||||
|         uint256 tokenId, | ||||
|         bytes calldata propertyData | ||||
|     ) | ||||
|         external | ||||
|         view; | ||||
| } | ||||
| @@ -0,0 +1,61 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "../src/IZeroEx.sol"; | ||||
| import "../src/vendor/IERC721Token.sol"; | ||||
| import "../src/features/libs/LibERC721Order.sol"; | ||||
|  | ||||
|  | ||||
| contract TestERC721OrderPresigner { | ||||
|     IZeroEx private immutable zeroEx; | ||||
|  | ||||
|     constructor(IZeroEx _zeroEx) | ||||
|         public | ||||
|     { | ||||
|         zeroEx = _zeroEx; | ||||
|     } | ||||
|  | ||||
|     function approveERC721(IERC721Token token) | ||||
|         external | ||||
|     { | ||||
|         token.setApprovalForAll(address(zeroEx), true); | ||||
|     } | ||||
|  | ||||
|     function approveERC20(IERC20TokenV06 token) | ||||
|         external | ||||
|     { | ||||
|         token.approve(address(zeroEx), uint256(-1)); | ||||
|     } | ||||
|  | ||||
|     function preSignOrder(LibERC721Order.ERC721Order calldata order) | ||||
|         external | ||||
|     { | ||||
|         zeroEx.preSignERC721Order(order); | ||||
|     } | ||||
|  | ||||
|     function cancelOrder(uint256 orderNonce) | ||||
|         external | ||||
|     { | ||||
|         zeroEx.cancelERC721Order(orderNonce); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										55
									
								
								contracts/zero-ex/contracts/test/TestFeeRecipient.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								contracts/zero-ex/contracts/test/TestFeeRecipient.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| contract TestFeeRecipient { | ||||
|     bytes4 constant private SUCCESS = this.receiveZeroExFeeCallback.selector; | ||||
|     bytes4 constant private FAILURE = 0xdeadbeef; | ||||
|  | ||||
|     uint256 constant private TRIGGER_REVERT = 333; | ||||
|     uint256 constant private TRIGGER_FAILURE = 666; | ||||
|  | ||||
|     event FeeReceived( | ||||
|         address tokenAddress, | ||||
|         uint256 amount | ||||
|     ); | ||||
|  | ||||
|     receive() external payable {} | ||||
|  | ||||
|     function receiveZeroExFeeCallback( | ||||
|         address tokenAddress, | ||||
|         uint256 amount, | ||||
|         bytes calldata /* feeData */ | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4 success) | ||||
|     { | ||||
|         emit FeeReceived(tokenAddress, amount); | ||||
|         if (amount == TRIGGER_REVERT) { | ||||
|             revert("TestFeeRecipient::receiveZeroExFeeCallback/REVERT"); | ||||
|         } else if (amount == TRIGGER_FAILURE) { | ||||
|             return FAILURE; | ||||
|         } else { | ||||
|             return SUCCESS; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -22,7 +22,7 @@ pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol"; | ||||
| import "../src/vendor/v3/IERC20Bridge.sol"; | ||||
| import "./TestMintableERC20Token.sol"; | ||||
| import "./tokens/TestMintableERC20Token.sol"; | ||||
|  | ||||
|  | ||||
| contract TestFillQuoteTransformerBridge { | ||||
|   | ||||
| @@ -23,7 +23,7 @@ pragma experimental ABIEncoderV2; | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; | ||||
| import "./TestMintableERC20Token.sol"; | ||||
| import "./tokens/TestMintableERC20Token.sol"; | ||||
| import "../src/features/libs/LibNativeOrder.sol"; | ||||
| import "../src/features/libs/LibSignature.sol"; | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,7 @@ pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "../src/transformers/IERC20Transformer.sol"; | ||||
| import "./TestMintableERC20Token.sol"; | ||||
| import "./tokens/TestMintableERC20Token.sol"; | ||||
| import "./TestTransformerHost.sol"; | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -46,6 +46,10 @@ contract TestMetaTransactionsTransformERC20Feature is | ||||
|         payable | ||||
|         returns (uint256 outputTokenAmount) | ||||
|     { | ||||
|         if (msg.value == 555) { | ||||
|             tx.origin.transfer(1); | ||||
|         } | ||||
|  | ||||
|         if (msg.value == 666) { | ||||
|             revert('FAIL'); | ||||
|         } | ||||
|   | ||||
| @@ -23,7 +23,7 @@ pragma experimental ABIEncoderV2; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "../src/transformers/IERC20Transformer.sol"; | ||||
| import "../src/transformers/LibERC20Transformer.sol"; | ||||
| import "./TestMintableERC20Token.sol"; | ||||
| import "./tokens/TestMintableERC20Token.sol"; | ||||
|  | ||||
|  | ||||
| contract TestMintTokenERC20Transformer is | ||||
|   | ||||
							
								
								
									
										39
									
								
								contracts/zero-ex/contracts/test/TestPropertyValidator.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								contracts/zero-ex/contracts/test/TestPropertyValidator.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
|  | ||||
| contract TestPropertyValidator { | ||||
|  | ||||
|     function validateProperty( | ||||
|         address tokenAddress, | ||||
|         uint256 tokenId, | ||||
|         bytes calldata propertyData | ||||
|     ) | ||||
|         external | ||||
|         view | ||||
|     { | ||||
|         require( | ||||
|             propertyData.length > 0, | ||||
|             "TestPropertyValidator::validateProperty/REVERT" | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -21,9 +21,9 @@ pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "../src/transformers/IERC20Transformer.sol"; | ||||
| import "./TestMintableERC20Token.sol"; | ||||
| import "./tokens/TestMintableERC20Token.sol"; | ||||
| import "./TestTransformerHost.sol"; | ||||
| import "./TestWeth.sol"; | ||||
| import "./tokens/TestWeth.sol"; | ||||
|  | ||||
|  | ||||
| contract TestWethTransformerHost is | ||||
|   | ||||
| @@ -21,7 +21,7 @@ pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "./TestMintableERC20Token.sol"; | ||||
| import "../tokens/TestMintableERC20Token.sol"; | ||||
| 
 | ||||
| contract TestCurve { | ||||
| 
 | ||||
| @@ -21,7 +21,7 @@ pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
| 
 | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "./TestMintableERC20Token.sol"; | ||||
| import "../tokens/TestMintableERC20Token.sol"; | ||||
| 
 | ||||
| contract TestMooniswap { | ||||
| 
 | ||||
| @@ -2,7 +2,7 @@ | ||||
| pragma solidity ^0.6; | ||||
| pragma experimental ABIEncoderV2; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "../src/vendor/IUniswapV2Pair.sol"; | ||||
| import "../../src/vendor/IUniswapV2Pair.sol"; | ||||
| 
 | ||||
| interface IUniswapV2PoolDeployer { | ||||
|     struct CreationParameters { | ||||
| @@ -2,7 +2,7 @@ | ||||
| pragma solidity ^0.6; | ||||
| pragma experimental ABIEncoderV2; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "../src/vendor/IUniswapV3Pool.sol"; | ||||
| import "../../src/vendor/IUniswapV3Pool.sol"; | ||||
| 
 | ||||
| interface IUniswapV3PoolDeployer { | ||||
|     struct CreationParameters { | ||||
| @@ -0,0 +1,385 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2020 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; | ||||
|  | ||||
|  | ||||
| interface IERC721Receiver { | ||||
|  | ||||
|     /// @notice Handle the receipt of an NFT | ||||
|     /// @dev The ERC721 smart contract calls this function on the recipient | ||||
|     ///  after a `transfer`. This function MAY throw to revert and reject the | ||||
|     ///  transfer. Return of other than the magic value MUST result in the | ||||
|     ///  transaction being reverted. | ||||
|     ///  Note: the contract address is always the message sender. | ||||
|     /// @param _operator The address which called `safeTransferFrom` function | ||||
|     /// @param _from The address which previously owned the token | ||||
|     /// @param _tokenId The NFT identifier which is being transferred | ||||
|     /// @param _data Additional data with no specified format | ||||
|     /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` | ||||
|     ///  unless throwing | ||||
|     function onERC721Received( | ||||
|         address _operator, | ||||
|         address _from, | ||||
|         uint256 _tokenId, | ||||
|         bytes calldata _data | ||||
|     ) | ||||
|         external | ||||
|         returns (bytes4); | ||||
| } | ||||
|  | ||||
| contract TestMintableERC721Token { | ||||
|     using LibSafeMathV06 for uint256; | ||||
|  | ||||
|     /// @dev This emits when ownership of any NFT changes by any mechanism. | ||||
|     ///      This event emits when NFTs are created (`from` == 0) and destroyed | ||||
|     ///      (`to` == 0). Exception: during contract creation, any number of NFTs | ||||
|     ///      may be created and assigned without emitting Transfer. At the time of | ||||
|     ///      any transfer, the approved address for that NFT (if any) is reset to none. | ||||
|     event Transfer( | ||||
|         address _from, | ||||
|         address _to, | ||||
|         uint256 _tokenId | ||||
|     ); | ||||
|  | ||||
|     /// @dev This emits when the approved address for an NFT is changed or | ||||
|     ///      reaffirmed. The zero address indicates there is no approved address. | ||||
|     ///      When a Transfer event emits, this also indicates that the approved | ||||
|     ///      address for that NFT (if any) is reset to none. | ||||
|     event Approval( | ||||
|         address indexed _owner, | ||||
|         address indexed _approved, | ||||
|         uint256 indexed _tokenId | ||||
|     ); | ||||
|  | ||||
|     /// @dev This emits when an operator is enabled or disabled for an owner. | ||||
|     ///      The operator can manage all NFTs of the owner. | ||||
|     event ApprovalForAll( | ||||
|         address indexed _owner, | ||||
|         address indexed _operator, | ||||
|         bool _approved | ||||
|     ); | ||||
|  | ||||
|     // Function selector for ERC721Receiver.onERC721Received | ||||
|     // 0x150b7a02 | ||||
|     bytes4 constant private ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")); | ||||
|  | ||||
|     // Mapping of tokenId => owner | ||||
|     mapping (uint256 => address) private owners; | ||||
|  | ||||
|     // Mapping of tokenId => approved address | ||||
|     mapping (uint256 => address) private approvals; | ||||
|  | ||||
|     // Mapping of owner => number of tokens owned | ||||
|     mapping (address => uint256) private balances; | ||||
|  | ||||
|     // Mapping of owner => operator => approved | ||||
|     mapping (address => mapping (address => bool)) private operatorApprovals; | ||||
|  | ||||
|     /// @dev Function to mint a new token | ||||
|     ///      Reverts if the given token ID already exists | ||||
|     /// @param _to Address of the beneficiary that will own the minted token | ||||
|     /// @param _tokenId ID of the token to be minted by the msg.sender     | ||||
|     function mint(address _to, uint256 _tokenId) | ||||
|         external | ||||
|     { | ||||
|         require( | ||||
|             _to != address(0), | ||||
|             "ERC721_ZERO_TO_ADDRESS" | ||||
|         ); | ||||
|  | ||||
|         address owner = owners[_tokenId]; | ||||
|         require( | ||||
|             owner == address(0), | ||||
|             "ERC721_OWNER_ALREADY_EXISTS" | ||||
|         ); | ||||
|  | ||||
|         owners[_tokenId] = _to; | ||||
|         balances[_to] = balances[_to].safeAdd(1); | ||||
|  | ||||
|         emit Transfer( | ||||
|             address(0), | ||||
|             _to, | ||||
|             _tokenId | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @dev Function to burn a token | ||||
|     ///      Reverts if the given token ID doesn't exist | ||||
|     /// @param _owner Owner of token with given token ID | ||||
|     /// @param _tokenId ID of the token to be burned by the msg.sender | ||||
|     function burn(address _owner, uint256 _tokenId) | ||||
|         external | ||||
|     { | ||||
|         require( | ||||
|             _owner != address(0), | ||||
|             "ERC721_ZERO_OWNER_ADDRESS" | ||||
|         ); | ||||
|  | ||||
|         address owner = owners[_tokenId]; | ||||
|         require( | ||||
|             owner == _owner, | ||||
|             "ERC721_OWNER_MISMATCH" | ||||
|         ); | ||||
|  | ||||
|         owners[_tokenId] = address(0); | ||||
|         balances[_owner] = balances[_owner].safeSub(1); | ||||
|  | ||||
|         emit Transfer( | ||||
|             _owner, | ||||
|             address(0), | ||||
|             _tokenId | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @notice Transfers the ownership of an NFT from one address to another address | ||||
|     /// @dev Throws unless `msg.sender` is the current owner, an authorized | ||||
|     ///      operator, or the approved address for this NFT. Throws if `_from` is | ||||
|     ///      not the current owner. Throws if `_to` is the zero address. Throws if | ||||
|     ///      `_tokenId` is not a valid NFT. When transfer is complete, this function | ||||
|     ///      checks if `_to` is a smart contract (code size > 0). If so, it calls | ||||
|     ///      `onERC721Received` on `_to` and throws if the return value is not | ||||
|     ///      `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. | ||||
|     /// @param _from The current owner of the NFT | ||||
|     /// @param _to The new owner | ||||
|     /// @param _tokenId The NFT to transfer | ||||
|     /// @param _data Additional data with no specified format, sent in call to `_to` | ||||
|     function safeTransferFrom( | ||||
|         address _from, | ||||
|         address _to, | ||||
|         uint256 _tokenId, | ||||
|         bytes calldata _data | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         transferFrom( | ||||
|             _from, | ||||
|             _to, | ||||
|             _tokenId | ||||
|         ); | ||||
|  | ||||
|         uint256 receiverCodeSize; | ||||
|         assembly { | ||||
|             receiverCodeSize := extcodesize(_to) | ||||
|         } | ||||
|         if (receiverCodeSize > 0) { | ||||
|             bytes4 selector = IERC721Receiver(_to).onERC721Received( | ||||
|                 msg.sender, | ||||
|                 _from, | ||||
|                 _tokenId, | ||||
|                 _data | ||||
|             ); | ||||
|             require( | ||||
|                 selector == ERC721_RECEIVED, | ||||
|                 "ERC721_INVALID_SELECTOR" | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @notice Transfers the ownership of an NFT from one address to another address | ||||
|     /// @dev This works identically to the other function with an extra data parameter, | ||||
|     ///      except this function just sets data to "". | ||||
|     /// @param _from The current owner of the NFT | ||||
|     /// @param _to The new owner | ||||
|     /// @param _tokenId The NFT to transfer | ||||
|     function safeTransferFrom( | ||||
|         address _from, | ||||
|         address _to, | ||||
|         uint256 _tokenId | ||||
|     ) | ||||
|         external | ||||
|     { | ||||
|         transferFrom( | ||||
|             _from, | ||||
|             _to, | ||||
|             _tokenId | ||||
|         ); | ||||
|  | ||||
|         uint256 receiverCodeSize; | ||||
|         assembly { | ||||
|             receiverCodeSize := extcodesize(_to) | ||||
|         } | ||||
|         if (receiverCodeSize > 0) { | ||||
|             bytes4 selector = IERC721Receiver(_to).onERC721Received( | ||||
|                 msg.sender, | ||||
|                 _from, | ||||
|                 _tokenId, | ||||
|                 "" | ||||
|             ); | ||||
|             require( | ||||
|                 selector == ERC721_RECEIVED, | ||||
|                 "ERC721_INVALID_SELECTOR" | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @notice Change or reaffirm the approved address for an NFT | ||||
|     /// @dev The zero address indicates there is no approved address. | ||||
|     ///      Throws unless `msg.sender` is the current NFT owner, or an authorized | ||||
|     ///      operator of the current owner. | ||||
|     /// @param _approved The new approved NFT controller | ||||
|     /// @param _tokenId The NFT to approve | ||||
|     function approve(address _approved, uint256 _tokenId) | ||||
|         external | ||||
|     { | ||||
|         address owner = ownerOf(_tokenId); | ||||
|         require( | ||||
|             msg.sender == owner || isApprovedForAll(owner, msg.sender), | ||||
|             "ERC721_INVALID_SENDER" | ||||
|         ); | ||||
|  | ||||
|         approvals[_tokenId] = _approved; | ||||
|         emit Approval( | ||||
|             owner, | ||||
|             _approved, | ||||
|             _tokenId | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @notice Enable or disable approval for a third party ("operator") to manage | ||||
|     ///         all of `msg.sender`'s assets | ||||
|     /// @dev Emits the ApprovalForAll event. The contract MUST allow | ||||
|     ///      multiple operators per owner. | ||||
|     /// @param _operator Address to add to the set of authorized operators | ||||
|     /// @param _approved True if the operator is approved, false to revoke approval | ||||
|     function setApprovalForAll(address _operator, bool _approved) | ||||
|         external | ||||
|     { | ||||
|         operatorApprovals[msg.sender][_operator] = _approved; | ||||
|         emit ApprovalForAll( | ||||
|             msg.sender, | ||||
|             _operator, | ||||
|             _approved | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @notice Count all NFTs assigned to an owner | ||||
|     /// @dev NFTs assigned to the zero address are considered invalid, and this | ||||
|     ///      function throws for queries about the zero address. | ||||
|     /// @param _owner An address for whom to query the balance | ||||
|     /// @return The number of NFTs owned by `_owner`, possibly zero | ||||
|     function balanceOf(address _owner) | ||||
|         external | ||||
|         view | ||||
|         returns (uint256) | ||||
|     { | ||||
|         require( | ||||
|             _owner != address(0), | ||||
|             "ERC721_ZERO_OWNER" | ||||
|         ); | ||||
|         return balances[_owner]; | ||||
|     } | ||||
|  | ||||
|     /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE | ||||
|     ///         TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE | ||||
|     ///         THEY MAY BE PERMANENTLY LOST | ||||
|     /// @dev Throws unless `msg.sender` is the current owner, an authorized | ||||
|     ///      operator, or the approved address for this NFT. Throws if `_from` is | ||||
|     ///      not the current owner. Throws if `_to` is the zero address. Throws if | ||||
|     ///      `_tokenId` is not a valid NFT. | ||||
|     /// @param _from The current owner of the NFT | ||||
|     /// @param _to The new owner | ||||
|     /// @param _tokenId The NFT to transfer | ||||
|     function transferFrom( | ||||
|         address _from, | ||||
|         address _to, | ||||
|         uint256 _tokenId | ||||
|     ) | ||||
|         public | ||||
|     { | ||||
|         require( | ||||
|             _to != address(0), | ||||
|             "ERC721_ZERO_TO_ADDRESS" | ||||
|         ); | ||||
|  | ||||
|         address owner = ownerOf(_tokenId); | ||||
|         require( | ||||
|             _from == owner, | ||||
|             "ERC721_OWNER_MISMATCH" | ||||
|         ); | ||||
|  | ||||
|         address spender = msg.sender; | ||||
|         address approvedAddress = getApproved(_tokenId); | ||||
|         require( | ||||
|             spender == owner || | ||||
|             isApprovedForAll(owner, spender) || | ||||
|             approvedAddress == spender, | ||||
|             "ERC721_INVALID_SPENDER" | ||||
|         ); | ||||
|  | ||||
|         if (approvedAddress != address(0)) { | ||||
|             approvals[_tokenId] = address(0); | ||||
|         } | ||||
|  | ||||
|         owners[_tokenId] = _to; | ||||
|         balances[_from] = balances[_from].safeSub(1); | ||||
|         balances[_to] = balances[_to].safeAdd(1); | ||||
|  | ||||
|         emit Transfer( | ||||
|             _from, | ||||
|             _to, | ||||
|             _tokenId | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /// @notice Find the owner of an NFT | ||||
|     /// @dev NFTs assigned to zero address are considered invalid, and queries | ||||
|     ///      about them do throw. | ||||
|     /// @param _tokenId The identifier for an NFT | ||||
|     /// @return The address of the owner of the NFT | ||||
|     function ownerOf(uint256 _tokenId) | ||||
|         public | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         address owner = owners[_tokenId]; | ||||
|         require( | ||||
|             owner != address(0), | ||||
|             "ERC721_ZERO_OWNER" | ||||
|         ); | ||||
|         return owner; | ||||
|     } | ||||
|  | ||||
|     /// @notice Get the approved address for a single NFT | ||||
|     /// @dev Throws if `_tokenId` is not a valid NFT. | ||||
|     /// @param _tokenId The NFT to find the approved address for | ||||
|     /// @return The approved address for this NFT, or the zero address if there is none | ||||
|     function getApproved(uint256 _tokenId) | ||||
|         public | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         return approvals[_tokenId]; | ||||
|     } | ||||
|  | ||||
|     /// @notice Query if an address is an authorized operator for another address | ||||
|     /// @param _owner The address that owns the NFTs | ||||
|     /// @param _operator The address that acts on behalf of the owner | ||||
|     /// @return True if `_operator` is an approved operator for `_owner`, false otherwise | ||||
|     function isApprovedForAll(address _owner, address _operator) | ||||
|         public | ||||
|         view | ||||
|         returns (bool) | ||||
|     { | ||||
|         return operatorApprovals[_owner][_operator]; | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-zero-ex", | ||||
|     "version": "0.29.2", | ||||
|     "version": "0.30.1", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -43,7 +43,7 @@ | ||||
|     "config": { | ||||
|         "publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature,OtcOrdersFeature,IOtcOrdersFeature", | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", | ||||
|         "abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBalancerV2|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMooniswap|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json" | ||||
|         "abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|ERC1155OrdersFeature|ERC721OrdersFeature|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinERC1155Spender|FixinERC721Spender|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|FundRecoveryFeature|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC1155OrderCallback|IERC1155OrdersFeature|IERC1155Token|IERC20Bridge|IERC20Transformer|IERC721OrderCallback|IERC721OrdersFeature|IERC721Token|IFeature|IFeeRecipient|IFlashWallet|IFundRecoveryFeature|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|IPropertyValidator|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC1155Order|LibERC1155OrdersRichErrors|LibERC1155OrdersStorage|LibERC20Transformer|LibERC721Order|LibERC721OrdersRichErrors|LibERC721OrdersStorage|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAaveV2|MixinBalancer|MixinBalancerV2|MixinBancor|MixinCoFiX|MixinCompound|MixinCryptoCom|MixinCurve|MixinCurveV2|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinLido|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|MultiplexLiquidityProvider|MultiplexOtc|MultiplexRfq|MultiplexTransformERC20|MultiplexUniswapV2|MultiplexUniswapV3|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestERC721OrderPresigner|TestFeeCollectorController|TestFeeRecipient|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMintableERC721Token|TestMooniswap|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestPropertyValidator|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV2Factory|TestUniswapV2Pool|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json" | ||||
|     }, | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
| @@ -56,10 +56,10 @@ | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/zero-ex", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.6.2", | ||||
|         "@0x/contract-addresses": "^6.8.0", | ||||
|         "@0x/contracts-erc20": "^3.3.21", | ||||
|         "@0x/contract-addresses": "^6.11.0", | ||||
|         "@0x/contracts-erc20": "^3.3.25", | ||||
|         "@0x/contracts-gen": "^2.0.40", | ||||
|         "@0x/contracts-test-utils": "^5.4.12", | ||||
|         "@0x/contracts-test-utils": "^5.4.16", | ||||
|         "@0x/dev-utils": "^4.2.9", | ||||
|         "@0x/order-utils": "^10.4.28", | ||||
|         "@0x/sol-compiler": "^4.7.5", | ||||
| @@ -83,7 +83,7 @@ | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.4.2", | ||||
|         "@0x/protocol-utils": "^1.9.3", | ||||
|         "@0x/protocol-utils": "^1.10.1", | ||||
|         "@0x/subproviders": "^6.6.0", | ||||
|         "@0x/types": "^3.3.4", | ||||
|         "@0x/typescript-typings": "^5.2.1", | ||||
|   | ||||
| @@ -12,6 +12,7 @@ import { | ||||
|     IZeroExContract, | ||||
|     MetaTransactionsFeatureContract, | ||||
|     NativeOrdersFeatureContract, | ||||
|     OtcOrdersFeatureContract, | ||||
|     OwnableFeatureContract, | ||||
|     SimpleFunctionRegistryFeatureContract, | ||||
|     TransformERC20FeatureContract, | ||||
| @@ -113,6 +114,7 @@ export interface FullFeatures extends BootstrapFeatures { | ||||
|     transformERC20: string; | ||||
|     metaTransactions: string; | ||||
|     nativeOrders: string; | ||||
|     otcOrders: string; | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -123,6 +125,7 @@ export interface FullFeatureArtifacts extends BootstrapFeatureArtifacts { | ||||
|     metaTransactions: SimpleContractArtifact; | ||||
|     nativeOrders: SimpleContractArtifact; | ||||
|     feeCollectorController: SimpleContractArtifact; | ||||
|     otcOrders: SimpleContractArtifact; | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -155,6 +158,7 @@ const DEFAULT_FULL_FEATURES_ARTIFACTS = { | ||||
|     metaTransactions: artifacts.MetaTransactionsFeature, | ||||
|     nativeOrders: artifacts.NativeOrdersFeature, | ||||
|     feeCollectorController: artifacts.FeeCollectorController, | ||||
|     otcOrders: artifacts.OtcOrdersFeature, | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -222,6 +226,18 @@ export async function deployFullFeaturesAsync( | ||||
|                     _config.protocolFeeMultiplier, | ||||
|                 ) | ||||
|             ).address, | ||||
|         otcOrders: | ||||
|             features.otcOrders || | ||||
|             ( | ||||
|                 await OtcOrdersFeatureContract.deployFrom0xArtifactAsync( | ||||
|                     _featureArtifacts.otcOrders, | ||||
|                     provider, | ||||
|                     txDefaults, | ||||
|                     artifacts, | ||||
|                     _config.zeroExAddress, | ||||
|                     _config.wethAddress, | ||||
|                 ) | ||||
|             ).address, | ||||
|     }; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -11,11 +11,15 @@ import * as BootstrapFeature from '../test/generated-artifacts/BootstrapFeature. | ||||
| import * as BridgeAdapter from '../test/generated-artifacts/BridgeAdapter.json'; | ||||
| import * as BridgeProtocols from '../test/generated-artifacts/BridgeProtocols.json'; | ||||
| import * as CurveLiquidityProvider from '../test/generated-artifacts/CurveLiquidityProvider.json'; | ||||
| import * as ERC1155OrdersFeature from '../test/generated-artifacts/ERC1155OrdersFeature.json'; | ||||
| import * as ERC721OrdersFeature from '../test/generated-artifacts/ERC721OrdersFeature.json'; | ||||
| import * as FeeCollector from '../test/generated-artifacts/FeeCollector.json'; | ||||
| import * as FeeCollectorController from '../test/generated-artifacts/FeeCollectorController.json'; | ||||
| import * as FillQuoteTransformer from '../test/generated-artifacts/FillQuoteTransformer.json'; | ||||
| import * as FixinCommon from '../test/generated-artifacts/FixinCommon.json'; | ||||
| import * as FixinEIP712 from '../test/generated-artifacts/FixinEIP712.json'; | ||||
| import * as FixinERC1155Spender from '../test/generated-artifacts/FixinERC1155Spender.json'; | ||||
| import * as FixinERC721Spender from '../test/generated-artifacts/FixinERC721Spender.json'; | ||||
| import * as FixinProtocolFees from '../test/generated-artifacts/FixinProtocolFees.json'; | ||||
| import * as FixinReentrancyGuard from '../test/generated-artifacts/FixinReentrancyGuard.json'; | ||||
| import * as FixinTokenSpender from '../test/generated-artifacts/FixinTokenSpender.json'; | ||||
| @@ -25,9 +29,16 @@ import * as FundRecoveryFeature from '../test/generated-artifacts/FundRecoveryFe | ||||
| import * as IBatchFillNativeOrdersFeature from '../test/generated-artifacts/IBatchFillNativeOrdersFeature.json'; | ||||
| import * as IBootstrapFeature from '../test/generated-artifacts/IBootstrapFeature.json'; | ||||
| import * as IBridgeAdapter from '../test/generated-artifacts/IBridgeAdapter.json'; | ||||
| import * as IERC1155OrderCallback from '../test/generated-artifacts/IERC1155OrderCallback.json'; | ||||
| import * as IERC1155OrdersFeature from '../test/generated-artifacts/IERC1155OrdersFeature.json'; | ||||
| import * as IERC1155Token from '../test/generated-artifacts/IERC1155Token.json'; | ||||
| import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json'; | ||||
| import * as IERC20Transformer from '../test/generated-artifacts/IERC20Transformer.json'; | ||||
| import * as IERC721OrderCallback from '../test/generated-artifacts/IERC721OrderCallback.json'; | ||||
| import * as IERC721OrdersFeature from '../test/generated-artifacts/IERC721OrdersFeature.json'; | ||||
| import * as IERC721Token from '../test/generated-artifacts/IERC721Token.json'; | ||||
| import * as IFeature from '../test/generated-artifacts/IFeature.json'; | ||||
| import * as IFeeRecipient from '../test/generated-artifacts/IFeeRecipient.json'; | ||||
| import * as IFlashWallet from '../test/generated-artifacts/IFlashWallet.json'; | ||||
| import * as IFundRecoveryFeature from '../test/generated-artifacts/IFundRecoveryFeature.json'; | ||||
| import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json'; | ||||
| @@ -42,6 +53,7 @@ import * as InitialMigration from '../test/generated-artifacts/InitialMigration. | ||||
| import * as IOtcOrdersFeature from '../test/generated-artifacts/IOtcOrdersFeature.json'; | ||||
| import * as IOwnableFeature from '../test/generated-artifacts/IOwnableFeature.json'; | ||||
| import * as IPancakeSwapFeature from '../test/generated-artifacts/IPancakeSwapFeature.json'; | ||||
| import * as IPropertyValidator from '../test/generated-artifacts/IPropertyValidator.json'; | ||||
| import * as ISimpleFunctionRegistryFeature from '../test/generated-artifacts/ISimpleFunctionRegistryFeature.json'; | ||||
| import * as IStaking from '../test/generated-artifacts/IStaking.json'; | ||||
| import * as ITestSimpleFunctionRegistryFeature from '../test/generated-artifacts/ITestSimpleFunctionRegistryFeature.json'; | ||||
| @@ -54,7 +66,13 @@ import * as IUniswapV3Pool from '../test/generated-artifacts/IUniswapV3Pool.json | ||||
| import * as IZeroEx from '../test/generated-artifacts/IZeroEx.json'; | ||||
| import * as LibBootstrap from '../test/generated-artifacts/LibBootstrap.json'; | ||||
| import * as LibCommonRichErrors from '../test/generated-artifacts/LibCommonRichErrors.json'; | ||||
| import * as LibERC1155Order from '../test/generated-artifacts/LibERC1155Order.json'; | ||||
| import * as LibERC1155OrdersRichErrors from '../test/generated-artifacts/LibERC1155OrdersRichErrors.json'; | ||||
| import * as LibERC1155OrdersStorage from '../test/generated-artifacts/LibERC1155OrdersStorage.json'; | ||||
| import * as LibERC20Transformer from '../test/generated-artifacts/LibERC20Transformer.json'; | ||||
| import * as LibERC721Order from '../test/generated-artifacts/LibERC721Order.json'; | ||||
| import * as LibERC721OrdersRichErrors from '../test/generated-artifacts/LibERC721OrdersRichErrors.json'; | ||||
| import * as LibERC721OrdersStorage from '../test/generated-artifacts/LibERC721OrdersStorage.json'; | ||||
| import * as LibFeeCollector from '../test/generated-artifacts/LibFeeCollector.json'; | ||||
| import * as LibLiquidityProviderRichErrors from '../test/generated-artifacts/LibLiquidityProviderRichErrors.json'; | ||||
| import * as LibMetaTransactionsRichErrors from '../test/generated-artifacts/LibMetaTransactionsRichErrors.json'; | ||||
| @@ -81,10 +99,12 @@ import * as LiquidityProviderFeature from '../test/generated-artifacts/Liquidity | ||||
| import * as LiquidityProviderSandbox from '../test/generated-artifacts/LiquidityProviderSandbox.json'; | ||||
| import * as LogMetadataTransformer from '../test/generated-artifacts/LogMetadataTransformer.json'; | ||||
| import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransactionsFeature.json'; | ||||
| import * as MixinAaveV2 from '../test/generated-artifacts/MixinAaveV2.json'; | ||||
| import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json'; | ||||
| import * as MixinBalancerV2 from '../test/generated-artifacts/MixinBalancerV2.json'; | ||||
| import * as MixinBancor from '../test/generated-artifacts/MixinBancor.json'; | ||||
| import * as MixinCoFiX from '../test/generated-artifacts/MixinCoFiX.json'; | ||||
| import * as MixinCompound from '../test/generated-artifacts/MixinCompound.json'; | ||||
| import * as MixinCryptoCom from '../test/generated-artifacts/MixinCryptoCom.json'; | ||||
| import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json'; | ||||
| import * as MixinCurveV2 from '../test/generated-artifacts/MixinCurveV2.json'; | ||||
| @@ -127,7 +147,9 @@ import * as TestBridge from '../test/generated-artifacts/TestBridge.json'; | ||||
| import * as TestCallTarget from '../test/generated-artifacts/TestCallTarget.json'; | ||||
| import * as TestCurve from '../test/generated-artifacts/TestCurve.json'; | ||||
| import * as TestDelegateCaller from '../test/generated-artifacts/TestDelegateCaller.json'; | ||||
| import * as TestERC721OrderPresigner from '../test/generated-artifacts/TestERC721OrderPresigner.json'; | ||||
| import * as TestFeeCollectorController from '../test/generated-artifacts/TestFeeCollectorController.json'; | ||||
| import * as TestFeeRecipient from '../test/generated-artifacts/TestFeeRecipient.json'; | ||||
| import * as TestFillQuoteTransformerBridge from '../test/generated-artifacts/TestFillQuoteTransformerBridge.json'; | ||||
| import * as TestFillQuoteTransformerExchange from '../test/generated-artifacts/TestFillQuoteTransformerExchange.json'; | ||||
| import * as TestFillQuoteTransformerHost from '../test/generated-artifacts/TestFillQuoteTransformerHost.json'; | ||||
| @@ -142,6 +164,7 @@ import * as TestMetaTransactionsNativeOrdersFeature from '../test/generated-arti | ||||
| import * as TestMetaTransactionsTransformERC20Feature from '../test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json'; | ||||
| import * as TestMigrator from '../test/generated-artifacts/TestMigrator.json'; | ||||
| import * as TestMintableERC20Token from '../test/generated-artifacts/TestMintableERC20Token.json'; | ||||
| import * as TestMintableERC721Token from '../test/generated-artifacts/TestMintableERC721Token.json'; | ||||
| import * as TestMintTokenERC20Transformer from '../test/generated-artifacts/TestMintTokenERC20Transformer.json'; | ||||
| import * as TestMooniswap from '../test/generated-artifacts/TestMooniswap.json'; | ||||
| import * as TestNativeOrdersFeature from '../test/generated-artifacts/TestNativeOrdersFeature.json'; | ||||
| @@ -149,6 +172,7 @@ import * as TestNoEthRecipient from '../test/generated-artifacts/TestNoEthRecipi | ||||
| import * as TestOrderSignerRegistryWithContractWallet from '../test/generated-artifacts/TestOrderSignerRegistryWithContractWallet.json'; | ||||
| import * as TestPermissionlessTransformerDeployerSuicidal from '../test/generated-artifacts/TestPermissionlessTransformerDeployerSuicidal.json'; | ||||
| import * as TestPermissionlessTransformerDeployerTransformer from '../test/generated-artifacts/TestPermissionlessTransformerDeployerTransformer.json'; | ||||
| import * as TestPropertyValidator from '../test/generated-artifacts/TestPropertyValidator.json'; | ||||
| import * as TestRfqOriginRegistration from '../test/generated-artifacts/TestRfqOriginRegistration.json'; | ||||
| import * as TestSimpleFunctionRegistryFeatureImpl1 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl1.json'; | ||||
| import * as TestSimpleFunctionRegistryFeatureImpl2 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl2.json'; | ||||
| @@ -179,6 +203,8 @@ export const artifacts = { | ||||
|     ZeroEx: ZeroEx as ContractArtifact, | ||||
|     ZeroExOptimized: ZeroExOptimized as ContractArtifact, | ||||
|     LibCommonRichErrors: LibCommonRichErrors as ContractArtifact, | ||||
|     LibERC1155OrdersRichErrors: LibERC1155OrdersRichErrors as ContractArtifact, | ||||
|     LibERC721OrdersRichErrors: LibERC721OrdersRichErrors as ContractArtifact, | ||||
|     LibLiquidityProviderRichErrors: LibLiquidityProviderRichErrors as ContractArtifact, | ||||
|     LibMetaTransactionsRichErrors: LibMetaTransactionsRichErrors as ContractArtifact, | ||||
|     LibNativeOrdersRichErrors: LibNativeOrdersRichErrors as ContractArtifact, | ||||
| @@ -199,6 +225,8 @@ export const artifacts = { | ||||
|     TransformerDeployer: TransformerDeployer as ContractArtifact, | ||||
|     BatchFillNativeOrdersFeature: BatchFillNativeOrdersFeature as ContractArtifact, | ||||
|     BootstrapFeature: BootstrapFeature as ContractArtifact, | ||||
|     ERC1155OrdersFeature: ERC1155OrdersFeature as ContractArtifact, | ||||
|     ERC721OrdersFeature: ERC721OrdersFeature as ContractArtifact, | ||||
|     FundRecoveryFeature: FundRecoveryFeature as ContractArtifact, | ||||
|     LiquidityProviderFeature: LiquidityProviderFeature as ContractArtifact, | ||||
|     MetaTransactionsFeature: MetaTransactionsFeature as ContractArtifact, | ||||
| @@ -212,6 +240,8 @@ export const artifacts = { | ||||
|     UniswapV3Feature: UniswapV3Feature as ContractArtifact, | ||||
|     IBatchFillNativeOrdersFeature: IBatchFillNativeOrdersFeature as ContractArtifact, | ||||
|     IBootstrapFeature: IBootstrapFeature as ContractArtifact, | ||||
|     IERC1155OrdersFeature: IERC1155OrdersFeature as ContractArtifact, | ||||
|     IERC721OrdersFeature: IERC721OrdersFeature as ContractArtifact, | ||||
|     IFeature: IFeature as ContractArtifact, | ||||
|     IFundRecoveryFeature: IFundRecoveryFeature as ContractArtifact, | ||||
|     ILiquidityProviderFeature: ILiquidityProviderFeature as ContractArtifact, | ||||
| @@ -227,6 +257,8 @@ export const artifacts = { | ||||
|     ITransformERC20Feature: ITransformERC20Feature as ContractArtifact, | ||||
|     IUniswapFeature: IUniswapFeature as ContractArtifact, | ||||
|     IUniswapV3Feature: IUniswapV3Feature as ContractArtifact, | ||||
|     LibERC1155Order: LibERC1155Order as ContractArtifact, | ||||
|     LibERC721Order: LibERC721Order as ContractArtifact, | ||||
|     LibNativeOrder: LibNativeOrder as ContractArtifact, | ||||
|     LibSignature: LibSignature as ContractArtifact, | ||||
|     MultiplexFeature: MultiplexFeature as ContractArtifact, | ||||
| @@ -242,6 +274,8 @@ export const artifacts = { | ||||
|     NativeOrdersSettlement: NativeOrdersSettlement as ContractArtifact, | ||||
|     FixinCommon: FixinCommon as ContractArtifact, | ||||
|     FixinEIP712: FixinEIP712 as ContractArtifact, | ||||
|     FixinERC1155Spender: FixinERC1155Spender as ContractArtifact, | ||||
|     FixinERC721Spender: FixinERC721Spender as ContractArtifact, | ||||
|     FixinProtocolFees: FixinProtocolFees as ContractArtifact, | ||||
|     FixinReentrancyGuard: FixinReentrancyGuard as ContractArtifact, | ||||
|     FixinTokenSpender: FixinTokenSpender as ContractArtifact, | ||||
| @@ -251,6 +285,8 @@ export const artifacts = { | ||||
|     InitialMigration: InitialMigration as ContractArtifact, | ||||
|     LibBootstrap: LibBootstrap as ContractArtifact, | ||||
|     LibMigrate: LibMigrate as ContractArtifact, | ||||
|     LibERC1155OrdersStorage: LibERC1155OrdersStorage as ContractArtifact, | ||||
|     LibERC721OrdersStorage: LibERC721OrdersStorage as ContractArtifact, | ||||
|     LibMetaTransactionsStorage: LibMetaTransactionsStorage as ContractArtifact, | ||||
|     LibNativeOrdersStorage: LibNativeOrdersStorage as ContractArtifact, | ||||
|     LibOtcOrdersStorage: LibOtcOrdersStorage as ContractArtifact, | ||||
| @@ -272,10 +308,12 @@ export const artifacts = { | ||||
|     BridgeAdapter: BridgeAdapter as ContractArtifact, | ||||
|     BridgeProtocols: BridgeProtocols as ContractArtifact, | ||||
|     IBridgeAdapter: IBridgeAdapter as ContractArtifact, | ||||
|     MixinAaveV2: MixinAaveV2 as ContractArtifact, | ||||
|     MixinBalancer: MixinBalancer as ContractArtifact, | ||||
|     MixinBalancerV2: MixinBalancerV2 as ContractArtifact, | ||||
|     MixinBancor: MixinBancor as ContractArtifact, | ||||
|     MixinCoFiX: MixinCoFiX as ContractArtifact, | ||||
|     MixinCompound: MixinCompound as ContractArtifact, | ||||
|     MixinCryptoCom: MixinCryptoCom as ContractArtifact, | ||||
|     MixinCurve: MixinCurve as ContractArtifact, | ||||
|     MixinCurveV2: MixinCurveV2 as ContractArtifact, | ||||
| @@ -294,8 +332,14 @@ export const artifacts = { | ||||
|     MixinUniswapV2: MixinUniswapV2 as ContractArtifact, | ||||
|     MixinUniswapV3: MixinUniswapV3 as ContractArtifact, | ||||
|     MixinZeroExBridge: MixinZeroExBridge as ContractArtifact, | ||||
|     IERC1155OrderCallback: IERC1155OrderCallback as ContractArtifact, | ||||
|     IERC1155Token: IERC1155Token as ContractArtifact, | ||||
|     IERC721OrderCallback: IERC721OrderCallback as ContractArtifact, | ||||
|     IERC721Token: IERC721Token as ContractArtifact, | ||||
|     IFeeRecipient: IFeeRecipient as ContractArtifact, | ||||
|     ILiquidityProvider: ILiquidityProvider as ContractArtifact, | ||||
|     IMooniswapPool: IMooniswapPool as ContractArtifact, | ||||
|     IPropertyValidator: IPropertyValidator as ContractArtifact, | ||||
|     IUniswapV2Pair: IUniswapV2Pair as ContractArtifact, | ||||
|     IUniswapV3Pool: IUniswapV3Pool as ContractArtifact, | ||||
|     IERC20Bridge: IERC20Bridge as ContractArtifact, | ||||
| @@ -303,9 +347,10 @@ export const artifacts = { | ||||
|     ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact, | ||||
|     TestBridge: TestBridge as ContractArtifact, | ||||
|     TestCallTarget: TestCallTarget as ContractArtifact, | ||||
|     TestCurve: TestCurve as ContractArtifact, | ||||
|     TestDelegateCaller: TestDelegateCaller as ContractArtifact, | ||||
|     TestERC721OrderPresigner: TestERC721OrderPresigner as ContractArtifact, | ||||
|     TestFeeCollectorController: TestFeeCollectorController as ContractArtifact, | ||||
|     TestFeeRecipient: TestFeeRecipient as ContractArtifact, | ||||
|     TestFillQuoteTransformerBridge: TestFillQuoteTransformerBridge as ContractArtifact, | ||||
|     TestFillQuoteTransformerExchange: TestFillQuoteTransformerExchange as ContractArtifact, | ||||
|     TestFillQuoteTransformerHost: TestFillQuoteTransformerHost as ContractArtifact, | ||||
| @@ -315,33 +360,36 @@ export const artifacts = { | ||||
|     TestInitialMigration: TestInitialMigration as ContractArtifact, | ||||
|     TestLibNativeOrder: TestLibNativeOrder as ContractArtifact, | ||||
|     TestLibSignature: TestLibSignature as ContractArtifact, | ||||
|     TestLiquidityProvider: TestLiquidityProvider as ContractArtifact, | ||||
|     TestMetaTransactionsNativeOrdersFeature: TestMetaTransactionsNativeOrdersFeature as ContractArtifact, | ||||
|     TestMetaTransactionsTransformERC20Feature: TestMetaTransactionsTransformERC20Feature as ContractArtifact, | ||||
|     TestMigrator: TestMigrator as ContractArtifact, | ||||
|     TestMintTokenERC20Transformer: TestMintTokenERC20Transformer as ContractArtifact, | ||||
|     TestMintableERC20Token: TestMintableERC20Token as ContractArtifact, | ||||
|     TestMooniswap: TestMooniswap as ContractArtifact, | ||||
|     TestNativeOrdersFeature: TestNativeOrdersFeature as ContractArtifact, | ||||
|     TestNoEthRecipient: TestNoEthRecipient as ContractArtifact, | ||||
|     TestOrderSignerRegistryWithContractWallet: TestOrderSignerRegistryWithContractWallet as ContractArtifact, | ||||
|     TestPermissionlessTransformerDeployerSuicidal: TestPermissionlessTransformerDeployerSuicidal as ContractArtifact, | ||||
|     TestPermissionlessTransformerDeployerTransformer: TestPermissionlessTransformerDeployerTransformer as ContractArtifact, | ||||
|     TestPropertyValidator: TestPropertyValidator as ContractArtifact, | ||||
|     TestRfqOriginRegistration: TestRfqOriginRegistration as ContractArtifact, | ||||
|     TestSimpleFunctionRegistryFeatureImpl1: TestSimpleFunctionRegistryFeatureImpl1 as ContractArtifact, | ||||
|     TestSimpleFunctionRegistryFeatureImpl2: TestSimpleFunctionRegistryFeatureImpl2 as ContractArtifact, | ||||
|     TestStaking: TestStaking as ContractArtifact, | ||||
|     TestTokenSpenderERC20Token: TestTokenSpenderERC20Token as ContractArtifact, | ||||
|     TestTransformERC20: TestTransformERC20 as ContractArtifact, | ||||
|     TestTransformerBase: TestTransformerBase as ContractArtifact, | ||||
|     TestTransformerDeployerTransformer: TestTransformerDeployerTransformer as ContractArtifact, | ||||
|     TestTransformerHost: TestTransformerHost as ContractArtifact, | ||||
|     TestUniswapV3Feature: TestUniswapV3Feature as ContractArtifact, | ||||
|     TestWethTransformerHost: TestWethTransformerHost as ContractArtifact, | ||||
|     TestZeroExFeature: TestZeroExFeature as ContractArtifact, | ||||
|     TestCurve: TestCurve as ContractArtifact, | ||||
|     TestLiquidityProvider: TestLiquidityProvider as ContractArtifact, | ||||
|     TestMooniswap: TestMooniswap as ContractArtifact, | ||||
|     TestUniswapV2Factory: TestUniswapV2Factory as ContractArtifact, | ||||
|     TestUniswapV2Pool: TestUniswapV2Pool as ContractArtifact, | ||||
|     TestUniswapV3Factory: TestUniswapV3Factory as ContractArtifact, | ||||
|     TestUniswapV3Feature: TestUniswapV3Feature as ContractArtifact, | ||||
|     TestUniswapV3Pool: TestUniswapV3Pool as ContractArtifact, | ||||
|     TestMintableERC20Token: TestMintableERC20Token as ContractArtifact, | ||||
|     TestMintableERC721Token: TestMintableERC721Token as ContractArtifact, | ||||
|     TestTokenSpenderERC20Token: TestTokenSpenderERC20Token as ContractArtifact, | ||||
|     TestWeth: TestWeth as ContractArtifact, | ||||
|     TestWethTransformerHost: TestWethTransformerHost as ContractArtifact, | ||||
|     TestZeroExFeature: TestZeroExFeature as ContractArtifact, | ||||
| }; | ||||
|   | ||||
							
								
								
									
										1756
									
								
								contracts/zero-ex/test/features/erc721_orders_test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1756
									
								
								contracts/zero-ex/test/features/erc721_orders_test.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -38,6 +38,7 @@ blockchainTests.resets('MetaTransactions feature', env => { | ||||
|     let nativeOrdersFeature: TestMetaTransactionsNativeOrdersFeatureContract; | ||||
|  | ||||
|     const MAX_FEE_AMOUNT = new BigNumber('1e18'); | ||||
|     const TRANSFORM_ERC20_ONE_WEI_VALUE = new BigNumber(555); | ||||
|     const TRANSFORM_ERC20_FAILING_VALUE = new BigNumber(666); | ||||
|     const TRANSFORM_ERC20_REENTER_VALUE = new BigNumber(777); | ||||
|     const TRANSFORM_ERC20_BATCH_REENTER_VALUE = new BigNumber(888); | ||||
| @@ -597,7 +598,7 @@ blockchainTests.resets('MetaTransactions feature', env => { | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         it('cannot reenter `executeMetaTransaction()`', async () => { | ||||
|         it('cannot reduce initial ETH balance', async () => { | ||||
|             const args = getRandomTransformERC20Args(); | ||||
|             const mtx = getRandomMetaTransaction({ | ||||
|                 callData: transformERC20Feature | ||||
| @@ -609,58 +610,23 @@ blockchainTests.resets('MetaTransactions feature', env => { | ||||
|                         args.transformations, | ||||
|                     ) | ||||
|                     .getABIEncodedTransactionData(), | ||||
|                 value: TRANSFORM_ERC20_REENTER_VALUE, | ||||
|                 value: TRANSFORM_ERC20_ONE_WEI_VALUE, | ||||
|             }); | ||||
|             const mtxHash = mtx.getHash(); | ||||
|             const signature = await mtx.getSignatureWithProviderAsync(env.provider); | ||||
|             const callOpts = { | ||||
|                 gasPrice: mtx.maxGasPrice, | ||||
|                 value: mtx.value, | ||||
|             }; | ||||
|             const tx = feature.executeMetaTransaction(mtx, signature).awaitTransactionSuccessAsync(callOpts); | ||||
|             return expect(tx).to.revertWith( | ||||
|                 new ZeroExRevertErrors.MetaTransactions.MetaTransactionCallFailedError( | ||||
|                     mtxHash, | ||||
|                     undefined, | ||||
|                     new ZeroExRevertErrors.Common.IllegalReentrancyError( | ||||
|                         feature.getSelector('executeMetaTransaction'), | ||||
|                         REENTRANCY_FLAG_MTX, | ||||
|                     ).encode(), | ||||
|                 ), | ||||
|             // Send pre-existing ETH to the EP. | ||||
|             await env.web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                 await env.web3Wrapper.sendTransactionAsync({ | ||||
|                     from: owner, | ||||
|                     to: zeroEx.address, | ||||
|                     value: new BigNumber(1), | ||||
|                 }), | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         it('cannot reenter `batchExecuteMetaTransactions()`', async () => { | ||||
|             const args = getRandomTransformERC20Args(); | ||||
|             const mtx = getRandomMetaTransaction({ | ||||
|                 callData: transformERC20Feature | ||||
|                     .transformERC20( | ||||
|                         args.inputToken, | ||||
|                         args.outputToken, | ||||
|                         args.inputTokenAmount, | ||||
|                         args.minOutputTokenAmount, | ||||
|                         args.transformations, | ||||
|                     ) | ||||
|                     .getABIEncodedTransactionData(), | ||||
|                 value: TRANSFORM_ERC20_BATCH_REENTER_VALUE, | ||||
|             }); | ||||
|             const mtxHash = mtx.getHash(); | ||||
|             const signature = await mtx.getSignatureWithProviderAsync(env.provider); | ||||
|             const callOpts = { | ||||
|                 gasPrice: mtx.maxGasPrice, | ||||
|                 value: mtx.value, | ||||
|             }; | ||||
|             const tx = feature.executeMetaTransaction(mtx, signature).awaitTransactionSuccessAsync(callOpts); | ||||
|             return expect(tx).to.revertWith( | ||||
|                 new ZeroExRevertErrors.MetaTransactions.MetaTransactionCallFailedError( | ||||
|                     mtxHash, | ||||
|                     undefined, | ||||
|                     new ZeroExRevertErrors.Common.IllegalReentrancyError( | ||||
|                         feature.getSelector('batchExecuteMetaTransactions'), | ||||
|                         REENTRANCY_FLAG_MTX, | ||||
|                     ).encode(), | ||||
|                 ), | ||||
|             ); | ||||
|             return expect(tx).to.revertWith('MetaTransactionsFeature/ETH_LEAK'); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
| @@ -817,6 +783,37 @@ blockchainTests.resets('MetaTransactions feature', env => { | ||||
|                 ), | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         it('cannot reduce initial ETH balance', async () => { | ||||
|             const args = getRandomTransformERC20Args(); | ||||
|             const mtx = getRandomMetaTransaction({ | ||||
|                 callData: transformERC20Feature | ||||
|                     .transformERC20( | ||||
|                         args.inputToken, | ||||
|                         args.outputToken, | ||||
|                         args.inputTokenAmount, | ||||
|                         args.minOutputTokenAmount, | ||||
|                         args.transformations, | ||||
|                     ) | ||||
|                     .getABIEncodedTransactionData(), | ||||
|                 value: TRANSFORM_ERC20_ONE_WEI_VALUE, | ||||
|             }); | ||||
|             const signature = await mtx.getSignatureWithProviderAsync(env.provider); | ||||
|             const callOpts = { | ||||
|                 gasPrice: mtx.maxGasPrice, | ||||
|                 value: mtx.value, | ||||
|             }; | ||||
|             // Send pre-existing ETH to the EP. | ||||
|             await env.web3Wrapper.awaitTransactionSuccessAsync( | ||||
|                 await env.web3Wrapper.sendTransactionAsync({ | ||||
|                     from: owner, | ||||
|                     to: zeroEx.address, | ||||
|                     value: new BigNumber(1), | ||||
|                 }), | ||||
|             ); | ||||
|             const tx = feature.batchExecuteMetaTransactions([mtx], [signature]).awaitTransactionSuccessAsync(callOpts); | ||||
|             return expect(tx).to.revertWith('MetaTransactionsFeature/ETH_LEAK'); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('getMetaTransactionExecutedBlock()', () => { | ||||
|   | ||||
							
								
								
									
										22
									
								
								contracts/zero-ex/test/utils/erc721_orders.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								contracts/zero-ex/test/utils/erc721_orders.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| import { constants, getRandomInteger, randomAddress } from '@0x/contracts-test-utils'; | ||||
| import { ERC721Order } from '@0x/protocol-utils'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
|  | ||||
| /** | ||||
|  * Generate a random ERC721 Order | ||||
|  */ | ||||
| export function getRandomERC721Order(fields: Partial<ERC721Order> = {}): ERC721Order { | ||||
|     return new ERC721Order({ | ||||
|         erc20Token: randomAddress(), | ||||
|         erc20TokenAmount: getRandomInteger('1e18', '10e18'), | ||||
|         erc721Token: randomAddress(), | ||||
|         erc721TokenId: getRandomInteger(0, constants.MAX_UINT256), | ||||
|         maker: randomAddress(), | ||||
|         taker: randomAddress(), | ||||
|         erc721TokenProperties: [], | ||||
|         fees: [], | ||||
|         nonce: getRandomInteger(0, constants.MAX_UINT256), | ||||
|         expiry: new BigNumber(Math.floor(Date.now() / 1000 + 60)), | ||||
|         ...fields, | ||||
|     }); | ||||
| } | ||||
| @@ -9,11 +9,15 @@ export * from '../test/generated-wrappers/bootstrap_feature'; | ||||
| export * from '../test/generated-wrappers/bridge_adapter'; | ||||
| export * from '../test/generated-wrappers/bridge_protocols'; | ||||
| export * from '../test/generated-wrappers/curve_liquidity_provider'; | ||||
| export * from '../test/generated-wrappers/erc1155_orders_feature'; | ||||
| export * from '../test/generated-wrappers/erc721_orders_feature'; | ||||
| export * from '../test/generated-wrappers/fee_collector'; | ||||
| export * from '../test/generated-wrappers/fee_collector_controller'; | ||||
| export * from '../test/generated-wrappers/fill_quote_transformer'; | ||||
| export * from '../test/generated-wrappers/fixin_common'; | ||||
| export * from '../test/generated-wrappers/fixin_e_i_p712'; | ||||
| export * from '../test/generated-wrappers/fixin_erc1155_spender'; | ||||
| export * from '../test/generated-wrappers/fixin_erc721_spender'; | ||||
| export * from '../test/generated-wrappers/fixin_protocol_fees'; | ||||
| export * from '../test/generated-wrappers/fixin_reentrancy_guard'; | ||||
| export * from '../test/generated-wrappers/fixin_token_spender'; | ||||
| @@ -23,9 +27,16 @@ export * from '../test/generated-wrappers/fund_recovery_feature'; | ||||
| export * from '../test/generated-wrappers/i_batch_fill_native_orders_feature'; | ||||
| export * from '../test/generated-wrappers/i_bootstrap_feature'; | ||||
| export * from '../test/generated-wrappers/i_bridge_adapter'; | ||||
| export * from '../test/generated-wrappers/i_erc1155_order_callback'; | ||||
| export * from '../test/generated-wrappers/i_erc1155_orders_feature'; | ||||
| export * from '../test/generated-wrappers/i_erc1155_token'; | ||||
| export * from '../test/generated-wrappers/i_erc20_bridge'; | ||||
| export * from '../test/generated-wrappers/i_erc20_transformer'; | ||||
| export * from '../test/generated-wrappers/i_erc721_order_callback'; | ||||
| export * from '../test/generated-wrappers/i_erc721_orders_feature'; | ||||
| export * from '../test/generated-wrappers/i_erc721_token'; | ||||
| export * from '../test/generated-wrappers/i_feature'; | ||||
| export * from '../test/generated-wrappers/i_fee_recipient'; | ||||
| export * from '../test/generated-wrappers/i_flash_wallet'; | ||||
| export * from '../test/generated-wrappers/i_fund_recovery_feature'; | ||||
| export * from '../test/generated-wrappers/i_liquidity_provider'; | ||||
| @@ -39,6 +50,7 @@ export * from '../test/generated-wrappers/i_native_orders_feature'; | ||||
| export * from '../test/generated-wrappers/i_otc_orders_feature'; | ||||
| export * from '../test/generated-wrappers/i_ownable_feature'; | ||||
| export * from '../test/generated-wrappers/i_pancake_swap_feature'; | ||||
| export * from '../test/generated-wrappers/i_property_validator'; | ||||
| export * from '../test/generated-wrappers/i_simple_function_registry_feature'; | ||||
| export * from '../test/generated-wrappers/i_staking'; | ||||
| export * from '../test/generated-wrappers/i_test_simple_function_registry_feature'; | ||||
| @@ -52,7 +64,13 @@ export * from '../test/generated-wrappers/i_zero_ex'; | ||||
| export * from '../test/generated-wrappers/initial_migration'; | ||||
| export * from '../test/generated-wrappers/lib_bootstrap'; | ||||
| export * from '../test/generated-wrappers/lib_common_rich_errors'; | ||||
| export * from '../test/generated-wrappers/lib_erc1155_order'; | ||||
| export * from '../test/generated-wrappers/lib_erc1155_orders_rich_errors'; | ||||
| export * from '../test/generated-wrappers/lib_erc1155_orders_storage'; | ||||
| export * from '../test/generated-wrappers/lib_erc20_transformer'; | ||||
| export * from '../test/generated-wrappers/lib_erc721_order'; | ||||
| export * from '../test/generated-wrappers/lib_erc721_orders_rich_errors'; | ||||
| export * from '../test/generated-wrappers/lib_erc721_orders_storage'; | ||||
| export * from '../test/generated-wrappers/lib_fee_collector'; | ||||
| export * from '../test/generated-wrappers/lib_liquidity_provider_rich_errors'; | ||||
| export * from '../test/generated-wrappers/lib_meta_transactions_rich_errors'; | ||||
| @@ -79,10 +97,12 @@ export * from '../test/generated-wrappers/liquidity_provider_feature'; | ||||
| export * from '../test/generated-wrappers/liquidity_provider_sandbox'; | ||||
| export * from '../test/generated-wrappers/log_metadata_transformer'; | ||||
| export * from '../test/generated-wrappers/meta_transactions_feature'; | ||||
| export * from '../test/generated-wrappers/mixin_aave_v2'; | ||||
| export * from '../test/generated-wrappers/mixin_balancer'; | ||||
| export * from '../test/generated-wrappers/mixin_balancer_v2'; | ||||
| export * from '../test/generated-wrappers/mixin_bancor'; | ||||
| export * from '../test/generated-wrappers/mixin_co_fi_x'; | ||||
| export * from '../test/generated-wrappers/mixin_compound'; | ||||
| export * from '../test/generated-wrappers/mixin_crypto_com'; | ||||
| export * from '../test/generated-wrappers/mixin_curve'; | ||||
| export * from '../test/generated-wrappers/mixin_curve_v2'; | ||||
| @@ -125,7 +145,9 @@ export * from '../test/generated-wrappers/test_bridge'; | ||||
| export * from '../test/generated-wrappers/test_call_target'; | ||||
| export * from '../test/generated-wrappers/test_curve'; | ||||
| export * from '../test/generated-wrappers/test_delegate_caller'; | ||||
| export * from '../test/generated-wrappers/test_erc721_order_presigner'; | ||||
| export * from '../test/generated-wrappers/test_fee_collector_controller'; | ||||
| export * from '../test/generated-wrappers/test_fee_recipient'; | ||||
| export * from '../test/generated-wrappers/test_fill_quote_transformer_bridge'; | ||||
| export * from '../test/generated-wrappers/test_fill_quote_transformer_exchange'; | ||||
| export * from '../test/generated-wrappers/test_fill_quote_transformer_host'; | ||||
| @@ -141,12 +163,14 @@ export * from '../test/generated-wrappers/test_meta_transactions_transform_erc20 | ||||
| export * from '../test/generated-wrappers/test_migrator'; | ||||
| export * from '../test/generated-wrappers/test_mint_token_erc20_transformer'; | ||||
| export * from '../test/generated-wrappers/test_mintable_erc20_token'; | ||||
| export * from '../test/generated-wrappers/test_mintable_erc721_token'; | ||||
| export * from '../test/generated-wrappers/test_mooniswap'; | ||||
| export * from '../test/generated-wrappers/test_native_orders_feature'; | ||||
| export * from '../test/generated-wrappers/test_no_eth_recipient'; | ||||
| export * from '../test/generated-wrappers/test_order_signer_registry_with_contract_wallet'; | ||||
| export * from '../test/generated-wrappers/test_permissionless_transformer_deployer_suicidal'; | ||||
| export * from '../test/generated-wrappers/test_permissionless_transformer_deployer_transformer'; | ||||
| export * from '../test/generated-wrappers/test_property_validator'; | ||||
| export * from '../test/generated-wrappers/test_rfq_origin_registration'; | ||||
| export * from '../test/generated-wrappers/test_simple_function_registry_feature_impl1'; | ||||
| export * from '../test/generated-wrappers/test_simple_function_registry_feature_impl2'; | ||||
|   | ||||
| @@ -42,11 +42,15 @@ | ||||
|         "test/generated-artifacts/BridgeAdapter.json", | ||||
|         "test/generated-artifacts/BridgeProtocols.json", | ||||
|         "test/generated-artifacts/CurveLiquidityProvider.json", | ||||
|         "test/generated-artifacts/ERC1155OrdersFeature.json", | ||||
|         "test/generated-artifacts/ERC721OrdersFeature.json", | ||||
|         "test/generated-artifacts/FeeCollector.json", | ||||
|         "test/generated-artifacts/FeeCollectorController.json", | ||||
|         "test/generated-artifacts/FillQuoteTransformer.json", | ||||
|         "test/generated-artifacts/FixinCommon.json", | ||||
|         "test/generated-artifacts/FixinEIP712.json", | ||||
|         "test/generated-artifacts/FixinERC1155Spender.json", | ||||
|         "test/generated-artifacts/FixinERC721Spender.json", | ||||
|         "test/generated-artifacts/FixinProtocolFees.json", | ||||
|         "test/generated-artifacts/FixinReentrancyGuard.json", | ||||
|         "test/generated-artifacts/FixinTokenSpender.json", | ||||
| @@ -56,9 +60,16 @@ | ||||
|         "test/generated-artifacts/IBatchFillNativeOrdersFeature.json", | ||||
|         "test/generated-artifacts/IBootstrapFeature.json", | ||||
|         "test/generated-artifacts/IBridgeAdapter.json", | ||||
|         "test/generated-artifacts/IERC1155OrderCallback.json", | ||||
|         "test/generated-artifacts/IERC1155OrdersFeature.json", | ||||
|         "test/generated-artifacts/IERC1155Token.json", | ||||
|         "test/generated-artifacts/IERC20Bridge.json", | ||||
|         "test/generated-artifacts/IERC20Transformer.json", | ||||
|         "test/generated-artifacts/IERC721OrderCallback.json", | ||||
|         "test/generated-artifacts/IERC721OrdersFeature.json", | ||||
|         "test/generated-artifacts/IERC721Token.json", | ||||
|         "test/generated-artifacts/IFeature.json", | ||||
|         "test/generated-artifacts/IFeeRecipient.json", | ||||
|         "test/generated-artifacts/IFlashWallet.json", | ||||
|         "test/generated-artifacts/IFundRecoveryFeature.json", | ||||
|         "test/generated-artifacts/ILiquidityProvider.json", | ||||
| @@ -72,6 +83,7 @@ | ||||
|         "test/generated-artifacts/IOtcOrdersFeature.json", | ||||
|         "test/generated-artifacts/IOwnableFeature.json", | ||||
|         "test/generated-artifacts/IPancakeSwapFeature.json", | ||||
|         "test/generated-artifacts/IPropertyValidator.json", | ||||
|         "test/generated-artifacts/ISimpleFunctionRegistryFeature.json", | ||||
|         "test/generated-artifacts/IStaking.json", | ||||
|         "test/generated-artifacts/ITestSimpleFunctionRegistryFeature.json", | ||||
| @@ -85,7 +97,13 @@ | ||||
|         "test/generated-artifacts/InitialMigration.json", | ||||
|         "test/generated-artifacts/LibBootstrap.json", | ||||
|         "test/generated-artifacts/LibCommonRichErrors.json", | ||||
|         "test/generated-artifacts/LibERC1155Order.json", | ||||
|         "test/generated-artifacts/LibERC1155OrdersRichErrors.json", | ||||
|         "test/generated-artifacts/LibERC1155OrdersStorage.json", | ||||
|         "test/generated-artifacts/LibERC20Transformer.json", | ||||
|         "test/generated-artifacts/LibERC721Order.json", | ||||
|         "test/generated-artifacts/LibERC721OrdersRichErrors.json", | ||||
|         "test/generated-artifacts/LibERC721OrdersStorage.json", | ||||
|         "test/generated-artifacts/LibFeeCollector.json", | ||||
|         "test/generated-artifacts/LibLiquidityProviderRichErrors.json", | ||||
|         "test/generated-artifacts/LibMetaTransactionsRichErrors.json", | ||||
| @@ -112,10 +130,12 @@ | ||||
|         "test/generated-artifacts/LiquidityProviderSandbox.json", | ||||
|         "test/generated-artifacts/LogMetadataTransformer.json", | ||||
|         "test/generated-artifacts/MetaTransactionsFeature.json", | ||||
|         "test/generated-artifacts/MixinAaveV2.json", | ||||
|         "test/generated-artifacts/MixinBalancer.json", | ||||
|         "test/generated-artifacts/MixinBalancerV2.json", | ||||
|         "test/generated-artifacts/MixinBancor.json", | ||||
|         "test/generated-artifacts/MixinCoFiX.json", | ||||
|         "test/generated-artifacts/MixinCompound.json", | ||||
|         "test/generated-artifacts/MixinCryptoCom.json", | ||||
|         "test/generated-artifacts/MixinCurve.json", | ||||
|         "test/generated-artifacts/MixinCurveV2.json", | ||||
| @@ -158,7 +178,9 @@ | ||||
|         "test/generated-artifacts/TestCallTarget.json", | ||||
|         "test/generated-artifacts/TestCurve.json", | ||||
|         "test/generated-artifacts/TestDelegateCaller.json", | ||||
|         "test/generated-artifacts/TestERC721OrderPresigner.json", | ||||
|         "test/generated-artifacts/TestFeeCollectorController.json", | ||||
|         "test/generated-artifacts/TestFeeRecipient.json", | ||||
|         "test/generated-artifacts/TestFillQuoteTransformerBridge.json", | ||||
|         "test/generated-artifacts/TestFillQuoteTransformerExchange.json", | ||||
|         "test/generated-artifacts/TestFillQuoteTransformerHost.json", | ||||
| @@ -174,12 +196,14 @@ | ||||
|         "test/generated-artifacts/TestMigrator.json", | ||||
|         "test/generated-artifacts/TestMintTokenERC20Transformer.json", | ||||
|         "test/generated-artifacts/TestMintableERC20Token.json", | ||||
|         "test/generated-artifacts/TestMintableERC721Token.json", | ||||
|         "test/generated-artifacts/TestMooniswap.json", | ||||
|         "test/generated-artifacts/TestNativeOrdersFeature.json", | ||||
|         "test/generated-artifacts/TestNoEthRecipient.json", | ||||
|         "test/generated-artifacts/TestOrderSignerRegistryWithContractWallet.json", | ||||
|         "test/generated-artifacts/TestPermissionlessTransformerDeployerSuicidal.json", | ||||
|         "test/generated-artifacts/TestPermissionlessTransformerDeployerTransformer.json", | ||||
|         "test/generated-artifacts/TestPropertyValidator.json", | ||||
|         "test/generated-artifacts/TestRfqOriginRegistration.json", | ||||
|         "test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl1.json", | ||||
|         "test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl2.json", | ||||
|   | ||||
| @@ -1,4 +1,196 @@ | ||||
| [ | ||||
|     { | ||||
|         "version": "16.46.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Enable `Curve` ETH/CVX pool", | ||||
|                 "pr": 394 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1641863395 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.45.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Handle 0 output samples and negative adjusted rate native orders in routing", | ||||
|                 "pr": 387 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1641827361 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.45.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Update `Celo` intermediate tokens", | ||||
|                 "pr": 390 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1641359319 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.45.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Capture router timings", | ||||
|                 "pr": 388 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1641308410 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.44.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Update neon-router and use router estimated output amount", | ||||
|                 "pr": 354 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1640778328 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.43.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "`UniswapV3` support for `Optimism`", | ||||
|                 "pr": 385 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1640364306 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.42.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "`UniswapV3` support for `Polygon`", | ||||
|                 "pr": 382 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Update `Beethoven` Graphql url", | ||||
|                 "pr": 383 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1640124159 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.41.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Update mcusd contract address, and made celo native asset", | ||||
|                 "pr": 376 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1638827302 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.40.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add `AaveV2` and `Compound` deposit/withdrawal liquidity source", | ||||
|                 "pr": 321 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1638390144 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.39.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Curve ETH/CRV pool", | ||||
|                 "pr": 378 | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.38.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Capture sampler metrics", | ||||
|                 "pr": 374 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1638228231 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.37.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Changed Sushiswap router address", | ||||
|                 "pr": 373 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1637349338 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.36.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Specify liquid routes for FEI/TRIBE FXS/FRAX and OHM/FRAX", | ||||
|                 "pr": 371 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1637290768 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.35.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add Beethoven X, MorpheusSwap and JetSwap to Fantom", | ||||
|                 "pr": 370 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1637206290 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.34.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add support Celo", | ||||
|                 "pr": 367 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1637102971 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.33.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add support for Uniswap V3 1 bps pools", | ||||
|                 "pr": 366 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1637065617 | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.32.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Extended Quote Report", | ||||
|                 "pr": 361 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1636480845 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1635903615, | ||||
|         "version": "16.31.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Added `Curve`, `Curve_V2` and `KyberDmm` to Avalanche", | ||||
|                 "pr": 363 | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1635903615, | ||||
|         "version": "16.30.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "16.30.0", | ||||
|         "changes": [ | ||||
|   | ||||
| @@ -5,6 +5,83 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v16.46.0 - _January 11, 2022_ | ||||
|  | ||||
|     * Enable `Curve` ETH/CVX pool (#394) | ||||
|  | ||||
| ## v16.45.2 - _January 10, 2022_ | ||||
|  | ||||
|     * Handle 0 output samples and negative adjusted rate native orders in routing (#387) | ||||
|  | ||||
| ## v16.45.1 - _January 5, 2022_ | ||||
|  | ||||
|     * Update `Celo` intermediate tokens (#390) | ||||
|  | ||||
| ## v16.45.0 - _January 4, 2022_ | ||||
|  | ||||
|     * Capture router timings (#388) | ||||
|  | ||||
| ## v16.44.0 - _December 29, 2021_ | ||||
|  | ||||
|     * Update neon-router and use router estimated output amount (#354) | ||||
|  | ||||
| ## v16.43.0 - _December 24, 2021_ | ||||
|  | ||||
|     * `UniswapV3` support for `Optimism` (#385) | ||||
|  | ||||
| ## v16.42.0 - _December 21, 2021_ | ||||
|  | ||||
|     * `UniswapV3` support for `Polygon` (#382) | ||||
|     * Update `Beethoven` Graphql url (#383) | ||||
|  | ||||
| ## v16.41.0 - _December 6, 2021_ | ||||
|  | ||||
|     * Update mcusd contract address, and made celo native asset (#376) | ||||
|  | ||||
| ## v16.40.0 - _December 1, 2021_ | ||||
|  | ||||
|     * Add `AaveV2` and `Compound` deposit/withdrawal liquidity source (#321) | ||||
|  | ||||
| ## v16.39.0 - _Invalid date_ | ||||
|  | ||||
|     * Curve ETH/CRV pool (#378) | ||||
|  | ||||
| ## v16.38.0 - _November 29, 2021_ | ||||
|  | ||||
|     * Capture sampler metrics (#374) | ||||
|  | ||||
| ## v16.37.0 - _November 19, 2021_ | ||||
|  | ||||
|     * Changed Sushiswap router address (#373) | ||||
|  | ||||
| ## v16.36.0 - _November 19, 2021_ | ||||
|  | ||||
|     * Specify liquid routes for FEI/TRIBE FXS/FRAX and OHM/FRAX (#371) | ||||
|  | ||||
| ## v16.35.0 - _November 18, 2021_ | ||||
|  | ||||
|     * Add Beethoven X, MorpheusSwap and JetSwap to Fantom (#370) | ||||
|  | ||||
| ## v16.34.0 - _November 16, 2021_ | ||||
|  | ||||
|     * Add support Celo (#367) | ||||
|  | ||||
| ## v16.33.0 - _November 16, 2021_ | ||||
|  | ||||
|     * Add support for Uniswap V3 1 bps pools (#366) | ||||
|  | ||||
| ## v16.32.0 - _November 9, 2021_ | ||||
|  | ||||
|     * Extended Quote Report (#361) | ||||
|  | ||||
| ## v16.31.0 - _November 3, 2021_ | ||||
|  | ||||
|     * Added `Curve`, `Curve_V2` and `KyberDmm` to Avalanche (#363) | ||||
|  | ||||
| ## v16.30.1 - _November 3, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v16.30.0 - _October 19, 2021_ | ||||
|  | ||||
|     * Fantom deployment (#347) | ||||
|   | ||||
							
								
								
									
										96
									
								
								packages/asset-swapper/contracts/src/CompoundSampler.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								packages/asset-swapper/contracts/src/CompoundSampler.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "./SamplerUtils.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
|  | ||||
| // Minimal CToken interface | ||||
| interface ICToken { | ||||
|     function mint(uint mintAmount) external returns (uint); | ||||
|     function redeem(uint redeemTokens) external returns (uint); | ||||
|     function redeemUnderlying(uint redeemAmount) external returns (uint); | ||||
|     function exchangeRateStored() external view returns (uint); | ||||
|     function decimals() external view returns (uint8); | ||||
| } | ||||
|  | ||||
| contract CompoundSampler is SamplerUtils { | ||||
|     uint256 constant private EXCHANGE_RATE_SCALE = 1e10; | ||||
|  | ||||
|     function sampleSellsFromCompound( | ||||
|         ICToken cToken, | ||||
|         IERC20TokenV06 takerToken, | ||||
|         IERC20TokenV06 makerToken, | ||||
|         uint256[] memory takerTokenAmounts | ||||
|     ) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256[] memory makerTokenAmounts) | ||||
|     { | ||||
|         uint256 numSamples = takerTokenAmounts.length; | ||||
|         makerTokenAmounts = new uint256[](numSamples); | ||||
|         // Exchange rate is scaled by 1 * 10^(18 - 8 + Underlying Token Decimals | ||||
|         uint256 exchangeRate = cToken.exchangeRateStored(); | ||||
|         uint256 cTokenDecimals = uint256(cToken.decimals()); | ||||
|  | ||||
|         if (address(makerToken) == address(cToken)) { | ||||
|             // mint | ||||
|             for (uint256 i = 0; i < numSamples; i++) { | ||||
|                 makerTokenAmounts[i] = (takerTokenAmounts[i] * EXCHANGE_RATE_SCALE * 10 ** cTokenDecimals) / exchangeRate; | ||||
|             } | ||||
|  | ||||
|         } else if (address(takerToken) == address(cToken)) { | ||||
|             // redeem | ||||
|             for (uint256 i = 0; i < numSamples; i++) { | ||||
|                 makerTokenAmounts[i] = (takerTokenAmounts[i] * exchangeRate) / (EXCHANGE_RATE_SCALE * 10 ** cTokenDecimals); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function sampleBuysFromCompound( | ||||
|         ICToken cToken, | ||||
|         IERC20TokenV06 takerToken, | ||||
|         IERC20TokenV06 makerToken, | ||||
|         uint256[] memory makerTokenAmounts | ||||
|     ) | ||||
|         public | ||||
|         view | ||||
|         returns (uint256[] memory takerTokenAmounts) | ||||
|     { | ||||
|         uint256 numSamples = makerTokenAmounts.length; | ||||
|         takerTokenAmounts = new uint256[](numSamples); | ||||
|         // Exchange rate is scaled by 1 * 10^(18 - 8 + Underlying Token Decimals | ||||
|         uint256 exchangeRate = cToken.exchangeRateStored(); | ||||
|         uint256 cTokenDecimals = uint256(cToken.decimals()); | ||||
|  | ||||
|         if (address(makerToken) == address(cToken)) { | ||||
|             // mint | ||||
|             for (uint256 i = 0; i < numSamples; i++) { | ||||
|                 takerTokenAmounts[i] = makerTokenAmounts[i] * exchangeRate / (EXCHANGE_RATE_SCALE * 10 ** cTokenDecimals); | ||||
|             } | ||||
|         } else if (address(takerToken) == address(cToken)) { | ||||
|             // redeem | ||||
|             for (uint256 i = 0; i < numSamples; i++) { | ||||
|                 takerTokenAmounts[i] = (makerTokenAmounts[i] * EXCHANGE_RATE_SCALE * 10 ** cTokenDecimals)/exchangeRate; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -23,6 +23,7 @@ pragma experimental ABIEncoderV2; | ||||
| import "./BalancerSampler.sol"; | ||||
| import "./BalancerV2Sampler.sol"; | ||||
| import "./BancorSampler.sol"; | ||||
| import "./CompoundSampler.sol"; | ||||
| import "./CurveSampler.sol"; | ||||
| import "./DODOSampler.sol"; | ||||
| import "./DODOV2Sampler.sol"; | ||||
| @@ -48,6 +49,7 @@ contract ERC20BridgeSampler is | ||||
|     BalancerSampler, | ||||
|     BalancerV2Sampler, | ||||
|     BancorSampler, | ||||
|     CompoundSampler, | ||||
|     CurveSampler, | ||||
|     DODOSampler, | ||||
|     DODOV2Sampler, | ||||
|   | ||||
| @@ -159,8 +159,11 @@ contract KyberDmmSampler | ||||
|                     (path[i], path[i + 1]) | ||||
|                 returns (address[] memory allPools) | ||||
|             { | ||||
|                 if (allPools.length == 0) { | ||||
|                     return new address[](0); | ||||
|                 } | ||||
|  | ||||
|                 uint256 maxSupply = 0; | ||||
|                 require(allPools.length >= 1, "KyberDMMSampler/NO_POOLS_FOUND"); | ||||
|                 for (uint256 j = 0; j < allPools.length; j++) { | ||||
|                     uint256 totalSupply = IKyberDmmPool(allPools[j]).totalSupply(); | ||||
|                     if (totalSupply > maxSupply) { | ||||
|   | ||||
| @@ -51,7 +51,7 @@ interface IUniswapV3Pool { | ||||
| contract UniswapV3Sampler | ||||
| { | ||||
|     /// @dev Gas limit for UniswapV3 calls. This is 100% a guess. | ||||
|     uint256 constant private QUOTE_GAS = 300e3; | ||||
|     uint256 constant private QUOTE_GAS = 600e3; | ||||
|  | ||||
|     /// @dev Sample sell quotes from UniswapV3. | ||||
|     /// @param quoter UniswapV3 Quoter contract. | ||||
| @@ -174,8 +174,9 @@ contract UniswapV3Sampler | ||||
|             tokenPath.length - startIndex >= 2, | ||||
|             "UniswapV3Sampler/tokenPath too short" | ||||
|         ); | ||||
|         uint24[3] memory validPoolFees = [ | ||||
|         uint24[4] memory validPoolFees = [ | ||||
|             // The launch pool fees. Could get hairier if they add more. | ||||
|             uint24(0.0001e6), | ||||
|             uint24(0.0005e6), | ||||
|             uint24(0.003e6), | ||||
|             uint24(0.01e6) | ||||
|   | ||||
| @@ -77,4 +77,19 @@ contract UtilitySampler { | ||||
|         assembly { size := extcodesize(account) } | ||||
|         return size > 0; | ||||
|     } | ||||
|  | ||||
|     function getGasLeft() | ||||
|         public | ||||
|         returns (uint256) | ||||
|     { | ||||
|         return gasleft(); | ||||
|     } | ||||
|  | ||||
|     function getBlockNumber() | ||||
|         public | ||||
|         view | ||||
|         returns (uint256) | ||||
|     { | ||||
|         return block.number; | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/asset-swapper", | ||||
|     "version": "16.30.0", | ||||
|     "version": "16.46.0", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -39,7 +39,7 @@ | ||||
|     "config": { | ||||
|         "publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker", | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", | ||||
|         "abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BalancerV2Sampler|BancorSampler|CurveSampler|DODOSampler|DODOV2Sampler|DummyLiquidityProvider|ERC20BridgeSampler|FakeTaker|IBalancer|IBancor|ICurve|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|ISmoothy|IUniswapExchangeQuotes|IUniswapV2Router01|KyberDmmSampler|KyberSampler|LidoSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SmoothySampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UniswapV3Sampler|UtilitySampler).json", | ||||
|         "abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BalancerV2Sampler|BancorSampler|CompoundSampler|CurveSampler|DODOSampler|DODOV2Sampler|DummyLiquidityProvider|ERC20BridgeSampler|FakeTaker|IBalancer|IBancor|ICurve|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|ISmoothy|IUniswapExchangeQuotes|IUniswapV2Router01|KyberDmmSampler|KyberSampler|LidoSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SmoothySampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UniswapV3Sampler|UtilitySampler).json", | ||||
|         "postpublish": { | ||||
|             "assets": [] | ||||
|         } | ||||
| @@ -60,14 +60,14 @@ | ||||
|     "dependencies": { | ||||
|         "@0x/assert": "^3.0.29", | ||||
|         "@0x/base-contract": "^6.4.2", | ||||
|         "@0x/contract-addresses": "^6.8.0", | ||||
|         "@0x/contract-wrappers": "^13.18.1", | ||||
|         "@0x/contracts-erc20": "^3.3.21", | ||||
|         "@0x/contracts-zero-ex": "^0.29.2", | ||||
|         "@0x/contract-addresses": "^6.11.0", | ||||
|         "@0x/contract-wrappers": "^13.18.5", | ||||
|         "@0x/contracts-erc20": "^3.3.25", | ||||
|         "@0x/contracts-zero-ex": "^0.30.1", | ||||
|         "@0x/dev-utils": "^4.2.9", | ||||
|         "@0x/json-schemas": "^6.3.0", | ||||
|         "@0x/neon-router": "^0.2.1", | ||||
|         "@0x/protocol-utils": "^1.9.3", | ||||
|         "@0x/neon-router": "^0.3.1", | ||||
|         "@0x/protocol-utils": "^1.10.1", | ||||
|         "@0x/quote-server": "^6.0.6", | ||||
|         "@0x/types": "^3.3.4", | ||||
|         "@0x/typescript-typings": "^5.2.1", | ||||
| @@ -98,10 +98,10 @@ | ||||
|         "@0x/contracts-exchange": "^3.2.38", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.37", | ||||
|         "@0x/contracts-gen": "^2.0.40", | ||||
|         "@0x/contracts-test-utils": "^5.4.12", | ||||
|         "@0x/contracts-utils": "^4.8.2", | ||||
|         "@0x/contracts-test-utils": "^5.4.16", | ||||
|         "@0x/contracts-utils": "^4.8.6", | ||||
|         "@0x/mesh-rpc-client": "^9.4.2", | ||||
|         "@0x/migrations": "^8.1.9", | ||||
|         "@0x/migrations": "^8.1.14", | ||||
|         "@0x/sol-compiler": "^4.7.5", | ||||
|         "@0x/subproviders": "^6.6.0", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|   | ||||
| @@ -28,7 +28,6 @@ const ONE_SECOND_MS = 1000; | ||||
| const ONE_MINUTE_SECS = 60; | ||||
| const ONE_MINUTE_MS = ONE_SECOND_MS * ONE_MINUTE_SECS; | ||||
| const DEFAULT_PER_PAGE = 1000; | ||||
| const ZERO_AMOUNT = new BigNumber(0); | ||||
| const ALT_MM_IMPUTED_INDICATIVE_EXPIRY_SECONDS = 180; | ||||
|  | ||||
| const DEFAULT_ORDER_PRUNER_OPTS: OrderPrunerOpts = { | ||||
| @@ -43,6 +42,7 @@ const PROTOCOL_FEE_MULTIPLIER = new BigNumber(0); | ||||
| // default 50% buffer for selecting native orders to be aggregated with other sources | ||||
| const MARKET_UTILS_AMOUNT_BUFFER_PERCENTAGE = 0.5; | ||||
|  | ||||
| export const ZERO_AMOUNT = new BigNumber(0); | ||||
| const DEFAULT_SWAP_QUOTER_OPTS: SwapQuoterOpts = { | ||||
|     chainId: ChainId.Mainnet, | ||||
|     orderRefreshIntervalMs: 10000, // 10 seconds | ||||
|   | ||||
| @@ -113,6 +113,7 @@ export { | ||||
|     SwapQuoterError, | ||||
|     SwapQuoterOpts, | ||||
|     SwapQuoterRfqOpts, | ||||
|     SamplerMetrics, | ||||
| } from './types'; | ||||
| export { affiliateFeeUtils } from './utils/affiliate_fee_utils'; | ||||
| export { | ||||
| @@ -162,14 +163,20 @@ export { | ||||
| export { ProtocolFeeUtils } from './utils/protocol_fee_utils'; | ||||
| export { | ||||
|     BridgeQuoteReportEntry, | ||||
|     jsonifyFillData, | ||||
|     MultiHopQuoteReportEntry, | ||||
|     NativeLimitOrderQuoteReportEntry, | ||||
|     NativeRfqOrderQuoteReportEntry, | ||||
|     QuoteReport, | ||||
|     QuoteReportEntry, | ||||
|     ExtendedQuoteReport, | ||||
|     ExtendedQuoteReportSources, | ||||
|     ExtendedQuoteReportEntry, | ||||
|     ExtendedQuoteReportIndexedEntry, | ||||
|     ExtendedQuoteReportIndexedEntryOutbound, | ||||
|     PriceComparisonsReport, | ||||
| } from './utils/quote_report_generator'; | ||||
| export { QuoteRequestor } from './utils/quote_requestor'; | ||||
| export { QuoteRequestor, V4RFQIndicativeQuoteMM } from './utils/quote_requestor'; | ||||
| export { ERC20BridgeSamplerContract, BalanceCheckerContract, FakeTakerContract } from './wrappers'; | ||||
| import { ERC20BridgeSource } from './utils/market_operation_utils/types'; | ||||
| export type Native = ERC20BridgeSource.Native; | ||||
|   | ||||
							
								
								
									
										57
									
								
								packages/asset-swapper/src/noop_samplers/AaveV2Sampler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								packages/asset-swapper/src/noop_samplers/AaveV2Sampler.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| import { BigNumber } from '@0x/utils'; | ||||
|  | ||||
| import { ZERO_AMOUNT } from '../constants'; | ||||
| export interface AaveInfo { | ||||
|     lendingPool: string; | ||||
|     aToken: string; | ||||
|     underlyingToken: string; | ||||
| } | ||||
| // tslint:disable-next-line:no-unnecessary-class | ||||
| export class AaveV2Sampler { | ||||
|     public static sampleSellsFromAaveV2( | ||||
|         aaveInfo: AaveInfo, | ||||
|         takerToken: string, | ||||
|         makerToken: string, | ||||
|         takerTokenAmounts: BigNumber[], | ||||
|     ): BigNumber[] { | ||||
|         // Deposit/Withdrawal underlying <-> aToken is always 1:1 | ||||
|         if ( | ||||
|             (takerToken.toLowerCase() === aaveInfo.aToken.toLowerCase() && | ||||
|                 makerToken.toLowerCase() === aaveInfo.underlyingToken.toLowerCase()) || | ||||
|             (takerToken.toLowerCase() === aaveInfo.underlyingToken.toLowerCase() && | ||||
|                 makerToken.toLowerCase() === aaveInfo.aToken.toLowerCase()) | ||||
|         ) { | ||||
|             return takerTokenAmounts; | ||||
|         } | ||||
|  | ||||
|         // Not matching the reserve return 0 results | ||||
|         const numSamples = takerTokenAmounts.length; | ||||
|  | ||||
|         const makerTokenAmounts = new Array(numSamples); | ||||
|         makerTokenAmounts.fill(ZERO_AMOUNT); | ||||
|         return makerTokenAmounts; | ||||
|     } | ||||
|  | ||||
|     public static sampleBuysFromAaveV2( | ||||
|         aaveInfo: AaveInfo, | ||||
|         takerToken: string, | ||||
|         makerToken: string, | ||||
|         makerTokenAmounts: BigNumber[], | ||||
|     ): BigNumber[] { | ||||
|         // Deposit/Withdrawal underlying <-> aToken is always 1:1 | ||||
|         if ( | ||||
|             (takerToken.toLowerCase() === aaveInfo.aToken.toLowerCase() && | ||||
|                 makerToken.toLowerCase() === aaveInfo.underlyingToken.toLowerCase()) || | ||||
|             (takerToken.toLowerCase() === aaveInfo.underlyingToken.toLowerCase() && | ||||
|                 makerToken.toLowerCase() === aaveInfo.aToken.toLowerCase()) | ||||
|         ) { | ||||
|             return makerTokenAmounts; | ||||
|         } | ||||
|  | ||||
|         // Not matching the reserve return 0 results | ||||
|         const numSamples = makerTokenAmounts.length; | ||||
|         const takerTokenAmounts = new Array(numSamples); | ||||
|         takerTokenAmounts.fill(ZERO_AMOUNT); | ||||
|         return takerTokenAmounts; | ||||
|     } | ||||
| } | ||||
| @@ -360,8 +360,9 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { | ||||
|  | ||||
|         // Build up the transforms. | ||||
|         const transforms = []; | ||||
|         if (isFromETH) { | ||||
|             // Create a WETH wrapper if coming from ETH. | ||||
|         // Create a WETH wrapper if coming from ETH. | ||||
|         // Dont add the wethTransformer to CELO. There is no wrap/unwrap logic for CELO. | ||||
|         if (isFromETH && this.chainId !== ChainId.Celo) { | ||||
|             transforms.push({ | ||||
|                 deploymentNonce: this.transformerNonces.wethTransformer, | ||||
|                 data: encodeWethTransformerData({ | ||||
| @@ -413,9 +414,9 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { | ||||
|                 }), | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         if (isToETH) { | ||||
|             // Create a WETH unwrapper if going to ETH. | ||||
|         // Create a WETH unwrapper if going to ETH. | ||||
|         // Dont add the wethTransformer on CELO. There is no wrap/unwrap logic for CELO. | ||||
|         if (isToETH && this.chainId !== ChainId.Celo) { | ||||
|             transforms.push({ | ||||
|                 deploymentNonce: this.transformerNonces.wethTransformer, | ||||
|                 data: encodeWethTransformerData({ | ||||
| @@ -492,10 +493,11 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { | ||||
|                 amounts: [], | ||||
|             }), | ||||
|         }); | ||||
|         const TO_ETH_ADDRESS = this.chainId === ChainId.Celo ? this.contractAddresses.etherToken : ETH_TOKEN_ADDRESS; | ||||
|         const calldataHexString = this._exchangeProxy | ||||
|             .transformERC20( | ||||
|                 isFromETH ? ETH_TOKEN_ADDRESS : sellToken, | ||||
|                 isToETH ? ETH_TOKEN_ADDRESS : buyToken, | ||||
|                 isToETH ? TO_ETH_ADDRESS : buyToken, | ||||
|                 shouldSellEntireBalance ? MAX_UINT256 : sellAmount, | ||||
|                 minBuyAmount, | ||||
|                 transforms, | ||||
|   | ||||
| @@ -505,6 +505,7 @@ function createSwapQuote( | ||||
|     const { | ||||
|         optimizedOrders, | ||||
|         quoteReport, | ||||
|         extendedQuoteReportSources, | ||||
|         sourceFlags, | ||||
|         takerAmountPerEth, | ||||
|         makerAmountPerEth, | ||||
| @@ -532,6 +533,7 @@ function createSwapQuote( | ||||
|         takerAmountPerEth, | ||||
|         makerAmountPerEth, | ||||
|         quoteReport, | ||||
|         extendedQuoteReportSources, | ||||
|         isTwoHop, | ||||
|         priceComparisonsReport, | ||||
|     }; | ||||
|   | ||||
| @@ -19,7 +19,8 @@ import { | ||||
|     OptimizedMarketOrder, | ||||
|     TokenAdjacencyGraph, | ||||
| } from './utils/market_operation_utils/types'; | ||||
| import { PriceComparisonsReport, QuoteReport } from './utils/quote_report_generator'; | ||||
| export { SamplerMetrics } from './utils/market_operation_utils/types'; | ||||
| import { ExtendedQuoteReportSources, PriceComparisonsReport, QuoteReport } from './utils/quote_report_generator'; | ||||
| import { MetricsProxy } from './utils/quote_requestor'; | ||||
|  | ||||
| /** | ||||
| @@ -171,6 +172,7 @@ export interface SwapQuoteBase { | ||||
|     worstCaseQuoteInfo: SwapQuoteInfo; | ||||
|     sourceBreakdown: SwapQuoteOrdersBreakdown; | ||||
|     quoteReport?: QuoteReport; | ||||
|     extendedQuoteReportSources?: ExtendedQuoteReportSources; | ||||
|     priceComparisonsReport?: PriceComparisonsReport; | ||||
|     isTwoHop: boolean; | ||||
|     makerTokenDecimals: number; | ||||
|   | ||||
| @@ -223,7 +223,17 @@ export async function returnQuoteFromAltMMAsync<ResponseT>( | ||||
|             cancelToken, | ||||
|         }) | ||||
|         .catch(err => { | ||||
|             warningLogger(err, `Alt RFQ MM request failed`); | ||||
|             if (err.response) { | ||||
|                 // request was made and market maker responded | ||||
|                 warningLogger( | ||||
|                     { data: err.response.data, status: err.response.status, headers: err.response.headers }, | ||||
|                     `Alt RFQ MM request failed`, | ||||
|                 ); | ||||
|             } else if (err.request) { | ||||
|                 warningLogger({}, 'Alt RFQ MM no response received'); | ||||
|             } else { | ||||
|                 warningLogger({ err: err.message }, 'Failed to construct Alt RFQ MM request'); | ||||
|             } | ||||
|             throw new Error(`Alt RFQ MM request failed`); | ||||
|         }); | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,106 @@ | ||||
| import { logUtils } from '@0x/utils'; | ||||
| import { gql, request } from 'graphql-request'; | ||||
|  | ||||
| import { constants } from '../../constants'; | ||||
|  | ||||
| const RESERVES_GQL_QUERY = gql` | ||||
|     { | ||||
|         reserves( | ||||
|             first: 300 | ||||
|             where: { isActive: true, isFrozen: false } | ||||
|             orderBy: totalLiquidity | ||||
|             orderDirection: desc | ||||
|         ) { | ||||
|             id | ||||
|             underlyingAsset | ||||
|             aToken { | ||||
|                 id | ||||
|             } | ||||
|             pool { | ||||
|                 id | ||||
|                 lendingPool | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| `; | ||||
|  | ||||
| export interface AaveReserve { | ||||
|     id: string; | ||||
|     underlyingAsset: string; | ||||
|     aToken: { | ||||
|         id: string; | ||||
|     }; | ||||
|     pool: { | ||||
|         id: string; | ||||
|         lendingPool: string; | ||||
|     }; | ||||
| } | ||||
|  | ||||
| interface Cache { | ||||
|     [key: string]: AaveReserve[]; | ||||
| } | ||||
|  | ||||
| // tslint:disable-next-line:custom-no-magic-numbers | ||||
| const RESERVES_REFRESH_INTERVAL_MS = 30 * constants.ONE_MINUTE_MS; | ||||
|  | ||||
| /** | ||||
|  * Fetches Aave V2 reserve information from the official subgraph(s). | ||||
|  * The reserve information is updated every 30 minutes and cached | ||||
|  * so that it can be accessed with the underlying token's address | ||||
|  */ | ||||
| export class AaveV2ReservesCache { | ||||
|     private _cache: Cache = {}; | ||||
|     constructor(private readonly _subgraphUrl: string) { | ||||
|         const resfreshReserves = async () => this.fetchAndUpdateReservesAsync(); | ||||
|         // tslint:disable-next-line:no-floating-promises | ||||
|         resfreshReserves(); | ||||
|         setInterval(resfreshReserves, RESERVES_REFRESH_INTERVAL_MS); | ||||
|     } | ||||
|     /** | ||||
|      * Fetches Aave V2 reserves from the subgraph and updates the cache | ||||
|      */ | ||||
|     public async fetchAndUpdateReservesAsync(): Promise<void> { | ||||
|         try { | ||||
|             const { reserves } = await request<{ reserves: AaveReserve[] }>(this._subgraphUrl, RESERVES_GQL_QUERY); | ||||
|             const newCache = reserves.reduce<Cache>((memo, reserve) => { | ||||
|                 const underlyingAsset = reserve.underlyingAsset.toLowerCase(); | ||||
|                 if (!memo[underlyingAsset]) { | ||||
|                     memo[underlyingAsset] = []; | ||||
|                 } | ||||
|  | ||||
|                 memo[underlyingAsset].push(reserve); | ||||
|                 return memo; | ||||
|             }, {}); | ||||
|  | ||||
|             this._cache = newCache; | ||||
|         } catch (err) { | ||||
|             logUtils.warn(`Failed to update Aave V2 reserves cache: ${err.message}`); | ||||
|             // Empty cache just to be safe | ||||
|             this._cache = {}; | ||||
|         } | ||||
|     } | ||||
|     public get(takerToken: string, makerToken: string): AaveReserve | undefined { | ||||
|         // Deposit takerToken into reserve | ||||
|         if (this._cache[takerToken.toLowerCase()]) { | ||||
|             const matchingReserve = this._cache[takerToken.toLowerCase()].find( | ||||
|                 r => r.aToken.id === makerToken.toLowerCase(), | ||||
|             ); | ||||
|             if (matchingReserve) { | ||||
|                 return matchingReserve; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Withdraw makerToken from reserve | ||||
|         if (this._cache[makerToken.toLowerCase()]) { | ||||
|             const matchingReserve = this._cache[makerToken.toLowerCase()].find( | ||||
|                 r => r.aToken.id === takerToken.toLowerCase(), | ||||
|             ); | ||||
|             if (matchingReserve) { | ||||
|                 return matchingReserve; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // No match | ||||
|         return undefined; | ||||
|     } | ||||
| } | ||||
| @@ -11,9 +11,11 @@ import { | ||||
|     COMETHSWAP_ROUTER_BY_CHAIN_ID, | ||||
|     COMPONENT_POOLS_BY_CHAIN_ID, | ||||
|     CRYPTO_COM_ROUTER_BY_CHAIN_ID, | ||||
|     CURVE_AVALANCHE_INFOS, | ||||
|     CURVE_FANTOM_INFOS, | ||||
|     CURVE_MAINNET_INFOS, | ||||
|     CURVE_POLYGON_INFOS, | ||||
|     CURVE_V2_AVALANCHE_INFOS, | ||||
|     CURVE_V2_FANTOM_INFOS, | ||||
|     CURVE_V2_MAINNET_INFOS, | ||||
|     CURVE_V2_POLYGON_INFOS, | ||||
| @@ -28,6 +30,7 @@ import { | ||||
|     KYBER_BRIDGED_LIQUIDITY_PREFIX, | ||||
|     MAX_DODOV2_POOLS_QUERIED, | ||||
|     MAX_KYBER_RESERVES_QUERIED, | ||||
|     MORPHEUSSWAP_ROUTER_BY_CHAIN_ID, | ||||
|     MSTABLE_POOLS_BY_CHAIN_ID, | ||||
|     NERVE_BSC_INFOS, | ||||
|     NULL_ADDRESS, | ||||
| @@ -47,6 +50,7 @@ import { | ||||
|     SUSHISWAP_ROUTER_BY_CHAIN_ID, | ||||
|     SWERVE_MAINNET_INFOS, | ||||
|     TRADER_JOE_ROUTER_BY_CHAIN_ID, | ||||
|     UBESWAP_ROUTER_BY_CHAIN_ID, | ||||
|     UNISWAPV2_ROUTER_BY_CHAIN_ID, | ||||
|     WAULTSWAP_ROUTER_BY_CHAIN_ID, | ||||
|     XSIGMA_MAINNET_INFOS, | ||||
| @@ -146,6 +150,15 @@ export function getCurveInfosForPair(chainId: ChainId, takerToken: string, maker | ||||
|                             [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), | ||||
|                 ), | ||||
|             ); | ||||
|         case ChainId.Avalanche: | ||||
|             return Object.values(CURVE_AVALANCHE_INFOS).filter(c => | ||||
|                 [makerToken, takerToken].every( | ||||
|                     t => | ||||
|                         (c.tokens.includes(t) && c.metaTokens === undefined) || | ||||
|                         (c.tokens.includes(t) && | ||||
|                             [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), | ||||
|                 ), | ||||
|             ); | ||||
|         default: | ||||
|             return []; | ||||
|     } | ||||
| @@ -181,6 +194,15 @@ export function getCurveV2InfosForPair(chainId: ChainId, takerToken: string, mak | ||||
|                             [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), | ||||
|                 ), | ||||
|             ); | ||||
|         case ChainId.Avalanche: | ||||
|             return Object.values(CURVE_V2_AVALANCHE_INFOS).filter(c => | ||||
|                 [makerToken, takerToken].every( | ||||
|                     t => | ||||
|                         (c.tokens.includes(t) && c.metaTokens === undefined) || | ||||
|                         (c.tokens.includes(t) && | ||||
|                             [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0), | ||||
|                 ), | ||||
|             ); | ||||
|         default: | ||||
|             return []; | ||||
|     } | ||||
| @@ -466,6 +488,8 @@ export function uniswapV2LikeRouterAddress( | ||||
|         | ERC20BridgeSource.JetSwap | ||||
|         | ERC20BridgeSource.TraderJoe | ||||
|         | ERC20BridgeSource.Pangolin | ||||
|         | ERC20BridgeSource.UbeSwap | ||||
|         | ERC20BridgeSource.MorpheusSwap | ||||
|         | ERC20BridgeSource.SpookySwap | ||||
|         | ERC20BridgeSource.SpiritSwap, | ||||
| ): string { | ||||
| @@ -508,6 +532,10 @@ export function uniswapV2LikeRouterAddress( | ||||
|             return PANGOLIN_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         case ERC20BridgeSource.TraderJoe: | ||||
|             return TRADER_JOE_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         case ERC20BridgeSource.UbeSwap: | ||||
|             return UBESWAP_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         case ERC20BridgeSource.MorpheusSwap: | ||||
|             return MORPHEUSSWAP_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         case ERC20BridgeSource.SpookySwap: | ||||
|             return SPOOKYSWAP_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         case ERC20BridgeSource.SpiritSwap: | ||||
|   | ||||
| @@ -0,0 +1,78 @@ | ||||
| import { logUtils } from '@0x/utils'; | ||||
| import axios from 'axios'; | ||||
|  | ||||
| import { constants } from '../../constants'; | ||||
|  | ||||
| export interface CToken { | ||||
|     tokenAddress: string; | ||||
|     underlyingAddress: string; | ||||
| } | ||||
|  | ||||
| interface CTokenApiResponse { | ||||
|     cToken: Array<{ | ||||
|         token_address: string; | ||||
|         underlying_address: string; | ||||
|     }>; | ||||
| } | ||||
|  | ||||
| interface Cache { | ||||
|     [key: string]: CToken; | ||||
| } | ||||
|  | ||||
| // tslint:disable-next-line:custom-no-magic-numbers | ||||
| const CTOKEN_REFRESH_INTERVAL_MS = 30 * constants.ONE_MINUTE_MS; | ||||
|  | ||||
| /** | ||||
|  * Fetches a list of CTokens from Compound's official API. | ||||
|  * The token information is updated every 30 minutes and cached | ||||
|  * so that it can be accessed with the underlying token's address. | ||||
|  */ | ||||
| export class CompoundCTokenCache { | ||||
|     private _cache: Cache = {}; | ||||
|     constructor(private readonly _apiUrl: string, private readonly _wethAddress: string) { | ||||
|         const refreshCTokenCache = async () => this.fetchAndUpdateCTokensAsync(); | ||||
|         // tslint:disable-next-line:no-floating-promises | ||||
|         refreshCTokenCache(); | ||||
|         setInterval(refreshCTokenCache, CTOKEN_REFRESH_INTERVAL_MS); | ||||
|     } | ||||
|  | ||||
|     public async fetchAndUpdateCTokensAsync(): Promise<void> { | ||||
|         try { | ||||
|             const { data } = await axios.get<CTokenApiResponse>(`${this._apiUrl}/ctoken`); | ||||
|             const newCache = data?.cToken.reduce<Cache>((memo, cToken) => { | ||||
|                 // NOTE: Re-map cETH with null underlying token address to WETH address (we only handle WETH internally) | ||||
|                 const underlyingAddressClean = cToken.underlying_address | ||||
|                     ? cToken.underlying_address.toLowerCase() | ||||
|                     : this._wethAddress; | ||||
|  | ||||
|                 const tokenData: CToken = { | ||||
|                     tokenAddress: cToken.token_address.toLowerCase(), | ||||
|                     underlyingAddress: underlyingAddressClean, | ||||
|                 }; | ||||
|                 memo[underlyingAddressClean] = tokenData; | ||||
|                 return memo; | ||||
|             }, {}); | ||||
|  | ||||
|             this._cache = newCache; | ||||
|         } catch (err) { | ||||
|             logUtils.warn(`Failed to update Compound cToken cache: ${err.message}`); | ||||
|             // NOTE: Safe to keep already cached data as tokens should only be added to the list | ||||
|         } | ||||
|     } | ||||
|     public get(takerToken: string, makerToken: string): CToken | undefined { | ||||
|         // mint cToken | ||||
|         let cToken = this._cache[takerToken.toLowerCase()]; | ||||
|         if (cToken && makerToken.toLowerCase() === cToken.tokenAddress.toLowerCase()) { | ||||
|             return cToken; | ||||
|         } | ||||
|  | ||||
|         // redeem cToken | ||||
|         cToken = this._cache[makerToken.toLowerCase()]; | ||||
|         if (cToken && takerToken.toLowerCase() === cToken.tokenAddress.toLowerCase()) { | ||||
|             return cToken; | ||||
|         } | ||||
|  | ||||
|         // No match | ||||
|         return undefined; | ||||
|     } | ||||
| } | ||||
| @@ -7,7 +7,9 @@ import { TokenAdjacencyGraphBuilder } from '../token_adjacency_graph_builder'; | ||||
|  | ||||
| import { SourceFilters } from './source_filters'; | ||||
| import { | ||||
|     AaveV2FillData, | ||||
|     BancorFillData, | ||||
|     CompoundFillData, | ||||
|     CurveFillData, | ||||
|     CurveFunctionSelectors, | ||||
|     CurveInfo, | ||||
| @@ -58,6 +60,8 @@ function valueByChainId<T>(rest: Partial<{ [key in ChainId]: T }>, defaultValue: | ||||
|         [ChainId.PolygonMumbai]: defaultValue, | ||||
|         [ChainId.Avalanche]: defaultValue, | ||||
|         [ChainId.Fantom]: defaultValue, | ||||
|         [ChainId.Celo]: defaultValue, | ||||
|         [ChainId.Optimism]: defaultValue, | ||||
|         ...(rest || {}), | ||||
|     }; | ||||
| } | ||||
| @@ -100,6 +104,9 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>( | ||||
|             ERC20BridgeSource.UniswapV3, | ||||
|             ERC20BridgeSource.CurveV2, | ||||
|             ERC20BridgeSource.ShibaSwap, | ||||
|             // TODO: enable after FQT has been redeployed on Ethereum mainnet | ||||
|             // ERC20BridgeSource.AaveV2, | ||||
|             // ERC20BridgeSource.Compound, | ||||
|         ]), | ||||
|         [ChainId.Ropsten]: new SourceFilters([ | ||||
|             ERC20BridgeSource.Kyber, | ||||
| @@ -136,6 +143,7 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>( | ||||
|             ERC20BridgeSource.FirebirdOneSwap, | ||||
|             ERC20BridgeSource.JetSwap, | ||||
|             ERC20BridgeSource.ACryptos, | ||||
|             ERC20BridgeSource.KyberDmm, | ||||
|         ]), | ||||
|         [ChainId.Polygon]: new SourceFilters([ | ||||
|             ERC20BridgeSource.SushiSwap, | ||||
| @@ -157,21 +165,36 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>( | ||||
|             ERC20BridgeSource.MultiHop, | ||||
|             ERC20BridgeSource.JetSwap, | ||||
|             ERC20BridgeSource.IronSwap, | ||||
|             ERC20BridgeSource.AaveV2, | ||||
|             ERC20BridgeSource.UniswapV3, | ||||
|         ]), | ||||
|         [ChainId.Avalanche]: new SourceFilters([ | ||||
|             ERC20BridgeSource.MultiHop, | ||||
|             ERC20BridgeSource.Pangolin, | ||||
|             ERC20BridgeSource.TraderJoe, | ||||
|             ERC20BridgeSource.SushiSwap, | ||||
|             ERC20BridgeSource.Curve, | ||||
|             ERC20BridgeSource.CurveV2, | ||||
|             ERC20BridgeSource.KyberDmm, | ||||
|             ERC20BridgeSource.AaveV2, | ||||
|         ]), | ||||
|         [ChainId.Fantom]: new SourceFilters([ | ||||
|             ERC20BridgeSource.MultiHop, | ||||
|             ERC20BridgeSource.Beethovenx, | ||||
|             ERC20BridgeSource.Curve, | ||||
|             ERC20BridgeSource.CurveV2, | ||||
|             ERC20BridgeSource.JetSwap, | ||||
|             ERC20BridgeSource.MorpheusSwap, | ||||
|             ERC20BridgeSource.SpiritSwap, | ||||
|             ERC20BridgeSource.SpookySwap, | ||||
|             ERC20BridgeSource.SushiSwap, | ||||
|         ]), | ||||
|         [ChainId.Celo]: new SourceFilters([ | ||||
|             ERC20BridgeSource.UbeSwap, | ||||
|             ERC20BridgeSource.SushiSwap, | ||||
|             ERC20BridgeSource.MultiHop, | ||||
|         ]), | ||||
|         [ChainId.Optimism]: new SourceFilters([ERC20BridgeSource.UniswapV3]), | ||||
|     }, | ||||
|     new SourceFilters([]), | ||||
| ); | ||||
| @@ -214,6 +237,9 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>( | ||||
|             ERC20BridgeSource.UniswapV3, | ||||
|             ERC20BridgeSource.CurveV2, | ||||
|             ERC20BridgeSource.ShibaSwap, | ||||
|             // TODO: enable after FQT has been redeployed on Ethereum mainnet | ||||
|             // ERC20BridgeSource.AaveV2, | ||||
|             // ERC20BridgeSource.Compound, | ||||
|         ]), | ||||
|         [ChainId.Ropsten]: new SourceFilters([ | ||||
|             ERC20BridgeSource.Kyber, | ||||
| @@ -250,6 +276,7 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>( | ||||
|             ERC20BridgeSource.FirebirdOneSwap, | ||||
|             ERC20BridgeSource.JetSwap, | ||||
|             ERC20BridgeSource.ACryptos, | ||||
|             ERC20BridgeSource.KyberDmm, | ||||
|         ]), | ||||
|         [ChainId.Polygon]: new SourceFilters([ | ||||
|             ERC20BridgeSource.SushiSwap, | ||||
| @@ -271,21 +298,36 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>( | ||||
|             ERC20BridgeSource.MultiHop, | ||||
|             ERC20BridgeSource.JetSwap, | ||||
|             ERC20BridgeSource.IronSwap, | ||||
|             ERC20BridgeSource.AaveV2, | ||||
|             ERC20BridgeSource.UniswapV3, | ||||
|         ]), | ||||
|         [ChainId.Avalanche]: new SourceFilters([ | ||||
|             ERC20BridgeSource.MultiHop, | ||||
|             ERC20BridgeSource.Pangolin, | ||||
|             ERC20BridgeSource.TraderJoe, | ||||
|             ERC20BridgeSource.SushiSwap, | ||||
|             ERC20BridgeSource.Curve, | ||||
|             ERC20BridgeSource.CurveV2, | ||||
|             ERC20BridgeSource.KyberDmm, | ||||
|             ERC20BridgeSource.AaveV2, | ||||
|         ]), | ||||
|         [ChainId.Fantom]: new SourceFilters([ | ||||
|             ERC20BridgeSource.MultiHop, | ||||
|             ERC20BridgeSource.Beethovenx, | ||||
|             ERC20BridgeSource.Curve, | ||||
|             ERC20BridgeSource.CurveV2, | ||||
|             ERC20BridgeSource.JetSwap, | ||||
|             ERC20BridgeSource.MorpheusSwap, | ||||
|             ERC20BridgeSource.SpiritSwap, | ||||
|             ERC20BridgeSource.SpookySwap, | ||||
|             ERC20BridgeSource.SushiSwap, | ||||
|         ]), | ||||
|         [ChainId.Celo]: new SourceFilters([ | ||||
|             ERC20BridgeSource.UbeSwap, | ||||
|             ERC20BridgeSource.SushiSwap, | ||||
|             ERC20BridgeSource.MultiHop, | ||||
|         ]), | ||||
|         [ChainId.Optimism]: new SourceFilters([ERC20BridgeSource.UniswapV3]), | ||||
|     }, | ||||
|     new SourceFilters([]), | ||||
| ); | ||||
| @@ -303,9 +345,11 @@ export const FEE_QUOTE_SOURCES_BY_CHAIN_ID = valueByChainId<ERC20BridgeSource[]> | ||||
|         [ChainId.Mainnet]: [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap, ERC20BridgeSource.UniswapV3], | ||||
|         [ChainId.BSC]: [ERC20BridgeSource.PancakeSwap, ERC20BridgeSource.Mooniswap, ERC20BridgeSource.SushiSwap], | ||||
|         [ChainId.Ropsten]: [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap], | ||||
|         [ChainId.Polygon]: [ERC20BridgeSource.QuickSwap, ERC20BridgeSource.SushiSwap], | ||||
|         [ChainId.Polygon]: [ERC20BridgeSource.QuickSwap, ERC20BridgeSource.SushiSwap, ERC20BridgeSource.UniswapV3], | ||||
|         [ChainId.Avalanche]: [ERC20BridgeSource.Pangolin, ERC20BridgeSource.TraderJoe, ERC20BridgeSource.SushiSwap], | ||||
|         [ChainId.Fantom]: [ERC20BridgeSource.SpiritSwap, ERC20BridgeSource.SpookySwap, ERC20BridgeSource.SushiSwap], | ||||
|         [ChainId.Celo]: [ERC20BridgeSource.UbeSwap, ERC20BridgeSource.SushiSwap], | ||||
|         [ChainId.Optimism]: [ERC20BridgeSource.UniswapV3], | ||||
|     }, | ||||
|     [], | ||||
| ); | ||||
| @@ -402,15 +446,23 @@ export const MAINNET_TOKENS = { | ||||
|     // StableSwap "open pools" (crv.finance) | ||||
|     STABLEx: '0xcd91538b91b4ba7797d39a2f66e63810b50a33d0', | ||||
|     alUSD: '0xbc6da0fe9ad5f3b0d58160288917aa56653660e9', | ||||
|     // Frax ecosystem | ||||
|     FRAX: '0x853d955acef822db058eb8505911ed77f175b99e', | ||||
|     FXS: '0x3432b6a60d23ca0dfca7761b7ab56459d9c964d0', | ||||
|     OHM: '0x383518188c0c6d7730d91b2c03a03c837814a899', | ||||
|     // | ||||
|     LUSD: '0x5f98805a4e8be255a32880fdec7f6728c6568ba0', | ||||
|     // Fei Ecosystem | ||||
|     FEI: '0x956f47f50a910163d8bf957cf5846d573e7f87ca', | ||||
|     TRIBE: '0xc7283b66eb1eb5fb86327f08e1b5816b0720212b', | ||||
|     // | ||||
|     DSU: '0x605d26fbd5be761089281d5cec2ce86eea667109', | ||||
|     ESS: '0x24ae124c4cc33d6791f8e8b63520ed7107ac8b3e', | ||||
|     cvxCRV: '0x62b9c7356a2dc64a1969e19c23e4f579f9810aa7', | ||||
|     CRV: '0xd533a949740bb3306d119cc777fa900ba034cd52', | ||||
|     MIM: '0x99d8a9c45b2eca8864373a26d1459e3dff1e17f3', | ||||
|     EURT: '0xc581b735a1688071a1746c968e0798d642ede491', | ||||
|     CVX: '0x4e3fbd56cd56c3e72c1403e103b45db9da5b9d2b', | ||||
| }; | ||||
|  | ||||
| export const BSC_TOKENS = { | ||||
| @@ -449,8 +501,33 @@ export const POLYGON_TOKENS = { | ||||
| export const AVALANCHE_TOKENS = { | ||||
|     WAVAX: '0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7', | ||||
|     WETH: '0x49d5c2bdffac6ce2bfdb6640f4f80f226bc10bab', | ||||
|     USDT: '0xc7198437980c041c805a1edcba50c1ce5db95118', | ||||
|     WBTC: '0x50b7545627a5162f82a992c33b87adc75187b218', | ||||
|     DAI: '0xd586e7f844cea2f87f50152665bcbc2c279d8d70', | ||||
|     USDC: '0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664', | ||||
|     USDT: '0xc7198437980c041c805a1edcba50c1ce5db95118', | ||||
|     aDAI: '0x47afa96cdc9fab46904a55a6ad4bf6660b53c38a', | ||||
|     aUSDC: '0x46a51127c3ce23fb7ab1de06226147f446e4a857', | ||||
|     aUSDT: '0x532e6537fea298397212f09a61e03311686f548e', | ||||
| }; | ||||
|  | ||||
| export const CELO_TOKENS = { | ||||
|     WCELO: '0x471ece3750da237f93b8e339c536989b8978a438', | ||||
|     // Some of these tokens are Optics bridge? tokens which | ||||
|     // had an issue and migrated from v1 to v2 | ||||
|     WETHv1: '0xe919f65739c26a42616b7b8eedc6b5524d1e3ac4', | ||||
|     WETH: '0x122013fd7df1c6f636a5bb8f03108e876548b455', | ||||
|     WBTC: '0xbaab46e28388d2779e6e31fd00cf0e5ad95e327b', | ||||
|     cUSD: '0x765de816845861e75a25fca122bb6898b8b1282a', | ||||
|     // ?? | ||||
|     WBTCv1: '0xd629eb00deced2a080b7ec630ef6ac117e614f1b', | ||||
|     cETH: '0x2def4285787d58a2f811af24755a8150622f4361', | ||||
|     UBE: '0x00be915b9dcf56a3cbe739d9b9c202ca692409ec', | ||||
|     // Moolah | ||||
|     mCELO: '0x7d00cd74ff385c955ea3d79e47bf06bd7386387d', | ||||
|     mCUSD: '0x918146359264c492bd6934071c6bd31c854edbc3', | ||||
|     mCEUR: '0xe273ad7ee11dcfaa87383ad5977ee1504ac07568', | ||||
|     amCUSD: '0x64defa3544c695db8c535d289d843a189aa26b98', | ||||
|     MOO: '0x17700282592d6917f6a73d0bf8accf4d578c131e', | ||||
| }; | ||||
|  | ||||
| export const FANTOM_TOKENS = { | ||||
| @@ -463,6 +540,14 @@ export const FANTOM_TOKENS = { | ||||
|     renBTC: '0xdbf31df14b66535af65aac99c32e9ea844e14501', | ||||
| }; | ||||
|  | ||||
| export const OPTIMISM_TOKENS = { | ||||
|     WETH: '0x4200000000000000000000000000000000000006', | ||||
|     USDC: '0x7f5c764cbc14f9669b88837ca1490cca17c31607', | ||||
|     USDT: '0x94b008aa00579c1307b0ef2c499ad98a8ce58e58', | ||||
|     DAI: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', | ||||
|     WBTC: '0x68f180fcce6836688e9084f035309e29bf0a2095', | ||||
| }; | ||||
|  | ||||
| export const CURVE_POOLS = { | ||||
|     compound: '0xa2b47e3d5c44877cca798226b7b8118f9bfb7a56', // 0.Compound | ||||
|     // 1.USDT is dead | ||||
| @@ -507,6 +592,8 @@ export const CURVE_POOLS = { | ||||
|     cvxcrv: '0x9d0464996170c6b9e75eed71c68b99ddedf279e8', | ||||
|     mim: '0x5a6a4d54456819380173272a5e8e9b9904bdf41b', | ||||
|     eurt: '0xfd5db7463a3ab53fd211b4af195c5bccc1a03890', | ||||
|     ethcrv: '0x8301ae4fc9c624d1d396cbdaa1ed877821d7c511', | ||||
|     ethcvx: '0xb576491f1e6e5e62f1d8f26062ee822b40b0e0d4', | ||||
| }; | ||||
|  | ||||
| export const CURVE_V2_POOLS = { | ||||
| @@ -524,6 +611,14 @@ export const CURVE_V2_POLYGON_POOLS = { | ||||
|     atricrypto3: '0x1d8b86e3d88cdb2d34688e87e72f388cb541b7c8', | ||||
| }; | ||||
|  | ||||
| export const CURVE_AVALANCHE_POOLS = { | ||||
|     aave: '0x7f90122bf0700f9e7e1f688fe926940e8839f353', | ||||
| }; | ||||
|  | ||||
| export const CURVE_V2_AVALANCHE_POOLS = { | ||||
|     atricrypto: '0x58e57ca18b7a47112b877e31929798cd3d703b0f', | ||||
| }; | ||||
|  | ||||
| export const CURVE_FANTOM_POOLS = { | ||||
|     fUSDT: '0x92d5ebf3593a92888c25c0abef126583d4b5312e', | ||||
|     twoPool: '0x27e611fd27b276acbd5ffd632e5eaebec9761e40', | ||||
| @@ -631,8 +726,11 @@ export const DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID = valueByChainId<string[]>( | ||||
|             AVALANCHE_TOKENS.WETH, | ||||
|             AVALANCHE_TOKENS.DAI, | ||||
|             AVALANCHE_TOKENS.USDT, | ||||
|             AVALANCHE_TOKENS.USDC, | ||||
|         ], | ||||
|         [ChainId.Fantom]: [FANTOM_TOKENS.WFTM, FANTOM_TOKENS.WETH, FANTOM_TOKENS.DAI, FANTOM_TOKENS.USDC], | ||||
|         [ChainId.Celo]: [CELO_TOKENS.WCELO, CELO_TOKENS.mCUSD, CELO_TOKENS.WETH, CELO_TOKENS.amCUSD, CELO_TOKENS.WBTC], | ||||
|         [ChainId.Optimism]: [OPTIMISM_TOKENS.WETH, OPTIMISM_TOKENS.DAI, OPTIMISM_TOKENS.USDC], | ||||
|     }, | ||||
|     [], | ||||
| ); | ||||
| @@ -649,6 +747,11 @@ export const DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID = valueByChainId<TokenAdj | ||||
|                 builder.add(MAINNET_TOKENS.MIR, MAINNET_TOKENS.UST); | ||||
|                 // Convex and Curve | ||||
|                 builder.add(MAINNET_TOKENS.cvxCRV, MAINNET_TOKENS.CRV).add(MAINNET_TOKENS.CRV, MAINNET_TOKENS.cvxCRV); | ||||
|                 // FEI TRIBE liquid in UniV2 | ||||
|                 builder.add(MAINNET_TOKENS.FEI, MAINNET_TOKENS.TRIBE).add(MAINNET_TOKENS.TRIBE, MAINNET_TOKENS.FEI); | ||||
|                 // FRAX ecosystem | ||||
|                 builder.add(MAINNET_TOKENS.FRAX, MAINNET_TOKENS.FXS).add(MAINNET_TOKENS.FXS, MAINNET_TOKENS.FRAX); | ||||
|                 builder.add(MAINNET_TOKENS.FRAX, MAINNET_TOKENS.OHM).add(MAINNET_TOKENS.OHM, MAINNET_TOKENS.FRAX); | ||||
|             }) | ||||
|             // Build | ||||
|             .build(), | ||||
| @@ -664,6 +767,12 @@ export const DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID = valueByChainId<TokenAdj | ||||
|         [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(), | ||||
|     }, | ||||
|     new TokenAdjacencyGraphBuilder({ default: [] }).build(), | ||||
| ); | ||||
| @@ -679,6 +788,8 @@ export const NATIVE_FEE_TOKEN_BY_CHAIN_ID = valueByChainId<string>( | ||||
|         [ChainId.Polygon]: getContractAddressesForChainOrThrow(ChainId.Polygon).etherToken, | ||||
|         [ChainId.Avalanche]: getContractAddressesForChainOrThrow(ChainId.Avalanche).etherToken, | ||||
|         [ChainId.Fantom]: getContractAddressesForChainOrThrow(ChainId.Fantom).etherToken, | ||||
|         [ChainId.Celo]: getContractAddressesForChainOrThrow(ChainId.Celo).etherToken, | ||||
|         [ChainId.Optimism]: getContractAddressesForChainOrThrow(ChainId.Optimism).etherToken, | ||||
|     }, | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
| @@ -953,6 +1064,28 @@ export const CURVE_MAINNET_INFOS: { [name: string]: CurveInfo } = { | ||||
|         pool: CURVE_POOLS.cvxcrv, | ||||
|         gasSchedule: 105e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.ethcrv]: { | ||||
|         ...createCurveExchangePool({ | ||||
|             // This pool uses ETH | ||||
|             tokens: [MAINNET_TOKENS.WETH, MAINNET_TOKENS.CRV], | ||||
|             pool: CURVE_POOLS.ethcrv, | ||||
|             gasSchedule: 350e3, | ||||
|         }), | ||||
|         // This pool has a custom get_dy and exchange selector with uint256 | ||||
|         sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_uint256, | ||||
|         exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying_uint256, | ||||
|     }, | ||||
|     [CURVE_POOLS.ethcvx]: { | ||||
|         ...createCurveExchangePool({ | ||||
|             // This pool uses ETH | ||||
|             tokens: [MAINNET_TOKENS.WETH, MAINNET_TOKENS.CVX], | ||||
|             pool: CURVE_POOLS.ethcvx, | ||||
|             gasSchedule: 350e3, | ||||
|         }), | ||||
|         // This pool has a custom get_dy and exchange selector with uint256 | ||||
|         sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_uint256, | ||||
|         exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying_uint256, | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| export const CURVE_V2_MAINNET_INFOS: { [name: string]: CurveInfo } = { | ||||
| @@ -999,6 +1132,37 @@ export const CURVE_V2_POLYGON_INFOS: { [name: string]: CurveInfo } = { | ||||
|     }), | ||||
| }; | ||||
|  | ||||
| export const CURVE_AVALANCHE_INFOS: { [name: string]: CurveInfo } = { | ||||
|     ['aave_exchangeunderlying']: createCurveExchangeUnderlyingPool({ | ||||
|         tokens: [AVALANCHE_TOKENS.DAI, AVALANCHE_TOKENS.USDC, AVALANCHE_TOKENS.USDT], | ||||
|         pool: CURVE_AVALANCHE_POOLS.aave, | ||||
|         gasSchedule: 850e3, | ||||
|     }), | ||||
|     ['aave_exchange']: createCurveExchangePool({ | ||||
|         tokens: [AVALANCHE_TOKENS.aDAI, AVALANCHE_TOKENS.aUSDC, AVALANCHE_TOKENS.aUSDT], | ||||
|         pool: CURVE_AVALANCHE_POOLS.aave, | ||||
|         gasSchedule: 150e3, | ||||
|     }), | ||||
| }; | ||||
|  | ||||
| export const CURVE_V2_AVALANCHE_INFOS: { [name: string]: CurveInfo } = { | ||||
|     [CURVE_V2_AVALANCHE_POOLS.atricrypto]: { | ||||
|         exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying_v2, | ||||
|         sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying_v2, | ||||
|         buyQuoteFunctionSelector: CurveFunctionSelectors.None, | ||||
|         tokens: [ | ||||
|             AVALANCHE_TOKENS.DAI, | ||||
|             AVALANCHE_TOKENS.USDC, | ||||
|             AVALANCHE_TOKENS.USDT, | ||||
|             AVALANCHE_TOKENS.WBTC, | ||||
|             AVALANCHE_TOKENS.WETH, | ||||
|         ], | ||||
|         metaTokens: undefined, | ||||
|         poolAddress: CURVE_V2_AVALANCHE_POOLS.atricrypto, | ||||
|         gasSchedule: 1300e3, | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| // TODO: modify gasSchedule | ||||
| export const CURVE_FANTOM_INFOS: { [name: string]: CurveInfo } = { | ||||
|     [CURVE_FANTOM_POOLS.ren]: createCurveExchangePool({ | ||||
| @@ -1320,6 +1484,7 @@ export const SUSHISWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
|         [ChainId.Polygon]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506', | ||||
|         [ChainId.Avalanche]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506', | ||||
|         [ChainId.Fantom]: '0x1b02da8cb0d097eb8d57a175b88c7d8b47997506', | ||||
|         [ChainId.Celo]: '0x1421bde4b10e8dd459b3bcb598810b1337d56842', | ||||
|     }, | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
| @@ -1389,6 +1554,9 @@ export const KYBER_DMM_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
|     { | ||||
|         [ChainId.Mainnet]: '0x1c87257f5e8609940bc751a07bb085bb7f8cdbe6', | ||||
|         [ChainId.Polygon]: '0x546c79662e028b661dfb4767664d0273184e4dd1', | ||||
|         [ChainId.BSC]: '0x78df70615ffc8066cc0887917f2cd72092c86409', | ||||
|         [ChainId.Avalanche]: '0x8efa5a9ad6d594cf76830267077b78ce0bc5a5f8', | ||||
|         [ChainId.Fantom]: '0x5d5a5a0a465129848c2549669e12cdc2f8de039a', | ||||
|     }, | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
| @@ -1538,6 +1706,13 @@ export const BALANCER_V2_VAULT_ADDRESS_BY_CHAIN = valueByChainId<string>( | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
|  | ||||
| export const BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN = valueByChainId<string>( | ||||
|     { | ||||
|         [ChainId.Fantom]: '0x20dd72ed959b6147912c2e529f0a0c651c33c9ce', | ||||
|     }, | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
|  | ||||
| export const LIDO_INFO_BY_CHAIN = valueByChainId<LidoInfo>( | ||||
|     { | ||||
|         [ChainId.Mainnet]: { | ||||
| @@ -1562,6 +1737,13 @@ export const BALANCER_V2_SUBGRAPH_URL_BY_CHAIN = valueByChainId<string>( | ||||
|     'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2', | ||||
| ); | ||||
|  | ||||
| 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( | ||||
|     { | ||||
|         [ChainId.Mainnet]: { | ||||
| @@ -1572,10 +1754,36 @@ export const UNISWAPV3_CONFIG_BY_CHAIN_ID = valueByChainId( | ||||
|             quoter: '0x2f9e608fd881861b8916257b76613cb22ee0652c', | ||||
|             router: '0x03782388516e94fcd4c18666303601a12aa729ea', | ||||
|         }, | ||||
|         [ChainId.Polygon]: { | ||||
|             quoter: '0xb27308f9f90d607463bb33ea1bebb41c27ce5ab6', | ||||
|             router: '0xe592427a0aece92de3edee1f18e0157c05861564', | ||||
|         }, | ||||
|         [ChainId.Optimism]: { | ||||
|             quoter: '0xb27308f9f90d607463bb33ea1bebb41c27ce5ab6', | ||||
|             router: '0xe592427a0aece92de3edee1f18e0157c05861564', | ||||
|         }, | ||||
|     }, | ||||
|     { quoter: NULL_ADDRESS, router: NULL_ADDRESS }, | ||||
| ); | ||||
|  | ||||
| export const AAVE_V2_SUBGRAPH_URL_BY_CHAIN_ID = valueByChainId( | ||||
|     { | ||||
|         // TODO: enable after FQT has been redeployed on Ethereum mainnet | ||||
|         // [ChainId.Mainnet]: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2', | ||||
|         [ChainId.Polygon]: 'https://api.thegraph.com/subgraphs/name/aave/aave-v2-matic', | ||||
|         [ChainId.Avalanche]: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2-avalanche', | ||||
|     }, | ||||
|     null, | ||||
| ); | ||||
|  | ||||
| export const COMPOUND_API_URL_BY_CHAIN_ID = valueByChainId( | ||||
|     { | ||||
|         // TODO: enable after FQT has been redeployed on Ethereum mainnet | ||||
|         // [ChainId.Mainnet]: 'https://api.compound.finance/api/v2', | ||||
|     }, | ||||
|     null, | ||||
| ); | ||||
|  | ||||
| // | ||||
| // BSC | ||||
| // | ||||
| @@ -1672,6 +1880,7 @@ export const JETSWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
|     { | ||||
|         [ChainId.BSC]: '0xbe65b8f75b9f20f4c522e0067a3887fada714800', | ||||
|         [ChainId.Polygon]: '0x5c6ec38fb0e2609672bdf628b1fd605a523e5923', | ||||
|         [ChainId.Fantom]: '0x845e76a8691423fbc4ecb8dd77556cb61c09ee25', | ||||
|     }, | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
| @@ -1690,6 +1899,20 @@ export const TRADER_JOE_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
|  | ||||
| export const UBESWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
|     { | ||||
|         [ChainId.Celo]: '0x7d28570135a2b1930f331c507f65039d4937f66c', | ||||
|     }, | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
|  | ||||
| export const MORPHEUSSWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
|     { | ||||
|         [ChainId.Fantom]: '0x8ac868293d97761a1fed6d4a01e9ff17c5594aa3', | ||||
|     }, | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
|  | ||||
| export const SPIRITSWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
|     { | ||||
|         [ChainId.Fantom]: '0x16327e3fbdaca3bcf7e38f5af2599d2ddc33ae52', | ||||
| @@ -1826,6 +2049,21 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = { | ||||
|         return gas; | ||||
|     }, | ||||
|     [ERC20BridgeSource.Lido]: () => 226e3, | ||||
|     [ERC20BridgeSource.AaveV2]: (fillData?: FillData) => { | ||||
|         const aaveFillData = fillData as AaveV2FillData; | ||||
|         // NOTE: The Aave deposit method is more expensive than the withdraw | ||||
|         return aaveFillData.takerToken === aaveFillData.underlyingToken ? 400e3 : 300e3; | ||||
|     }, | ||||
|     [ERC20BridgeSource.Compound]: (fillData?: FillData) => { | ||||
|         // NOTE: cETH is handled differently than other cTokens | ||||
|         const wethAddress = NATIVE_FEE_TOKEN_BY_CHAIN_ID[ChainId.Mainnet]; | ||||
|         const compoundFillData = fillData as CompoundFillData; | ||||
|         if (compoundFillData.takerToken === compoundFillData.cToken) { | ||||
|             return compoundFillData.makerToken === wethAddress ? 120e3 : 150e3; | ||||
|         } else { | ||||
|             return compoundFillData.takerToken === wethAddress ? 210e3 : 250e3; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     // | ||||
|     // BSC | ||||
| @@ -1855,11 +2093,18 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = { | ||||
|     [ERC20BridgeSource.Pangolin]: uniswapV2CloneGasSchedule, | ||||
|     [ERC20BridgeSource.TraderJoe]: uniswapV2CloneGasSchedule, | ||||
|  | ||||
|     // | ||||
|     // Celo | ||||
|     // | ||||
|     [ERC20BridgeSource.UbeSwap]: uniswapV2CloneGasSchedule, | ||||
|  | ||||
|     // | ||||
|     // Fantom | ||||
|     // | ||||
|     [ERC20BridgeSource.MorpheusSwap]: uniswapV2CloneGasSchedule, | ||||
|     [ERC20BridgeSource.SpiritSwap]: uniswapV2CloneGasSchedule, | ||||
|     [ERC20BridgeSource.SpookySwap]: uniswapV2CloneGasSchedule, | ||||
|     [ERC20BridgeSource.Beethovenx]: () => 100e3, | ||||
| }; | ||||
|  | ||||
| export const DEFAULT_FEE_SCHEDULE: Required<FeeSchedule> = { ...DEFAULT_GAS_SCHEDULE }; | ||||
| @@ -1885,4 +2130,5 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: Omit<GetMarketOrdersOpts, 'gasPrice | ||||
|     shouldGenerateQuoteReport: true, | ||||
|     shouldIncludePriceComparisonsReport: false, | ||||
|     tokenAdjacencyGraph: { default: [] }, | ||||
|     neonRouterNumSamples: 14, | ||||
| }; | ||||
|   | ||||
| @@ -18,12 +18,15 @@ import { | ||||
|  | ||||
| import { | ||||
|     dexSampleToReportSource, | ||||
|     ExtendedQuoteReportSources, | ||||
|     generateExtendedQuoteReportSources, | ||||
|     generateQuoteReport, | ||||
|     multiHopSampleToReportSource, | ||||
|     nativeOrderToReportEntry, | ||||
|     PriceComparisonsReport, | ||||
|     QuoteReport, | ||||
| } from './../quote_report_generator'; | ||||
|  | ||||
| import { getComparisonPrices } from './comparison_price'; | ||||
| import { | ||||
|     BUY_SOURCE_FILTER_BY_CHAIN_ID, | ||||
| @@ -78,6 +81,25 @@ export class MarketOperationUtils { | ||||
|         return generateQuoteReport(side, quotes.nativeOrders, liquidityDelivered, comparisonPrice, quoteRequestor); | ||||
|     } | ||||
|  | ||||
|     private static _computeExtendedQuoteReportSources( | ||||
|         quoteRequestor: QuoteRequestor | undefined, | ||||
|         marketSideLiquidity: MarketSideLiquidity, | ||||
|         amount: BigNumber, | ||||
|         optimizerResult: OptimizerResult, | ||||
|         comparisonPrice?: BigNumber | undefined, | ||||
|     ): ExtendedQuoteReportSources { | ||||
|         const { side, quotes } = marketSideLiquidity; | ||||
|         const { liquidityDelivered } = optimizerResult; | ||||
|         return generateExtendedQuoteReportSources( | ||||
|             side, | ||||
|             quotes, | ||||
|             liquidityDelivered, | ||||
|             amount, | ||||
|             comparisonPrice, | ||||
|             quoteRequestor, | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     private static _computePriceComparisonsReport( | ||||
|         quoteRequestor: QuoteRequestor | undefined, | ||||
|         marketSideLiquidity: MarketSideLiquidity, | ||||
| @@ -136,6 +158,8 @@ export class MarketOperationUtils { | ||||
|  | ||||
|         // Call the sampler contract. | ||||
|         const samplerPromise = this._sampler.executeAsync( | ||||
|             this._sampler.getBlockNumber(), | ||||
|             this._sampler.getGasLeft(), | ||||
|             this._sampler.getTokenDecimals([makerToken, takerToken]), | ||||
|             // Get native order fillable amounts. | ||||
|             this._sampler.getLimitOrderFillableTakerAmounts(nativeOrders, this.contractAddresses.exchangeProxy), | ||||
| @@ -162,6 +186,7 @@ export class MarketOperationUtils { | ||||
|                 takerAmount, | ||||
|             ), | ||||
|             this._sampler.isAddressContract(txOrigin), | ||||
|             this._sampler.getGasLeft(), | ||||
|         ); | ||||
|  | ||||
|         // Refresh the cached pools asynchronously if required | ||||
| @@ -169,6 +194,8 @@ export class MarketOperationUtils { | ||||
|  | ||||
|         const [ | ||||
|             [ | ||||
|                 blockNumber, | ||||
|                 gasBefore, | ||||
|                 tokenDecimals, | ||||
|                 orderFillableTakerAmounts, | ||||
|                 outputAmountPerEth, | ||||
| @@ -176,9 +203,14 @@ export class MarketOperationUtils { | ||||
|                 dexQuotes, | ||||
|                 rawTwoHopQuotes, | ||||
|                 isTxOriginContract, | ||||
|                 gasAfter, | ||||
|             ], | ||||
|         ] = await Promise.all([samplerPromise]); | ||||
|  | ||||
|         // Log the gas metrics | ||||
|         _opts.samplerMetrics?.logGasDetails({ gasBefore, gasAfter }); | ||||
|         _opts.samplerMetrics?.logBlockNumber(blockNumber); | ||||
|  | ||||
|         // Filter out any invalid two hop quotes where we couldn't find a route | ||||
|         const twoHopQuotes = rawTwoHopQuotes.filter( | ||||
|             q => q && q.fillData && q.fillData.firstHopSource && q.fillData.secondHopSource, | ||||
| @@ -411,6 +443,7 @@ export class MarketOperationUtils { | ||||
|                             feeSchedule: _opts.feeSchedule, | ||||
|                             allowFallback: _opts.allowFallback, | ||||
|                             gasPrice: _opts.gasPrice, | ||||
|                             neonRouterNumSamples: _opts.neonRouterNumSamples, | ||||
|                         }, | ||||
|                     ); | ||||
|                     return optimizerResult; | ||||
| @@ -499,9 +532,18 @@ export class MarketOperationUtils { | ||||
|                 penaltyOpts, | ||||
|                 opts.feeSchedule, | ||||
|                 this._sampler.chainId, | ||||
|                 opts.neonRouterNumSamples, | ||||
|                 opts.samplerMetrics, | ||||
|             ); | ||||
|         } else { | ||||
|             optimalPath = await findOptimalPathJSAsync(side, fills, inputAmount, opts.runLimit, penaltyOpts); | ||||
|             optimalPath = await findOptimalPathJSAsync( | ||||
|                 side, | ||||
|                 fills, | ||||
|                 inputAmount, | ||||
|                 opts.runLimit, | ||||
|                 opts.samplerMetrics, | ||||
|                 penaltyOpts, | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         const optimalPathRate = optimalPath ? optimalPath.adjustedRate() : ZERO_AMOUNT; | ||||
| @@ -564,6 +606,8 @@ export class MarketOperationUtils { | ||||
|             allowFallback: _opts.allowFallback, | ||||
|             exchangeProxyOverhead: _opts.exchangeProxyOverhead, | ||||
|             gasPrice: _opts.gasPrice, | ||||
|             neonRouterNumSamples: _opts.neonRouterNumSamples, | ||||
|             samplerMetrics: _opts.samplerMetrics, | ||||
|         }; | ||||
|  | ||||
|         if (nativeOrders.length === 0) { | ||||
| @@ -702,6 +746,16 @@ export class MarketOperationUtils { | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         // Always compute the Extended Quote Report | ||||
|         let extendedQuoteReportSources: ExtendedQuoteReportSources | undefined; | ||||
|         extendedQuoteReportSources = MarketOperationUtils._computeExtendedQuoteReportSources( | ||||
|             _opts.rfqt ? _opts.rfqt.quoteRequestor : undefined, | ||||
|             marketSideLiquidity, | ||||
|             amount, | ||||
|             optimizerResult, | ||||
|             wholeOrderPrice, | ||||
|         ); | ||||
|  | ||||
|         let priceComparisonsReport: PriceComparisonsReport | undefined; | ||||
|         if (_opts.shouldIncludePriceComparisonsReport) { | ||||
|             priceComparisonsReport = MarketOperationUtils._computePriceComparisonsReport( | ||||
| @@ -710,7 +764,7 @@ export class MarketOperationUtils { | ||||
|                 wholeOrderPrice, | ||||
|             ); | ||||
|         } | ||||
|         return { ...optimizerResult, quoteReport, priceComparisonsReport }; | ||||
|         return { ...optimizerResult, quoteReport, extendedQuoteReportSources, priceComparisonsReport }; | ||||
|     } | ||||
|  | ||||
|     private async _refreshPoolCacheIfRequiredAsync(takerToken: string, makerToken: string): Promise<void> { | ||||
| @@ -764,6 +818,8 @@ export class MarketOperationUtils { | ||||
|                     sturdyPenaltyOpts, | ||||
|                     opts.feeSchedule, | ||||
|                     this._sampler.chainId, | ||||
|                     opts.neonRouterNumSamples, | ||||
|                     undefined, // hack: set sampler metrics to undefined to avoid fallback timings | ||||
|                 ); | ||||
|             } else { | ||||
|                 const sturdyFills = fills.filter(p => p.length > 0 && !fragileSources.includes(p[0].source)); | ||||
| @@ -772,6 +828,7 @@ export class MarketOperationUtils { | ||||
|                     sturdyFills, | ||||
|                     inputAmount, | ||||
|                     opts.runLimit, | ||||
|                     undefined, // hack: set sampler metrics to undefined to avoid fallback timings | ||||
|                     sturdyPenaltyOpts, | ||||
|                 ); | ||||
|             } | ||||
|   | ||||
| @@ -5,11 +5,13 @@ import { AssetSwapperContractAddresses, MarketOperation } from '../../types'; | ||||
|  | ||||
| import { MAX_UINT256, ZERO_AMOUNT } from './constants'; | ||||
| import { | ||||
|     AaveV2FillData, | ||||
|     AggregationError, | ||||
|     BalancerFillData, | ||||
|     BalancerV2FillData, | ||||
|     BancorFillData, | ||||
|     CollapsedFill, | ||||
|     CompoundFillData, | ||||
|     CurveFillData, | ||||
|     DexSample, | ||||
|     DODOFillData, | ||||
| @@ -184,10 +186,20 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'Pangolin'); | ||||
|         case ERC20BridgeSource.TraderJoe: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'TraderJoe'); | ||||
|         case ERC20BridgeSource.UbeSwap: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'UbeSwap'); | ||||
|         case ERC20BridgeSource.Beethovenx: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.BalancerV2, 'Beethovenx'); | ||||
|         case ERC20BridgeSource.SpiritSwap: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'SpiritSwap'); | ||||
|         case ERC20BridgeSource.SpookySwap: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'SpookySwap'); | ||||
|         case ERC20BridgeSource.MorpheusSwap: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'MorpheusSwap'); | ||||
|         case ERC20BridgeSource.AaveV2: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.AaveV2, 'AaveV2'); | ||||
|         case ERC20BridgeSource.Compound: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.Compound, 'Compound'); | ||||
|         default: | ||||
|             throw new Error(AggregationError.NoBridgeForSource); | ||||
|     } | ||||
| @@ -236,6 +248,7 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder | ||||
|             bridgeData = encoder.encode([balancerFillData.poolAddress]); | ||||
|             break; | ||||
|         case ERC20BridgeSource.BalancerV2: | ||||
|         case ERC20BridgeSource.Beethovenx: | ||||
|             const balancerV2FillData = (order as OptimizedMarketBridgeOrder<BalancerV2FillData>).fillData; | ||||
|             const { vault, poolId } = balancerV2FillData; | ||||
|             bridgeData = encoder.encode([vault, poolId]); | ||||
| @@ -264,8 +277,10 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder | ||||
|         case ERC20BridgeSource.JetSwap: | ||||
|         case ERC20BridgeSource.Pangolin: | ||||
|         case ERC20BridgeSource.TraderJoe: | ||||
|         case ERC20BridgeSource.UbeSwap: | ||||
|         case ERC20BridgeSource.SpiritSwap: | ||||
|         case ERC20BridgeSource.SpookySwap: | ||||
|         case ERC20BridgeSource.MorpheusSwap: | ||||
|             const uniswapV2FillData = (order as OptimizedMarketBridgeOrder<UniswapV2FillData>).fillData; | ||||
|             bridgeData = encoder.encode([uniswapV2FillData.router, uniswapV2FillData.tokenAddressPath]); | ||||
|             break; | ||||
| @@ -330,6 +345,15 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder | ||||
|             const lidoFillData = (order as OptimizedMarketBridgeOrder<LidoFillData>).fillData; | ||||
|             bridgeData = encoder.encode([lidoFillData.stEthTokenAddress]); | ||||
|             break; | ||||
|         case ERC20BridgeSource.AaveV2: | ||||
|             const aaveFillData = (order as OptimizedMarketBridgeOrder<AaveV2FillData>).fillData; | ||||
|             bridgeData = encoder.encode([aaveFillData.lendingPool, aaveFillData.aToken]); | ||||
|             break; | ||||
|         case ERC20BridgeSource.Compound: | ||||
|             const compoundFillData = (order as OptimizedMarketBridgeOrder<CompoundFillData>).fillData; | ||||
|             bridgeData = encoder.encode([compoundFillData.cToken]); | ||||
|             break; | ||||
|  | ||||
|         default: | ||||
|             throw new Error(AggregationError.NoBridgeForSource); | ||||
|     } | ||||
| @@ -458,6 +482,9 @@ export const BRIDGE_ENCODERS: { | ||||
|     [ERC20BridgeSource.TraderJoe]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.SpiritSwap]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.SpookySwap]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.MorpheusSwap]: routerAddressPathEncoder, | ||||
|     // Celo | ||||
|     [ERC20BridgeSource.UbeSwap]: routerAddressPathEncoder, | ||||
|     // BSC | ||||
|     [ERC20BridgeSource.PancakeSwap]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.PancakeSwapV2]: routerAddressPathEncoder, | ||||
| @@ -485,12 +512,15 @@ export const BRIDGE_ENCODERS: { | ||||
|     // Custom integrations | ||||
|     [ERC20BridgeSource.MakerPsm]: makerPsmEncoder, | ||||
|     [ERC20BridgeSource.BalancerV2]: balancerV2Encoder, | ||||
|     [ERC20BridgeSource.Beethovenx]: balancerV2Encoder, | ||||
|     [ERC20BridgeSource.UniswapV3]: AbiEncoder.create([ | ||||
|         { name: 'router', type: 'address' }, | ||||
|         { name: 'path', type: 'bytes' }, | ||||
|     ]), | ||||
|     [ERC20BridgeSource.KyberDmm]: AbiEncoder.create('(address,address[],address[])'), | ||||
|     [ERC20BridgeSource.Lido]: AbiEncoder.create('(address)'), | ||||
|     [ERC20BridgeSource.AaveV2]: AbiEncoder.create('(address,address)'), | ||||
|     [ERC20BridgeSource.Compound]: AbiEncoder.create('(address)'), | ||||
| }; | ||||
|  | ||||
| function getFillTokenAmounts(fill: CollapsedFill, side: MarketOperation): [BigNumber, BigNumber] { | ||||
|   | ||||
| @@ -1,23 +1,21 @@ | ||||
| import { assert } from '@0x/assert'; | ||||
| import { ChainId } from '@0x/contract-addresses'; | ||||
| import { OptimizerCapture, route, SerializedPath } from '@0x/neon-router'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import { BigNumber, hexUtils } from '@0x/utils'; | ||||
| import * as _ from 'lodash'; | ||||
| import { performance } from 'perf_hooks'; | ||||
|  | ||||
| import { DEFAULT_INFO_LOGGER } from '../../constants'; | ||||
| import { MarketOperation, NativeOrderWithFillableAmounts } from '../../types'; | ||||
| import { VIP_ERC20_BRIDGE_SOURCES_BY_CHAIN_ID } from '../market_operation_utils/constants'; | ||||
|  | ||||
| import { dexSamplesToFills, ethToOutputAmount, nativeOrdersToFills } from './fills'; | ||||
| import { DEFAULT_PATH_PENALTY_OPTS, Path, PathPenaltyOpts } from './path'; | ||||
| import { getRate } from './rate_utils'; | ||||
| import { DexSample, ERC20BridgeSource, FeeSchedule, Fill, FillData } from './types'; | ||||
| import { DexSample, ERC20BridgeSource, FeeSchedule, Fill, FillData, SamplerMetrics } from './types'; | ||||
|  | ||||
| // tslint:disable: prefer-for-of custom-no-magic-numbers completed-docs no-bitwise | ||||
|  | ||||
| const RUN_LIMIT_DECAY_FACTOR = 0.5; | ||||
| const RUST_ROUTER_NUM_SAMPLES = 200; | ||||
| const FILL_QUOTE_TRANSFORMER_GAS_OVERHEAD = new BigNumber(150e3); | ||||
| // NOTE: The Rust router will panic with less than 3 samples | ||||
| const MIN_NUM_SAMPLE_INPUTS = 3; | ||||
| @@ -69,21 +67,6 @@ function calculateOuputFee( | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Use linear interpolation to approximate the output | ||||
| // at a certain input somewhere between the two samples | ||||
| // See https://en.wikipedia.org/wiki/Linear_interpolation | ||||
| const interpolateOutputFromSamples = ( | ||||
|     left: { input: BigNumber; output: BigNumber }, | ||||
|     right: { input: BigNumber; output: BigNumber }, | ||||
|     targetInput: BigNumber, | ||||
| ): BigNumber => | ||||
|     left.output.plus( | ||||
|         right.output | ||||
|             .minus(left.output) | ||||
|             .dividedBy(right.input.minus(left.input)) | ||||
|             .times(targetInput.minus(left.input)), | ||||
|     ); | ||||
|  | ||||
| function findRoutesAndCreateOptimalPath( | ||||
|     side: MarketOperation, | ||||
|     samples: DexSample[][], | ||||
| @@ -91,29 +74,27 @@ function findRoutesAndCreateOptimalPath( | ||||
|     input: BigNumber, | ||||
|     opts: PathPenaltyOpts, | ||||
|     fees: FeeSchedule, | ||||
|     neonRouterNumSamples: number, | ||||
| ): Path | undefined { | ||||
|     const createFill = (sample: DexSample) => | ||||
|         dexSamplesToFills(side, [sample], opts.outputAmountPerEth, opts.inputAmountPerEth, fees)[0]; | ||||
|     // Track sample id's to integers (required by rust router) | ||||
|     const sampleIdLookup: { [key: string]: number } = {}; | ||||
|     let sampleIdCounter = 0; | ||||
|     const sampleToId = (source: ERC20BridgeSource, index: number): number => { | ||||
|         const key = `${source}-${index}`; | ||||
|         if (sampleIdLookup[key]) { | ||||
|             return sampleIdLookup[key]; | ||||
|         } else { | ||||
|             sampleIdLookup[key] = ++sampleIdCounter; | ||||
|             return sampleIdLookup[key]; | ||||
|     const createFill = (sample: DexSample): Fill | undefined => { | ||||
|         const fills = dexSamplesToFills(side, [sample], opts.outputAmountPerEth, opts.inputAmountPerEth, fees); | ||||
|         // NOTE: If the sample has 0 output dexSamplesToFills will return [] because no fill can be created | ||||
|         if (fills.length === 0) { | ||||
|             return undefined; | ||||
|         } | ||||
|  | ||||
|         return fills[0]; | ||||
|     }; | ||||
|  | ||||
|     const samplesAndNativeOrdersWithResults: Array<DexSample[] | NativeOrderWithFillableAmounts[]> = []; | ||||
|     const serializedPaths: SerializedPath[] = []; | ||||
|     const sampleSourcePathIds: string[] = []; | ||||
|     for (const singleSourceSamples of samples) { | ||||
|         if (singleSourceSamples.length === 0) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         const sourcePathId = hexUtils.random(); | ||||
|         const singleSourceSamplesWithOutput = [...singleSourceSamples]; | ||||
|         for (let i = singleSourceSamples.length - 1; i >= 0; i--) { | ||||
|             if (singleSourceSamples[i].output.isZero()) { | ||||
| @@ -131,7 +112,7 @@ function findRoutesAndCreateOptimalPath( | ||||
|         // TODO(kimpers): Do we need to handle 0 entries, from eg Kyber? | ||||
|         const serializedPath = singleSourceSamplesWithOutput.reduce<SerializedPath>( | ||||
|             (memo, sample, sampleIdx) => { | ||||
|                 memo.ids.push(sampleToId(sample.source, sampleIdx)); | ||||
|                 memo.ids.push(`${sample.source}-${serializedPaths.length}-${sampleIdx}`); | ||||
|                 memo.inputs.push(sample.input.integerValue().toNumber()); | ||||
|                 memo.outputs.push(sample.output.integerValue().toNumber()); | ||||
|                 memo.outputFees.push( | ||||
| @@ -152,8 +133,10 @@ function findRoutesAndCreateOptimalPath( | ||||
|  | ||||
|         samplesAndNativeOrdersWithResults.push(singleSourceSamplesWithOutput); | ||||
|         serializedPaths.push(serializedPath); | ||||
|         sampleSourcePathIds.push(sourcePathId); | ||||
|     } | ||||
|  | ||||
|     const nativeOrdersourcePathId = hexUtils.random(); | ||||
|     for (const [idx, nativeOrder] of nativeOrders.entries()) { | ||||
|         const { input: normalizedOrderInput, output: normalizedOrderOutput } = nativeOrderToNormalizedAmounts( | ||||
|             side, | ||||
| @@ -164,32 +147,25 @@ function findRoutesAndCreateOptimalPath( | ||||
|         if (normalizedOrderInput.isLessThanOrEqualTo(0) || normalizedOrderOutput.isLessThanOrEqualTo(0)) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         // HACK: the router requires at minimum 3 samples as a basis for interpolation | ||||
|         const inputs = [ | ||||
|             0, | ||||
|             normalizedOrderInput | ||||
|                 .dividedBy(2) | ||||
|                 .integerValue() | ||||
|                 .toNumber(), | ||||
|             normalizedOrderInput.integerValue().toNumber(), | ||||
|         ]; | ||||
|         const outputs = [ | ||||
|             0, | ||||
|             normalizedOrderOutput | ||||
|                 .dividedBy(2) | ||||
|                 .integerValue() | ||||
|                 .toNumber(), | ||||
|             normalizedOrderOutput.integerValue().toNumber(), | ||||
|         ]; | ||||
|         // NOTE: same fee no matter if full or partial fill | ||||
|         const fee = calculateOuputFee(side, nativeOrder, opts.outputAmountPerEth, opts.inputAmountPerEth, fees) | ||||
|             .integerValue() | ||||
|             .toNumber(); | ||||
|         const outputFees = [fee, fee, fee]; | ||||
|         // NOTE: ids can be the same for all fake samples | ||||
|         const id = sampleToId(ERC20BridgeSource.Native, idx); | ||||
|         const ids = [id, id, id]; | ||||
|  | ||||
|         // HACK: due to an issue with the Rust router interpolation we need to create exactly 13 samples from the native order | ||||
|         const ids = []; | ||||
|         const inputs = []; | ||||
|         const outputs = []; | ||||
|         const outputFees = []; | ||||
|         for (let i = 1; i <= 13; i++) { | ||||
|             const fraction = i / 13; | ||||
|             const currentInput = BigNumber.min(normalizedOrderInput.times(fraction), normalizedOrderInput); | ||||
|             const currentOutput = BigNumber.min(normalizedOrderOutput.times(fraction), normalizedOrderOutput); | ||||
|             const id = `${ERC20BridgeSource.Native}-${serializedPaths.length}-${idx}-${i}`; | ||||
|             inputs.push(currentInput.integerValue().toNumber()); | ||||
|             outputs.push(currentOutput.integerValue().toNumber()); | ||||
|             outputFees.push(fee); | ||||
|             ids.push(id); | ||||
|         } | ||||
|  | ||||
|         const serializedPath: SerializedPath = { | ||||
|             ids, | ||||
| @@ -200,6 +176,7 @@ function findRoutesAndCreateOptimalPath( | ||||
|  | ||||
|         samplesAndNativeOrdersWithResults.push([nativeOrder]); | ||||
|         serializedPaths.push(serializedPath); | ||||
|         sampleSourcePathIds.push(nativeOrdersourcePathId); | ||||
|     } | ||||
|  | ||||
|     if (serializedPaths.length === 0) { | ||||
| @@ -212,30 +189,33 @@ function findRoutesAndCreateOptimalPath( | ||||
|         pathsIn: serializedPaths, | ||||
|     }; | ||||
|  | ||||
|     const before = performance.now(); | ||||
|     const allSourcesRustRoute = new Float64Array(rustArgs.pathsIn.length); | ||||
|     route(rustArgs, allSourcesRustRoute, RUST_ROUTER_NUM_SAMPLES); | ||||
|     DEFAULT_INFO_LOGGER( | ||||
|         { router: 'neon-router', performanceMs: performance.now() - before, type: 'real' }, | ||||
|         'Rust router real routing performance', | ||||
|     ); | ||||
|  | ||||
|     const strategySourcesOutputAmounts = new Float64Array(rustArgs.pathsIn.length); | ||||
|     route(rustArgs, allSourcesRustRoute, strategySourcesOutputAmounts, neonRouterNumSamples); | ||||
|     assert.assert( | ||||
|         rustArgs.pathsIn.length === allSourcesRustRoute.length, | ||||
|         'different number of sources in the Router output than the input', | ||||
|     ); | ||||
|     assert.assert( | ||||
|         rustArgs.pathsIn.length === strategySourcesOutputAmounts.length, | ||||
|         'different number of sources in the Router output amounts results than the input', | ||||
|     ); | ||||
|  | ||||
|     const routesAndSamples = _.zip(allSourcesRustRoute, samplesAndNativeOrdersWithResults); | ||||
|  | ||||
|     const routesAndSamplesAndOutputs = _.zip( | ||||
|         allSourcesRustRoute, | ||||
|         samplesAndNativeOrdersWithResults, | ||||
|         strategySourcesOutputAmounts, | ||||
|         sampleSourcePathIds, | ||||
|     ); | ||||
|     const adjustedFills: Fill[] = []; | ||||
|     const totalRoutedAmount = BigNumber.sum(...allSourcesRustRoute); | ||||
|  | ||||
|     const scale = input.dividedBy(totalRoutedAmount); | ||||
|     for (const [routeInput, routeSamplesAndNativeOrders] of routesAndSamples) { | ||||
|         if (!routeInput || !routeSamplesAndNativeOrders) { | ||||
|     for (const [routeInput, routeSamplesAndNativeOrders, outputAmount, sourcePathId] of routesAndSamplesAndOutputs) { | ||||
|         if (!routeInput || !routeSamplesAndNativeOrders || !outputAmount || !Number.isFinite(outputAmount)) { | ||||
|             continue; | ||||
|         } | ||||
|         // TODO(kimpers): [TKR-241] amounts are sometimes clipped in the router due to precisions loss for number/f64 | ||||
|         // TODO(kimpers): [TKR-241] amounts are sometimes clipped in the router due to precision loss for number/f64 | ||||
|         // we can work around it by scaling it and rounding up. However now we end up with a total amount of a couple base units too much | ||||
|         const rustInputAdjusted = BigNumber.min( | ||||
|             new BigNumber(routeInput).multipliedBy(scale).integerValue(BigNumber.ROUND_CEIL), | ||||
| @@ -251,14 +231,21 @@ function findRoutesAndCreateOptimalPath( | ||||
|                 opts.outputAmountPerEth, | ||||
|                 opts.inputAmountPerEth, | ||||
|                 fees, | ||||
|             )[0]; | ||||
|             // NOTE: For Limit/RFQ orders we are done here. No need to scale output | ||||
|             adjustedFills.push(nativeFill); | ||||
|             )[0] as Fill | undefined; | ||||
|             // Note: If the order has an adjusted rate of less than or equal to 0 it will be skipped | ||||
|             // and nativeFill will be `undefined` | ||||
|             if (nativeFill) { | ||||
|                 // NOTE: For Limit/RFQ orders we are done here. No need to scale output | ||||
|                 adjustedFills.push({ ...nativeFill, sourcePathId: sourcePathId ?? hexUtils.random() }); | ||||
|             } | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         // NOTE: For DexSamples only | ||||
|         let fill = createFill(current); | ||||
|         if (!fill) { | ||||
|             continue; | ||||
|         } | ||||
|         const routeSamples = routeSamplesAndNativeOrders as Array<DexSample<FillData>>; | ||||
|         // Descend to approach a closer fill for fillData which may not be consistent | ||||
|         // throughout the path (UniswapV3) and for a closer guesstimate at | ||||
| @@ -267,49 +254,47 @@ function findRoutesAndCreateOptimalPath( | ||||
|         assert.assert(routeSamples.length >= 1, 'Found no sample to use for source'); | ||||
|         for (let k = routeSamples.length - 1; k >= 0; k--) { | ||||
|             if (k === 0) { | ||||
|                 fill = createFill(routeSamples[0]); | ||||
|                 fill = createFill(routeSamples[0]) ?? fill; | ||||
|             } | ||||
|             if (rustInputAdjusted.isGreaterThan(routeSamples[k].input)) { | ||||
|                 // Between here and the previous fill | ||||
|                 // HACK: Use the midpoint between the two | ||||
|                 const left = routeSamples[k]; | ||||
|                 const right = routeSamples[k + 1]; | ||||
|                 if (left && right) { | ||||
|                     // Approximate how much output we get for the input with the surrounding samples | ||||
|                     const interpolatedOutput = interpolateOutputFromSamples( | ||||
|                         left, | ||||
|                         right, | ||||
|                         rustInputAdjusted, | ||||
|                     ).decimalPlaces(0, side === MarketOperation.Sell ? BigNumber.ROUND_FLOOR : BigNumber.ROUND_CEIL); | ||||
|  | ||||
|                     fill = createFill({ | ||||
|                         ...right, // default to the greater (for gas used) | ||||
|                         input: rustInputAdjusted, | ||||
|                         output: interpolatedOutput, | ||||
|                     }); | ||||
|                     fill = | ||||
|                         createFill({ | ||||
|                             ...right, // default to the greater (for gas used) | ||||
|                             input: rustInputAdjusted, | ||||
|                             output: new BigNumber(outputAmount), | ||||
|                         }) ?? fill; | ||||
|                 } else { | ||||
|                     assert.assert(Boolean(left || right), 'No valid sample to use'); | ||||
|                     fill = createFill(left || right); | ||||
|                     fill = createFill(left || right) ?? fill; | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         const scaleOutput = (output: BigNumber) => | ||||
|         // TODO(kimpers): remove once we have solved the rounding/precision loss issues in the Rust router | ||||
|         const scaleOutput = (fillInput: BigNumber, output: BigNumber) => | ||||
|             output | ||||
|                 .dividedBy(fill.input) | ||||
|                 .dividedBy(fillInput) | ||||
|                 .times(rustInputAdjusted) | ||||
|                 .decimalPlaces(0, side === MarketOperation.Sell ? BigNumber.ROUND_FLOOR : BigNumber.ROUND_CEIL); | ||||
|         adjustedFills.push({ | ||||
|             ...fill, | ||||
|             input: rustInputAdjusted, | ||||
|             output: scaleOutput(fill.output), | ||||
|             adjustedOutput: scaleOutput(fill.adjustedOutput), | ||||
|             output: scaleOutput(fill.input, fill.output), | ||||
|             adjustedOutput: scaleOutput(fill.input, fill.adjustedOutput), | ||||
|             index: 0, | ||||
|             parent: undefined, | ||||
|             sourcePathId: sourcePathId ?? hexUtils.random(), | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     if (adjustedFills.length === 0) { | ||||
|         return undefined; | ||||
|     } | ||||
|  | ||||
|     const pathFromRustInputs = Path.create(side, adjustedFills, input); | ||||
|  | ||||
|     return pathFromRustInputs; | ||||
| @@ -323,15 +308,27 @@ export function findOptimalRustPathFromSamples( | ||||
|     opts: PathPenaltyOpts, | ||||
|     fees: FeeSchedule, | ||||
|     chainId: ChainId, | ||||
|     neonRouterNumSamples: number, | ||||
|     samplerMetrics?: SamplerMetrics, | ||||
| ): Path | undefined { | ||||
|     const before = performance.now(); | ||||
|     const logPerformance = () => | ||||
|         DEFAULT_INFO_LOGGER( | ||||
|             { router: 'neon-router', performanceMs: performance.now() - before, type: 'total' }, | ||||
|             'Rust router total routing performance', | ||||
|         ); | ||||
|  | ||||
|     const allSourcesPath = findRoutesAndCreateOptimalPath(side, samples, nativeOrders, input, opts, fees); | ||||
|     const beforeAllTimeMs = performance.now(); | ||||
|     let beforeTimeMs = performance.now(); | ||||
|     const allSourcesPath = findRoutesAndCreateOptimalPath( | ||||
|         side, | ||||
|         samples, | ||||
|         nativeOrders, | ||||
|         input, | ||||
|         opts, | ||||
|         fees, | ||||
|         neonRouterNumSamples, | ||||
|     ); | ||||
|     // tslint:disable-next-line: no-unused-expression | ||||
|     samplerMetrics && | ||||
|         samplerMetrics.logRouterDetails({ | ||||
|             router: 'neon-router', | ||||
|             type: 'all', | ||||
|             timingMs: performance.now() - beforeTimeMs, | ||||
|         }); | ||||
|     if (!allSourcesPath) { | ||||
|         return undefined; | ||||
|     } | ||||
| @@ -341,11 +338,27 @@ export function findOptimalRustPathFromSamples( | ||||
|     // HACK(kimpers): The Rust router currently doesn't account for VIP sources correctly | ||||
|     // we need to try to route them in isolation and compare with the results all sources | ||||
|     if (vipSources.length > 0) { | ||||
|         beforeTimeMs = performance.now(); | ||||
|         const vipSourcesSet = new Set(vipSources); | ||||
|         const vipSourcesSamples = samples.filter(s => s[0] && vipSourcesSet.has(s[0].source)); | ||||
|  | ||||
|         if (vipSourcesSamples.length > 0) { | ||||
|             const vipSourcesPath = findRoutesAndCreateOptimalPath(side, vipSourcesSamples, [], input, opts, fees); | ||||
|             const vipSourcesPath = findRoutesAndCreateOptimalPath( | ||||
|                 side, | ||||
|                 vipSourcesSamples, | ||||
|                 [], | ||||
|                 input, | ||||
|                 opts, | ||||
|                 fees, | ||||
|                 neonRouterNumSamples, | ||||
|             ); | ||||
|             // tslint:disable-next-line: no-unused-expression | ||||
|             samplerMetrics && | ||||
|                 samplerMetrics.logRouterDetails({ | ||||
|                     router: 'neon-router', | ||||
|                     type: 'vip', | ||||
|                     timingMs: performance.now() - beforeTimeMs, | ||||
|                 }); | ||||
|  | ||||
|             const { input: allSourcesInput, output: allSourcesOutput } = allSourcesPath.adjustedSize(); | ||||
|             // NOTE: For sell quotes input is the taker asset and for buy quotes input is the maker asset | ||||
| @@ -358,13 +371,18 @@ export function findOptimalRustPathFromSamples( | ||||
|             const allSourcesAdjustedRateWithFqtOverhead = getRate(side, allSourcesInput, outputWithFqtOverhead); | ||||
|  | ||||
|             if (vipSourcesPath?.adjustedRate().isGreaterThan(allSourcesAdjustedRateWithFqtOverhead)) { | ||||
|                 logPerformance(); | ||||
|                 return vipSourcesPath; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     // tslint:disable-next-line: no-unused-expression | ||||
|     samplerMetrics && | ||||
|         samplerMetrics.logRouterDetails({ | ||||
|             router: 'neon-router', | ||||
|             type: 'total', | ||||
|             timingMs: performance.now() - beforeAllTimeMs, | ||||
|         }); | ||||
|  | ||||
|     logPerformance(); | ||||
|     return allSourcesPath; | ||||
| } | ||||
|  | ||||
| @@ -377,8 +395,10 @@ export async function findOptimalPathJSAsync( | ||||
|     fills: Fill[][], | ||||
|     targetInput: BigNumber, | ||||
|     runLimit: number = 2 ** 8, | ||||
|     samplerMetrics?: SamplerMetrics, | ||||
|     opts: PathPenaltyOpts = DEFAULT_PATH_PENALTY_OPTS, | ||||
| ): Promise<Path | undefined> { | ||||
|     const beforeTimeMs = performance.now(); | ||||
|     // Sort fill arrays by descending adjusted completed rate. | ||||
|     // Remove any paths which cannot impact the optimal path | ||||
|     const sortedPaths = reducePaths(fillsToSortedPaths(fills, side, targetInput, opts), side); | ||||
| @@ -392,7 +412,15 @@ export async function findOptimalPathJSAsync( | ||||
|         // Yield to event loop. | ||||
|         await Promise.resolve(); | ||||
|     } | ||||
|     return optimalPath.isComplete() ? optimalPath : undefined; | ||||
|     const finalPath = optimalPath.isComplete() ? optimalPath : undefined; | ||||
|     // tslint:disable-next-line: no-unused-expression | ||||
|     samplerMetrics && | ||||
|         samplerMetrics.logRouterDetails({ | ||||
|             router: 'js', | ||||
|             type: 'total', | ||||
|             timingMs: performance.now() - beforeTimeMs, | ||||
|         }); | ||||
|     return finalPath; | ||||
| } | ||||
|  | ||||
| // Sort fill arrays by descending adjusted completed rate. | ||||
|   | ||||
| @@ -14,7 +14,8 @@ import { BatchedOperation, ERC20BridgeSource, LiquidityProviderRegistry, TokenAd | ||||
|  */ | ||||
| export function getSampleAmounts(maxFillAmount: BigNumber, numSamples: number, expBase: number = 1): BigNumber[] { | ||||
|     const distribution = [...Array<BigNumber>(numSamples)].map((_v, i) => new BigNumber(expBase).pow(i)); | ||||
|     const stepSizes = distribution.map(d => d.div(BigNumber.sum(...distribution))); | ||||
|     const distributionSum = BigNumber.sum(...distribution); | ||||
|     const stepSizes = distribution.map(d => d.div(distributionSum)); | ||||
|     const amounts = stepSizes.map((_s, i) => { | ||||
|         if (i === numSamples - 1) { | ||||
|             return maxFillAmount; | ||||
| @@ -130,6 +131,37 @@ export class DexOrderSampler extends SamplerOperations { | ||||
|         BatchedOperationResult<T8> | ||||
|     ]>; | ||||
|  | ||||
|     // prettier-ignore | ||||
|     public async executeAsync< | ||||
|         T1, T2, T3, T4, T5, T6, T7, T8, T9 | ||||
|     >(...ops: [T1, T2, T3, T4, T5, T6, T7, T8, T9]): Promise<[ | ||||
|         BatchedOperationResult<T1>, | ||||
|         BatchedOperationResult<T2>, | ||||
|         BatchedOperationResult<T3>, | ||||
|         BatchedOperationResult<T4>, | ||||
|         BatchedOperationResult<T5>, | ||||
|         BatchedOperationResult<T6>, | ||||
|         BatchedOperationResult<T7>, | ||||
|         BatchedOperationResult<T8>, | ||||
|         BatchedOperationResult<T9> | ||||
|     ]>; | ||||
|  | ||||
|     // prettier-ignore | ||||
|     public async executeAsync< | ||||
|         T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 | ||||
|     >(...ops: [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]): Promise<[ | ||||
|         BatchedOperationResult<T1>, | ||||
|         BatchedOperationResult<T2>, | ||||
|         BatchedOperationResult<T3>, | ||||
|         BatchedOperationResult<T4>, | ||||
|         BatchedOperationResult<T5>, | ||||
|         BatchedOperationResult<T6>, | ||||
|         BatchedOperationResult<T7>, | ||||
|         BatchedOperationResult<T8>, | ||||
|         BatchedOperationResult<T9>, | ||||
|         BatchedOperationResult<T10>, | ||||
|     ]>; | ||||
|  | ||||
|     /** | ||||
|      * Run a series of operations from `DexOrderSampler.ops` in a single transaction. | ||||
|      */ | ||||
|   | ||||
| @@ -0,0 +1,36 @@ | ||||
| import { BigNumber, logUtils, NULL_BYTES } from '@0x/utils'; | ||||
|  | ||||
| import { ERC20BridgeSource, FillData, SourceQuoteOperation } from './types'; | ||||
|  | ||||
| interface SamplerNoOperationCall { | ||||
|     callback: () => BigNumber[]; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * SamplerNoOperation can be used for sources where we already have all the necessary information | ||||
|  * required to perform the sample operations, without needing access to any on-chain data. Using a noop sample | ||||
|  * you can skip the eth_call, and just calculate the results directly in typescript land. | ||||
|  */ | ||||
| export class SamplerNoOperation<TFillData extends FillData = FillData> implements SourceQuoteOperation<TFillData> { | ||||
|     public readonly source: ERC20BridgeSource; | ||||
|     public fillData: TFillData; | ||||
|     private readonly _callback: () => BigNumber[]; | ||||
|  | ||||
|     constructor(opts: { source: ERC20BridgeSource; fillData?: TFillData } & SamplerNoOperationCall) { | ||||
|         this.source = opts.source; | ||||
|         this.fillData = opts.fillData || ({} as TFillData); // tslint:disable-line:no-object-literal-type-assertion | ||||
|         this._callback = opts.callback; | ||||
|     } | ||||
|  | ||||
|     // tslint:disable-next-line:prefer-function-over-method | ||||
|     public encodeCall(): string { | ||||
|         return NULL_BYTES; | ||||
|     } | ||||
|     public handleCallResults(_callResults: string): BigNumber[] { | ||||
|         return this._callback(); | ||||
|     } | ||||
|     public handleRevert(_callResults: string): BigNumber[] { | ||||
|         logUtils.warn(`SamplerNoOperation: ${this.source} reverted`); | ||||
|         return []; | ||||
|     } | ||||
| } | ||||
| @@ -3,9 +3,11 @@ import { LimitOrderFields } from '@0x/protocol-utils'; | ||||
| import { BigNumber, logUtils } from '@0x/utils'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { AaveV2Sampler } from '../../noop_samplers/AaveV2Sampler'; | ||||
| import { SamplerCallResult, SignedNativeOrder } from '../../types'; | ||||
| import { ERC20BridgeSamplerContract } from '../../wrappers'; | ||||
|  | ||||
| import { AaveV2ReservesCache } from './aave_reserves_cache'; | ||||
| import { BancorService } from './bancor_service'; | ||||
| import { | ||||
|     getCurveLikeInfosForPair, | ||||
| @@ -17,9 +19,14 @@ import { | ||||
|     isValidAddress, | ||||
|     uniswapV2LikeRouterAddress, | ||||
| } from './bridge_source_utils'; | ||||
| import { CompoundCTokenCache } from './compound_ctoken_cache'; | ||||
| import { | ||||
|     AAVE_V2_SUBGRAPH_URL_BY_CHAIN_ID, | ||||
|     BALANCER_V2_VAULT_ADDRESS_BY_CHAIN, | ||||
|     BANCOR_REGISTRY_BY_CHAIN_ID, | ||||
|     BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN, | ||||
|     BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN, | ||||
|     COMPOUND_API_URL_BY_CHAIN_ID, | ||||
|     DODOV1_CONFIG_BY_CHAIN_ID, | ||||
|     DODOV2_FACTORIES_BY_CHAIN_ID, | ||||
|     KYBER_CONFIG_BY_CHAIN_ID, | ||||
| @@ -43,13 +50,17 @@ import { getLiquidityProvidersForPair } from './liquidity_provider_utils'; | ||||
| import { getIntermediateTokens } from './multihop_utils'; | ||||
| import { BalancerPoolsCache, BalancerV2PoolsCache, CreamPoolsCache, PoolsCache } from './pools_cache'; | ||||
| import { SamplerContractOperation } from './sampler_contract_operation'; | ||||
| import { SamplerNoOperation } from './sampler_no_operation'; | ||||
| import { SourceFilters } from './source_filters'; | ||||
| import { | ||||
|     AaveV2FillData, | ||||
|     AaveV2Info, | ||||
|     BalancerFillData, | ||||
|     BalancerV2FillData, | ||||
|     BalancerV2PoolInfo, | ||||
|     BancorFillData, | ||||
|     BatchedOperation, | ||||
|     CompoundFillData, | ||||
|     CurveFillData, | ||||
|     CurveInfo, | ||||
|     DexSample, | ||||
| @@ -97,6 +108,8 @@ export const BATCH_SOURCE_FILTERS = SourceFilters.all().exclude([ERC20BridgeSour | ||||
| export class SamplerOperations { | ||||
|     public readonly liquidityProviderRegistry: LiquidityProviderRegistry; | ||||
|     public readonly poolsCaches: { [key in SourcesWithPoolsCache]: PoolsCache }; | ||||
|     public readonly aaveReservesCache: AaveV2ReservesCache | undefined; | ||||
|     public readonly compoundCTokenCache: CompoundCTokenCache | undefined; | ||||
|     protected _bancorService?: BancorService; | ||||
|     public static constant<T>(result: T): BatchedOperation<T> { | ||||
|         return { | ||||
| @@ -122,9 +135,26 @@ export class SamplerOperations { | ||||
|             ? poolsCaches | ||||
|             : { | ||||
|                   [ERC20BridgeSource.BalancerV2]: new BalancerV2PoolsCache(chainId), | ||||
|                   [ERC20BridgeSource.Beethovenx]: new BalancerV2PoolsCache( | ||||
|                       chainId, | ||||
|                       BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN[chainId], | ||||
|                   ), | ||||
|                   [ERC20BridgeSource.Balancer]: new BalancerPoolsCache(), | ||||
|                   [ERC20BridgeSource.Cream]: new CreamPoolsCache(), | ||||
|               }; | ||||
|  | ||||
|         const aaveSubgraphUrl = AAVE_V2_SUBGRAPH_URL_BY_CHAIN_ID[chainId]; | ||||
|         if (aaveSubgraphUrl) { | ||||
|             this.aaveReservesCache = new AaveV2ReservesCache(aaveSubgraphUrl); | ||||
|         } | ||||
|  | ||||
|         const compoundApiUrl = COMPOUND_API_URL_BY_CHAIN_ID[chainId]; | ||||
|         if (compoundApiUrl) { | ||||
|             this.compoundCTokenCache = new CompoundCTokenCache( | ||||
|                 compoundApiUrl, | ||||
|                 NATIVE_FEE_TOKEN_BY_CHAIN_ID[this.chainId], | ||||
|             ); | ||||
|         } | ||||
|         // Initialize the Bancor service, fetching paths in the background | ||||
|         bancorServiceFn() | ||||
|             .then(service => (this._bancorService = service)) | ||||
| @@ -152,6 +182,30 @@ export class SamplerOperations { | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     public getGasLeft(): BatchedOperation<BigNumber> { | ||||
|         return { | ||||
|             encodeCall: () => this._samplerContract.getGasLeft().getABIEncodedTransactionData(), | ||||
|             handleCallResults: (callResults: string) => | ||||
|                 this._samplerContract.getABIDecodedReturnData<BigNumber>('getGasLeft', callResults), | ||||
|             handleRevert: () => { | ||||
|                 /* should never happen */ | ||||
|                 throw new Error('Invalid result for getGasLeft'); | ||||
|             }, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     public getBlockNumber(): BatchedOperation<BigNumber> { | ||||
|         return { | ||||
|             encodeCall: () => this._samplerContract.getBlockNumber().getABIEncodedTransactionData(), | ||||
|             handleCallResults: (callResults: string) => | ||||
|                 this._samplerContract.getABIDecodedReturnData<BigNumber>('getBlockNumber', callResults), | ||||
|             handleRevert: () => { | ||||
|                 /* should never happen */ | ||||
|                 throw new Error('Invalid result for getBlockNumber'); | ||||
|             }, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     public getLimitOrderFillableTakerAmounts( | ||||
|         orders: SignedNativeOrder[], | ||||
|         exchangeAddress: string, | ||||
| @@ -1069,6 +1123,64 @@ export class SamplerOperations { | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     // tslint:disable-next-line:prefer-function-over-method | ||||
|     public getAaveV2SellQuotes( | ||||
|         aaveInfo: AaveV2Info, | ||||
|         makerToken: string, | ||||
|         takerToken: string, | ||||
|         takerFillAmounts: BigNumber[], | ||||
|     ): SourceQuoteOperation<AaveV2FillData> { | ||||
|         return new SamplerNoOperation({ | ||||
|             source: ERC20BridgeSource.AaveV2, | ||||
|             fillData: { ...aaveInfo, takerToken }, | ||||
|             callback: () => AaveV2Sampler.sampleSellsFromAaveV2(aaveInfo, takerToken, makerToken, takerFillAmounts), | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     // tslint:disable-next-line:prefer-function-over-method | ||||
|     public getAaveV2BuyQuotes( | ||||
|         aaveInfo: AaveV2Info, | ||||
|         makerToken: string, | ||||
|         takerToken: string, | ||||
|         makerFillAmounts: BigNumber[], | ||||
|     ): SourceQuoteOperation<AaveV2FillData> { | ||||
|         return new SamplerNoOperation({ | ||||
|             source: ERC20BridgeSource.AaveV2, | ||||
|             fillData: { ...aaveInfo, takerToken }, | ||||
|             callback: () => AaveV2Sampler.sampleBuysFromAaveV2(aaveInfo, takerToken, makerToken, makerFillAmounts), | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     public getCompoundSellQuotes( | ||||
|         cToken: string, | ||||
|         makerToken: string, | ||||
|         takerToken: string, | ||||
|         takerFillAmounts: BigNumber[], | ||||
|     ): SourceQuoteOperation<CompoundFillData> { | ||||
|         return new SamplerContractOperation({ | ||||
|             source: ERC20BridgeSource.Compound, | ||||
|             fillData: { cToken, takerToken, makerToken }, | ||||
|             contract: this._samplerContract, | ||||
|             function: this._samplerContract.sampleSellsFromCompound, | ||||
|             params: [cToken, takerToken, makerToken, takerFillAmounts], | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     public getCompoundBuyQuotes( | ||||
|         cToken: string, | ||||
|         makerToken: string, | ||||
|         takerToken: string, | ||||
|         makerFillAmounts: BigNumber[], | ||||
|     ): SourceQuoteOperation<CompoundFillData> { | ||||
|         return new SamplerContractOperation({ | ||||
|             source: ERC20BridgeSource.Compound, | ||||
|             fillData: { cToken, takerToken, makerToken }, | ||||
|             contract: this._samplerContract, | ||||
|             function: this._samplerContract.sampleBuysFromCompound, | ||||
|             params: [cToken, takerToken, makerToken, makerFillAmounts], | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     public getMedianSellRate( | ||||
|         sources: ERC20BridgeSource[], | ||||
|         makerToken: string, | ||||
| @@ -1197,8 +1309,10 @@ export class SamplerOperations { | ||||
|                     case ERC20BridgeSource.JetSwap: | ||||
|                     case ERC20BridgeSource.Pangolin: | ||||
|                     case ERC20BridgeSource.TraderJoe: | ||||
|                     case ERC20BridgeSource.UbeSwap: | ||||
|                     case ERC20BridgeSource.SpiritSwap: | ||||
|                     case ERC20BridgeSource.SpookySwap: | ||||
|                     case ERC20BridgeSource.MorpheusSwap: | ||||
|                         const uniLikeRouter = uniswapV2LikeRouterAddress(this.chainId, source); | ||||
|                         if (!isValidAddress(uniLikeRouter)) { | ||||
|                             return []; | ||||
| @@ -1300,13 +1414,14 @@ export class SamplerOperations { | ||||
|                             ), | ||||
|                         ); | ||||
|                     case ERC20BridgeSource.BalancerV2: | ||||
|                     case ERC20BridgeSource.Beethovenx: | ||||
|                         const poolIds = | ||||
|                             this.poolsCaches[ERC20BridgeSource.BalancerV2].getCachedPoolAddressesForPair( | ||||
|                                 takerToken, | ||||
|                                 makerToken, | ||||
|                             ) || []; | ||||
|                             this.poolsCaches[source].getCachedPoolAddressesForPair(takerToken, makerToken) || []; | ||||
|  | ||||
|                         const vault = BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[this.chainId]; | ||||
|                         const vault = | ||||
|                             source === ERC20BridgeSource.BalancerV2 | ||||
|                                 ? BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[this.chainId] | ||||
|                                 : BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId]; | ||||
|                         if (vault === NULL_ADDRESS) { | ||||
|                             return []; | ||||
|                         } | ||||
| @@ -1316,10 +1431,9 @@ export class SamplerOperations { | ||||
|                                 makerToken, | ||||
|                                 takerToken, | ||||
|                                 takerFillAmounts, | ||||
|                                 ERC20BridgeSource.BalancerV2, | ||||
|                                 source, | ||||
|                             ), | ||||
|                         ); | ||||
|  | ||||
|                     case ERC20BridgeSource.Cream: | ||||
|                         return ( | ||||
|                             this.poolsCaches[ERC20BridgeSource.Cream].getCachedPoolAddressesForPair( | ||||
| @@ -1417,6 +1531,38 @@ export class SamplerOperations { | ||||
|  | ||||
|                         return this.getLidoSellQuotes(lidoInfo, makerToken, takerToken, takerFillAmounts); | ||||
|                     } | ||||
|                     case ERC20BridgeSource.AaveV2: { | ||||
|                         if (!this.aaveReservesCache) { | ||||
|                             return []; | ||||
|                         } | ||||
|                         const reserve = this.aaveReservesCache.get(takerToken, makerToken); | ||||
|                         if (!reserve) { | ||||
|                             return []; | ||||
|                         } | ||||
|  | ||||
|                         const info: AaveV2Info = { | ||||
|                             lendingPool: reserve.pool.lendingPool, | ||||
|                             aToken: reserve.aToken.id, | ||||
|                             underlyingToken: reserve.underlyingAsset, | ||||
|                         }; | ||||
|                         return this.getAaveV2SellQuotes(info, makerToken, takerToken, takerFillAmounts); | ||||
|                     } | ||||
|                     case ERC20BridgeSource.Compound: { | ||||
|                         if (!this.compoundCTokenCache) { | ||||
|                             return []; | ||||
|                         } | ||||
|  | ||||
|                         const cToken = this.compoundCTokenCache.get(takerToken, makerToken); | ||||
|                         if (!cToken) { | ||||
|                             return []; | ||||
|                         } | ||||
|                         return this.getCompoundSellQuotes( | ||||
|                             cToken.tokenAddress, | ||||
|                             makerToken, | ||||
|                             takerToken, | ||||
|                             takerFillAmounts, | ||||
|                         ); | ||||
|                     } | ||||
|                     default: | ||||
|                         throw new Error(`Unsupported sell sample source: ${source}`); | ||||
|                 } | ||||
| @@ -1468,8 +1614,10 @@ export class SamplerOperations { | ||||
|                     case ERC20BridgeSource.JetSwap: | ||||
|                     case ERC20BridgeSource.Pangolin: | ||||
|                     case ERC20BridgeSource.TraderJoe: | ||||
|                     case ERC20BridgeSource.UbeSwap: | ||||
|                     case ERC20BridgeSource.SpiritSwap: | ||||
|                     case ERC20BridgeSource.SpookySwap: | ||||
|                     case ERC20BridgeSource.MorpheusSwap: | ||||
|                         const uniLikeRouter = uniswapV2LikeRouterAddress(this.chainId, source); | ||||
|                         if (!isValidAddress(uniLikeRouter)) { | ||||
|                             return []; | ||||
| @@ -1571,13 +1719,14 @@ export class SamplerOperations { | ||||
|                             ), | ||||
|                         ); | ||||
|                     case ERC20BridgeSource.BalancerV2: | ||||
|                     case ERC20BridgeSource.Beethovenx: | ||||
|                         const poolIds = | ||||
|                             this.poolsCaches[ERC20BridgeSource.BalancerV2].getCachedPoolAddressesForPair( | ||||
|                                 takerToken, | ||||
|                                 makerToken, | ||||
|                             ) || []; | ||||
|                             this.poolsCaches[source].getCachedPoolAddressesForPair(takerToken, makerToken) || []; | ||||
|  | ||||
|                         const vault = BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[this.chainId]; | ||||
|                         const vault = | ||||
|                             source === ERC20BridgeSource.BalancerV2 | ||||
|                                 ? BALANCER_V2_VAULT_ADDRESS_BY_CHAIN[this.chainId] | ||||
|                                 : BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId]; | ||||
|                         if (vault === NULL_ADDRESS) { | ||||
|                             return []; | ||||
|                         } | ||||
| @@ -1587,7 +1736,7 @@ export class SamplerOperations { | ||||
|                                 makerToken, | ||||
|                                 takerToken, | ||||
|                                 makerFillAmounts, | ||||
|                                 ERC20BridgeSource.BalancerV2, | ||||
|                                 source, | ||||
|                             ), | ||||
|                         ); | ||||
|                     case ERC20BridgeSource.Cream: | ||||
| @@ -1683,6 +1832,32 @@ export class SamplerOperations { | ||||
|  | ||||
|                         return this.getLidoBuyQuotes(lidoInfo, makerToken, takerToken, makerFillAmounts); | ||||
|                     } | ||||
|                     case ERC20BridgeSource.AaveV2: { | ||||
|                         if (!this.aaveReservesCache) { | ||||
|                             return []; | ||||
|                         } | ||||
|                         const reserve = this.aaveReservesCache.get(takerToken, makerToken); | ||||
|                         if (!reserve) { | ||||
|                             return []; | ||||
|                         } | ||||
|                         const info: AaveV2Info = { | ||||
|                             lendingPool: reserve.pool.lendingPool, | ||||
|                             aToken: reserve.aToken.id, | ||||
|                             underlyingToken: reserve.underlyingAsset, | ||||
|                         }; | ||||
|                         return this.getAaveV2BuyQuotes(info, makerToken, takerToken, makerFillAmounts); | ||||
|                     } | ||||
|                     case ERC20BridgeSource.Compound: { | ||||
|                         if (!this.compoundCTokenCache) { | ||||
|                             return []; | ||||
|                         } | ||||
|  | ||||
|                         const cToken = this.compoundCTokenCache.get(takerToken, makerToken); | ||||
|                         if (!cToken) { | ||||
|                             return []; | ||||
|                         } | ||||
|                         return this.getCompoundBuyQuotes(cToken.tokenAddress, makerToken, takerToken, makerFillAmounts); | ||||
|                     } | ||||
|                     default: | ||||
|                         throw new Error(`Unsupported buy sample source: ${source}`); | ||||
|                 } | ||||
|   | ||||
| @@ -3,13 +3,12 @@ import { | ||||
|     FillQuoteTransformerOrderType, | ||||
|     FillQuoteTransformerRfqOrderInfo, | ||||
| } from '@0x/protocol-utils'; | ||||
| import { V4RFQIndicativeQuote } from '@0x/quote-server'; | ||||
| import { MarketOperation } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
|  | ||||
| import { NativeOrderWithFillableAmounts, RfqFirmQuoteValidator, RfqRequestOpts } from '../../types'; | ||||
| import { QuoteRequestor } from '../../utils/quote_requestor'; | ||||
| import { PriceComparisonsReport, QuoteReport } from '../quote_report_generator'; | ||||
| import { QuoteRequestor, V4RFQIndicativeQuoteMM } from '../../utils/quote_requestor'; | ||||
| import { ExtendedQuoteReportSources, PriceComparisonsReport, QuoteReport } from '../quote_report_generator'; | ||||
|  | ||||
| import { CollapsedPath } from './path'; | ||||
| import { SourceFilters } from './source_filters'; | ||||
| @@ -69,6 +68,8 @@ export enum ERC20BridgeSource { | ||||
|     CurveV2 = 'Curve_V2', | ||||
|     Lido = 'Lido', | ||||
|     ShibaSwap = 'ShibaSwap', | ||||
|     AaveV2 = 'Aave_V2', | ||||
|     Compound = 'Compound', | ||||
|     // BSC only | ||||
|     PancakeSwap = 'PancakeSwap', | ||||
|     PancakeSwapV2 = 'PancakeSwap_V2', | ||||
| @@ -93,11 +94,19 @@ export enum ERC20BridgeSource { | ||||
|     // Avalanche | ||||
|     Pangolin = 'Pangolin', | ||||
|     TraderJoe = 'TraderJoe', | ||||
|     // Celo only | ||||
|     UbeSwap = 'UbeSwap', | ||||
|     // Fantom | ||||
|     SpiritSwap = 'SpiritSwap', | ||||
|     SpookySwap = 'SpookySwap', | ||||
|     Beethovenx = 'Beethovenx', | ||||
|     MorpheusSwap = 'MorpheusSwap', | ||||
| } | ||||
| export type SourcesWithPoolsCache = ERC20BridgeSource.Balancer | ERC20BridgeSource.BalancerV2 | ERC20BridgeSource.Cream; | ||||
| export type SourcesWithPoolsCache = | ||||
|     | ERC20BridgeSource.Balancer | ||||
|     | ERC20BridgeSource.BalancerV2 | ||||
|     | ERC20BridgeSource.Beethovenx | ||||
|     | ERC20BridgeSource.Cream; | ||||
|  | ||||
| // tslint:disable: enum-naming | ||||
| /** | ||||
| @@ -109,8 +118,10 @@ export enum CurveFunctionSelectors { | ||||
|     exchange_underlying = '0xa6417ed6', | ||||
|     get_dy_underlying = '0x07211ef7', | ||||
|     get_dx_underlying = '0x0e71d1b9', | ||||
|     get_dy = '0x5e0d443f', | ||||
|     get_dy = '0x5e0d443f', // get_dy(int128,int128,uint256) | ||||
|     get_dx = '0x67df02ca', | ||||
|     get_dy_uint256 = '0x556d6e9f', // get_dy(uint256,uint256,uint256) | ||||
|     exchange_underlying_uint256 = '0x65b2489b', // exchange_underlying(uint256,uint256,uint256,uint256) | ||||
|     // Curve V2 | ||||
|     exchange_v2 = '0x5b41b908', | ||||
|     exchange_underlying_v2 = '0x65b2489b', | ||||
| @@ -163,6 +174,12 @@ export interface BalancerV2PoolInfo { | ||||
|     vault: string; | ||||
| } | ||||
|  | ||||
| export interface AaveV2Info { | ||||
|     lendingPool: string; | ||||
|     aToken: string; | ||||
|     underlyingToken: string; | ||||
| } | ||||
|  | ||||
| // Internal `fillData` field for `Fill` objects. | ||||
| export interface FillData {} | ||||
|  | ||||
| @@ -270,6 +287,19 @@ export interface LidoFillData extends FillData { | ||||
|     takerToken: string; | ||||
| } | ||||
|  | ||||
| export interface AaveV2FillData extends FillData { | ||||
|     lendingPool: string; | ||||
|     aToken: string; | ||||
|     underlyingToken: string; | ||||
|     takerToken: string; | ||||
| } | ||||
|  | ||||
| export interface CompoundFillData extends FillData { | ||||
|     cToken: string; | ||||
|     takerToken: string; | ||||
|     makerToken: string; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Represents a node on a fill path. | ||||
|  */ | ||||
| @@ -425,6 +455,10 @@ export interface GetMarketOrdersOpts { | ||||
|      * Default: 1.25. | ||||
|      */ | ||||
|     sampleDistributionBase: number; | ||||
|     /** | ||||
|      * Number of samples to use when creating fill curves with neon-router | ||||
|      */ | ||||
|     neonRouterNumSamples: number; | ||||
|     /** | ||||
|      * Fees for each liquidity source, expressed in gas. | ||||
|      */ | ||||
| @@ -462,6 +496,37 @@ export interface GetMarketOrdersOpts { | ||||
|      * Gas price to use for quote | ||||
|      */ | ||||
|     gasPrice: BigNumber; | ||||
|  | ||||
|     /** | ||||
|      * Sampler metrics for recording data on the sampler service and operations | ||||
|      */ | ||||
|     samplerMetrics?: SamplerMetrics; | ||||
| } | ||||
|  | ||||
| export interface SamplerMetrics { | ||||
|     /** | ||||
|      * Logs the gas information performed during a sampler call. | ||||
|      * | ||||
|      * @param data.gasBefore The gas remaining measured before any operations have been performed | ||||
|      * @param data.gasAfter The gas remaining measured after all operations have been performed | ||||
|      */ | ||||
|     logGasDetails(data: { gasBefore: BigNumber; gasAfter: BigNumber }): void; | ||||
|  | ||||
|     /** | ||||
|      * Logs the block number | ||||
|      * | ||||
|      * @param blockNumber block number of the sampler call | ||||
|      */ | ||||
|     logBlockNumber(blockNumber: BigNumber): void; | ||||
|  | ||||
|     /** | ||||
|      * Logs the routing timings | ||||
|      * | ||||
|      * @param data.router The router type (neon-router or js) | ||||
|      * @param data.type The type of timing being recorded (e.g total timing, all sources timing or vip timing) | ||||
|      * @param data.timingMs The timing in milliseconds | ||||
|      */ | ||||
|     logRouterDetails(data: { router: 'neon-router' | 'js'; type: 'all' | 'vip' | 'total'; timingMs: number }): void; | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -491,6 +556,7 @@ export interface OptimizerResult { | ||||
|  | ||||
| export interface OptimizerResultWithReport extends OptimizerResult { | ||||
|     quoteReport?: QuoteReport; | ||||
|     extendedQuoteReportSources?: ExtendedQuoteReportSources; | ||||
|     priceComparisonsReport?: PriceComparisonsReport; | ||||
| } | ||||
|  | ||||
| @@ -519,7 +585,7 @@ export interface MarketSideLiquidity { | ||||
|  | ||||
| export interface RawQuotes { | ||||
|     nativeOrders: NativeOrderWithFillableAmounts[]; | ||||
|     rfqtIndicativeQuotes: V4RFQIndicativeQuote[]; | ||||
|     rfqtIndicativeQuotes: V4RFQIndicativeQuoteMM[]; | ||||
|     twoHopQuotes: Array<DexSample<MultiHopFillData>>; | ||||
|     dexQuotes: Array<Array<DexSample<FillData>>>; | ||||
| } | ||||
| @@ -546,6 +612,8 @@ export interface GenerateOptimizedOrdersOpts { | ||||
|     allowFallback?: boolean; | ||||
|     shouldBatchBridgeOrders?: boolean; | ||||
|     gasPrice: BigNumber; | ||||
|     neonRouterNumSamples: number; | ||||
|     samplerMetrics?: SamplerMetrics; | ||||
| } | ||||
|  | ||||
| export interface ComparisonPrice { | ||||
|   | ||||
| @@ -14,8 +14,9 @@ import { | ||||
|     NativeFillData, | ||||
|     NativeLimitOrderFillData, | ||||
|     NativeRfqOrderFillData, | ||||
|     RawQuotes, | ||||
| } from './market_operation_utils/types'; | ||||
| import { QuoteRequestor } from './quote_requestor'; | ||||
| import { QuoteRequestor, V4RFQIndicativeQuoteMM } from './quote_requestor'; | ||||
|  | ||||
| export interface QuoteReportEntryBase { | ||||
|     liquiditySource: ERC20BridgeSource; | ||||
| @@ -36,30 +37,77 @@ export interface NativeLimitOrderQuoteReportEntry extends QuoteReportEntryBase { | ||||
|     liquiditySource: ERC20BridgeSource.Native; | ||||
|     fillData: NativeFillData; | ||||
|     fillableTakerAmount: BigNumber; | ||||
|     isRfqt: false; | ||||
|     isRFQ: false; | ||||
| } | ||||
|  | ||||
| export interface NativeRfqOrderQuoteReportEntry extends QuoteReportEntryBase { | ||||
|     liquiditySource: ERC20BridgeSource.Native; | ||||
|     fillData: NativeFillData; | ||||
|     fillableTakerAmount: BigNumber; | ||||
|     isRfqt: true; | ||||
|     isRFQ: true; | ||||
|     nativeOrder: RfqOrderFields; | ||||
|     makerUri: string; | ||||
|     comparisonPrice?: number; | ||||
| } | ||||
|  | ||||
| export interface IndicativeRfqOrderQuoteReportEntry extends QuoteReportEntryBase { | ||||
|     liquiditySource: ERC20BridgeSource.Native; | ||||
|     fillableTakerAmount: BigNumber; | ||||
|     isRFQ: true; | ||||
|     makerUri?: string; | ||||
|     comparisonPrice?: number; | ||||
| } | ||||
|  | ||||
| export type QuoteReportEntry = | ||||
|     | BridgeQuoteReportEntry | ||||
|     | MultiHopQuoteReportEntry | ||||
|     | NativeLimitOrderQuoteReportEntry | ||||
|     | NativeRfqOrderQuoteReportEntry; | ||||
|  | ||||
| export type ExtendedQuoteReportEntry = | ||||
|     | BridgeQuoteReportEntry | ||||
|     | MultiHopQuoteReportEntry | ||||
|     | NativeLimitOrderQuoteReportEntry | ||||
|     | NativeRfqOrderQuoteReportEntry | ||||
|     | IndicativeRfqOrderQuoteReportEntry; | ||||
|  | ||||
| export type ExtendedQuoteReportIndexedEntry = ExtendedQuoteReportEntry & { | ||||
|     quoteEntryIndex: number; | ||||
|     isDelivered: boolean; | ||||
| }; | ||||
|  | ||||
| export type ExtendedQuoteReportIndexedEntryOutbound = Omit<ExtendedQuoteReportIndexedEntry, 'fillData'> & { | ||||
|     fillData?: string; | ||||
| }; | ||||
|  | ||||
| export interface QuoteReport { | ||||
|     sourcesConsidered: QuoteReportEntry[]; | ||||
|     sourcesDelivered: QuoteReportEntry[]; | ||||
| } | ||||
|  | ||||
| export interface ExtendedQuoteReportSources { | ||||
|     sourcesConsidered: ExtendedQuoteReportIndexedEntry[]; | ||||
|     sourcesDelivered: ExtendedQuoteReportIndexedEntry[] | undefined; | ||||
| } | ||||
|  | ||||
| export interface ExtendedQuoteReport { | ||||
|     quoteId?: string; | ||||
|     taker?: string; | ||||
|     timestamp: number; | ||||
|     firmQuoteReport: boolean; | ||||
|     submissionBy: 'taker' | 'metaTxn' | 'rfqm'; | ||||
|     buyAmount?: string; | ||||
|     sellAmount?: string; | ||||
|     buyTokenAddress: string; | ||||
|     sellTokenAddress: string; | ||||
|     integratorId?: string; | ||||
|     slippageBips?: number; | ||||
|     zeroExTransactionHash?: string; | ||||
|     decodedUniqueId?: string; | ||||
|     sourcesConsidered: ExtendedQuoteReportIndexedEntryOutbound[]; | ||||
|     sourcesDelivered: ExtendedQuoteReportIndexedEntryOutbound[] | undefined; | ||||
| } | ||||
|  | ||||
| export interface PriceComparisonsReport { | ||||
|     dexSources: BridgeQuoteReportEntry[]; | ||||
|     multiHopSources: MultiHopQuoteReportEntry[]; | ||||
| @@ -80,7 +128,7 @@ export function generateQuoteReport( | ||||
|     const nativeOrderSourcesConsidered = nativeOrders.map(order => | ||||
|         nativeOrderToReportEntry(order.type, order as any, order.fillableTakerAmount, comparisonPrice, quoteRequestor), | ||||
|     ); | ||||
|     const sourcesConsidered = [...nativeOrderSourcesConsidered.filter(order => order.isRfqt)]; | ||||
|     const sourcesConsidered = [...nativeOrderSourcesConsidered.filter(order => order.isRFQ)]; | ||||
|  | ||||
|     let sourcesDelivered; | ||||
|     if (Array.isArray(liquidityDelivered)) { | ||||
| @@ -116,6 +164,105 @@ export function generateQuoteReport( | ||||
|     }; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Generates a report of sources considered while computing the optimized | ||||
|  * swap quote, the sources ultimately included in the computed quote. This | ||||
|  * extende version incudes all considered quotes, not only native liquidity. | ||||
|  */ | ||||
| export function generateExtendedQuoteReportSources( | ||||
|     marketOperation: MarketOperation, | ||||
|     quotes: RawQuotes, | ||||
|     liquidityDelivered: ReadonlyArray<CollapsedFill> | DexSample<MultiHopFillData>, | ||||
|     amount: BigNumber, | ||||
|     comparisonPrice?: BigNumber | undefined, | ||||
|     quoteRequestor?: QuoteRequestor, | ||||
| ): ExtendedQuoteReportSources { | ||||
|     const sourcesConsidered: ExtendedQuoteReportEntry[] = []; | ||||
|  | ||||
|     // NativeOrders | ||||
|     sourcesConsidered.push( | ||||
|         ...quotes.nativeOrders.map(order => | ||||
|             nativeOrderToReportEntry( | ||||
|                 order.type, | ||||
|                 order as any, | ||||
|                 order.fillableTakerAmount, | ||||
|                 comparisonPrice, | ||||
|                 quoteRequestor, | ||||
|             ), | ||||
|         ), | ||||
|     ); | ||||
|  | ||||
|     // IndicativeQuotes | ||||
|     sourcesConsidered.push( | ||||
|         ...quotes.rfqtIndicativeQuotes.map(order => indicativeQuoteToReportEntry(order, comparisonPrice)), | ||||
|     ); | ||||
|  | ||||
|     // MultiHop | ||||
|     sourcesConsidered.push(...quotes.twoHopQuotes.map(quote => multiHopSampleToReportSource(quote, marketOperation))); | ||||
|  | ||||
|     // Dex Quotes | ||||
|     sourcesConsidered.push( | ||||
|         ..._.flatten( | ||||
|             quotes.dexQuotes.map(dex => | ||||
|                 dex | ||||
|                     .filter(quote => isDexSampleForTotalAmount(quote, marketOperation, amount)) | ||||
|                     .map(quote => dexSampleToReportSource(quote, marketOperation)), | ||||
|             ), | ||||
|         ), | ||||
|     ); | ||||
|     const sourcesConsideredIndexed = sourcesConsidered.map( | ||||
|         (quote, index): ExtendedQuoteReportIndexedEntry => { | ||||
|             return { | ||||
|                 ...quote, | ||||
|                 quoteEntryIndex: index, | ||||
|                 isDelivered: false, | ||||
|             }; | ||||
|         }, | ||||
|     ); | ||||
|     let sourcesDelivered; | ||||
|     if (Array.isArray(liquidityDelivered)) { | ||||
|         // create easy way to look up fillable amounts | ||||
|         const nativeOrderSignaturesToFillableAmounts = _.fromPairs( | ||||
|             quotes.nativeOrders.map(o => { | ||||
|                 return [_nativeDataToId(o), o.fillableTakerAmount]; | ||||
|             }), | ||||
|         ); | ||||
|         // map sources delivered | ||||
|         sourcesDelivered = liquidityDelivered.map(collapsedFill => { | ||||
|             if (_isNativeOrderFromCollapsedFill(collapsedFill)) { | ||||
|                 return nativeOrderToReportEntry( | ||||
|                     collapsedFill.type, | ||||
|                     collapsedFill.fillData, | ||||
|                     nativeOrderSignaturesToFillableAmounts[_nativeDataToId(collapsedFill.fillData)], | ||||
|                     comparisonPrice, | ||||
|                     quoteRequestor, | ||||
|                 ); | ||||
|             } else { | ||||
|                 return dexSampleToReportSource(collapsedFill, marketOperation); | ||||
|             } | ||||
|         }); | ||||
|     } else { | ||||
|         sourcesDelivered = [ | ||||
|             // tslint:disable-next-line: no-unnecessary-type-assertion | ||||
|             multiHopSampleToReportSource(liquidityDelivered as DexSample<MultiHopFillData>, marketOperation), | ||||
|         ]; | ||||
|     } | ||||
|     const sourcesDeliveredIndexed = sourcesDelivered.map( | ||||
|         (quote, index): ExtendedQuoteReportIndexedEntry => { | ||||
|             return { | ||||
|                 ...quote, | ||||
|                 quoteEntryIndex: index, | ||||
|                 isDelivered: false, | ||||
|             }; | ||||
|         }, | ||||
|     ); | ||||
|  | ||||
|     return { | ||||
|         sourcesConsidered: sourcesConsideredIndexed, | ||||
|         sourcesDelivered: sourcesDeliveredIndexed, | ||||
|     }; | ||||
| } | ||||
|  | ||||
| function _nativeDataToId(data: { signature: Signature }): string { | ||||
|     const { v, r, s } = data.signature; | ||||
|     return `${v}${r}${s}`; | ||||
| @@ -153,6 +300,22 @@ export function dexSampleToReportSource(ds: DexSample, marketOperation: MarketOp | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Checks if a DEX sample is the one that represents the whole amount requested by taker | ||||
|  * NOTE: this is used for the QuoteReport to filter samples | ||||
|  */ | ||||
| function isDexSampleForTotalAmount(ds: DexSample, marketOperation: MarketOperation, amount: BigNumber): boolean { | ||||
|     // input and output map to different values | ||||
|     // based on the market operation | ||||
|     if (marketOperation === MarketOperation.Buy) { | ||||
|         return ds.input === amount; | ||||
|     } else if (marketOperation === MarketOperation.Sell) { | ||||
|         return ds.output === amount; | ||||
|     } else { | ||||
|         throw new Error(`Unexpected marketOperation ${marketOperation}`); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Generates a report sample for a MultiHop source | ||||
|  * NOTE: this is used for the QuoteReport and quote price comparison data | ||||
| @@ -208,17 +371,17 @@ export function nativeOrderToReportEntry( | ||||
|     }; | ||||
|  | ||||
|     // if we find this is an rfqt order, label it as such and associate makerUri | ||||
|     const isRfqt = type === FillQuoteTransformerOrderType.Rfq; | ||||
|     const isRFQ = type === FillQuoteTransformerOrderType.Rfq; | ||||
|     const rfqtMakerUri = | ||||
|         isRfqt && quoteRequestor ? quoteRequestor.getMakerUriForSignature(fillData.signature) : undefined; | ||||
|         isRFQ && quoteRequestor ? quoteRequestor.getMakerUriForSignature(fillData.signature) : undefined; | ||||
|  | ||||
|     if (isRfqt) { | ||||
|     if (isRFQ) { | ||||
|         const nativeOrder = fillData.order as RfqOrderFields; | ||||
|         // tslint:disable-next-line: no-object-literal-type-assertion | ||||
|         return { | ||||
|             liquiditySource: ERC20BridgeSource.Native, | ||||
|             ...nativeOrderBase, | ||||
|             isRfqt: true, | ||||
|             isRFQ: true, | ||||
|             makerUri: rfqtMakerUri || '', | ||||
|             ...(comparisonPrice ? { comparisonPrice: comparisonPrice.toNumber() } : {}), | ||||
|             nativeOrder, | ||||
| @@ -229,8 +392,49 @@ export function nativeOrderToReportEntry( | ||||
|         return { | ||||
|             liquiditySource: ERC20BridgeSource.Native, | ||||
|             ...nativeOrderBase, | ||||
|             isRfqt: false, | ||||
|             isRFQ: false, | ||||
|             fillData, | ||||
|         }; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Generates a report entry for an indicative RFQ Quote | ||||
|  * NOTE: this is used for the QuoteReport and quote price comparison data | ||||
|  */ | ||||
| export function indicativeQuoteToReportEntry( | ||||
|     order: V4RFQIndicativeQuoteMM, | ||||
|     comparisonPrice?: BigNumber | undefined, | ||||
| ): IndicativeRfqOrderQuoteReportEntry { | ||||
|     const nativeOrderBase = { | ||||
|         makerAmount: order.makerAmount, | ||||
|         takerAmount: order.takerAmount, | ||||
|         fillableTakerAmount: order.takerAmount, | ||||
|     }; | ||||
|  | ||||
|     // tslint:disable-next-line: no-object-literal-type-assertion | ||||
|     return { | ||||
|         liquiditySource: ERC20BridgeSource.Native, | ||||
|         ...nativeOrderBase, | ||||
|         isRFQ: true, | ||||
|         makerUri: order.makerUri, | ||||
|         fillData: {}, | ||||
|         ...(comparisonPrice ? { comparisonPrice: comparisonPrice.toNumber() } : {}), | ||||
|     }; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * For the extended quote report, we output the filldata as JSON | ||||
|  */ | ||||
| export function jsonifyFillData(source: ExtendedQuoteReportIndexedEntry): ExtendedQuoteReportIndexedEntryOutbound { | ||||
|     return { | ||||
|         ...source, | ||||
|         fillData: JSON.stringify(source.fillData, (key: string, value: any) => { | ||||
|             if (key === '_samplerContract') { | ||||
|                 return {}; | ||||
|             } else { | ||||
|                 return value; | ||||
|             } | ||||
|         }), | ||||
|     }; | ||||
| } | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user