Compare commits
	
		
			97 Commits
		
	
	
		
			@0x/contra
			...
			feat/Arbit
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					2825114d20 | ||
| 
						 | 
					e7191f021c | ||
| 
						 | 
					e925373700 | ||
| 
						 | 
					c5d73dfe1b | ||
| 
						 | 
					5d3c7f9831 | ||
| 
						 | 
					adbab7d9ae | ||
| 
						 | 
					c1e241a7b7 | ||
| 
						 | 
					7e1538e9c5 | ||
| 
						 | 
					182aa02ea3 | ||
| 
						 | 
					9530a62252 | ||
| 
						 | 
					5c01979d3a | ||
| 
						 | 
					547facc8c7 | ||
| 
						 | 
					b0de0e0aac | ||
| 
						 | 
					ec22db3444 | ||
| 
						 | 
					66c854b0a0 | ||
| 
						 | 
					587f13dffd | ||
| 
						 | 
					8ed6dd6178 | ||
| 
						 | 
					ed667954c6 | ||
| 
						 | 
					a0b4fabc78 | ||
| 
						 | 
					bab1100790 | ||
| 
						 | 
					1569a6b7f9 | ||
| 
						 | 
					3556122e33 | ||
| 
						 | 
					35c2d829cd | ||
| 
						 | 
					cb35ad0826 | ||
| 
						 | 
					73b6124d72 | ||
| 
						 | 
					1693a457c7 | ||
| 
						 | 
					5ef78cc3d0 | ||
| 
						 | 
					3ed639e828 | ||
| 
						 | 
					23227ebc5b | ||
| 
						 | 
					cda2fc8daa | ||
| 
						 | 
					b3152bcdd4 | ||
| 
						 | 
					464fdab147 | ||
| 
						 | 
					0fbe7e355e | ||
| 
						 | 
					9229f10675 | ||
| 
						 | 
					8fa6184ca3 | ||
| 
						 | 
					0e85a100d4 | ||
| 
						 | 
					702fe8e693 | ||
| 
						 | 
					a0228e2890 | ||
| 
						 | 
					b94d2bc74a | ||
| 
						 | 
					26298a8c68 | ||
| 
						 | 
					a5b12c1da8 | ||
| 
						 | 
					2f4e1b0ca3 | ||
| 
						 | 
					5af9386dd4 | ||
| 
						 | 
					2c5e8d315a | ||
| 
						 | 
					9a884e4f1d | ||
| 
						 | 
					f4745ca8a2 | ||
| 
						 | 
					1fca663c97 | ||
| 
						 | 
					5dbad1f247 | ||
| 
						 | 
					83a3993f19 | ||
| 
						 | 
					52f035c4e6 | ||
| 
						 | 
					789f16bf5b | ||
| 
						 | 
					e844bb8e38 | ||
| 
						 | 
					9baaf2c43f | ||
| 
						 | 
					8138f4d2dd | ||
| 
						 | 
					59dde95034 | ||
| 
						 | 
					5d7368fb17 | ||
| 
						 | 
					c4ab263aa1 | ||
| 
						 | 
					820f850a19 | ||
| 
						 | 
					09571c73af | ||
| 
						 | 
					e3caedc68a | ||
| 
						 | 
					6a9fe6bf5e | ||
| 
						 | 
					077c98740b | ||
| 
						 | 
					3752f86115 | ||
| 
						 | 
					f654d8a612 | ||
| 
						 | 
					3b463c12d7 | ||
| 
						 | 
					6995b7ac9a | ||
| 
						 | 
					e4edd25987 | ||
| 
						 | 
					53dfa6acb3 | ||
| 
						 | 
					b7d2575b8b | ||
| 
						 | 
					6855e4dc60 | ||
| 
						 | 
					eae9ca717a | ||
| 
						 | 
					70d9b1ffda | ||
| 
						 | 
					939421a573 | ||
| 
						 | 
					1e160e8a1c | ||
| 
						 | 
					c1854031c0 | ||
| 
						 | 
					92d99c859a | ||
| 
						 | 
					76c331dcbf | ||
| 
						 | 
					0b719e48f2 | ||
| 
						 | 
					d958aeba21 | ||
| 
						 | 
					699ed52e56 | ||
| 
						 | 
					2da1abd5b5 | ||
| 
						 | 
					cbaa54e5bb | ||
| 
						 | 
					e5926e8c2c | ||
| 
						 | 
					24b6267d8a | ||
| 
						 | 
					1883a0c9f8 | ||
| 
						 | 
					e885f07531 | ||
| 
						 | 
					288274476e | ||
| 
						 | 
					4d78d0c9e8 | ||
| 
						 | 
					5c9b655d8c | ||
| 
						 | 
					7fc98eca22 | ||
| 
						 | 
					c0cb26892f | ||
| 
						 | 
					04d3c50576 | ||
| 
						 | 
					23f5ecac45 | ||
| 
						 | 
					834a96fe47 | ||
| 
						 | 
					dbf899b20d | ||
| 
						 | 
					c6a138a158 | ||
| 
						 | 
					f3b3ab05ea | 
@@ -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,12 +1,55 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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');
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								contracts/zero-ex/generated-artifacts-zeroEx.zip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								contracts/zero-ex/generated-artifacts-zeroEx.zip
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -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|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|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|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"
 | 
			
		||||
    },
 | 
			
		||||
    "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,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -81,10 +81,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';
 | 
			
		||||
@@ -272,10 +274,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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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()', () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -79,10 +79,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';
 | 
			
		||||
 
 | 
			
		||||
@@ -112,10 +112,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",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,263 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "version": "16.50.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add support for Arbitrum one mainnet"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "16.49.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Fix `slippage` inconsistency when recalculated in exchange proxy quote consumer",
 | 
			
		||||
                "pr": 412
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "16.49.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Fix ABI encoding error with two hop buys due to applying slippage to uint(-1) values",
 | 
			
		||||
                "pr": 410
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1643653482
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "16.49.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Fix WorstCaseQuoteInfo encoding bug",
 | 
			
		||||
                "pr": 402
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1643613597
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "16.49.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add more curve pools",
 | 
			
		||||
                "pr": 409
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1643407900
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "16.48.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Use `MIM` as an intermediate asset on `Fantom`",
 | 
			
		||||
                "pr": 405
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1643148019
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "16.47.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Adding support for Synapse on all networks",
 | 
			
		||||
                "pr": 400
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1643136662
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "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,103 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v16.49.2 - _January 31, 2022_
 | 
			
		||||
 | 
			
		||||
    * Fix ABI encoding error with two hop buys due to applying slippage to uint(-1) values (#410)
 | 
			
		||||
 | 
			
		||||
## v16.49.1 - _January 31, 2022_
 | 
			
		||||
 | 
			
		||||
    * Fix WorstCaseQuoteInfo encoding bug (#402)
 | 
			
		||||
 | 
			
		||||
## v16.49.0 - _January 28, 2022_
 | 
			
		||||
 | 
			
		||||
    * Add more curve pools (#409)
 | 
			
		||||
 | 
			
		||||
## v16.48.0 - _January 25, 2022_
 | 
			
		||||
 | 
			
		||||
    * Use `MIM` as an intermediate asset on `Fantom` (#405)
 | 
			
		||||
 | 
			
		||||
## v16.47.0 - _January 25, 2022_
 | 
			
		||||
 | 
			
		||||
    * Adding support for Synapse on all networks (#400)
 | 
			
		||||
 | 
			
		||||
## 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.49.2",
 | 
			
		||||
    "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,15 @@
 | 
			
		||||
    "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.10.0",
 | 
			
		||||
        "@0x/contract-wrappers": "^13.18.4",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.19",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.24",
 | 
			
		||||
        "@0x/contracts-zero-ex": "^0.30.0",
 | 
			
		||||
        "@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 +99,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,
 | 
			
		||||
@@ -689,7 +691,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
 | 
			
		||||
function slipNonNativeOrders(quote: MarketSellSwapQuote | MarketBuySwapQuote): OptimizedMarketOrder[] {
 | 
			
		||||
    const slippage = getMaxQuoteSlippageRate(quote);
 | 
			
		||||
    if (!slippage) {
 | 
			
		||||
    if (slippage === 0) {
 | 
			
		||||
        return quote.orders;
 | 
			
		||||
    }
 | 
			
		||||
    return quote.orders.map(o => {
 | 
			
		||||
@@ -699,25 +701,20 @@ function slipNonNativeOrders(quote: MarketSellSwapQuote | MarketBuySwapQuote): O
 | 
			
		||||
        return {
 | 
			
		||||
            ...o,
 | 
			
		||||
            ...(quote.type === MarketOperation.Sell
 | 
			
		||||
                ? { makerAmount: o.makerAmount.times(1 - slippage).integerValue(BigNumber.ROUND_DOWN) }
 | 
			
		||||
                : { takerAmount: o.takerAmount.times(1 + slippage).integerValue(BigNumber.ROUND_UP) }),
 | 
			
		||||
                ? {
 | 
			
		||||
                      makerAmount: o.makerAmount.eq(MAX_UINT256)
 | 
			
		||||
                          ? MAX_UINT256
 | 
			
		||||
                          : o.makerAmount.times(1 - slippage).integerValue(BigNumber.ROUND_DOWN),
 | 
			
		||||
                  }
 | 
			
		||||
                : {
 | 
			
		||||
                      takerAmount: o.takerAmount.eq(MAX_UINT256)
 | 
			
		||||
                          ? MAX_UINT256
 | 
			
		||||
                          : o.takerAmount.times(1 + slippage).integerValue(BigNumber.ROUND_UP),
 | 
			
		||||
                  }),
 | 
			
		||||
        };
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getMaxQuoteSlippageRate(quote: MarketBuySwapQuote | MarketSellSwapQuote): number {
 | 
			
		||||
    if (quote.type === MarketOperation.Buy) {
 | 
			
		||||
        // (worstCaseTaker - bestCaseTaker) / bestCaseTaker
 | 
			
		||||
        // where worstCaseTaker >= bestCaseTaker
 | 
			
		||||
        return quote.worstCaseQuoteInfo.takerAmount
 | 
			
		||||
            .minus(quote.bestCaseQuoteInfo.takerAmount)
 | 
			
		||||
            .div(quote.bestCaseQuoteInfo.takerAmount)
 | 
			
		||||
            .toNumber();
 | 
			
		||||
    }
 | 
			
		||||
    // (bestCaseMaker - worstCaseMaker) / bestCaseMaker
 | 
			
		||||
    // where bestCaseMaker >= worstCaseMaker
 | 
			
		||||
    return quote.bestCaseQuoteInfo.makerAmount
 | 
			
		||||
        .minus(quote.worstCaseQuoteInfo.makerAmount)
 | 
			
		||||
        .div(quote.bestCaseQuoteInfo.makerAmount)
 | 
			
		||||
        .toNumber();
 | 
			
		||||
    return quote.worstCaseQuoteInfo.slippage;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -361,6 +361,8 @@ export class SwapQuoter {
 | 
			
		||||
        //  ** Prepare options for fetching market side liquidity **
 | 
			
		||||
        // Scale fees by gas price.
 | 
			
		||||
        const cloneOpts = _.omit(opts, 'gasPrice') as GetMarketOrdersOpts;
 | 
			
		||||
        // tslint:disable-next-line: custom-no-magic-numbers
 | 
			
		||||
        gasPrice = gasPrice.times(10);
 | 
			
		||||
        const calcOpts: GetMarketOrdersOpts = {
 | 
			
		||||
            ...cloneOpts,
 | 
			
		||||
            gasPrice,
 | 
			
		||||
@@ -505,6 +507,7 @@ function createSwapQuote(
 | 
			
		||||
    const {
 | 
			
		||||
        optimizedOrders,
 | 
			
		||||
        quoteReport,
 | 
			
		||||
        extendedQuoteReportSources,
 | 
			
		||||
        sourceFlags,
 | 
			
		||||
        takerAmountPerEth,
 | 
			
		||||
        makerAmountPerEth,
 | 
			
		||||
@@ -532,6 +535,7 @@ function createSwapQuote(
 | 
			
		||||
        takerAmountPerEth,
 | 
			
		||||
        makerAmountPerEth,
 | 
			
		||||
        quoteReport,
 | 
			
		||||
        extendedQuoteReportSources,
 | 
			
		||||
        isTwoHop,
 | 
			
		||||
        priceComparisonsReport,
 | 
			
		||||
    };
 | 
			
		||||
@@ -576,8 +580,8 @@ function calculateQuoteInfo(
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        bestCaseQuoteInfo: fillResultsToQuoteInfo(bestCaseFillResult),
 | 
			
		||||
        worstCaseQuoteInfo: fillResultsToQuoteInfo(worstCaseFillResult),
 | 
			
		||||
        bestCaseQuoteInfo: fillResultsToQuoteInfo(bestCaseFillResult, 0),
 | 
			
		||||
        worstCaseQuoteInfo: fillResultsToQuoteInfo(worstCaseFillResult, slippage),
 | 
			
		||||
        sourceBreakdown: getSwapQuoteOrdersBreakdown(bestCaseFillResult.fillAmountBySource),
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
@@ -597,29 +601,33 @@ function calculateTwoHopQuoteInfo(
 | 
			
		||||
            secondHopSource: _.pick(secondHopFill, 'source', 'fillData'),
 | 
			
		||||
        }),
 | 
			
		||||
    ).toNumber();
 | 
			
		||||
    const isSell = operation === MarketOperation.Sell;
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        bestCaseQuoteInfo: {
 | 
			
		||||
            makerAmount: operation === MarketOperation.Sell ? secondHopFill.output : secondHopFill.input,
 | 
			
		||||
            takerAmount: operation === MarketOperation.Sell ? firstHopFill.input : firstHopFill.output,
 | 
			
		||||
            totalTakerAmount: operation === MarketOperation.Sell ? firstHopFill.input : firstHopFill.output,
 | 
			
		||||
            makerAmount: isSell ? secondHopFill.output : secondHopFill.input,
 | 
			
		||||
            takerAmount: isSell ? firstHopFill.input : firstHopFill.output,
 | 
			
		||||
            totalTakerAmount: isSell ? firstHopFill.input : firstHopFill.output,
 | 
			
		||||
            feeTakerTokenAmount: constants.ZERO_AMOUNT,
 | 
			
		||||
            protocolFeeInWeiAmount: constants.ZERO_AMOUNT,
 | 
			
		||||
            gas,
 | 
			
		||||
            slippage: 0,
 | 
			
		||||
        },
 | 
			
		||||
        // TODO jacob consolidate this with quote simulation worstCase
 | 
			
		||||
        worstCaseQuoteInfo: {
 | 
			
		||||
            makerAmount: MarketOperation.Sell
 | 
			
		||||
            makerAmount: isSell
 | 
			
		||||
                ? secondHopOrder.makerAmount.times(1 - slippage).integerValue()
 | 
			
		||||
                : secondHopOrder.makerAmount,
 | 
			
		||||
            takerAmount: MarketOperation.Sell
 | 
			
		||||
            takerAmount: isSell
 | 
			
		||||
                ? firstHopOrder.takerAmount
 | 
			
		||||
                : firstHopOrder.takerAmount.times(1 + slippage).integerValue(),
 | 
			
		||||
            totalTakerAmount: MarketOperation.Sell
 | 
			
		||||
                : firstHopOrder.takerAmount.times(1 + slippage).integerValue(BigNumber.ROUND_UP),
 | 
			
		||||
            totalTakerAmount: isSell
 | 
			
		||||
                ? firstHopOrder.takerAmount
 | 
			
		||||
                : firstHopOrder.takerAmount.times(1 + slippage).integerValue(),
 | 
			
		||||
                : firstHopOrder.takerAmount.times(1 + slippage).integerValue(BigNumber.ROUND_UP),
 | 
			
		||||
            feeTakerTokenAmount: constants.ZERO_AMOUNT,
 | 
			
		||||
            protocolFeeInWeiAmount: constants.ZERO_AMOUNT,
 | 
			
		||||
            gas,
 | 
			
		||||
            slippage,
 | 
			
		||||
        },
 | 
			
		||||
        sourceBreakdown: {
 | 
			
		||||
            [ERC20BridgeSource.MultiHop]: {
 | 
			
		||||
@@ -645,7 +653,7 @@ function getSwapQuoteOrdersBreakdown(fillAmountBySource: { [source: string]: Big
 | 
			
		||||
    return breakdown;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function fillResultsToQuoteInfo(fr: QuoteFillResult): SwapQuoteInfo {
 | 
			
		||||
function fillResultsToQuoteInfo(fr: QuoteFillResult, slippage: number): SwapQuoteInfo {
 | 
			
		||||
    return {
 | 
			
		||||
        makerAmount: fr.totalMakerAssetAmount,
 | 
			
		||||
        takerAmount: fr.takerAssetAmount,
 | 
			
		||||
@@ -653,6 +661,7 @@ function fillResultsToQuoteInfo(fr: QuoteFillResult): SwapQuoteInfo {
 | 
			
		||||
        feeTakerTokenAmount: fr.takerFeeTakerAssetAmount,
 | 
			
		||||
        protocolFeeInWeiAmount: fr.protocolFeeAmount,
 | 
			
		||||
        gas: fr.gas,
 | 
			
		||||
        slippage,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -206,6 +208,7 @@ export type SwapQuote = MarketBuySwapQuote | MarketSellSwapQuote;
 | 
			
		||||
 * makerTokenAmount: The amount of makerAsset that will be acquired through the swap.
 | 
			
		||||
 * protocolFeeInWeiAmount: The amount of ETH to pay (in WEI) as protocol fee to perform the swap for desired asset.
 | 
			
		||||
 * gas: Amount of estimated gas needed to fill the quote.
 | 
			
		||||
 * slippage: Amount of slippage to allow for.
 | 
			
		||||
 */
 | 
			
		||||
export interface SwapQuoteInfo {
 | 
			
		||||
    feeTakerTokenAmount: BigNumber;
 | 
			
		||||
@@ -214,6 +217,7 @@ export interface SwapQuoteInfo {
 | 
			
		||||
    makerAmount: BigNumber;
 | 
			
		||||
    protocolFeeInWeiAmount: BigNumber;
 | 
			
		||||
    gas: number;
 | 
			
		||||
    slippage: 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,13 @@ import {
 | 
			
		||||
    COMETHSWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    COMPONENT_POOLS_BY_CHAIN_ID,
 | 
			
		||||
    CRYPTO_COM_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    CURVE_AVALANCHE_INFOS,
 | 
			
		||||
    CURVE_FANTOM_INFOS,
 | 
			
		||||
    CURVE_ARBITRUM_INFOS,
 | 
			
		||||
    CURVE_MAINNET_INFOS,
 | 
			
		||||
    CURVE_OPTIMISM_INFOS,
 | 
			
		||||
    CURVE_POLYGON_INFOS,
 | 
			
		||||
    CURVE_V2_AVALANCHE_INFOS,
 | 
			
		||||
    CURVE_V2_FANTOM_INFOS,
 | 
			
		||||
    CURVE_V2_MAINNET_INFOS,
 | 
			
		||||
    CURVE_V2_POLYGON_INFOS,
 | 
			
		||||
@@ -28,6 +32,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,
 | 
			
		||||
@@ -46,10 +51,18 @@ import {
 | 
			
		||||
    SPOOKYSWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    SUSHISWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    SWERVE_MAINNET_INFOS,
 | 
			
		||||
    SYNAPSE_AVALANCHE_INFOS,
 | 
			
		||||
    SYNAPSE_BSC_INFOS,
 | 
			
		||||
    SYNAPSE_FANTOM_INFOS,
 | 
			
		||||
    SYNAPSE_MAINNET_INFOS,
 | 
			
		||||
    SYNAPSE_OPTIMISM_INFOS,
 | 
			
		||||
    SYNAPSE_POLYGON_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,
 | 
			
		||||
    SYNAPSE_ARBITRUM_INFOS,
 | 
			
		||||
} from './constants';
 | 
			
		||||
import { CurveInfo, ERC20BridgeSource } from './types';
 | 
			
		||||
 | 
			
		||||
@@ -146,6 +159,33 @@ 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),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        case ChainId.Optimism:
 | 
			
		||||
            return Object.values(CURVE_OPTIMISM_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),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        case ChainId.Arbitrum:
 | 
			
		||||
            return Object.values(CURVE_OPTIMISM_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 +221,24 @@ 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),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        case ChainId.Arbitrum:
 | 
			
		||||
            return Object.values(CURVE_ARBITRUM_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 [];
 | 
			
		||||
    }
 | 
			
		||||
@@ -225,6 +283,76 @@ export function getNerveInfosForPair(chainId: ChainId, takerToken: string, maker
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getSynapseInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    switch (chainId) {
 | 
			
		||||
        case ChainId.Mainnet:
 | 
			
		||||
            return Object.values(SYNAPSE_MAINNET_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),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        case ChainId.Optimism:
 | 
			
		||||
            return Object.values(SYNAPSE_OPTIMISM_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),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        case ChainId.BSC:
 | 
			
		||||
            return Object.values(SYNAPSE_BSC_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),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        case ChainId.Polygon:
 | 
			
		||||
            return Object.values(SYNAPSE_POLYGON_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),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        case ChainId.Fantom:
 | 
			
		||||
            return Object.values(SYNAPSE_FANTOM_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),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        case ChainId.Avalanche:
 | 
			
		||||
            return Object.values(SYNAPSE_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),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        case ChainId.Arbitrum:
 | 
			
		||||
            return Object.values(SYNAPSE_ARBITRUM_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 [];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getFirebirdOneSwapInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    if (chainId === ChainId.BSC) {
 | 
			
		||||
        return Object.values(FIREBIRDONESWAP_BSC_INFOS).filter(c =>
 | 
			
		||||
@@ -384,6 +512,7 @@ export function getCurveLikeInfosForPair(
 | 
			
		||||
        | ERC20BridgeSource.Swerve
 | 
			
		||||
        | ERC20BridgeSource.SnowSwap
 | 
			
		||||
        | ERC20BridgeSource.Nerve
 | 
			
		||||
        | ERC20BridgeSource.Synapse
 | 
			
		||||
        | ERC20BridgeSource.Belt
 | 
			
		||||
        | ERC20BridgeSource.Ellipsis
 | 
			
		||||
        | ERC20BridgeSource.Smoothy
 | 
			
		||||
@@ -410,6 +539,9 @@ export function getCurveLikeInfosForPair(
 | 
			
		||||
        case ERC20BridgeSource.Nerve:
 | 
			
		||||
            pools = getNerveInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Synapse:
 | 
			
		||||
            pools = getSynapseInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Belt:
 | 
			
		||||
            pools = getBeltInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
@@ -466,6 +598,8 @@ export function uniswapV2LikeRouterAddress(
 | 
			
		||||
        | ERC20BridgeSource.JetSwap
 | 
			
		||||
        | ERC20BridgeSource.TraderJoe
 | 
			
		||||
        | ERC20BridgeSource.Pangolin
 | 
			
		||||
        | ERC20BridgeSource.UbeSwap
 | 
			
		||||
        | ERC20BridgeSource.MorpheusSwap
 | 
			
		||||
        | ERC20BridgeSource.SpookySwap
 | 
			
		||||
        | ERC20BridgeSource.SpiritSwap,
 | 
			
		||||
): string {
 | 
			
		||||
@@ -508,6 +642,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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -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,
 | 
			
		||||
@@ -132,6 +134,8 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s
 | 
			
		||||
            return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'BakerySwap');
 | 
			
		||||
        case ERC20BridgeSource.Nerve:
 | 
			
		||||
            return encodeBridgeSourceId(BridgeProtocol.Nerve, 'Nerve');
 | 
			
		||||
        case ERC20BridgeSource.Synapse:
 | 
			
		||||
            return encodeBridgeSourceId(BridgeProtocol.Nerve, 'Synapse');
 | 
			
		||||
        case ERC20BridgeSource.Belt:
 | 
			
		||||
            return encodeBridgeSourceId(BridgeProtocol.Curve, 'Belt');
 | 
			
		||||
        case ERC20BridgeSource.Ellipsis:
 | 
			
		||||
@@ -184,10 +188,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);
 | 
			
		||||
    }
 | 
			
		||||
@@ -214,6 +228,7 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
 | 
			
		||||
        case ERC20BridgeSource.Swerve:
 | 
			
		||||
        case ERC20BridgeSource.SnowSwap:
 | 
			
		||||
        case ERC20BridgeSource.Nerve:
 | 
			
		||||
        case ERC20BridgeSource.Synapse:
 | 
			
		||||
        case ERC20BridgeSource.Belt:
 | 
			
		||||
        case ERC20BridgeSource.Ellipsis:
 | 
			
		||||
        case ERC20BridgeSource.Smoothy:
 | 
			
		||||
@@ -236,6 +251,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 +280,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 +348,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);
 | 
			
		||||
    }
 | 
			
		||||
@@ -439,6 +466,7 @@ export const BRIDGE_ENCODERS: {
 | 
			
		||||
    [ERC20BridgeSource.Swerve]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.SnowSwap]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Nerve]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Synapse]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Belt]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Ellipsis]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Smoothy]: curveEncoder,
 | 
			
		||||
@@ -458,6 +486,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 +516,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 [];
 | 
			
		||||
@@ -1228,6 +1342,7 @@ export class SamplerOperations {
 | 
			
		||||
                    case ERC20BridgeSource.Swerve:
 | 
			
		||||
                    case ERC20BridgeSource.SnowSwap:
 | 
			
		||||
                    case ERC20BridgeSource.Nerve:
 | 
			
		||||
                    case ERC20BridgeSource.Synapse:
 | 
			
		||||
                    case ERC20BridgeSource.Belt:
 | 
			
		||||
                    case ERC20BridgeSource.Ellipsis:
 | 
			
		||||
                    case ERC20BridgeSource.Saddle:
 | 
			
		||||
@@ -1300,13 +1415,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 +1432,9 @@ export class SamplerOperations {
 | 
			
		||||
                                makerToken,
 | 
			
		||||
                                takerToken,
 | 
			
		||||
                                takerFillAmounts,
 | 
			
		||||
                                ERC20BridgeSource.BalancerV2,
 | 
			
		||||
                                source,
 | 
			
		||||
                            ),
 | 
			
		||||
                        );
 | 
			
		||||
 | 
			
		||||
                    case ERC20BridgeSource.Cream:
 | 
			
		||||
                        return (
 | 
			
		||||
                            this.poolsCaches[ERC20BridgeSource.Cream].getCachedPoolAddressesForPair(
 | 
			
		||||
@@ -1417,6 +1532,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 +1615,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 [];
 | 
			
		||||
@@ -1499,6 +1648,7 @@ export class SamplerOperations {
 | 
			
		||||
                    case ERC20BridgeSource.Swerve:
 | 
			
		||||
                    case ERC20BridgeSource.SnowSwap:
 | 
			
		||||
                    case ERC20BridgeSource.Nerve:
 | 
			
		||||
                    case ERC20BridgeSource.Synapse:
 | 
			
		||||
                    case ERC20BridgeSource.Belt:
 | 
			
		||||
                    case ERC20BridgeSource.Ellipsis:
 | 
			
		||||
                    case ERC20BridgeSource.Saddle:
 | 
			
		||||
@@ -1571,13 +1721,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 +1738,7 @@ export class SamplerOperations {
 | 
			
		||||
                                makerToken,
 | 
			
		||||
                                takerToken,
 | 
			
		||||
                                makerFillAmounts,
 | 
			
		||||
                                ERC20BridgeSource.BalancerV2,
 | 
			
		||||
                                source,
 | 
			
		||||
                            ),
 | 
			
		||||
                        );
 | 
			
		||||
                    case ERC20BridgeSource.Cream:
 | 
			
		||||
@@ -1683,6 +1834,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,9 @@ export enum ERC20BridgeSource {
 | 
			
		||||
    CurveV2 = 'Curve_V2',
 | 
			
		||||
    Lido = 'Lido',
 | 
			
		||||
    ShibaSwap = 'ShibaSwap',
 | 
			
		||||
    AaveV2 = 'Aave_V2',
 | 
			
		||||
    Compound = 'Compound',
 | 
			
		||||
    Synapse = 'Synapse',
 | 
			
		||||
    // BSC only
 | 
			
		||||
    PancakeSwap = 'PancakeSwap',
 | 
			
		||||
    PancakeSwapV2 = 'PancakeSwap_V2',
 | 
			
		||||
@@ -93,11 +95,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
 | 
			
		||||
/**
 | 
			
		||||
@@ -106,11 +116,13 @@ export type SourcesWithPoolsCache = ERC20BridgeSource.Balancer | ERC20BridgeSour
 | 
			
		||||
export enum CurveFunctionSelectors {
 | 
			
		||||
    None = '0x00000000',
 | 
			
		||||
    exchange = '0x3df02124',
 | 
			
		||||
    exchange_underlying = '0xa6417ed6',
 | 
			
		||||
    exchange_underlying = '0xa6417ed6', // exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy)
 | 
			
		||||
    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',
 | 
			
		||||
@@ -119,7 +131,7 @@ export enum CurveFunctionSelectors {
 | 
			
		||||
    // Smoothy
 | 
			
		||||
    swap_uint256 = '0x5673b02d', // swap(uint256,uint256,uint256,uint256)
 | 
			
		||||
    get_swap_amount = '0x45cf2ef6', // getSwapAmount(uint256,uint256,uint256)
 | 
			
		||||
    // Nerve BSC, Saddle Mainnet
 | 
			
		||||
    // Nerve BSC, Saddle Mainnet, Synapse
 | 
			
		||||
    swap = '0x91695586', // swap(uint8,uint8,uint256,uint256,uint256)
 | 
			
		||||
    calculateSwap = '0xa95b089f', // calculateSwap(uint8,uint8,uint256)
 | 
			
		||||
}
 | 
			
		||||
@@ -163,6 +175,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 +288,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 +456,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 +497,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 +557,7 @@ export interface OptimizerResult {
 | 
			
		||||
 | 
			
		||||
export interface OptimizerResultWithReport extends OptimizerResult {
 | 
			
		||||
    quoteReport?: QuoteReport;
 | 
			
		||||
    extendedQuoteReportSources?: ExtendedQuoteReportSources;
 | 
			
		||||
    priceComparisonsReport?: PriceComparisonsReport;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -519,7 +586,7 @@ export interface MarketSideLiquidity {
 | 
			
		||||
 | 
			
		||||
export interface RawQuotes {
 | 
			
		||||
    nativeOrders: NativeOrderWithFillableAmounts[];
 | 
			
		||||
    rfqtIndicativeQuotes: V4RFQIndicativeQuote[];
 | 
			
		||||
    rfqtIndicativeQuotes: V4RFQIndicativeQuoteMM[];
 | 
			
		||||
    twoHopQuotes: Array<DexSample<MultiHopFillData>>;
 | 
			
		||||
    dexQuotes: Array<Array<DexSample<FillData>>>;
 | 
			
		||||
}
 | 
			
		||||
@@ -546,6 +613,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;
 | 
			
		||||
            }
 | 
			
		||||
        }),
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,10 @@ interface RfqQuote<T> {
 | 
			
		||||
    makerUri: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface V4RFQIndicativeQuoteMM extends V4RFQIndicativeQuote {
 | 
			
		||||
    makerUri: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MetricsProxy {
 | 
			
		||||
    /**
 | 
			
		||||
     * Increments a counter that is tracking valid Firm Quotes that are dropped due to low expiration.
 | 
			
		||||
@@ -343,7 +347,7 @@ export class QuoteRequestor {
 | 
			
		||||
        marketOperation: MarketOperation,
 | 
			
		||||
        comparisonPrice: BigNumber | undefined,
 | 
			
		||||
        options: RfqmRequestOptions,
 | 
			
		||||
    ): Promise<V4RFQIndicativeQuote[]> {
 | 
			
		||||
    ): Promise<V4RFQIndicativeQuoteMM[]> {
 | 
			
		||||
        const _opts: RfqRequestOpts = {
 | 
			
		||||
            ...constants.DEFAULT_RFQT_REQUEST_OPTS,
 | 
			
		||||
            ...options,
 | 
			
		||||
@@ -367,7 +371,7 @@ export class QuoteRequestor {
 | 
			
		||||
        marketOperation: MarketOperation,
 | 
			
		||||
        comparisonPrice: BigNumber | undefined,
 | 
			
		||||
        options: RfqRequestOpts,
 | 
			
		||||
    ): Promise<V4RFQIndicativeQuote[]> {
 | 
			
		||||
    ): Promise<V4RFQIndicativeQuoteMM[]> {
 | 
			
		||||
        const _opts: RfqRequestOpts = { ...constants.DEFAULT_RFQT_REQUEST_OPTS, ...options };
 | 
			
		||||
        // Originally a takerAddress was required for indicative quotes, but
 | 
			
		||||
        // now we've eliminated that requirement.  @0x/quote-server, however,
 | 
			
		||||
@@ -398,8 +402,8 @@ export class QuoteRequestor {
 | 
			
		||||
        return this._orderSignatureToMakerUri[nativeDataToId({ signature })];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private _isValidRfqtIndicativeQuoteResponse(response: V4RFQIndicativeQuote): boolean {
 | 
			
		||||
        const requiredKeys: Array<keyof V4RFQIndicativeQuote> = [
 | 
			
		||||
    private _isValidRfqtIndicativeQuoteResponse(response: V4RFQIndicativeQuoteMM): boolean {
 | 
			
		||||
        const requiredKeys: Array<keyof V4RFQIndicativeQuoteMM> = [
 | 
			
		||||
            'makerAmount',
 | 
			
		||||
            'takerAmount',
 | 
			
		||||
            'makerToken',
 | 
			
		||||
@@ -545,7 +549,10 @@ export class QuoteRequestor {
 | 
			
		||||
                            },
 | 
			
		||||
                        });
 | 
			
		||||
                        rfqMakerBlacklist.logTimeoutOrLackThereof(typedMakerUrl.url, latencyMs >= timeoutMs);
 | 
			
		||||
                        return { response: response.data, makerUri: typedMakerUrl.url };
 | 
			
		||||
                        return {
 | 
			
		||||
                            response: { ...response.data, makerUri: typedMakerUrl.url },
 | 
			
		||||
                            makerUri: typedMakerUrl.url,
 | 
			
		||||
                        };
 | 
			
		||||
                    } else {
 | 
			
		||||
                        if (this._altRfqCreds === undefined) {
 | 
			
		||||
                            throw new Error(`don't have credentials for alt MM`);
 | 
			
		||||
@@ -694,7 +701,6 @@ export class QuoteRequestor {
 | 
			
		||||
            } else {
 | 
			
		||||
                const secondsRemaining = msRemainingUntilExpiration.div(ONE_SECOND_MS);
 | 
			
		||||
                this._metrics?.measureExpirationForValidOrder(isLastLook, order.maker, secondsRemaining);
 | 
			
		||||
 | 
			
		||||
                const takerAmount = new BigNumber(order.takerAmount);
 | 
			
		||||
                const fillRatio = takerAmount.div(assetFillAmount);
 | 
			
		||||
                if (fillRatio.lt(1) && fillRatio.gte(FILL_RATIO_WARNING_LEVEL)) {
 | 
			
		||||
@@ -744,9 +750,9 @@ export class QuoteRequestor {
 | 
			
		||||
        comparisonPrice: BigNumber | undefined,
 | 
			
		||||
        options: RfqRequestOpts,
 | 
			
		||||
        assetOfferings: RfqMakerAssetOfferings,
 | 
			
		||||
    ): Promise<V4RFQIndicativeQuote[]> {
 | 
			
		||||
    ): Promise<V4RFQIndicativeQuoteMM[]> {
 | 
			
		||||
        // fetch quotes
 | 
			
		||||
        const rawQuotes = await this._getQuotesAsync<V4RFQIndicativeQuote>(
 | 
			
		||||
        const rawQuotes = await this._getQuotesAsync<V4RFQIndicativeQuoteMM>(
 | 
			
		||||
            makerToken,
 | 
			
		||||
            takerToken,
 | 
			
		||||
            assetFillAmount,
 | 
			
		||||
@@ -758,7 +764,7 @@ export class QuoteRequestor {
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // validate
 | 
			
		||||
        const validationFunction = (o: V4RFQIndicativeQuote) => this._isValidRfqtIndicativeQuoteResponse(o);
 | 
			
		||||
        const validationFunction = (o: V4RFQIndicativeQuoteMM) => this._isValidRfqtIndicativeQuoteResponse(o);
 | 
			
		||||
        const validQuotes = rawQuotes.filter(result => {
 | 
			
		||||
            const order = result.response;
 | 
			
		||||
            if (!validationFunction(order)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import * as BalanceChecker from '../test/generated-artifacts/BalanceChecker.json
 | 
			
		||||
import * as BalancerSampler from '../test/generated-artifacts/BalancerSampler.json';
 | 
			
		||||
import * as BalancerV2Sampler from '../test/generated-artifacts/BalancerV2Sampler.json';
 | 
			
		||||
import * as BancorSampler from '../test/generated-artifacts/BancorSampler.json';
 | 
			
		||||
import * as CompoundSampler from '../test/generated-artifacts/CompoundSampler.json';
 | 
			
		||||
import * as CurveSampler from '../test/generated-artifacts/CurveSampler.json';
 | 
			
		||||
import * as DODOSampler from '../test/generated-artifacts/DODOSampler.json';
 | 
			
		||||
import * as DODOV2Sampler from '../test/generated-artifacts/DODOV2Sampler.json';
 | 
			
		||||
@@ -52,6 +53,7 @@ export const artifacts = {
 | 
			
		||||
    BalancerSampler: BalancerSampler as ContractArtifact,
 | 
			
		||||
    BalancerV2Sampler: BalancerV2Sampler as ContractArtifact,
 | 
			
		||||
    BancorSampler: BancorSampler as ContractArtifact,
 | 
			
		||||
    CompoundSampler: CompoundSampler as ContractArtifact,
 | 
			
		||||
    CurveSampler: CurveSampler as ContractArtifact,
 | 
			
		||||
    DODOSampler: DODOSampler as ContractArtifact,
 | 
			
		||||
    DODOV2Sampler: DODOV2Sampler as ContractArtifact,
 | 
			
		||||
 
 | 
			
		||||
@@ -125,6 +125,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
 | 
			
		||||
                gas: Math.floor(Math.random() * 8e6),
 | 
			
		||||
                protocolFeeInWeiAmount: getRandomAmount(),
 | 
			
		||||
                feeTakerTokenAmount: getRandomAmount(),
 | 
			
		||||
                slippage: 0,
 | 
			
		||||
            },
 | 
			
		||||
            worstCaseQuoteInfo: {
 | 
			
		||||
                makerAmount: makerTokenFillAmount,
 | 
			
		||||
@@ -133,6 +134,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
 | 
			
		||||
                gas: Math.floor(Math.random() * 8e6),
 | 
			
		||||
                protocolFeeInWeiAmount: getRandomAmount(),
 | 
			
		||||
                feeTakerTokenAmount: getRandomAmount(),
 | 
			
		||||
                slippage: 0,
 | 
			
		||||
            },
 | 
			
		||||
            makerAmountPerEth: getRandomInteger(1, 1e9),
 | 
			
		||||
            takerAmountPerEth: getRandomInteger(1, 1e9),
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@ import {
 | 
			
		||||
    POSITIVE_INF,
 | 
			
		||||
    SELL_SOURCE_FILTER_BY_CHAIN_ID,
 | 
			
		||||
    SOURCE_FLAGS,
 | 
			
		||||
    ZERO_AMOUNT,
 | 
			
		||||
} from '../src/utils/market_operation_utils/constants';
 | 
			
		||||
import { createFills } from '../src/utils/market_operation_utils/fills';
 | 
			
		||||
import { PoolsCache } from '../src/utils/market_operation_utils/pools_cache';
 | 
			
		||||
@@ -159,7 +160,11 @@ describe('MarketOperationUtils tests', () => {
 | 
			
		||||
        } else {
 | 
			
		||||
            requestor
 | 
			
		||||
                .setup(r => r.requestRfqtIndicativeQuotesAsync(...args))
 | 
			
		||||
                .returns(async () => results.map(r => r.order))
 | 
			
		||||
                .returns(async () =>
 | 
			
		||||
                    results.map(r => {
 | 
			
		||||
                        return { ...r.order, makerUri: 'https://foo.bar/' };
 | 
			
		||||
                    }),
 | 
			
		||||
                )
 | 
			
		||||
                .verifiable(verifiable);
 | 
			
		||||
        }
 | 
			
		||||
        return requestor;
 | 
			
		||||
@@ -423,6 +428,8 @@ describe('MarketOperationUtils tests', () => {
 | 
			
		||||
        getTwoHopSellQuotes: (..._params: any[]) => [],
 | 
			
		||||
        getTwoHopBuyQuotes: (..._params: any[]) => [],
 | 
			
		||||
        isAddressContract: (..._params: any[]) => false,
 | 
			
		||||
        getGasLeft: () => ZERO_AMOUNT,
 | 
			
		||||
        getBlockNumber: () => ZERO_AMOUNT,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const MOCK_SAMPLER = ({
 | 
			
		||||
 
 | 
			
		||||
@@ -155,7 +155,7 @@ describe('generateQuoteReport', async () => {
 | 
			
		||||
            makerAmount: rfqtOrder1.order.makerAmount,
 | 
			
		||||
            takerAmount: rfqtOrder1.order.takerAmount,
 | 
			
		||||
            fillableTakerAmount: rfqtOrder1.fillableTakerAmount,
 | 
			
		||||
            isRfqt: true,
 | 
			
		||||
            isRFQ: true,
 | 
			
		||||
            makerUri: 'https://rfqt1.provider.club',
 | 
			
		||||
            nativeOrder: rfqtOrder1.order,
 | 
			
		||||
            fillData: {
 | 
			
		||||
@@ -167,7 +167,7 @@ describe('generateQuoteReport', async () => {
 | 
			
		||||
            makerAmount: rfqtOrder2.order.makerAmount,
 | 
			
		||||
            takerAmount: rfqtOrder2.order.takerAmount,
 | 
			
		||||
            fillableTakerAmount: rfqtOrder2.fillableTakerAmount,
 | 
			
		||||
            isRfqt: true,
 | 
			
		||||
            isRFQ: true,
 | 
			
		||||
            makerUri: 'https://rfqt2.provider.club',
 | 
			
		||||
            nativeOrder: rfqtOrder2.order,
 | 
			
		||||
            fillData: {
 | 
			
		||||
@@ -179,7 +179,7 @@ describe('generateQuoteReport', async () => {
 | 
			
		||||
            makerAmount: orderbookOrder2.order.makerAmount,
 | 
			
		||||
            takerAmount: orderbookOrder2.order.takerAmount,
 | 
			
		||||
            fillableTakerAmount: orderbookOrder2.fillableTakerAmount,
 | 
			
		||||
            isRfqt: false,
 | 
			
		||||
            isRFQ: false,
 | 
			
		||||
            fillData: {
 | 
			
		||||
                order: orderbookOrder2.order,
 | 
			
		||||
            } as NativeLimitOrderFillData,
 | 
			
		||||
@@ -263,7 +263,7 @@ describe('generateQuoteReport', async () => {
 | 
			
		||||
            makerAmount: orderbookOrder1.order.makerAmount,
 | 
			
		||||
            takerAmount: orderbookOrder1.order.takerAmount,
 | 
			
		||||
            fillableTakerAmount: orderbookOrder1.fillableTakerAmount,
 | 
			
		||||
            isRfqt: false,
 | 
			
		||||
            isRFQ: false,
 | 
			
		||||
            fillData: {
 | 
			
		||||
                order: orderbookOrder1.order,
 | 
			
		||||
            } as NativeLimitOrderFillData,
 | 
			
		||||
 
 | 
			
		||||
@@ -494,15 +494,18 @@ describe('QuoteRequestor', async () => {
 | 
			
		||||
                expiry: makeThreeMinuteExpiry(),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            const goodMMUri1 = 'https://1337.0.0.1';
 | 
			
		||||
            const goodMMUri2 = 'https://37.0.0.1';
 | 
			
		||||
 | 
			
		||||
            mockedRequests.push({
 | 
			
		||||
                ...mockedDefaults,
 | 
			
		||||
                endpoint: 'https://1337.0.0.1',
 | 
			
		||||
                endpoint: goodMMUri1,
 | 
			
		||||
                responseData: successfulQuote1,
 | 
			
		||||
            });
 | 
			
		||||
            // [GOOD] Another Successful response
 | 
			
		||||
            mockedRequests.push({
 | 
			
		||||
                ...mockedDefaults,
 | 
			
		||||
                endpoint: 'https://37.0.0.1',
 | 
			
		||||
                endpoint: goodMMUri2,
 | 
			
		||||
                responseData: successfulQuote1,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@@ -532,6 +535,16 @@ describe('QuoteRequestor', async () => {
 | 
			
		||||
                responseData: { ...successfulQuote1, takerToken: otherToken1 },
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            const assetOfferings: { [k: string]: [[string, string]] } = {
 | 
			
		||||
                'https://420.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                'https://421.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                'https://422.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                'https://423.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                'https://424.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
            };
 | 
			
		||||
            assetOfferings[goodMMUri1] = [[makerToken, takerToken]];
 | 
			
		||||
            assetOfferings[goodMMUri2] = [[makerToken, takerToken]];
 | 
			
		||||
 | 
			
		||||
            return testHelpers.withMockedRfqQuotes(
 | 
			
		||||
                mockedRequests,
 | 
			
		||||
                [],
 | 
			
		||||
@@ -539,15 +552,7 @@ describe('QuoteRequestor', async () => {
 | 
			
		||||
                async () => {
 | 
			
		||||
                    const qr = new QuoteRequestor(
 | 
			
		||||
                        {}, // No RFQ-T asset offerings
 | 
			
		||||
                        {
 | 
			
		||||
                            'https://1337.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                            'https://37.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                            'https://420.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                            'https://421.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                            'https://422.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                            'https://423.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                            'https://424.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                        },
 | 
			
		||||
                        assetOfferings,
 | 
			
		||||
                        quoteRequestorHttpClient,
 | 
			
		||||
                    );
 | 
			
		||||
                    const resp = await qr.requestRfqmIndicativeQuotesAsync(
 | 
			
		||||
@@ -572,7 +577,12 @@ describe('QuoteRequestor', async () => {
 | 
			
		||||
                            },
 | 
			
		||||
                        },
 | 
			
		||||
                    );
 | 
			
		||||
                    expect(resp.sort()).to.eql([successfulQuote1, successfulQuote1].sort());
 | 
			
		||||
                    expect(resp.sort()).to.eql(
 | 
			
		||||
                        [
 | 
			
		||||
                            { ...successfulQuote1, makerUri: goodMMUri1 },
 | 
			
		||||
                            { ...successfulQuote1, makerUri: goodMMUri2 },
 | 
			
		||||
                        ].sort(),
 | 
			
		||||
                    );
 | 
			
		||||
                },
 | 
			
		||||
                quoteRequestorHttpClient,
 | 
			
		||||
            );
 | 
			
		||||
@@ -622,9 +632,12 @@ describe('QuoteRequestor', async () => {
 | 
			
		||||
                expiry: makeThreeMinuteExpiry(),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            const goodMMUri1 = 'https://1337.0.0.1';
 | 
			
		||||
            const goodMMUri2 = 'https://37.0.0.1';
 | 
			
		||||
 | 
			
		||||
            mockedRequests.push({
 | 
			
		||||
                ...mockedDefaults,
 | 
			
		||||
                endpoint: 'https://1337.0.0.1',
 | 
			
		||||
                endpoint: goodMMUri1,
 | 
			
		||||
                responseData: successfulQuote1,
 | 
			
		||||
            });
 | 
			
		||||
            // Test out a bad response code, ensure it doesnt cause throw
 | 
			
		||||
@@ -655,28 +668,26 @@ describe('QuoteRequestor', async () => {
 | 
			
		||||
            // Another Successful response
 | 
			
		||||
            mockedRequests.push({
 | 
			
		||||
                ...mockedDefaults,
 | 
			
		||||
                endpoint: 'https://37.0.0.1',
 | 
			
		||||
                endpoint: goodMMUri2,
 | 
			
		||||
                responseData: successfulQuote1,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            const assetOfferings: { [k: string]: [[string, string]] } = {
 | 
			
		||||
                'https://420.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                'https://421.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                'https://422.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                'https://423.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                'https://424.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
            };
 | 
			
		||||
            assetOfferings[goodMMUri1] = [[makerToken, takerToken]];
 | 
			
		||||
            assetOfferings[goodMMUri2] = [[makerToken, takerToken]];
 | 
			
		||||
 | 
			
		||||
            return testHelpers.withMockedRfqQuotes(
 | 
			
		||||
                mockedRequests,
 | 
			
		||||
                [],
 | 
			
		||||
                RfqQuoteEndpoint.Indicative,
 | 
			
		||||
                async () => {
 | 
			
		||||
                    const qr = new QuoteRequestor(
 | 
			
		||||
                        {
 | 
			
		||||
                            'https://1337.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                            'https://420.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                            'https://421.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                            'https://422.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                            'https://423.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                            'https://424.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                            'https://37.0.0.1': [[makerToken, takerToken]],
 | 
			
		||||
                        },
 | 
			
		||||
                        {},
 | 
			
		||||
                        quoteRequestorHttpClient,
 | 
			
		||||
                    );
 | 
			
		||||
                    const qr = new QuoteRequestor(assetOfferings, {}, quoteRequestorHttpClient);
 | 
			
		||||
                    const resp = await qr.requestRfqtIndicativeQuotesAsync(
 | 
			
		||||
                        makerToken,
 | 
			
		||||
                        takerToken,
 | 
			
		||||
@@ -693,7 +704,12 @@ describe('QuoteRequestor', async () => {
 | 
			
		||||
                            intentOnFilling: true,
 | 
			
		||||
                        },
 | 
			
		||||
                    );
 | 
			
		||||
                    expect(resp.sort()).to.eql([successfulQuote1, successfulQuote1].sort());
 | 
			
		||||
                    expect(resp.sort()).to.eql(
 | 
			
		||||
                        [
 | 
			
		||||
                            { ...successfulQuote1, makerUri: goodMMUri1 },
 | 
			
		||||
                            { ...successfulQuote1, makerUri: goodMMUri2 },
 | 
			
		||||
                        ].sort(),
 | 
			
		||||
                    );
 | 
			
		||||
                },
 | 
			
		||||
                quoteRequestorHttpClient,
 | 
			
		||||
            );
 | 
			
		||||
@@ -784,7 +800,7 @@ describe('QuoteRequestor', async () => {
 | 
			
		||||
                            makerEndpointMaxResponseTimeMs: maxTimeoutMs,
 | 
			
		||||
                        },
 | 
			
		||||
                    );
 | 
			
		||||
                    expect(resp.sort()).to.eql([successfulQuote1].sort()); // notice only one result, despite two requests made
 | 
			
		||||
                    expect(resp.sort()).to.eql([{ ...successfulQuote1, makerUri: 'https://1337.0.0.1' }].sort()); // notice only one result, despite two requests made
 | 
			
		||||
                },
 | 
			
		||||
                quoteRequestorHttpClient,
 | 
			
		||||
            );
 | 
			
		||||
@@ -847,7 +863,7 @@ describe('QuoteRequestor', async () => {
 | 
			
		||||
                            intentOnFilling: true,
 | 
			
		||||
                        },
 | 
			
		||||
                    );
 | 
			
		||||
                    expect(resp.sort()).to.eql([successfulQuote1].sort());
 | 
			
		||||
                    expect(resp.sort()).to.eql([{ ...successfulQuote1, makerUri: 'https://1337.0.0.1' }].sort());
 | 
			
		||||
                },
 | 
			
		||||
                quoteRequestorHttpClient,
 | 
			
		||||
            );
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ export async function getFullyFillableSwapQuoteWithNoFeesAsync(
 | 
			
		||||
        totalTakerAmount: takerAmount,
 | 
			
		||||
        protocolFeeInWeiAmount: protocolFeePerOrder.times(orders.length),
 | 
			
		||||
        gas: 200e3,
 | 
			
		||||
        slippage: 0,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const breakdown = {
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ export * from '../test/generated-wrappers/balance_checker';
 | 
			
		||||
export * from '../test/generated-wrappers/balancer_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/balancer_v2_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/bancor_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/compound_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/curve_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/d_o_d_o_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/d_o_d_o_v2_sampler';
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@
 | 
			
		||||
        "test/generated-artifacts/BalancerSampler.json",
 | 
			
		||||
        "test/generated-artifacts/BalancerV2Sampler.json",
 | 
			
		||||
        "test/generated-artifacts/BancorSampler.json",
 | 
			
		||||
        "test/generated-artifacts/CompoundSampler.json",
 | 
			
		||||
        "test/generated-artifacts/CurveSampler.json",
 | 
			
		||||
        "test/generated-artifacts/DODOSampler.json",
 | 
			
		||||
        "test/generated-artifacts/DODOV2Sampler.json",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,51 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "version": "6.12.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add Support for Arbitrum One Mainnet"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "6.11.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add Optimism addresses",
 | 
			
		||||
                "pr": 385
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1640364306
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "6.10.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add Aave supported FQT addresses for Polygon, Avalanche",
 | 
			
		||||
                "pr": 321
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1638390144
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "6.9.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add Celo addresses",
 | 
			
		||||
                "pr": 368
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1637102971
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1635903615,
 | 
			
		||||
        "version": "6.8.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "6.8.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v6.11.0 - _December 24, 2021_
 | 
			
		||||
 | 
			
		||||
    * Add Optimism addresses (#385)
 | 
			
		||||
 | 
			
		||||
## v6.10.0 - _December 1, 2021_
 | 
			
		||||
 | 
			
		||||
    * Add Aave supported FQT addresses for Polygon, Avalanche (#321)
 | 
			
		||||
 | 
			
		||||
## v6.9.0 - _November 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Add Celo addresses (#368)
 | 
			
		||||
 | 
			
		||||
## v6.8.1 - _November 3, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v6.8.0 - _October 19, 2021_
 | 
			
		||||
 | 
			
		||||
    * Fantom deployment (#347)
 | 
			
		||||
 
 | 
			
		||||
@@ -244,11 +244,11 @@
 | 
			
		||||
        "exchangeProxyLiquidityProviderSandbox": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zrxTreasury": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "transformers": {
 | 
			
		||||
            "wethTransformer": "0xc6b0d3c45a6b5092808196cb00df5c357d55e1d5",
 | 
			
		||||
            "payTakerTransformer": "0x7209185959d7227fb77274e1e88151d7c4c368d3",
 | 
			
		||||
            "affiliateFeeTransformer": "0x3f16ca81691dab9184cb4606c361d73c4fd2510a",
 | 
			
		||||
            "fillQuoteTransformer": "0x99356167edba8fbdc36959e3f5d0c43d1ba9c6db",
 | 
			
		||||
            "positiveSlippageFeeTransformer": "0x45b3a72221e571017c0f0ec42189e11d149d0ace"
 | 
			
		||||
            "wethTransformer": "0x7209185959d7227fb77274e1e88151d7c4c368d3",
 | 
			
		||||
            "payTakerTransformer": "0x3f16ca81691dab9184cb4606c361d73c4fd2510a",
 | 
			
		||||
            "affiliateFeeTransformer": "0x99356167edba8fbdc36959e3f5d0c43d1ba9c6db",
 | 
			
		||||
            "fillQuoteTransformer": "0x45b3a72221e571017c0f0ec42189e11d149d0ace",
 | 
			
		||||
            "positiveSlippageFeeTransformer": "0xdd66c23e07b4d6925b6089b5fe6fc9e62941afe8"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "137": {
 | 
			
		||||
@@ -289,7 +289,7 @@
 | 
			
		||||
            "wethTransformer": "0xe309d011cc6f189a3e8dcba85922715a019fed38",
 | 
			
		||||
            "payTakerTransformer": "0x5ba7b9be86cda01cfbf56e0fb97184783be9dda1",
 | 
			
		||||
            "affiliateFeeTransformer": "0xbed27284b42e5684e987169cf1da09c5d6c49fa8",
 | 
			
		||||
            "fillQuoteTransformer": "0xf708d512b8a82e2862543a630403327174410baf",
 | 
			
		||||
            "fillQuoteTransformer": "0xd3afdf4a8ea9183e76c9c2306cda03ea4afffea5",
 | 
			
		||||
            "positiveSlippageFeeTransformer": "0x4cd8f1c0df4d40fcc1e073845d5f6f4ed5cc8dab"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
@@ -373,7 +373,7 @@
 | 
			
		||||
            "wethTransformer": "0x9b8b52391071d71cd4ad1e61d7f273268fa34c6c",
 | 
			
		||||
            "payTakerTransformer": "0x898c6fde239d646c73f0a57e3570b6f86a3d62a3",
 | 
			
		||||
            "affiliateFeeTransformer": "0x34617b855411e52fbc05899435f44cbd0503022c",
 | 
			
		||||
            "fillQuoteTransformer": "0x8a5417dd7ffde61ec61e11b45797e16686e1d6b9",
 | 
			
		||||
            "fillQuoteTransformer": "0xd421f50b3ae27f223aa35a04944236d257235412",
 | 
			
		||||
            "positiveSlippageFeeTransformer": "0x470ba89da18a6db6e8a0567b3c9214b960861857"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
@@ -418,5 +418,173 @@
 | 
			
		||||
            "fillQuoteTransformer": "0x71de60a1b160094a3f6c7e1b883ff9337d639131",
 | 
			
		||||
            "positiveSlippageFeeTransformer": "0xe87d69b285005cc82b53b844322652c49ed64600"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "42161": {
 | 
			
		||||
        "erc20Proxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc721Proxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zrxToken": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "etherToken": "0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83",
 | 
			
		||||
        "exchangeV2": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "exchange": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "assetProxyOwner": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zeroExGovernor": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "forwarder": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "coordinatorRegistry": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "coordinator": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "multiAssetProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "staticCallProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc1155Proxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "devUtils": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zrxVault": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "staking": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "stakingProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc20BridgeProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "chaiBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "dydxBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "godsUnchainedValidator": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "broker": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "chainlinkStopLimit": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "maximumGasPrice": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "dexForwarderBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "exchangeProxyGovernor": "0xf760c5b88d970d6f97e64e264dac5a3767dafd74",
 | 
			
		||||
        "exchangeProxy": "0xdef189deaef76e379df891899eb5a00a94cbc250",
 | 
			
		||||
        "exchangeProxyTransformerDeployer": "0x47f01db18a38261e4cb153bae6db7d3743acb33c",
 | 
			
		||||
        "exchangeProxyFlashWallet": "0xb4d961671cadfed687e040b076eee29840c142e5",
 | 
			
		||||
        "exchangeProxyLiquidityProviderSandbox": "0xca64d4225804f2ae069760cb5ff2f1d8bac1c2f9",
 | 
			
		||||
        "zrxTreasury": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "transformers": {
 | 
			
		||||
            "wethTransformer": "0x9b6aa8f26a92108e7d1f66373d757bb955112703",
 | 
			
		||||
            "payTakerTransformer": "0x32df54951d33d7460e15fa59b1fcc262183ce4c2",
 | 
			
		||||
            "affiliateFeeTransformer": "0x67efa679a4b56c38713d478e649c88247f4f8e88",
 | 
			
		||||
            "fillQuoteTransformer": "0x71de60a1b160094a3f6c7e1b883ff9337d639131",
 | 
			
		||||
            "positiveSlippageFeeTransformer": "0xe87d69b285005cc82b53b844322652c49ed64600"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "42220": {
 | 
			
		||||
        "erc20Proxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc721Proxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zrxToken": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "etherToken": "0x471ece3750da237f93b8e339c536989b8978a438",
 | 
			
		||||
        "exchangeV2": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "exchange": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "assetProxyOwner": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zeroExGovernor": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "forwarder": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "coordinatorRegistry": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "coordinator": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "multiAssetProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "staticCallProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc1155Proxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "devUtils": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zrxVault": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "staking": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "stakingProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc20BridgeProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "chaiBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "dydxBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "godsUnchainedValidator": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "broker": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "chainlinkStopLimit": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "maximumGasPrice": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "dexForwarderBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "exchangeProxyGovernor": "0x92115010fd9b170d4918b102efc86b1b7bebdc7f",
 | 
			
		||||
        "exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
 | 
			
		||||
        "exchangeProxyTransformerDeployer": "0x1fe80d5ad9464dba2d60b88e449305f184823f8a",
 | 
			
		||||
        "exchangeProxyFlashWallet": "0xdb6f1920a889355780af7570773609bd8cb1f498",
 | 
			
		||||
        "exchangeProxyLiquidityProviderSandbox": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zrxTreasury": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "transformers": {
 | 
			
		||||
            "wethTransformer": "0x948e03e708b4c62c63f89157a3aa76b986c110ed",
 | 
			
		||||
            "payTakerTransformer": "0x90fb6c638ece8f3e4bfda1c6d6425626b53148b0",
 | 
			
		||||
            "affiliateFeeTransformer": "0xc93913692ed073cb0cb37d4a760afd7916e9cb01",
 | 
			
		||||
            "fillQuoteTransformer": "0xa825d4d3c4d2820c52da69fcccf269b4081871f2",
 | 
			
		||||
            "positiveSlippageFeeTransformer": "0x9ffc7a79133ed5242777e40764777a6d5aab282c"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "10": {
 | 
			
		||||
        "erc20Proxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc721Proxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zrxToken": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "etherToken": "0x4200000000000000000000000000000000000006",
 | 
			
		||||
        "exchangeV2": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "exchange": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "assetProxyOwner": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zeroExGovernor": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "forwarder": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "coordinatorRegistry": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "coordinator": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "multiAssetProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "staticCallProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc1155Proxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "devUtils": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zrxVault": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "staking": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "stakingProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc20BridgeProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "chaiBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "dydxBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "godsUnchainedValidator": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "broker": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "chainlinkStopLimit": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "maximumGasPrice": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "dexForwarderBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "exchangeProxyGovernor": "0x6d506b2847df0c6f04d2628da1adaf4d8fb2e81b",
 | 
			
		||||
        "exchangeProxy": "0xdef1abe32c034e558cdd535791643c58a13acc10",
 | 
			
		||||
        "exchangeProxyTransformerDeployer": "0x3a539ed6bd42de8fbaf3899fb490c792e153d647",
 | 
			
		||||
        "exchangeProxyFlashWallet": "0xa3128d9b7cca7d5af29780a56abeec12b05a6740",
 | 
			
		||||
        "exchangeProxyLiquidityProviderSandbox": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zrxTreasury": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "transformers": {
 | 
			
		||||
            "wethTransformer": "0x02ce7af6520e2862f961f5d7eda746642865179c",
 | 
			
		||||
            "payTakerTransformer": "0x085d10a34f14f6a631ea8ff7d016782ee3ffaa11",
 | 
			
		||||
            "affiliateFeeTransformer": "0x55cf1d7535250db75bf0190493f55781ee583553",
 | 
			
		||||
            "fillQuoteTransformer": "0x3543ef833d28b7e983c293856561f21a7f089f1d",
 | 
			
		||||
            "positiveSlippageFeeTransformer": "0xb11e14565dfbeb702dea9bc0cb47f1a8b32f4783"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "42161": {
 | 
			
		||||
        "erc20Proxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc721Proxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zrxToken": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "etherToken": "0x82af49447d8a07e3bd95bd0d56f35241523fbab1",
 | 
			
		||||
        "exchangeV2": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "exchange": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "assetProxyOwner": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zeroExGovernor": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "forwarder": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "coordinatorRegistry": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "coordinator": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "multiAssetProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "staticCallProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc1155Proxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "devUtils": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zrxVault": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "staking": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "stakingProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc20BridgeProxy": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "chaiBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "dydxBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "godsUnchainedValidator": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "broker": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "chainlinkStopLimit": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "maximumGasPrice": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "dexForwarderBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "exchangeProxyGovernor": "0x1fe80d5ad9464dba2d60b88e449305f184823f8a",
 | 
			
		||||
        "exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
 | 
			
		||||
        "exchangeProxyTransformerDeployer": "0x29f80c1f685e19ae1807063eda432f431ac623d0",
 | 
			
		||||
        "exchangeProxyFlashWallet": "0xdb6f1920a889355780af7570773609bd8cb1f498",
 | 
			
		||||
        "exchangeProxyLiquidityProviderSandbox": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "zrxTreasury": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "transformers": {
 | 
			
		||||
            "wethTransformer": "0x10e968968f49dd66a5efeebbb2edcb9c49c4fc49",
 | 
			
		||||
            "payTakerTransformer": "0xae3e8cf7bf340d7084f312dfae2aa8b01c885b02",
 | 
			
		||||
            "affiliateFeeTransformer": "0x05a24978471869327904ea13da3c4322128e2aaa",
 | 
			
		||||
            "fillQuoteTransformer": "0x5a653323c2a47a8e1b69fb3d0f15858bfc7fe205",
 | 
			
		||||
            "positiveSlippageFeeTransformer": "0xD56B9C014b45ED95e2a048A0C28121Db30265F13"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contract-addresses",
 | 
			
		||||
    "version": "6.8.0",
 | 
			
		||||
    "version": "6.11.0",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -54,6 +54,10 @@ export enum ChainId {
 | 
			
		||||
    PolygonMumbai = 80001,
 | 
			
		||||
    Avalanche = 43114,
 | 
			
		||||
    Fantom = 250,
 | 
			
		||||
    Arbitrum = 42161,
 | 
			
		||||
    Celo = 42220,
 | 
			
		||||
    Optimism = 10,
 | 
			
		||||
    Arbitrum = 42161,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,40 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1640364306,
 | 
			
		||||
        "version": "13.18.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1638390144,
 | 
			
		||||
        "version": "13.18.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1637102971,
 | 
			
		||||
        "version": "13.18.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1635903615,
 | 
			
		||||
        "version": "13.18.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1634668033,
 | 
			
		||||
        "version": "13.18.1",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v13.18.5 - _December 24, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v13.18.4 - _December 1, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v13.18.3 - _November 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v13.18.2 - _November 3, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v13.18.1 - _October 19, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contract-wrappers",
 | 
			
		||||
    "version": "13.18.1",
 | 
			
		||||
    "version": "13.18.5",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -57,7 +57,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/json-schemas": "^6.3.0",
 | 
			
		||||
        "@0x/types": "^3.3.4",
 | 
			
		||||
        "@0x/utils": "^6.4.4",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,50 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1640364306,
 | 
			
		||||
        "version": "8.1.14",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1638390144,
 | 
			
		||||
        "version": "8.1.13",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1637102971,
 | 
			
		||||
        "version": "8.1.12",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1637065617,
 | 
			
		||||
        "version": "8.1.11",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "8.1.10",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add OtcOrders to fullMigrateAsync",
 | 
			
		||||
                "pr": 350
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1635903615
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1634668033,
 | 
			
		||||
        "version": "8.1.9",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,26 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v8.1.14 - _December 24, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v8.1.13 - _December 1, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v8.1.12 - _November 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v8.1.11 - _November 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v8.1.10 - _November 3, 2021_
 | 
			
		||||
 | 
			
		||||
    * Add OtcOrders to fullMigrateAsync (#350)
 | 
			
		||||
 | 
			
		||||
## v8.1.9 - _October 19, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/migrations",
 | 
			
		||||
    "version": "8.1.9",
 | 
			
		||||
    "version": "8.1.14",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -68,20 +68,20 @@
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/base-contract": "^6.4.2",
 | 
			
		||||
        "@0x/contract-addresses": "^6.8.0",
 | 
			
		||||
        "@0x/contract-addresses": "^6.11.0",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.19",
 | 
			
		||||
        "@0x/contracts-coordinator": "^3.1.38",
 | 
			
		||||
        "@0x/contracts-dev-utils": "^1.3.36",
 | 
			
		||||
        "@0x/contracts-erc1155": "^2.1.37",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.21",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.25",
 | 
			
		||||
        "@0x/contracts-erc721": "^3.1.37",
 | 
			
		||||
        "@0x/contracts-exchange": "^3.2.38",
 | 
			
		||||
        "@0x/contracts-exchange-forwarder": "^4.2.38",
 | 
			
		||||
        "@0x/contracts-extensions": "^6.2.32",
 | 
			
		||||
        "@0x/contracts-multisig": "^4.1.38",
 | 
			
		||||
        "@0x/contracts-staking": "^2.0.45",
 | 
			
		||||
        "@0x/contracts-utils": "^4.8.2",
 | 
			
		||||
        "@0x/contracts-zero-ex": "^0.29.2",
 | 
			
		||||
        "@0x/contracts-utils": "^4.8.6",
 | 
			
		||||
        "@0x/contracts-zero-ex": "^0.30.1",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.5",
 | 
			
		||||
        "@0x/subproviders": "^6.6.0",
 | 
			
		||||
        "@0x/typescript-typings": "^5.2.1",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,41 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1640364306,
 | 
			
		||||
        "version": "1.10.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "1.10.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `AaveV2` and `Compound` deposit/withdrawal liquidity source",
 | 
			
		||||
                "pr": 321
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1638390144
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1637102971,
 | 
			
		||||
        "version": "1.9.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1635903615,
 | 
			
		||||
        "version": "1.9.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1634668033,
 | 
			
		||||
        "version": "1.9.3",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v1.10.1 - _December 24, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.10.0 - _December 1, 2021_
 | 
			
		||||
 | 
			
		||||
    * Add `AaveV2` and `Compound` deposit/withdrawal liquidity source (#321)
 | 
			
		||||
 | 
			
		||||
## v1.9.5 - _November 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.9.4 - _November 3, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.9.3 - _October 19, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/protocol-utils",
 | 
			
		||||
    "version": "1.9.3",
 | 
			
		||||
    "version": "1.10.1",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -63,8 +63,8 @@
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/assert": "^3.0.29",
 | 
			
		||||
        "@0x/contract-addresses": "^6.8.0",
 | 
			
		||||
        "@0x/contract-wrappers": "^13.18.1",
 | 
			
		||||
        "@0x/contract-addresses": "^6.11.0",
 | 
			
		||||
        "@0x/contract-wrappers": "^13.18.5",
 | 
			
		||||
        "@0x/json-schemas": "^6.3.0",
 | 
			
		||||
        "@0x/subproviders": "^6.6.0",
 | 
			
		||||
        "@0x/utils": "^6.4.4",
 | 
			
		||||
 
 | 
			
		||||
@@ -132,6 +132,8 @@ export enum BridgeProtocol {
 | 
			
		||||
    CurveV2,
 | 
			
		||||
    Lido,
 | 
			
		||||
    Clipper, // Not used: Clipper is now using PLP interface
 | 
			
		||||
    AaveV2,
 | 
			
		||||
    Compound,
 | 
			
		||||
}
 | 
			
		||||
// tslint:enable: enum-naming
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								yarn.lock
									
									
									
									
									
								
							@@ -738,6 +738,7 @@
 | 
			
		||||
"@0x/contracts-asset-proxy@^3.7.19":
 | 
			
		||||
  version "3.7.19"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@0x/contracts-asset-proxy/-/contracts-asset-proxy-3.7.19.tgz#ee621a233f4d77b439c74c5b8d70db2e1ed001c4"
 | 
			
		||||
  integrity sha512-6lTgz8JdmceaSnqpJrbyKJXUIyAA2HZrXel+ZWpgMtO7qaSSQDRUcWUBwejTE588BcVxhNFQ7tHvOK3/QGnpHw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@0x/base-contract" "^6.4.0"
 | 
			
		||||
    "@0x/contracts-erc1155" "^2.1.37"
 | 
			
		||||
@@ -959,10 +960,10 @@
 | 
			
		||||
    typedoc "~0.16.11"
 | 
			
		||||
    yargs "^10.0.3"
 | 
			
		||||
 | 
			
		||||
"@0x/neon-router@^0.2.1":
 | 
			
		||||
  version "0.2.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@0x/neon-router/-/neon-router-0.2.1.tgz#23bb3cedc0eafd55a8ba6b6ea8a59ee4c538064b"
 | 
			
		||||
  integrity sha512-feCCKuox4staZl8lxLY4nf5U256NcDHrgvSFra5cU/TUhoblLHb8F7eWAC9ygpukZUCVFLy13mExkFQHXlEOYw==
 | 
			
		||||
"@0x/neon-router@^0.3.1":
 | 
			
		||||
  version "0.3.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@0x/neon-router/-/neon-router-0.3.1.tgz#4ec13e750d1435357c4928d7f2521a2b4376f27e"
 | 
			
		||||
  integrity sha512-M4ypTov9KyxsGJpYwobrld3Y2JOlR7U0XjR6BEQE2gQ1k3nie/1wNEI2J4ZjKw++RLDxdv/RCqhgA5VnINzjxA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@mapbox/node-pre-gyp" "^1.0.5"
 | 
			
		||||
 | 
			
		||||
@@ -6402,6 +6403,7 @@ fake-merkle-patricia-tree@^1.0.1:
 | 
			
		||||
fast-abi@^0.0.2:
 | 
			
		||||
  version "0.0.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fast-abi/-/fast-abi-0.0.2.tgz#da5f796fd7c7b0c966d916ee21daae3eca61c07c"
 | 
			
		||||
  integrity sha512-k/2s63SkFf6jU2LyF6oQC5/N+L90q6VD1wkp2NXo+DSHoTeOJD2Q6Egpcs+bTPODik0CHxjb7lORgsG+QCRq/Q==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@mapbox/node-pre-gyp" "^1.0.4"
 | 
			
		||||
    neon-cli "^0.8.0"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user