Compare commits
	
		
			90 Commits
		
	
	
		
			@0x/contra
			...
			protocol@a
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					aae46bef84 | ||
| 
						 | 
					a0bb36954e | ||
| 
						 | 
					4f32f3174f | ||
| 
						 | 
					b84107d142 | ||
| 
						 | 
					b46eeadc64 | ||
| 
						 | 
					692231c2ea | ||
| 
						 | 
					3a1becc3e4 | ||
| 
						 | 
					3653e2d7f9 | ||
| 
						 | 
					65def38d98 | ||
| 
						 | 
					859c36cb10 | ||
| 
						 | 
					3e34386812 | ||
| 
						 | 
					a35af11981 | ||
| 
						 | 
					59eabec71e | ||
| 
						 | 
					bf4c7e7d50 | ||
| 
						 | 
					fd098ca4df | ||
| 
						 | 
					c360f8d8fd | ||
| 
						 | 
					b358559421 | ||
| 
						 | 
					df5aad8e8e | ||
| 
						 | 
					8dbf79db59 | ||
| 
						 | 
					1839608e84 | ||
| 
						 | 
					6e3e795b8b | ||
| 
						 | 
					d9c410a7e3 | ||
| 
						 | 
					609727afe8 | ||
| 
						 | 
					8a5c74c0b4 | ||
| 
						 | 
					cd93f3b07e | ||
| 
						 | 
					8397b12de6 | ||
| 
						 | 
					3f85acec3a | ||
| 
						 | 
					d6a9e3d600 | ||
| 
						 | 
					361569ac2f | ||
| 
						 | 
					719664c145 | ||
| 
						 | 
					f800d6c24c | ||
| 
						 | 
					a9a81bcafb | ||
| 
						 | 
					4280307a15 | ||
| 
						 | 
					7b57d3ae51 | ||
| 
						 | 
					8a8a5bbda0 | ||
| 
						 | 
					76987c8db1 | ||
| 
						 | 
					6f8971cc42 | ||
| 
						 | 
					71ab882143 | ||
| 
						 | 
					5a4961c8d9 | ||
| 
						 | 
					4c4fb99d87 | ||
| 
						 | 
					872abf09e9 | ||
| 
						 | 
					f10bfe7d04 | ||
| 
						 | 
					a74d8deff3 | ||
| 
						 | 
					835ee4e8de | ||
| 
						 | 
					63ec42303f | ||
| 
						 | 
					f789aebddc | ||
| 
						 | 
					efd83be779 | ||
| 
						 | 
					603bc1d51c | ||
| 
						 | 
					32a930a7fc | ||
| 
						 | 
					f464bf68d7 | ||
| 
						 | 
					ebdc4fb509 | ||
| 
						 | 
					7580719586 | ||
| 
						 | 
					aba9db2be7 | ||
| 
						 | 
					a6680411c8 | ||
| 
						 | 
					0d0e87de94 | ||
| 
						 | 
					ccf2000c09 | ||
| 
						 | 
					3eb2e0f56a | ||
| 
						 | 
					d07c7d5b69 | ||
| 
						 | 
					adf6684c29 | ||
| 
						 | 
					9bf889aa30 | ||
| 
						 | 
					e81c88564e | ||
| 
						 | 
					901d400d62 | ||
| 
						 | 
					289474e2ce | ||
| 
						 | 
					407ca21168 | ||
| 
						 | 
					5c68fc24d2 | ||
| 
						 | 
					548800e0a9 | ||
| 
						 | 
					bde3d6dc6a | ||
| 
						 | 
					56550a6acc | ||
| 
						 | 
					e51b83accc | ||
| 
						 | 
					d5ae971f1c | ||
| 
						 | 
					5a2f5f9a42 | ||
| 
						 | 
					75a3b70cef | ||
| 
						 | 
					803cf65ba1 | ||
| 
						 | 
					5d3947b838 | ||
| 
						 | 
					4397a59008 | ||
| 
						 | 
					966d54c935 | ||
| 
						 | 
					234ddb495d | ||
| 
						 | 
					a744acc7bc | ||
| 
						 | 
					27c624633c | ||
| 
						 | 
					7ef75101b4 | ||
| 
						 | 
					6f8aace00d | ||
| 
						 | 
					6c264b2f18 | ||
| 
						 | 
					df055e1958 | ||
| 
						 | 
					70d2117470 | ||
| 
						 | 
					2c173ccaf3 | ||
| 
						 | 
					d2f4a0c5f3 | ||
| 
						 | 
					0d6021e5e3 | ||
| 
						 | 
					bb04726e7f | ||
| 
						 | 
					220ca370c2 | ||
| 
						 | 
					63af4e3e98 | 
@@ -2,11 +2,11 @@ version: 2.1
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
    build:
 | 
			
		||||
        resource_class: large
 | 
			
		||||
        resource_class: xlarge
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:12
 | 
			
		||||
        environment:
 | 
			
		||||
            NODE_OPTIONS: '--max-old-space-size=6442'
 | 
			
		||||
            NODE_OPTIONS: '--max-old-space-size=16384'
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
@@ -18,8 +18,8 @@ jobs:
 | 
			
		||||
                  name: yarn
 | 
			
		||||
                  command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
 | 
			
		||||
            - setup_remote_docker
 | 
			
		||||
            - run: yarn build:ci || yarn build:ci || yarn build:ci
 | 
			
		||||
            - run: yarn build:ts || yarn build:ts || yarn build:ts
 | 
			
		||||
            - run: yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci
 | 
			
		||||
            - run: yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts
 | 
			
		||||
            - save_cache:
 | 
			
		||||
                  key: repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
                  paths:
 | 
			
		||||
 
 | 
			
		||||
@@ -3,5 +3,6 @@
 | 
			
		||||
    "tabWidth": 4,
 | 
			
		||||
    "singleQuote": true,
 | 
			
		||||
    "trailingComma": "all",
 | 
			
		||||
    "bracketSpacing": true
 | 
			
		||||
    "bracketSpacing": true,
 | 
			
		||||
    "arrowParens": "avoid"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,6 @@
 | 
			
		||||
| Package | Version |
 | 
			
		||||
| ------: | :------ |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<!-- For example:
 | 
			
		||||
|             `0x.js` | 2.0.4   |
 | 
			
		||||
| `Exchange Contract` | v2      |
 | 
			
		||||
 
 | 
			
		||||
@@ -43,12 +43,12 @@ These packages are all under development. See [/contracts/README.md](/contracts/
 | 
			
		||||
#### 0x-specific packages
 | 
			
		||||
 | 
			
		||||
| Package                                                  | Version                                                                                                                 | Description                                                                                    |
 | 
			
		||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
 | 
			
		||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
 | 
			
		||||
| [`@0x/contract-addresses`](/packages/contract-addresses) | [](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. |
 | 
			
		||||
| [`@0x/contract-wrappers`](/packages/contract-wrappers)   | [](https://www.npmjs.com/package/@0x/contract-wrappers)   | JS/TS wrappers for interacting with the 0x smart contracts                                     |
 | 
			
		||||
| [`@0x/order-utils`](/packages/order-utils)               | [](https://www.npmjs.com/package/@0x/order-utils)               | A set of utilities for generating, parsing, signing and validating 0x orders                   |
 | 
			
		||||
| [`@0x/migrations`](/packages/migrations)                 | [](https://www.npmjs.com/package/@0x/migrations)                 | Migration tool for deploying 0x smart contracts on private testnets                            |
 | 
			
		||||
| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts                                                        |  |
 | 
			
		||||
| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts                                                        |     |
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,76 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "3.7.19",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "3.7.18",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "3.7.17",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "3.7.16",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "3.7.15",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "3.7.14",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "3.7.13",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "3.7.12",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1620214333,
 | 
			
		||||
        "version": "3.7.11",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v3.7.19 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.18 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.17 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.16 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.15 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.14 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.13 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.12 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.11 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-asset-proxy",
 | 
			
		||||
    "version": "3.7.11",
 | 
			
		||||
    "version": "3.7.19",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -52,10 +52,10 @@
 | 
			
		||||
    "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/contract-wrappers": "^13.16.1",
 | 
			
		||||
        "@0x/contract-wrappers": "^13.17.4",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.8",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.16",
 | 
			
		||||
        "@0x/dev-utils": "^4.2.7",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/ts-doc-gen": "^0.0.28",
 | 
			
		||||
@@ -80,11 +80,11 @@
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/base-contract": "^6.4.0",
 | 
			
		||||
        "@0x/contracts-erc1155": "^2.1.29",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.8",
 | 
			
		||||
        "@0x/contracts-erc721": "^3.1.29",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.29",
 | 
			
		||||
        "@0x/order-utils": "^10.4.21",
 | 
			
		||||
        "@0x/contracts-erc1155": "^2.1.37",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.16",
 | 
			
		||||
        "@0x/contracts-erc721": "^3.1.37",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.37",
 | 
			
		||||
        "@0x/order-utils": "^10.4.28",
 | 
			
		||||
        "@0x/types": "^3.3.3",
 | 
			
		||||
        "@0x/typescript-typings": "^5.2.0",
 | 
			
		||||
        "@0x/utils": "^6.4.3",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,76 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "1.1.37",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "1.1.36",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "1.1.35",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "1.1.34",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "1.1.33",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "1.1.32",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "1.1.31",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "1.1.30",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1620214333,
 | 
			
		||||
        "version": "1.1.29",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v1.1.37 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.1.36 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.1.35 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.1.34 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.1.33 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.1.32 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.1.31 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.1.30 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.1.29 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-broker",
 | 
			
		||||
    "version": "1.1.29",
 | 
			
		||||
    "version": "1.1.37",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -52,14 +52,14 @@
 | 
			
		||||
    "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.11",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.8",
 | 
			
		||||
        "@0x/contracts-erc721": "^3.1.29",
 | 
			
		||||
        "@0x/contracts-exchange": "^3.2.30",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.29",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.19",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.16",
 | 
			
		||||
        "@0x/contracts-erc721": "^3.1.37",
 | 
			
		||||
        "@0x/contracts-exchange": "^3.2.38",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.37",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.8",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.16",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/ts-doc-gen": "^0.0.28",
 | 
			
		||||
        "@0x/tslint-config": "^4.1.4",
 | 
			
		||||
@@ -85,7 +85,7 @@
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/base-contract": "^6.4.0",
 | 
			
		||||
        "@0x/order-utils": "^10.4.21",
 | 
			
		||||
        "@0x/order-utils": "^10.4.28",
 | 
			
		||||
        "@0x/typescript-typings": "^5.2.0",
 | 
			
		||||
        "@0x/utils": "^6.4.3",
 | 
			
		||||
        "ethereum-types": "^3.5.0"
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,10 @@ export interface GodsUnchainedProperties {
 | 
			
		||||
    quality: BigNumber | number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const propertyDataEncoder = AbiEncoder.create([{ name: 'proto', type: 'uint16' }, { name: 'quality', type: 'uint8' }]);
 | 
			
		||||
const propertyDataEncoder = AbiEncoder.create([
 | 
			
		||||
    { name: 'proto', type: 'uint16' },
 | 
			
		||||
    { name: 'quality', type: 'uint8' },
 | 
			
		||||
]);
 | 
			
		||||
const brokerDataEncoder = AbiEncoder.create([
 | 
			
		||||
    { name: 'godsUnchainedAddress', type: 'address' },
 | 
			
		||||
    { name: 'validatorAddress', type: 'address' },
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,76 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "3.1.38",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "3.1.37",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "3.1.36",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "3.1.35",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "3.1.34",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "3.1.33",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "3.1.32",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "3.1.31",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1620214333,
 | 
			
		||||
        "version": "3.1.30",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v3.1.38 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.37 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.36 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.35 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.34 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.33 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.32 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.31 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.30 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-coordinator",
 | 
			
		||||
    "version": "3.1.30",
 | 
			
		||||
    "version": "3.1.38",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -53,12 +53,12 @@
 | 
			
		||||
    "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.11",
 | 
			
		||||
        "@0x/contracts-dev-utils": "^1.3.28",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.8",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.19",
 | 
			
		||||
        "@0x/contracts-dev-utils": "^1.3.36",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.16",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/dev-utils": "^4.2.7",
 | 
			
		||||
        "@0x/order-utils": "^10.4.21",
 | 
			
		||||
        "@0x/order-utils": "^10.4.28",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/ts-doc-gen": "^0.0.28",
 | 
			
		||||
        "@0x/tslint-config": "^4.1.4",
 | 
			
		||||
@@ -84,10 +84,10 @@
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/assert": "^3.0.27",
 | 
			
		||||
        "@0x/base-contract": "^6.4.0",
 | 
			
		||||
        "@0x/contract-addresses": "^6.1.0",
 | 
			
		||||
        "@0x/contracts-exchange": "^3.2.30",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.8",
 | 
			
		||||
        "@0x/contract-addresses": "^6.6.0",
 | 
			
		||||
        "@0x/contracts-exchange": "^3.2.38",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.16",
 | 
			
		||||
        "@0x/json-schemas": "^6.1.3",
 | 
			
		||||
        "@0x/types": "^3.3.3",
 | 
			
		||||
        "@0x/typescript-typings": "^5.2.0",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,76 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "1.3.36",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "1.3.35",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "1.3.34",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "1.3.33",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "1.3.32",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "1.3.31",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "1.3.30",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "1.3.29",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1620214333,
 | 
			
		||||
        "version": "1.3.28",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v1.3.36 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.3.35 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.3.34 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.3.33 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.3.32 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.3.31 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.3.30 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.3.29 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.3.28 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-dev-utils",
 | 
			
		||||
    "version": "1.3.28",
 | 
			
		||||
    "version": "1.3.36",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -43,10 +43,10 @@
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/assert": "^3.0.27",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.11",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.8",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.19",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.16",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/ts-doc-gen": "^0.0.28",
 | 
			
		||||
        "@0x/tslint-config": "^4.1.4",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,76 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "2.1.37",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "2.1.36",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "2.1.35",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "2.1.34",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "2.1.33",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "2.1.32",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "2.1.31",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "2.1.30",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1620214333,
 | 
			
		||||
        "version": "2.1.29",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v2.1.37 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.36 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.35 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.34 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.33 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.32 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.31 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.30 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.29 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-erc1155",
 | 
			
		||||
    "version": "2.1.29",
 | 
			
		||||
    "version": "2.1.37",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -54,7 +54,7 @@
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.8",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.16",
 | 
			
		||||
        "@0x/dev-utils": "^4.2.7",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/ts-doc-gen": "^0.0.28",
 | 
			
		||||
@@ -81,7 +81,7 @@
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/base-contract": "^6.4.0",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/utils": "^6.4.3",
 | 
			
		||||
        "@0x/web3-wrapper": "^7.5.3",
 | 
			
		||||
        "lodash": "^4.17.11"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,77 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "3.3.16",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "3.3.15",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add ethers as a dependency",
 | 
			
		||||
                "pr": 305
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1628665757
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "3.3.14",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "3.3.13",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "3.3.12",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "3.3.11",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "3.3.10",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "3.3.9",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1620214333,
 | 
			
		||||
        "version": "3.3.8",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v3.3.16 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.3.15 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Add ethers as a dependency (#305)
 | 
			
		||||
 | 
			
		||||
## v3.3.14 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.3.13 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.3.12 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.3.11 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.3.10 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.3.9 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.3.8 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ library LibERC20TokenV06 {
 | 
			
		||||
    bytes constant private DECIMALS_CALL_DATA = hex"313ce567";
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20TokenV06(token).approve()`.
 | 
			
		||||
    ///      Reverts if the result fails `isSuccessfulResult()` or the call reverts.
 | 
			
		||||
    ///      Reverts if the return data is invalid or the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param spender The address that receives an allowance.
 | 
			
		||||
    /// @param allowance The allowance to set.
 | 
			
		||||
@@ -49,7 +49,7 @@ library LibERC20TokenV06 {
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20TokenV06(token).approve()` and sets the allowance to the
 | 
			
		||||
    ///      maximum if the current approval is not already >= an amount.
 | 
			
		||||
    ///      Reverts if the result fails `isSuccessfulResult()` or the call reverts.
 | 
			
		||||
    ///      Reverts if the return data is invalid or the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param spender The address that receives an allowance.
 | 
			
		||||
    /// @param amount The minimum allowance needed.
 | 
			
		||||
@@ -66,7 +66,7 @@ library LibERC20TokenV06 {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20TokenV06(token).transfer()`.
 | 
			
		||||
    ///      Reverts if the result fails `isSuccessfulResult()` or the call reverts.
 | 
			
		||||
    ///      Reverts if the return data is invalid or the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param to The address that receives the tokens
 | 
			
		||||
    /// @param amount Number of tokens to transfer.
 | 
			
		||||
@@ -86,7 +86,7 @@ library LibERC20TokenV06 {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20TokenV06(token).transferFrom()`.
 | 
			
		||||
    ///      Reverts if the result fails `isSuccessfulResult()` or the call reverts.
 | 
			
		||||
    ///      Reverts if the return data is invalid or the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param from The owner of the tokens.
 | 
			
		||||
    /// @param to The address that receives the tokens
 | 
			
		||||
@@ -168,27 +168,6 @@ library LibERC20TokenV06 {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Check if the data returned by a non-static call to an ERC20 token
 | 
			
		||||
    ///      is a successful result. Supported functions are `transfer()`,
 | 
			
		||||
    ///      `transferFrom()`, and `approve()`.
 | 
			
		||||
    /// @param resultData The raw data returned by a non-static call to the ERC20 token.
 | 
			
		||||
    /// @return isSuccessful Whether the result data indicates success.
 | 
			
		||||
    function isSuccessfulResult(bytes memory resultData)
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bool isSuccessful)
 | 
			
		||||
    {
 | 
			
		||||
        if (resultData.length == 0) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        if (resultData.length >= 32) {
 | 
			
		||||
            uint256 result = LibBytesV06.readUint256(resultData, 0);
 | 
			
		||||
            if (result == 1) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes a call on address `target` with calldata `callData`
 | 
			
		||||
    ///      and asserts that either nothing was returned or a single boolean
 | 
			
		||||
    ///      was returned equal to `true`.
 | 
			
		||||
@@ -201,9 +180,31 @@ library LibERC20TokenV06 {
 | 
			
		||||
        private
 | 
			
		||||
    {
 | 
			
		||||
        (bool didSucceed, bytes memory resultData) = target.call(callData);
 | 
			
		||||
        if (didSucceed && isSuccessfulResult(resultData)) {
 | 
			
		||||
        // Revert if the call reverted.
 | 
			
		||||
        if (!didSucceed) {
 | 
			
		||||
            LibRichErrorsV06.rrevert(resultData);
 | 
			
		||||
        }
 | 
			
		||||
        // If we get back 0 returndata, this may be a non-standard ERC-20 that
 | 
			
		||||
        // does not return a boolean. Check that it at least contains code.
 | 
			
		||||
        if (resultData.length == 0) {
 | 
			
		||||
            uint256 size;
 | 
			
		||||
            assembly { size := extcodesize(target) }
 | 
			
		||||
            require(size > 0, "invalid token address, contains no code");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // If we get back at least 32 bytes, we know the target address
 | 
			
		||||
        // contains code, and we assume it is a token that returned a boolean
 | 
			
		||||
        // success value, which must be true.
 | 
			
		||||
        if (resultData.length >= 32) {
 | 
			
		||||
            uint256 result = LibBytesV06.readUint256(resultData, 0);
 | 
			
		||||
            if (result == 1) {
 | 
			
		||||
                return;
 | 
			
		||||
            } else {
 | 
			
		||||
                LibRichErrorsV06.rrevert(resultData);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // If 0 < returndatasize < 32, the target is a contract, but not a
 | 
			
		||||
        // valid token.
 | 
			
		||||
        LibRichErrorsV06.rrevert(resultData);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-erc20",
 | 
			
		||||
    "version": "3.3.8",
 | 
			
		||||
    "version": "3.3.16",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -53,8 +53,8 @@
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.8",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.16",
 | 
			
		||||
        "@0x/dev-utils": "^4.2.7",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/ts-doc-gen": "^0.0.28",
 | 
			
		||||
@@ -82,7 +82,8 @@
 | 
			
		||||
        "typescript": "4.2.2"
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/base-contract": "^6.4.0"
 | 
			
		||||
        "@0x/base-contract": "^6.4.0",
 | 
			
		||||
        "ethers": "~4.0.4"
 | 
			
		||||
    },
 | 
			
		||||
    "publishConfig": {
 | 
			
		||||
        "access": "public"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,76 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "3.1.37",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "3.1.36",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "3.1.35",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "3.1.34",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "3.1.33",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "3.1.32",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "3.1.31",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "3.1.30",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1620214333,
 | 
			
		||||
        "version": "3.1.29",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v3.1.37 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.36 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.35 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.34 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.33 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.32 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.31 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.30 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.29 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-erc721",
 | 
			
		||||
    "version": "3.1.29",
 | 
			
		||||
    "version": "3.1.37",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -54,8 +54,8 @@
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.8",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.16",
 | 
			
		||||
        "@0x/dev-utils": "^4.2.7",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/ts-doc-gen": "^0.0.28",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,76 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "4.2.38",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "4.2.37",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "4.2.36",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "4.2.35",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "4.2.34",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "4.2.33",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "4.2.32",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "4.2.31",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1620214333,
 | 
			
		||||
        "version": "4.2.30",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v4.2.38 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.2.37 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.2.36 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.2.35 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.2.34 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.2.33 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.2.32 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.2.31 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.2.30 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-exchange-forwarder",
 | 
			
		||||
    "version": "4.2.30",
 | 
			
		||||
    "version": "4.2.38",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -53,18 +53,18 @@
 | 
			
		||||
    "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.11",
 | 
			
		||||
        "@0x/contracts-dev-utils": "^1.3.28",
 | 
			
		||||
        "@0x/contracts-erc1155": "^2.1.29",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.8",
 | 
			
		||||
        "@0x/contracts-erc721": "^3.1.29",
 | 
			
		||||
        "@0x/contracts-exchange": "^3.2.30",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.29",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.19",
 | 
			
		||||
        "@0x/contracts-dev-utils": "^1.3.36",
 | 
			
		||||
        "@0x/contracts-erc1155": "^2.1.37",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.16",
 | 
			
		||||
        "@0x/contracts-erc721": "^3.1.37",
 | 
			
		||||
        "@0x/contracts-exchange": "^3.2.38",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.37",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.8",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.16",
 | 
			
		||||
        "@0x/dev-utils": "^4.2.7",
 | 
			
		||||
        "@0x/order-utils": "^10.4.21",
 | 
			
		||||
        "@0x/order-utils": "^10.4.28",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/ts-doc-gen": "^0.0.28",
 | 
			
		||||
        "@0x/tslint-config": "^4.1.4",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,76 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "4.3.37",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "4.3.36",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "4.3.35",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "4.3.34",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "4.3.33",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "4.3.32",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "4.3.31",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "4.3.30",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1620214333,
 | 
			
		||||
        "version": "4.3.29",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v4.3.37 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.3.36 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.3.35 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.3.34 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.3.33 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.3.32 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.3.31 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.3.30 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.3.29 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-exchange-libs",
 | 
			
		||||
    "version": "4.3.29",
 | 
			
		||||
    "version": "4.3.37",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -81,9 +81,9 @@
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/base-contract": "^6.4.0",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.8",
 | 
			
		||||
        "@0x/order-utils": "^10.4.21",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.16",
 | 
			
		||||
        "@0x/order-utils": "^10.4.28",
 | 
			
		||||
        "@0x/types": "^3.3.3",
 | 
			
		||||
        "@0x/typescript-typings": "^5.2.0",
 | 
			
		||||
        "@0x/utils": "^6.4.3",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,76 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "3.2.38",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "3.2.37",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "3.2.36",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "3.2.35",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "3.2.34",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "3.2.33",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "3.2.32",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "3.2.31",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1620214333,
 | 
			
		||||
        "version": "3.2.30",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v3.2.38 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.2.37 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.2.36 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.2.35 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.2.34 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.2.33 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.2.32 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.2.31 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.2.30 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-exchange",
 | 
			
		||||
    "version": "3.2.30",
 | 
			
		||||
    "version": "3.2.38",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -53,13 +53,13 @@
 | 
			
		||||
    "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.11",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.29",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.19",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.37",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/contracts-multisig": "^4.1.30",
 | 
			
		||||
        "@0x/contracts-staking": "^2.0.37",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.8",
 | 
			
		||||
        "@0x/contracts-multisig": "^4.1.38",
 | 
			
		||||
        "@0x/contracts-staking": "^2.0.45",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.16",
 | 
			
		||||
        "@0x/dev-utils": "^4.2.7",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/ts-doc-gen": "^0.0.28",
 | 
			
		||||
@@ -89,11 +89,11 @@
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/base-contract": "^6.4.0",
 | 
			
		||||
        "@0x/contracts-dev-utils": "^1.3.28",
 | 
			
		||||
        "@0x/contracts-erc1155": "^2.1.29",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.8",
 | 
			
		||||
        "@0x/contracts-erc721": "^3.1.29",
 | 
			
		||||
        "@0x/order-utils": "^10.4.21",
 | 
			
		||||
        "@0x/contracts-dev-utils": "^1.3.36",
 | 
			
		||||
        "@0x/contracts-erc1155": "^2.1.37",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.16",
 | 
			
		||||
        "@0x/contracts-erc721": "^3.1.37",
 | 
			
		||||
        "@0x/order-utils": "^10.4.28",
 | 
			
		||||
        "@0x/utils": "^6.4.3",
 | 
			
		||||
        "lodash": "^4.17.11"
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,11 @@ export const exchangeDataEncoder = {
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        } else if (constants.BATCH_FILL_FN_NAMES.indexOf(fnName) !== -1) {
 | 
			
		||||
            data = (exchangeInstance as any)
 | 
			
		||||
                [fnName](orders, orders.map(order => order.takerAssetAmount), orders.map(order => order.signature))
 | 
			
		||||
                [fnName](
 | 
			
		||||
                    orders,
 | 
			
		||||
                    orders.map(order => order.takerAssetAmount),
 | 
			
		||||
                    orders.map(order => order.signature),
 | 
			
		||||
                )
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        } else if (constants.MARKET_FILL_FN_NAMES.indexOf(fnName) !== -1) {
 | 
			
		||||
            const fillAsset = /Buy/.test(fnName) ? 'makerAssetAmount' : 'takerAssetAmount';
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,10 @@ blockchainTests.resets('Reentrancy Tests', env => {
 | 
			
		||||
        // Handle tuples.
 | 
			
		||||
        if (item.type === 'tuple') {
 | 
			
		||||
            const tuple = item as TupleDataItem;
 | 
			
		||||
            return _.zipObject(tuple.components.map(c => c.name), tuple.components.map(createFunctionInputs));
 | 
			
		||||
            return _.zipObject(
 | 
			
		||||
                tuple.components.map(c => c.name),
 | 
			
		||||
                tuple.components.map(createFunctionInputs),
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        // Handle strings.
 | 
			
		||||
        if (item.type === 'string') {
 | 
			
		||||
 
 | 
			
		||||
@@ -109,7 +109,11 @@ export class ExchangeWrapper {
 | 
			
		||||
        opts: { makerAssetFillAmount: BigNumber; gas?: number; gasPrice?: BigNumber },
 | 
			
		||||
    ): Promise<TransactionReceiptWithDecodedLogs> {
 | 
			
		||||
        return this.exchangeContract
 | 
			
		||||
            .marketBuyOrdersNoThrow(orders, opts.makerAssetFillAmount, orders.map(signedOrder => signedOrder.signature))
 | 
			
		||||
            .marketBuyOrdersNoThrow(
 | 
			
		||||
                orders,
 | 
			
		||||
                opts.makerAssetFillAmount,
 | 
			
		||||
                orders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
            )
 | 
			
		||||
            .awaitTransactionSuccessAsync({ from, gas: opts.gas });
 | 
			
		||||
    }
 | 
			
		||||
    public async marketSellOrdersFillOrKillAsync(
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,76 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "6.2.32",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "6.2.31",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "6.2.30",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "6.2.29",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "6.2.28",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "6.2.27",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "6.2.26",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "6.2.25",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1620214333,
 | 
			
		||||
        "version": "6.2.24",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v6.2.32 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v6.2.31 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v6.2.30 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v6.2.29 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v6.2.28 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v6.2.27 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v6.2.26 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v6.2.25 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v6.2.24 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-extensions",
 | 
			
		||||
    "version": "6.2.24",
 | 
			
		||||
    "version": "6.2.32",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -53,16 +53,16 @@
 | 
			
		||||
    "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.11",
 | 
			
		||||
        "@0x/contracts-dev-utils": "^1.3.28",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.8",
 | 
			
		||||
        "@0x/contracts-erc721": "^3.1.29",
 | 
			
		||||
        "@0x/contracts-exchange": "^3.2.30",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.29",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.19",
 | 
			
		||||
        "@0x/contracts-dev-utils": "^1.3.36",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.16",
 | 
			
		||||
        "@0x/contracts-erc721": "^3.1.37",
 | 
			
		||||
        "@0x/contracts-exchange": "^3.2.38",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.37",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.8",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.16",
 | 
			
		||||
        "@0x/dev-utils": "^4.2.7",
 | 
			
		||||
        "@0x/order-utils": "^10.4.21",
 | 
			
		||||
        "@0x/order-utils": "^10.4.28",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/ts-doc-gen": "^0.0.28",
 | 
			
		||||
        "@0x/tslint-config": "^4.1.4",
 | 
			
		||||
@@ -91,7 +91,7 @@
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/base-contract": "^6.4.0",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/typescript-typings": "^5.2.0",
 | 
			
		||||
        "ethereum-types": "^3.5.0"
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-integrations",
 | 
			
		||||
    "version": "2.7.41",
 | 
			
		||||
    "version": "2.7.64",
 | 
			
		||||
    "private": true,
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
@@ -53,21 +53,21 @@
 | 
			
		||||
    "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/contract-addresses": "^6.1.0",
 | 
			
		||||
        "@0x/contract-wrappers": "^13.16.1",
 | 
			
		||||
        "@0x/contracts-broker": "^1.1.29",
 | 
			
		||||
        "@0x/contracts-coordinator": "^3.1.30",
 | 
			
		||||
        "@0x/contracts-dev-utils": "^1.3.28",
 | 
			
		||||
        "@0x/contracts-exchange-forwarder": "^4.2.30",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.29",
 | 
			
		||||
        "@0x/contracts-extensions": "^6.2.24",
 | 
			
		||||
        "@0x/contract-addresses": "^6.6.0",
 | 
			
		||||
        "@0x/contract-wrappers": "^13.17.4",
 | 
			
		||||
        "@0x/contracts-broker": "^1.1.37",
 | 
			
		||||
        "@0x/contracts-coordinator": "^3.1.38",
 | 
			
		||||
        "@0x/contracts-dev-utils": "^1.3.36",
 | 
			
		||||
        "@0x/contracts-exchange-forwarder": "^4.2.38",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.37",
 | 
			
		||||
        "@0x/contracts-extensions": "^6.2.32",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.8",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.16",
 | 
			
		||||
        "@0x/coordinator-server": "^1.0.5",
 | 
			
		||||
        "@0x/dev-utils": "^4.2.7",
 | 
			
		||||
        "@0x/migrations": "^8.0.6",
 | 
			
		||||
        "@0x/order-utils": "^10.4.21",
 | 
			
		||||
        "@0x/protocol-utils": "^1.6.0",
 | 
			
		||||
        "@0x/migrations": "^8.1.1",
 | 
			
		||||
        "@0x/order-utils": "^10.4.28",
 | 
			
		||||
        "@0x/protocol-utils": "^1.8.2",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/tslint-config": "^4.1.4",
 | 
			
		||||
        "@0x/web3-wrapper": "^7.5.3",
 | 
			
		||||
@@ -93,17 +93,17 @@
 | 
			
		||||
        "typescript": "4.2.2"
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/asset-swapper": "^6.11.0",
 | 
			
		||||
        "@0x/asset-swapper": "^16.25.0",
 | 
			
		||||
        "@0x/base-contract": "^6.4.0",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.11",
 | 
			
		||||
        "@0x/contracts-erc1155": "^2.1.29",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.8",
 | 
			
		||||
        "@0x/contracts-erc721": "^3.1.29",
 | 
			
		||||
        "@0x/contracts-exchange": "^3.2.30",
 | 
			
		||||
        "@0x/contracts-multisig": "^4.1.30",
 | 
			
		||||
        "@0x/contracts-staking": "^2.0.37",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-zero-ex": "^0.23.0",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.19",
 | 
			
		||||
        "@0x/contracts-erc1155": "^2.1.37",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.16",
 | 
			
		||||
        "@0x/contracts-erc721": "^3.1.37",
 | 
			
		||||
        "@0x/contracts-exchange": "^3.2.38",
 | 
			
		||||
        "@0x/contracts-multisig": "^4.1.38",
 | 
			
		||||
        "@0x/contracts-staking": "^2.0.45",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/contracts-zero-ex": "^0.28.0",
 | 
			
		||||
        "@0x/subproviders": "^6.5.3",
 | 
			
		||||
        "@0x/types": "^3.3.3",
 | 
			
		||||
        "@0x/typescript-typings": "^5.2.0",
 | 
			
		||||
 
 | 
			
		||||
@@ -534,9 +534,14 @@ blockchainTests.skip('Coordinator Client', env => {
 | 
			
		||||
            const signedOrders = [signedOrder, signedOrderWithDifferentFeeRecipient];
 | 
			
		||||
            const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount];
 | 
			
		||||
            await coordinatorClient
 | 
			
		||||
                .batchFillOrdersAsync(signedOrders, takerAssetFillAmounts, signedOrders.map(o => o.signature), {
 | 
			
		||||
                    from: takerAddress,
 | 
			
		||||
                })
 | 
			
		||||
                .batchFillOrdersAsync(
 | 
			
		||||
                    signedOrders,
 | 
			
		||||
                    takerAssetFillAmounts,
 | 
			
		||||
                    signedOrders.map(o => o.signature),
 | 
			
		||||
                    {
 | 
			
		||||
                        from: takerAddress,
 | 
			
		||||
                    },
 | 
			
		||||
                )
 | 
			
		||||
                .then(res => {
 | 
			
		||||
                    expect(res).to.be.undefined();
 | 
			
		||||
                })
 | 
			
		||||
@@ -570,9 +575,14 @@ blockchainTests.skip('Coordinator Client', env => {
 | 
			
		||||
            const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator];
 | 
			
		||||
            const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount];
 | 
			
		||||
            await coordinatorClient
 | 
			
		||||
                .batchFillOrdersAsync(signedOrders, takerAssetFillAmounts, signedOrders.map(o => o.signature), {
 | 
			
		||||
                    from: takerAddress,
 | 
			
		||||
                })
 | 
			
		||||
                .batchFillOrdersAsync(
 | 
			
		||||
                    signedOrders,
 | 
			
		||||
                    takerAssetFillAmounts,
 | 
			
		||||
                    signedOrders.map(o => o.signature),
 | 
			
		||||
                    {
 | 
			
		||||
                        from: takerAddress,
 | 
			
		||||
                    },
 | 
			
		||||
                )
 | 
			
		||||
                .then(res => {
 | 
			
		||||
                    expect(res).to.be.undefined();
 | 
			
		||||
                })
 | 
			
		||||
@@ -600,9 +610,14 @@ blockchainTests.skip('Coordinator Client', env => {
 | 
			
		||||
            const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator];
 | 
			
		||||
            const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount];
 | 
			
		||||
            await coordinatorClient
 | 
			
		||||
                .batchFillOrdersAsync(signedOrders, takerAssetFillAmounts, signedOrders.map(o => o.signature), {
 | 
			
		||||
                    from: takerAddress,
 | 
			
		||||
                })
 | 
			
		||||
                .batchFillOrdersAsync(
 | 
			
		||||
                    signedOrders,
 | 
			
		||||
                    takerAssetFillAmounts,
 | 
			
		||||
                    signedOrders.map(o => o.signature),
 | 
			
		||||
                    {
 | 
			
		||||
                        from: takerAddress,
 | 
			
		||||
                    },
 | 
			
		||||
                )
 | 
			
		||||
                .then(res => {
 | 
			
		||||
                    expect(res).to.be.undefined();
 | 
			
		||||
                })
 | 
			
		||||
 
 | 
			
		||||
@@ -267,7 +267,11 @@ blockchainTests.resets('Coordinator integration tests', env => {
 | 
			
		||||
                expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value);
 | 
			
		||||
                await balanceStore.updateBalancesAsync();
 | 
			
		||||
                balanceStore.assertEquals(expectedBalances);
 | 
			
		||||
                verifyEvents(txReceipt, orders.map(order => expectedFillEvent(order)), ExchangeEvents.Fill);
 | 
			
		||||
                verifyEvents(
 | 
			
		||||
                    txReceipt,
 | 
			
		||||
                    orders.map(order => expectedFillEvent(order)),
 | 
			
		||||
                    ExchangeEvents.Fill,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`${fnName} should fill the orders if called by approver (eth fee, no refund)`, async () => {
 | 
			
		||||
                await balanceStore.updateBalancesAsync();
 | 
			
		||||
@@ -280,7 +284,11 @@ blockchainTests.resets('Coordinator integration tests', env => {
 | 
			
		||||
                expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value);
 | 
			
		||||
                await balanceStore.updateBalancesAsync();
 | 
			
		||||
                balanceStore.assertEquals(expectedBalances);
 | 
			
		||||
                verifyEvents(txReceipt, orders.map(order => expectedFillEvent(order)), ExchangeEvents.Fill);
 | 
			
		||||
                verifyEvents(
 | 
			
		||||
                    txReceipt,
 | 
			
		||||
                    orders.map(order => expectedFillEvent(order)),
 | 
			
		||||
                    ExchangeEvents.Fill,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`${fnName} should fill the orders if called by approver (mixed fees, refund)`, async () => {
 | 
			
		||||
                await balanceStore.updateBalancesAsync();
 | 
			
		||||
@@ -293,7 +301,11 @@ blockchainTests.resets('Coordinator integration tests', env => {
 | 
			
		||||
                expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value);
 | 
			
		||||
                await balanceStore.updateBalancesAsync();
 | 
			
		||||
                balanceStore.assertEquals(expectedBalances);
 | 
			
		||||
                verifyEvents(txReceipt, orders.map(order => expectedFillEvent(order)), ExchangeEvents.Fill);
 | 
			
		||||
                verifyEvents(
 | 
			
		||||
                    txReceipt,
 | 
			
		||||
                    orders.map(order => expectedFillEvent(order)),
 | 
			
		||||
                    ExchangeEvents.Fill,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`${fnName} should revert with an invalid approval signature`, async () => {
 | 
			
		||||
                const approvalSignature = hexUtils.concat(
 | 
			
		||||
@@ -360,7 +372,11 @@ blockchainTests.resets('Coordinator integration tests', env => {
 | 
			
		||||
                .executeTransaction(transaction, maker.address, transaction.signature, [])
 | 
			
		||||
                .awaitTransactionSuccessAsync({ from: maker.address });
 | 
			
		||||
 | 
			
		||||
            verifyEvents(txReceipt, orders.map(order => expectedCancelEvent(order)), ExchangeEvents.Cancel);
 | 
			
		||||
            verifyEvents(
 | 
			
		||||
                txReceipt,
 | 
			
		||||
                orders.map(order => expectedCancelEvent(order)),
 | 
			
		||||
                ExchangeEvents.Cancel,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('cancelOrdersUpTo call should be successful without an approval', async () => {
 | 
			
		||||
            const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrdersUpTo, []);
 | 
			
		||||
 
 | 
			
		||||
@@ -186,13 +186,13 @@ blockchainTests.resets('LibAssetData', env => {
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should decode multiasset data', async () => {
 | 
			
		||||
            expect(await devUtils.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData).callAsync()).to.deep.equal(
 | 
			
		||||
                [
 | 
			
		||||
                    AssetProxyId.MultiAsset,
 | 
			
		||||
                    KNOWN_MULTI_ASSET_ENCODING.amounts,
 | 
			
		||||
                    KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
 | 
			
		||||
                ],
 | 
			
		||||
            );
 | 
			
		||||
            expect(
 | 
			
		||||
                await devUtils.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData).callAsync(),
 | 
			
		||||
            ).to.deep.equal([
 | 
			
		||||
                AssetProxyId.MultiAsset,
 | 
			
		||||
                KNOWN_MULTI_ASSET_ENCODING.amounts,
 | 
			
		||||
                KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
 | 
			
		||||
            ]);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should encode StaticCall data', async () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -278,15 +278,21 @@ blockchainTests.resets('matchOrders integration tests', env => {
 | 
			
		||||
                ExchangeRevertErrors.BatchMatchOrdersErrorCodes.InvalidLengthRightSignatures,
 | 
			
		||||
            );
 | 
			
		||||
            let tx = deployment.exchange
 | 
			
		||||
                .batchMatchOrders(leftOrders, rightOrders, leftOrders.map(order => order.signature), [
 | 
			
		||||
                    rightOrders[0].signature,
 | 
			
		||||
                ])
 | 
			
		||||
                .batchMatchOrders(
 | 
			
		||||
                    leftOrders,
 | 
			
		||||
                    rightOrders,
 | 
			
		||||
                    leftOrders.map(order => order.signature),
 | 
			
		||||
                    [rightOrders[0].signature],
 | 
			
		||||
                )
 | 
			
		||||
                .awaitTransactionSuccessAsync({ from: matcher.address });
 | 
			
		||||
            await expect(tx).to.revertWith(expectedError);
 | 
			
		||||
            tx = deployment.exchange
 | 
			
		||||
                .batchMatchOrdersWithMaximalFill(leftOrders, rightOrders, leftOrders.map(order => order.signature), [
 | 
			
		||||
                    rightOrders[0].signature,
 | 
			
		||||
                ])
 | 
			
		||||
                .batchMatchOrdersWithMaximalFill(
 | 
			
		||||
                    leftOrders,
 | 
			
		||||
                    rightOrders,
 | 
			
		||||
                    leftOrders.map(order => order.signature),
 | 
			
		||||
                    [rightOrders[0].signature],
 | 
			
		||||
                )
 | 
			
		||||
                .awaitTransactionSuccessAsync({ from: matcher.address });
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
@@ -475,7 +481,10 @@ blockchainTests.resets('matchOrders integration tests', env => {
 | 
			
		||||
                ],
 | 
			
		||||
                leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
 | 
			
		||||
                rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
 | 
			
		||||
                matchIndices: [[0, 0], [1, 0]],
 | 
			
		||||
                matchIndices: [
 | 
			
		||||
                    [0, 0],
 | 
			
		||||
                    [1, 0],
 | 
			
		||||
                ],
 | 
			
		||||
                shouldMaximallyFill: false,
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
@@ -524,7 +533,10 @@ blockchainTests.resets('matchOrders integration tests', env => {
 | 
			
		||||
                ],
 | 
			
		||||
                leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
 | 
			
		||||
                rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
 | 
			
		||||
                matchIndices: [[0, 0], [0, 1]],
 | 
			
		||||
                matchIndices: [
 | 
			
		||||
                    [0, 0],
 | 
			
		||||
                    [0, 1],
 | 
			
		||||
                ],
 | 
			
		||||
                shouldMaximallyFill: false,
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
@@ -626,7 +638,11 @@ blockchainTests.resets('matchOrders integration tests', env => {
 | 
			
		||||
                ],
 | 
			
		||||
                leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
 | 
			
		||||
                rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
 | 
			
		||||
                matchIndices: [[0, 0], [0, 1], [1, 1]],
 | 
			
		||||
                matchIndices: [
 | 
			
		||||
                    [0, 0],
 | 
			
		||||
                    [0, 1],
 | 
			
		||||
                    [1, 1],
 | 
			
		||||
                ],
 | 
			
		||||
                shouldMaximallyFill: false,
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
@@ -801,7 +817,11 @@ blockchainTests.resets('matchOrders integration tests', env => {
 | 
			
		||||
                ],
 | 
			
		||||
                leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
 | 
			
		||||
                rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
 | 
			
		||||
                matchIndices: [[0, 0], [1, 0], [1, 1]],
 | 
			
		||||
                matchIndices: [
 | 
			
		||||
                    [0, 0],
 | 
			
		||||
                    [1, 0],
 | 
			
		||||
                    [1, 1],
 | 
			
		||||
                ],
 | 
			
		||||
                shouldMaximallyFill: true,
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 
 | 
			
		||||
@@ -106,7 +106,12 @@ blockchainTests.fork.resets('Forwarder mainnet tests', env => {
 | 
			
		||||
                orders[1].takerAssetAmount.dividedToIntegerBy(2),
 | 
			
		||||
            );
 | 
			
		||||
            const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder
 | 
			
		||||
                .marketSellOrdersWithEth(orders, orders.map(o => o.signature), [], [])
 | 
			
		||||
                .marketSellOrdersWithEth(
 | 
			
		||||
                    orders,
 | 
			
		||||
                    orders.map(o => o.signature),
 | 
			
		||||
                    [],
 | 
			
		||||
                    [],
 | 
			
		||||
                )
 | 
			
		||||
                .callAsync({
 | 
			
		||||
                    from: takerAddress,
 | 
			
		||||
                    value: ethSellAmount,
 | 
			
		||||
@@ -161,7 +166,13 @@ blockchainTests.fork.resets('Forwarder mainnet tests', env => {
 | 
			
		||||
                orders[1].makerAssetAmount.dividedToIntegerBy(2),
 | 
			
		||||
            );
 | 
			
		||||
            const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder
 | 
			
		||||
                .marketBuyOrdersWithEth(orders, makerAssetBuyAmount, orders.map(o => o.signature), [], [])
 | 
			
		||||
                .marketBuyOrdersWithEth(
 | 
			
		||||
                    orders,
 | 
			
		||||
                    makerAssetBuyAmount,
 | 
			
		||||
                    orders.map(o => o.signature),
 | 
			
		||||
                    [],
 | 
			
		||||
                    [],
 | 
			
		||||
                )
 | 
			
		||||
                .callAsync({
 | 
			
		||||
                    from: takerAddress,
 | 
			
		||||
                    value: ethSellAmount,
 | 
			
		||||
 
 | 
			
		||||
@@ -190,9 +190,14 @@ export function MakerMixin<TBase extends Constructor>(Base: TBase): TBase & Cons
 | 
			
		||||
                rightTakerAssetData,
 | 
			
		||||
                makerFeeAssetData,
 | 
			
		||||
                takerFeeAssetData,
 | 
			
		||||
            ] = [leftMakerToken, leftTakerToken, rightMakerToken, rightTakerToken, makerFeeToken, takerFeeToken].map(
 | 
			
		||||
                token => encodeERC20AssetData(token.address),
 | 
			
		||||
            );
 | 
			
		||||
            ] = [
 | 
			
		||||
                leftMakerToken,
 | 
			
		||||
                leftTakerToken,
 | 
			
		||||
                rightMakerToken,
 | 
			
		||||
                rightTakerToken,
 | 
			
		||||
                makerFeeToken,
 | 
			
		||||
                takerFeeToken,
 | 
			
		||||
            ].map(token => encodeERC20AssetData(token.address));
 | 
			
		||||
 | 
			
		||||
            // Construct and sign the left order
 | 
			
		||||
            const leftOrder = await this.signOrderAsync({
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,10 @@ import { Actor, Constructor } from './base';
 | 
			
		||||
 * Useful for BalanceStore.
 | 
			
		||||
 */
 | 
			
		||||
export function actorAddressesByName(actors: Actor[]): ObjectMap<string> {
 | 
			
		||||
    return _.zipObject(actors.map(actor => actor.name), actors.map(actor => actor.address));
 | 
			
		||||
    return _.zipObject(
 | 
			
		||||
        actors.map(actor => actor.name),
 | 
			
		||||
        actors.map(actor => actor.address),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -77,19 +77,24 @@ tests('Exchange signature validation fuzz tests', env => {
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        chainId = await env.web3Wrapper.getChainIdAsync();
 | 
			
		||||
        accounts = await env.getAccountAddressesAsync();
 | 
			
		||||
        privateKeys = _.zipObject(accounts, accounts.map((a, i) => constants.TESTRPC_PRIVATE_KEYS[i]));
 | 
			
		||||
        privateKeys = _.zipObject(
 | 
			
		||||
            accounts,
 | 
			
		||||
            accounts.map((a, i) => constants.TESTRPC_PRIVATE_KEYS[i]),
 | 
			
		||||
        );
 | 
			
		||||
        deployment = await DeploymentManager.deployAsync(env, {
 | 
			
		||||
            numErc20TokensToDeploy: 0,
 | 
			
		||||
            numErc721TokensToDeploy: 0,
 | 
			
		||||
            numErc1155TokensToDeploy: 0,
 | 
			
		||||
        });
 | 
			
		||||
        exchange = deployment.exchange;
 | 
			
		||||
        walletContractAddress = (await TestSignatureValidationWalletContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.TestSignatureValidationWallet,
 | 
			
		||||
            env.provider,
 | 
			
		||||
            env.txDefaults,
 | 
			
		||||
            {},
 | 
			
		||||
        )).address;
 | 
			
		||||
        walletContractAddress = (
 | 
			
		||||
            await TestSignatureValidationWalletContract.deployFrom0xArtifactAsync(
 | 
			
		||||
                artifacts.TestSignatureValidationWallet,
 | 
			
		||||
                env.provider,
 | 
			
		||||
                env.txDefaults,
 | 
			
		||||
                {},
 | 
			
		||||
            )
 | 
			
		||||
        ).address;
 | 
			
		||||
        // This just has to be a contract address that doesn't implement the
 | 
			
		||||
        // wallet spec.
 | 
			
		||||
        notWalletContractAddress = exchange.address;
 | 
			
		||||
@@ -715,7 +720,7 @@ tests('Exchange signature validation fuzz tests', env => {
 | 
			
		||||
            invalidTestTransactionMangledSignature(),
 | 
			
		||||
        ];
 | 
			
		||||
        const simulationEnvironment = new SimulationEnvironment(deployment, new BlockchainBalanceStore({}, {}), []);
 | 
			
		||||
        const simulation = new class extends Simulation {
 | 
			
		||||
        const simulation = new (class extends Simulation {
 | 
			
		||||
            // tslint:disable-next-line: prefer-function-over-method
 | 
			
		||||
            protected async *_assertionGenerator(): AsyncIterableIterator<AssertionResult | void> {
 | 
			
		||||
                while (true) {
 | 
			
		||||
@@ -723,7 +728,7 @@ tests('Exchange signature validation fuzz tests', env => {
 | 
			
		||||
                    yield (await action!.next()).value;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }(simulationEnvironment);
 | 
			
		||||
        })(simulationEnvironment);
 | 
			
		||||
        simulation.resets = true;
 | 
			
		||||
        return simulation.fuzzAsync();
 | 
			
		||||
    });
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,76 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "4.1.38",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "4.1.37",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "4.1.36",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "4.1.35",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "4.1.34",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "4.1.33",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "4.1.32",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "4.1.31",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1620214333,
 | 
			
		||||
        "version": "4.1.30",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v4.1.38 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.1.37 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.1.36 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.1.35 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.1.34 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.1.33 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.1.32 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.1.31 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.1.30 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-multisig",
 | 
			
		||||
    "version": "4.1.30",
 | 
			
		||||
    "version": "4.1.38",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -50,11 +50,11 @@
 | 
			
		||||
    "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/multisig",
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.11",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.8",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.19",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.16",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.8",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.16",
 | 
			
		||||
        "@0x/dev-utils": "^4.2.7",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/tslint-config": "^4.1.4",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,76 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "2.0.45",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "2.0.44",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "2.0.43",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "2.0.42",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "2.0.41",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "2.0.40",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "2.0.39",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "2.0.38",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.0.37",
 | 
			
		||||
        "changes": [
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v2.0.45 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.44 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.43 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.42 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.41 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.40 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.39 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.38 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.37 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Patch epoch finalization issue (#221)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-staking",
 | 
			
		||||
    "version": "2.0.37",
 | 
			
		||||
    "version": "2.0.45",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -54,14 +54,14 @@
 | 
			
		||||
    "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.11",
 | 
			
		||||
        "@0x/contracts-dev-utils": "^1.3.28",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.8",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.29",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.19",
 | 
			
		||||
        "@0x/contracts-dev-utils": "^1.3.36",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.16",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.37",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.8",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.16",
 | 
			
		||||
        "@0x/dev-utils": "^4.2.7",
 | 
			
		||||
        "@0x/order-utils": "^10.4.21",
 | 
			
		||||
        "@0x/order-utils": "^10.4.28",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/ts-doc-gen": "^0.0.28",
 | 
			
		||||
        "@0x/tslint-config": "^4.1.4",
 | 
			
		||||
@@ -88,7 +88,7 @@
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/base-contract": "^6.4.0",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/typescript-typings": "^5.2.0",
 | 
			
		||||
        "@0x/utils": "^6.4.3",
 | 
			
		||||
        "ethereum-types": "^3.5.0",
 | 
			
		||||
 
 | 
			
		||||
@@ -157,11 +157,11 @@ export class FinalizerActor extends BaseActor {
 | 
			
		||||
            const delegators = delegatorsByPoolId[poolId];
 | 
			
		||||
            delegatorBalancesByPoolId[poolId] = {};
 | 
			
		||||
            for (const delegator of delegators) {
 | 
			
		||||
                delegatorBalancesByPoolId[poolId][
 | 
			
		||||
                    delegator
 | 
			
		||||
                ] = (await this._stakingApiWrapper.stakingContract
 | 
			
		||||
                    .getStakeDelegatedToPoolByOwner(delegator, poolId)
 | 
			
		||||
                    .callAsync()).currentEpochBalance;
 | 
			
		||||
                delegatorBalancesByPoolId[poolId][delegator] = (
 | 
			
		||||
                    await this._stakingApiWrapper.stakingContract
 | 
			
		||||
                        .getStakeDelegatedToPoolByOwner(delegator, poolId)
 | 
			
		||||
                        .callAsync()
 | 
			
		||||
                ).currentEpochBalance;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return delegatorBalancesByPoolId;
 | 
			
		||||
@@ -253,7 +253,10 @@ export class FinalizerActor extends BaseActor {
 | 
			
		||||
        const totalFeesCollected = BigNumber.sum(...activePools.map(p => p.feesCollected));
 | 
			
		||||
        const totalWeightedStake = BigNumber.sum(...activePools.map(p => p.weightedStake));
 | 
			
		||||
        if (totalRewards.eq(0) || totalFeesCollected.eq(0) || totalWeightedStake.eq(0)) {
 | 
			
		||||
            return _.zipObject(poolIds, _.times(poolIds.length, () => new BigNumber(0)));
 | 
			
		||||
            return _.zipObject(
 | 
			
		||||
                poolIds,
 | 
			
		||||
                _.times(poolIds.length, () => new BigNumber(0)),
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        const rewards = await Promise.all(
 | 
			
		||||
            activePools.map(async pool =>
 | 
			
		||||
 
 | 
			
		||||
@@ -102,13 +102,15 @@ blockchainTests('Migration tests', env => {
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('should set the correct initial params', async () => {
 | 
			
		||||
                const stakingProxyContractAddress = (await StakingProxyContract.deployFrom0xArtifactAsync(
 | 
			
		||||
                    artifacts.StakingProxy,
 | 
			
		||||
                    env.provider,
 | 
			
		||||
                    env.txDefaults,
 | 
			
		||||
                    artifacts,
 | 
			
		||||
                    stakingContract.address,
 | 
			
		||||
                )).address;
 | 
			
		||||
                const stakingProxyContractAddress = (
 | 
			
		||||
                    await StakingProxyContract.deployFrom0xArtifactAsync(
 | 
			
		||||
                        artifacts.StakingProxy,
 | 
			
		||||
                        env.provider,
 | 
			
		||||
                        env.txDefaults,
 | 
			
		||||
                        artifacts,
 | 
			
		||||
                        stakingContract.address,
 | 
			
		||||
                    )
 | 
			
		||||
                ).address;
 | 
			
		||||
 | 
			
		||||
                const stakingProxyContract = new StakingContract(
 | 
			
		||||
                    stakingProxyContractAddress,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,76 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "5.4.8",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "5.4.7",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "5.4.6",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "5.4.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "5.4.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "5.4.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "5.4.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "5.4.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "5.4.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v5.4.8 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v5.4.7 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v5.4.6 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v5.4.5 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v5.4.4 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v5.4.3 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v5.4.2 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v5.4.1 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v5.4.0 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Set default ganache gas limit to 100e6 (#197)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-test-utils",
 | 
			
		||||
    "version": "5.4.0",
 | 
			
		||||
    "version": "5.4.8",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -44,10 +44,10 @@
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/assert": "^3.0.27",
 | 
			
		||||
        "@0x/base-contract": "^6.4.0",
 | 
			
		||||
        "@0x/contract-addresses": "^6.1.0",
 | 
			
		||||
        "@0x/contract-addresses": "^6.6.0",
 | 
			
		||||
        "@0x/dev-utils": "^4.2.7",
 | 
			
		||||
        "@0x/json-schemas": "^6.1.3",
 | 
			
		||||
        "@0x/order-utils": "^10.4.21",
 | 
			
		||||
        "@0x/order-utils": "^10.4.28",
 | 
			
		||||
        "@0x/sol-coverage": "^4.0.37",
 | 
			
		||||
        "@0x/sol-profiler": "^4.1.27",
 | 
			
		||||
        "@0x/sol-trace": "^3.0.37",
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,6 @@ export function verifyEventsFromLogs<TEventArgs>(
 | 
			
		||||
    const _logs = filterLogsToArguments<TEventArgs>(logs, eventName);
 | 
			
		||||
    expect(_logs.length, `Number of ${eventName} events emitted`).to.eq(expectedEvents.length);
 | 
			
		||||
    _logs.forEach((log, index) => {
 | 
			
		||||
        expect(log, `${eventName} event ${index}`).to.deep.equal(expectedEvents[index]);
 | 
			
		||||
        expect(log, `${eventName} event ${index}`).to.deep.equal({ ...log, ...expectedEvents[index] });
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -108,9 +108,7 @@ export async function testWithReferenceFuncAsync(
 | 
			
		||||
                    return expect.fail(
 | 
			
		||||
                        actualError,
 | 
			
		||||
                        expectedError,
 | 
			
		||||
                        `${testCaseString}: expected error message '${actualError.message}' to equal '${
 | 
			
		||||
                            expectedError.message
 | 
			
		||||
                        }'`,
 | 
			
		||||
                        `${testCaseString}: expected error message '${actualError.message}' to equal '${expectedError.message}'`,
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,87 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "1.3.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "1.3.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "1.3.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Added proposal 1 params and test",
 | 
			
		||||
                "pr": 298
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1628225642
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "1.2.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "1.2.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "1.2.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "1.2.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Added proposal 0 params and test",
 | 
			
		||||
                "pr": 252
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1622154125
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "1.1.8",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "1.1.7",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1620214333,
 | 
			
		||||
        "version": "1.1.6",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,42 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v1.3.2 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.3.1 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.3.0 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Added proposal 1 params and test (#298)
 | 
			
		||||
 | 
			
		||||
## v1.2.3 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.2.2 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.2.1 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.2.0 - _May 27, 2021_
 | 
			
		||||
 | 
			
		||||
    * Added proposal 0 params and test (#252)
 | 
			
		||||
 | 
			
		||||
## v1.1.8 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.1.7 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.1.6 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -21,13 +21,10 @@ pragma solidity ^0.6.12;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
 | 
			
		||||
import "./IStaking.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract DefaultPoolOperator {
 | 
			
		||||
    using LibERC20TokenV06 for IERC20TokenV06;
 | 
			
		||||
 | 
			
		||||
    // Immutables
 | 
			
		||||
    IStaking public immutable stakingProxy;
 | 
			
		||||
    IERC20TokenV06 public immutable weth;
 | 
			
		||||
@@ -57,7 +54,7 @@ contract DefaultPoolOperator {
 | 
			
		||||
    function returnStakingRewards()
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        uint256 wethBalance = weth.compatBalanceOf(address(this));
 | 
			
		||||
        weth.compatTransfer(address(stakingProxy), wethBalance);
 | 
			
		||||
        uint256 wethBalance = weth.balanceOf(address(this));
 | 
			
		||||
        weth.transfer(address(stakingProxy), wethBalance);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-treasury",
 | 
			
		||||
    "version": "1.1.6",
 | 
			
		||||
    "version": "1.3.2",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -47,12 +47,12 @@
 | 
			
		||||
    "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury",
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/contract-addresses": "^6.1.0",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.11",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.8",
 | 
			
		||||
        "@0x/contract-addresses": "^6.6.0",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^3.7.19",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.16",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/contracts-staking": "^2.0.37",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-staking": "^2.0.45",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/ts-doc-gen": "^0.0.28",
 | 
			
		||||
        "@0x/tslint-config": "^4.1.4",
 | 
			
		||||
@@ -73,7 +73,7 @@
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/base-contract": "^6.4.0",
 | 
			
		||||
        "@0x/protocol-utils": "^1.6.0",
 | 
			
		||||
        "@0x/protocol-utils": "^1.8.2",
 | 
			
		||||
        "@0x/subproviders": "^6.5.3",
 | 
			
		||||
        "@0x/types": "^3.3.3",
 | 
			
		||||
        "@0x/typescript-typings": "^5.2.0",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										57
									
								
								contracts/treasury/src/proposals.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								contracts/treasury/src/proposals.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										222
									
								
								contracts/treasury/test/proposal_test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								contracts/treasury/test/proposal_test.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,222 @@
 | 
			
		||||
import { artifacts as erc20Artifacts, ERC20TokenEvents } from '@0x/contracts-erc20';
 | 
			
		||||
import { StakingContract, StakingProxyContract } from '@0x/contracts-staking';
 | 
			
		||||
import { blockchainTests, constants, verifyEventsFromLogs } from '@0x/contracts-test-utils';
 | 
			
		||||
import { BigNumber, hexUtils, logUtils } from '@0x/utils';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { proposals } from '../src/proposals';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
import { ZrxTreasuryContract, ZrxTreasuryEvents } from './wrappers';
 | 
			
		||||
 | 
			
		||||
const SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/mzhu25/zeroex-staking';
 | 
			
		||||
const STAKING_PROXY_ADDRESS = '0xa26e80e7dea86279c6d778d702cc413e6cffa777';
 | 
			
		||||
const TREASURY_ADDRESS = '0x0bb1810061c2f5b2088054ee184e6c79e1591101';
 | 
			
		||||
const PROPOSER = process.env.PROPOSER || constants.NULL_ADDRESS;
 | 
			
		||||
const VOTER = '0xba4f44e774158408e2dc6c5cb65bc995f0a89180';
 | 
			
		||||
const VOTER_OPERATED_POOLS = ['0x0000000000000000000000000000000000000000000000000000000000000017'];
 | 
			
		||||
blockchainTests.configure({
 | 
			
		||||
    fork: {
 | 
			
		||||
        unlockedAccounts: [PROPOSER, VOTER],
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
async function querySubgraphAsync(operatorAddress: string): Promise<string[]> {
 | 
			
		||||
    const query = `
 | 
			
		||||
        {
 | 
			
		||||
            stakingActor(id: "${operatorAddress}") {
 | 
			
		||||
                operatedPools {
 | 
			
		||||
                    id
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    `;
 | 
			
		||||
    const response = await fetch(SUBGRAPH_URL, {
 | 
			
		||||
        method: 'POST',
 | 
			
		||||
        headers: {
 | 
			
		||||
            Accept: 'application/json',
 | 
			
		||||
            'Content-Type': 'application/json',
 | 
			
		||||
        },
 | 
			
		||||
        body: JSON.stringify({
 | 
			
		||||
            query,
 | 
			
		||||
        }),
 | 
			
		||||
    });
 | 
			
		||||
    const {
 | 
			
		||||
        data: { stakingActor },
 | 
			
		||||
    } = await response.json();
 | 
			
		||||
    if (stakingActor) {
 | 
			
		||||
        return stakingActor.operatedPools.map((pool: { id: string }) => hexUtils.leftPad(pool.id));
 | 
			
		||||
    } else {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
blockchainTests.fork.skip('Treasury proposal mainnet fork tests', env => {
 | 
			
		||||
    let staking: StakingContract;
 | 
			
		||||
    let stakingProxy: StakingProxyContract;
 | 
			
		||||
    let treasury: ZrxTreasuryContract;
 | 
			
		||||
    let votingPeriod: BigNumber;
 | 
			
		||||
 | 
			
		||||
    async function fastForwardToNextEpochAsync(): Promise<void> {
 | 
			
		||||
        const epochEndTime = await staking.getCurrentEpochEarliestEndTimeInSeconds().callAsync();
 | 
			
		||||
        const lastBlockTime = await env.web3Wrapper.getBlockTimestampAsync('latest');
 | 
			
		||||
        const dt = Math.max(0, epochEndTime.minus(lastBlockTime).toNumber());
 | 
			
		||||
        await env.web3Wrapper.increaseTimeAsync(dt);
 | 
			
		||||
        // mine next block
 | 
			
		||||
        await env.web3Wrapper.mineBlockAsync();
 | 
			
		||||
        const lastPoolId = new BigNumber(await staking.lastPoolId().callAsync(), 16);
 | 
			
		||||
        const batchExecuteCalldata = [
 | 
			
		||||
            ...[...new Array(lastPoolId.toNumber())].map((_x, i) =>
 | 
			
		||||
                staking.finalizePool(hexUtils.leftPad(i + 1)).getABIEncodedTransactionData(),
 | 
			
		||||
            ),
 | 
			
		||||
            staking.endEpoch().getABIEncodedTransactionData(),
 | 
			
		||||
            ...[...new Array(lastPoolId.toNumber())].map((_x, i) =>
 | 
			
		||||
                staking.finalizePool(hexUtils.leftPad(i + 1)).getABIEncodedTransactionData(),
 | 
			
		||||
            ),
 | 
			
		||||
            ...[...new Array(lastPoolId.toNumber())].map((_x, i) =>
 | 
			
		||||
                staking.finalizePool(hexUtils.leftPad(i + 1)).getABIEncodedTransactionData(),
 | 
			
		||||
            ),
 | 
			
		||||
        ];
 | 
			
		||||
        await stakingProxy.batchExecute(batchExecuteCalldata).awaitTransactionSuccessAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        const abis = _.mapValues({ ...artifacts, ...erc20Artifacts }, v => v.compilerOutput.abi);
 | 
			
		||||
        treasury = new ZrxTreasuryContract(TREASURY_ADDRESS, env.provider, env.txDefaults, abis);
 | 
			
		||||
        votingPeriod = await treasury.votingPeriod().callAsync();
 | 
			
		||||
        staking = new StakingContract(STAKING_PROXY_ADDRESS, env.provider, env.txDefaults);
 | 
			
		||||
        stakingProxy = new StakingProxyContract(STAKING_PROXY_ADDRESS, env.provider, env.txDefaults);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('Proposal 0', () => {
 | 
			
		||||
        it('works', async () => {
 | 
			
		||||
            const proposal = proposals[0];
 | 
			
		||||
            let executionEpoch: BigNumber;
 | 
			
		||||
            if (proposal.executionEpoch) {
 | 
			
		||||
                executionEpoch = proposal.executionEpoch;
 | 
			
		||||
            } else {
 | 
			
		||||
                const currentEpoch = await staking.currentEpoch().callAsync();
 | 
			
		||||
                executionEpoch = currentEpoch.plus(2);
 | 
			
		||||
            }
 | 
			
		||||
            const pools = await querySubgraphAsync(PROPOSER);
 | 
			
		||||
            const proposeTx = treasury.propose(proposal.actions, executionEpoch, proposal.description, pools);
 | 
			
		||||
 | 
			
		||||
            const calldata = proposeTx.getABIEncodedTransactionData();
 | 
			
		||||
            logUtils.log('ZrxTreasury.propose calldata:');
 | 
			
		||||
            logUtils.log(calldata);
 | 
			
		||||
 | 
			
		||||
            const proposalId = await proposeTx.callAsync({ from: PROPOSER });
 | 
			
		||||
            const receipt = await proposeTx.awaitTransactionSuccessAsync({ from: PROPOSER });
 | 
			
		||||
            verifyEventsFromLogs(
 | 
			
		||||
                receipt.logs,
 | 
			
		||||
                [
 | 
			
		||||
                    {
 | 
			
		||||
                        ...proposal,
 | 
			
		||||
                        proposalId,
 | 
			
		||||
                        executionEpoch,
 | 
			
		||||
                        proposer: PROPOSER,
 | 
			
		||||
                        operatedPoolIds: pools,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
                ZrxTreasuryEvents.ProposalCreated,
 | 
			
		||||
            );
 | 
			
		||||
            await fastForwardToNextEpochAsync();
 | 
			
		||||
            await fastForwardToNextEpochAsync();
 | 
			
		||||
            await treasury
 | 
			
		||||
                .castVote(proposalId, true, VOTER_OPERATED_POOLS)
 | 
			
		||||
                .awaitTransactionSuccessAsync({ from: VOTER });
 | 
			
		||||
            await env.web3Wrapper.increaseTimeAsync(votingPeriod.plus(1).toNumber());
 | 
			
		||||
            await env.web3Wrapper.mineBlockAsync();
 | 
			
		||||
            const executeTx = await treasury.execute(proposalId, proposal.actions).awaitTransactionSuccessAsync();
 | 
			
		||||
            verifyEventsFromLogs(
 | 
			
		||||
                executeTx.logs,
 | 
			
		||||
                [
 | 
			
		||||
                    {
 | 
			
		||||
                        proposalId,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
                ZrxTreasuryEvents.ProposalExecuted,
 | 
			
		||||
            );
 | 
			
		||||
            const recipient = '0xf9347f751a6a1467abc722ec7d80ba2698dd9d6c';
 | 
			
		||||
            verifyEventsFromLogs(
 | 
			
		||||
                executeTx.logs,
 | 
			
		||||
                [
 | 
			
		||||
                    {
 | 
			
		||||
                        _from: TREASURY_ADDRESS,
 | 
			
		||||
                        _to: recipient,
 | 
			
		||||
                        _value: new BigNumber(400_000).times('1e18'),
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
                ERC20TokenEvents.Transfer,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
    describe('Proposal 1', () => {
 | 
			
		||||
        it('works', async () => {
 | 
			
		||||
            const proposal = proposals[1];
 | 
			
		||||
            let executionEpoch: BigNumber;
 | 
			
		||||
            if (proposal.executionEpoch) {
 | 
			
		||||
                executionEpoch = proposal.executionEpoch;
 | 
			
		||||
            } else {
 | 
			
		||||
                const currentEpoch = await staking.currentEpoch().callAsync();
 | 
			
		||||
                executionEpoch = currentEpoch.plus(2);
 | 
			
		||||
            }
 | 
			
		||||
            const pools = await querySubgraphAsync(PROPOSER);
 | 
			
		||||
            const proposeTx = treasury.propose(proposal.actions, executionEpoch, proposal.description, pools);
 | 
			
		||||
 | 
			
		||||
            const calldata = proposeTx.getABIEncodedTransactionData();
 | 
			
		||||
            logUtils.log('ZrxTreasury.propose calldata:');
 | 
			
		||||
            logUtils.log(calldata);
 | 
			
		||||
 | 
			
		||||
            const proposalId = await proposeTx.callAsync({ from: PROPOSER });
 | 
			
		||||
            const receipt = await proposeTx.awaitTransactionSuccessAsync({ from: PROPOSER });
 | 
			
		||||
            verifyEventsFromLogs(
 | 
			
		||||
                receipt.logs,
 | 
			
		||||
                [
 | 
			
		||||
                    {
 | 
			
		||||
                        ...proposal,
 | 
			
		||||
                        proposalId,
 | 
			
		||||
                        executionEpoch,
 | 
			
		||||
                        proposer: PROPOSER,
 | 
			
		||||
                        operatedPoolIds: pools,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
                ZrxTreasuryEvents.ProposalCreated,
 | 
			
		||||
            );
 | 
			
		||||
            await fastForwardToNextEpochAsync();
 | 
			
		||||
            await fastForwardToNextEpochAsync();
 | 
			
		||||
            await treasury
 | 
			
		||||
                .castVote(proposalId, true, VOTER_OPERATED_POOLS)
 | 
			
		||||
                .awaitTransactionSuccessAsync({ from: VOTER });
 | 
			
		||||
            await env.web3Wrapper.increaseTimeAsync(votingPeriod.plus(1).toNumber());
 | 
			
		||||
            await env.web3Wrapper.mineBlockAsync();
 | 
			
		||||
            const executeTx = await treasury.execute(proposalId, proposal.actions).awaitTransactionSuccessAsync();
 | 
			
		||||
            verifyEventsFromLogs(
 | 
			
		||||
                executeTx.logs,
 | 
			
		||||
                [
 | 
			
		||||
                    {
 | 
			
		||||
                        proposalId,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
                ZrxTreasuryEvents.ProposalExecuted,
 | 
			
		||||
            );
 | 
			
		||||
            const recipient = '0xab66cc8fd10457ebc9d13b9760c835f0a4cbc487';
 | 
			
		||||
            verifyEventsFromLogs(
 | 
			
		||||
                executeTx.logs,
 | 
			
		||||
                [
 | 
			
		||||
                    {
 | 
			
		||||
                        _from: TREASURY_ADDRESS,
 | 
			
		||||
                        _to: recipient,
 | 
			
		||||
                        _value: new BigNumber(330_813).times('1e18'),
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        _from: TREASURY_ADDRESS,
 | 
			
		||||
                        _to: recipient,
 | 
			
		||||
                        _value: new BigNumber(420000).times('1e18'),
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
                ERC20TokenEvents.Transfer,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@@ -1,4 +1,76 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1629079369,
 | 
			
		||||
        "version": "4.7.16",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "4.7.15",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628225642,
 | 
			
		||||
        "version": "4.7.14",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1624356181,
 | 
			
		||||
        "version": "4.7.13",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "4.7.12",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1622609597,
 | 
			
		||||
        "version": "4.7.11",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "4.7.10",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621600614,
 | 
			
		||||
        "version": "4.7.9",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1620214333,
 | 
			
		||||
        "version": "4.7.8",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v4.7.16 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.7.15 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.7.14 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.7.13 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.7.12 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.7.11 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.7.10 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.7.9 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.7.8 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-utils",
 | 
			
		||||
    "version": "4.7.8",
 | 
			
		||||
    "version": "4.7.16",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -52,9 +52,9 @@
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.6.0",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.38",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.0",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.8",
 | 
			
		||||
        "@0x/dev-utils": "^4.2.7",
 | 
			
		||||
        "@0x/order-utils": "^10.4.21",
 | 
			
		||||
        "@0x/order-utils": "^10.4.28",
 | 
			
		||||
        "@0x/sol-compiler": "^4.7.3",
 | 
			
		||||
        "@0x/tslint-config": "^4.1.4",
 | 
			
		||||
        "@0x/types": "^3.3.3",
 | 
			
		||||
 
 | 
			
		||||
@@ -536,7 +536,11 @@ blockchainTests('LibBytes', env => {
 | 
			
		||||
            ]));
 | 
			
		||||
 | 
			
		||||
        describe('copies forward within one word and one byte overlap', () =>
 | 
			
		||||
            test([[0, 0, 1, 'one byte'], [10, 0, 11, 'eleven bytes'], [15, 0, 16, 'sixteen bytes']]));
 | 
			
		||||
            test([
 | 
			
		||||
                [0, 0, 1, 'one byte'],
 | 
			
		||||
                [10, 0, 11, 'eleven bytes'],
 | 
			
		||||
                [15, 0, 16, 'sixteen bytes'],
 | 
			
		||||
            ]));
 | 
			
		||||
 | 
			
		||||
        describe('copies backward', () =>
 | 
			
		||||
            test([
 | 
			
		||||
@@ -603,7 +607,11 @@ blockchainTests('LibBytes', env => {
 | 
			
		||||
            ]));
 | 
			
		||||
 | 
			
		||||
        describe('copies forward within one word and one byte overlap', () =>
 | 
			
		||||
            test([[0, 0, 1, 'one byte'], [0, 10, 11, 'eleven bytes'], [0, 15, 16, 'sixteen bytes']]));
 | 
			
		||||
            test([
 | 
			
		||||
                [0, 0, 1, 'one byte'],
 | 
			
		||||
                [0, 10, 11, 'eleven bytes'],
 | 
			
		||||
                [0, 15, 16, 'sixteen bytes'],
 | 
			
		||||
            ]));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('slice', () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,96 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "version": "0.28.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Transfer output tokens in TransformERC20Feature",
 | 
			
		||||
                "pr": 279
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add support for takerToken=0xeee... in OtcOrdersFeature",
 | 
			
		||||
                "pr": 287
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add support for OTC orders in MultiplexFeature",
 | 
			
		||||
                "pr": 287
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Multiplex v2: Refactor into multiple files, add ETH support, and other miscellanea",
 | 
			
		||||
                "pr": 263
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1629079369
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1628665757,
 | 
			
		||||
        "version": "0.27.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "0.27.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `Clipper` as a custom liquidity source"
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1628225642
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "0.26.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add Lido stETH deposit integration",
 | 
			
		||||
                "pr": 260
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1624356181
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1623382456,
 | 
			
		||||
        "version": "0.25.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "0.25.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add OtcOrdersFeature",
 | 
			
		||||
                "pr": 244
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add UniswapV3 VIP feature",
 | 
			
		||||
                "pr": 237
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1622609597
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1621944788,
 | 
			
		||||
        "version": "0.24.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "0.24.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add special selectors to selector collision test",
 | 
			
		||||
                "pr": 243
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1621600614
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "0.23.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,42 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v0.28.0 - _August 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Transfer output tokens in TransformERC20Feature (#279)
 | 
			
		||||
    * Add support for takerToken=0xeee... in OtcOrdersFeature (#287)
 | 
			
		||||
    * Add support for OTC orders in MultiplexFeature (#287)
 | 
			
		||||
    * Multiplex v2: Refactor into multiple files, add ETH support, and other miscellanea (#263)
 | 
			
		||||
 | 
			
		||||
## v0.27.1 - _August 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v0.27.0 - _August 6, 2021_
 | 
			
		||||
 | 
			
		||||
    * Add `Clipper` as a custom liquidity source
 | 
			
		||||
 | 
			
		||||
## v0.26.0 - _June 22, 2021_
 | 
			
		||||
 | 
			
		||||
    * Add Lido stETH deposit integration (#260)
 | 
			
		||||
 | 
			
		||||
## v0.25.1 - _June 11, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v0.25.0 - _June 2, 2021_
 | 
			
		||||
 | 
			
		||||
    * Add OtcOrdersFeature (#244)
 | 
			
		||||
    * Add UniswapV3 VIP feature (#237)
 | 
			
		||||
 | 
			
		||||
## v0.24.1 - _May 25, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v0.24.0 - _May 21, 2021_
 | 
			
		||||
 | 
			
		||||
    * Add special selectors to selector collision test (#243)
 | 
			
		||||
 | 
			
		||||
## v0.23.0 - _May 5, 2021_
 | 
			
		||||
 | 
			
		||||
    * Added ETH support to `MixinCurve` (#220)
 | 
			
		||||
 
 | 
			
		||||
@@ -26,11 +26,13 @@ import "./features/interfaces/ITokenSpenderFeature.sol";
 | 
			
		||||
import "./features/interfaces/ITransformERC20Feature.sol";
 | 
			
		||||
import "./features/interfaces/IMetaTransactionsFeature.sol";
 | 
			
		||||
import "./features/interfaces/IUniswapFeature.sol";
 | 
			
		||||
import "./features/interfaces/IUniswapV3Feature.sol";
 | 
			
		||||
import "./features/interfaces/IPancakeSwapFeature.sol";
 | 
			
		||||
import "./features/interfaces/ILiquidityProviderFeature.sol";
 | 
			
		||||
import "./features/interfaces/INativeOrdersFeature.sol";
 | 
			
		||||
import "./features/interfaces/IBatchFillNativeOrdersFeature.sol";
 | 
			
		||||
import "./features/interfaces/IMultiplexFeature.sol";
 | 
			
		||||
import "./features/interfaces/IOtcOrdersFeature.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev Interface for a fully featured Exchange Proxy.
 | 
			
		||||
@@ -40,11 +42,13 @@ interface IZeroEx is
 | 
			
		||||
    ITransformERC20Feature,
 | 
			
		||||
    IMetaTransactionsFeature,
 | 
			
		||||
    IUniswapFeature,
 | 
			
		||||
    IUniswapV3Feature,
 | 
			
		||||
    IPancakeSwapFeature,
 | 
			
		||||
    ILiquidityProviderFeature,
 | 
			
		||||
    INativeOrdersFeature,
 | 
			
		||||
    IBatchFillNativeOrdersFeature,
 | 
			
		||||
    IMultiplexFeature
 | 
			
		||||
    IMultiplexFeature,
 | 
			
		||||
    IOtcOrdersFeature
 | 
			
		||||
{
 | 
			
		||||
    // solhint-disable state-visibility
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -48,7 +48,7 @@ contract BatchFillNativeOrdersFeature is
 | 
			
		||||
    /// @dev Name of this feature.
 | 
			
		||||
    string public constant override FEATURE_NAME = "BatchFill";
 | 
			
		||||
    /// @dev Version of this feature.
 | 
			
		||||
    uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
 | 
			
		||||
    uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 0);
 | 
			
		||||
 | 
			
		||||
    constructor(address zeroExAddress)
 | 
			
		||||
        public
 | 
			
		||||
@@ -170,6 +170,8 @@ contract BatchFillNativeOrdersFeature is
 | 
			
		||||
                        orders[i],
 | 
			
		||||
                        signatures[i],
 | 
			
		||||
                        takerTokenFillAmounts[i],
 | 
			
		||||
                        msg.sender,
 | 
			
		||||
                        false,
 | 
			
		||||
                        msg.sender
 | 
			
		||||
                    )
 | 
			
		||||
                returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
 | 
			
		||||
 
 | 
			
		||||
@@ -108,7 +108,7 @@ contract LiquidityProviderFeature is
 | 
			
		||||
 | 
			
		||||
        if (!LibERC20Transformer.isTokenETH(inputToken)) {
 | 
			
		||||
            // Transfer input ERC20 tokens to the provider.
 | 
			
		||||
            _transferERC20Tokens(
 | 
			
		||||
            _transferERC20TokensFrom(
 | 
			
		||||
                inputToken,
 | 
			
		||||
                msg.sender,
 | 
			
		||||
                address(provider),
 | 
			
		||||
 
 | 
			
		||||
@@ -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, 1, 1);
 | 
			
		||||
    uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 2, 0);
 | 
			
		||||
    /// @dev EIP712 typehash of the `MetaTransactionData` struct.
 | 
			
		||||
    bytes32 public immutable MTX_EIP712_TYPEHASH = keccak256(
 | 
			
		||||
        "MetaTransactionData("
 | 
			
		||||
@@ -251,7 +251,7 @@ contract MetaTransactionsFeature is
 | 
			
		||||
 | 
			
		||||
        // Pay the fee to the sender.
 | 
			
		||||
        if (state.mtx.feeAmount > 0) {
 | 
			
		||||
            _transferERC20Tokens(
 | 
			
		||||
            _transferERC20TokensFrom(
 | 
			
		||||
                state.mtx.feeToken,
 | 
			
		||||
                state.mtx.signer,
 | 
			
		||||
                state.sender,
 | 
			
		||||
@@ -415,7 +415,9 @@ contract MetaTransactionsFeature is
 | 
			
		||||
                    outputToken: args.outputToken,
 | 
			
		||||
                    inputTokenAmount: args.inputTokenAmount,
 | 
			
		||||
                    minOutputTokenAmount: args.minOutputTokenAmount,
 | 
			
		||||
                    transformations: args.transformations
 | 
			
		||||
                    transformations: args.transformations,
 | 
			
		||||
                    useSelfBalance: false,
 | 
			
		||||
                    recipient: state.mtx.signer
 | 
			
		||||
              })
 | 
			
		||||
            ),
 | 
			
		||||
            state.mtx.value
 | 
			
		||||
@@ -498,7 +500,9 @@ contract MetaTransactionsFeature is
 | 
			
		||||
                order,
 | 
			
		||||
                signature,
 | 
			
		||||
                takerTokenFillAmount,
 | 
			
		||||
                state.mtx.signer // taker is mtx signer
 | 
			
		||||
                state.mtx.signer, // taker is mtx signer
 | 
			
		||||
                false,
 | 
			
		||||
                state.mtx.signer
 | 
			
		||||
            ),
 | 
			
		||||
            state.mtx.value
 | 
			
		||||
        );
 | 
			
		||||
 
 | 
			
		||||
@@ -1,803 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2021 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6.5;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
 | 
			
		||||
import "../external/ILiquidityProviderSandbox.sol";
 | 
			
		||||
import "../fixins/FixinCommon.sol";
 | 
			
		||||
import "../fixins/FixinEIP712.sol";
 | 
			
		||||
import "../fixins/FixinTokenSpender.sol";
 | 
			
		||||
import "../migrations/LibMigrate.sol";
 | 
			
		||||
import "../transformers/LibERC20Transformer.sol";
 | 
			
		||||
import "../vendor/ILiquidityProvider.sol";
 | 
			
		||||
import "../vendor/IUniswapV2Pair.sol";
 | 
			
		||||
import "./interfaces/IFeature.sol";
 | 
			
		||||
import "./interfaces/IMultiplexFeature.sol";
 | 
			
		||||
import "./interfaces/INativeOrdersFeature.sol";
 | 
			
		||||
import "./interfaces/ITransformERC20Feature.sol";
 | 
			
		||||
import "./libs/LibNativeOrder.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev This feature enables efficient batch and multi-hop trades
 | 
			
		||||
///      using different liquidity sources.
 | 
			
		||||
contract MultiplexFeature is
 | 
			
		||||
    IFeature,
 | 
			
		||||
    IMultiplexFeature,
 | 
			
		||||
    FixinCommon,
 | 
			
		||||
    FixinEIP712,
 | 
			
		||||
    FixinTokenSpender
 | 
			
		||||
{
 | 
			
		||||
    using LibERC20Transformer for IERC20TokenV06;
 | 
			
		||||
    using LibSafeMathV06 for uint128;
 | 
			
		||||
    using LibSafeMathV06 for uint256;
 | 
			
		||||
 | 
			
		||||
    /// @dev Name of this feature.
 | 
			
		||||
    string public constant override FEATURE_NAME = "MultiplexFeature";
 | 
			
		||||
    /// @dev Version of this feature.
 | 
			
		||||
    uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 1);
 | 
			
		||||
 | 
			
		||||
    /// @dev The WETH token contract.
 | 
			
		||||
    IEtherTokenV06 private immutable weth;
 | 
			
		||||
    /// @dev The sandbox contract address.
 | 
			
		||||
    ILiquidityProviderSandbox public immutable sandbox;
 | 
			
		||||
    // address of the UniswapV2Factory contract.
 | 
			
		||||
    address private constant UNISWAP_FACTORY = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
 | 
			
		||||
    // address of the (Sushiswap) UniswapV2Factory contract.
 | 
			
		||||
    address private constant SUSHISWAP_FACTORY = 0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac;
 | 
			
		||||
    // Init code hash of the UniswapV2Pair contract.
 | 
			
		||||
    uint256 private constant UNISWAP_PAIR_INIT_CODE_HASH = 0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f;
 | 
			
		||||
    // Init code hash of the (Sushiswap) UniswapV2Pair contract.
 | 
			
		||||
    uint256 private constant SUSHISWAP_PAIR_INIT_CODE_HASH = 0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303;
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        address zeroExAddress,
 | 
			
		||||
        IEtherTokenV06 weth_,
 | 
			
		||||
        ILiquidityProviderSandbox sandbox_
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        FixinEIP712(zeroExAddress)
 | 
			
		||||
    {
 | 
			
		||||
        weth = weth_;
 | 
			
		||||
        sandbox = sandbox_;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Initialize and register this feature.
 | 
			
		||||
    ///      Should be delegatecalled by `Migrate.migrate()`.
 | 
			
		||||
    /// @return success `LibMigrate.SUCCESS` on success.
 | 
			
		||||
    function migrate()
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        _registerFeatureFunction(this.batchFill.selector);
 | 
			
		||||
        _registerFeatureFunction(this.multiHopFill.selector);
 | 
			
		||||
        return LibMigrate.MIGRATE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes a batch of fills selling `fillData.inputToken`
 | 
			
		||||
    ///      for `fillData.outputToken` in sequence. Refer to the
 | 
			
		||||
    ///      internal variant `_batchFill` for the allowed nested
 | 
			
		||||
    ///      operations.
 | 
			
		||||
    /// @param fillData Encodes the input/output tokens, the sell
 | 
			
		||||
    ///        amount, and the nested operations for this batch fill.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of `fillData.outputToken`
 | 
			
		||||
    ///        to buy. Reverts if this amount is not met.
 | 
			
		||||
    /// @return outputTokenAmount The amount of the output token bought.
 | 
			
		||||
    function batchFill(
 | 
			
		||||
        BatchFillData memory fillData,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        payable
 | 
			
		||||
        override
 | 
			
		||||
        returns (uint256 outputTokenAmount)
 | 
			
		||||
    {
 | 
			
		||||
        // Cache the sender's balance of the output token.
 | 
			
		||||
        outputTokenAmount = fillData.outputToken.getTokenBalanceOf(msg.sender);
 | 
			
		||||
        // Cache the contract's ETH balance prior to this call.
 | 
			
		||||
        uint256 ethBalanceBefore = address(this).balance.safeSub(msg.value);
 | 
			
		||||
 | 
			
		||||
        // Perform the batch fill.
 | 
			
		||||
        _batchFill(fillData);
 | 
			
		||||
 | 
			
		||||
        // The `outputTokenAmount` returned by `_batchFill` may not
 | 
			
		||||
        // be fully accurate (e.g. due to some janky token).
 | 
			
		||||
        outputTokenAmount = fillData.outputToken.getTokenBalanceOf(msg.sender)
 | 
			
		||||
            .safeSub(outputTokenAmount);
 | 
			
		||||
        require(
 | 
			
		||||
            outputTokenAmount >= minBuyAmount,
 | 
			
		||||
            "MultiplexFeature::batchFill/UNDERBOUGHT"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        uint256 ethBalanceAfter = address(this).balance;
 | 
			
		||||
        require(
 | 
			
		||||
            ethBalanceAfter >= ethBalanceBefore,
 | 
			
		||||
            "MultiplexFeature::batchFill/OVERSPENT_ETH"
 | 
			
		||||
        );
 | 
			
		||||
        // Refund ETH
 | 
			
		||||
        if (ethBalanceAfter > ethBalanceBefore) {
 | 
			
		||||
            _transferEth(msg.sender, ethBalanceAfter - ethBalanceBefore);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes a sequence of fills "hopping" through the
 | 
			
		||||
    ///      path of tokens given by `fillData.tokens`. Refer to the
 | 
			
		||||
    ///      internal variant `_multiHopFill` for the allowed nested
 | 
			
		||||
    ///      operations.
 | 
			
		||||
    /// @param fillData Encodes the path of tokens, the sell amount,
 | 
			
		||||
    ///        and the nested operations for this multi-hop fill.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of the output token
 | 
			
		||||
    ///        to buy. Reverts if this amount is not met.
 | 
			
		||||
    /// @return outputTokenAmount The amount of the output token bought.
 | 
			
		||||
    function multiHopFill(
 | 
			
		||||
        MultiHopFillData memory fillData,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        payable
 | 
			
		||||
        override
 | 
			
		||||
        returns (uint256 outputTokenAmount)
 | 
			
		||||
    {
 | 
			
		||||
        IERC20TokenV06 outputToken = IERC20TokenV06(fillData.tokens[fillData.tokens.length - 1]);
 | 
			
		||||
        // Cache the sender's balance of the output token.
 | 
			
		||||
        outputTokenAmount = outputToken.getTokenBalanceOf(msg.sender);
 | 
			
		||||
        // Cache the contract's ETH balance prior to this call.
 | 
			
		||||
        uint256 ethBalanceBefore = address(this).balance.safeSub(msg.value);
 | 
			
		||||
 | 
			
		||||
        // Perform the multi-hop fill. Pass in `msg.value` as the maximum
 | 
			
		||||
        // allowable amount of ETH for the wrapped calls to consume.
 | 
			
		||||
        _multiHopFill(fillData, msg.value);
 | 
			
		||||
 | 
			
		||||
        // The `outputTokenAmount` returned by `_multiHopFill` may not
 | 
			
		||||
        // be fully accurate (e.g. due to some janky token).
 | 
			
		||||
        outputTokenAmount = outputToken.getTokenBalanceOf(msg.sender)
 | 
			
		||||
            .safeSub(outputTokenAmount);
 | 
			
		||||
        require(
 | 
			
		||||
            outputTokenAmount >= minBuyAmount,
 | 
			
		||||
            "MultiplexFeature::multiHopFill/UNDERBOUGHT"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        uint256 ethBalanceAfter = address(this).balance;
 | 
			
		||||
        require(
 | 
			
		||||
            ethBalanceAfter >= ethBalanceBefore,
 | 
			
		||||
            "MultiplexFeature::multiHopFill/OVERSPENT_ETH"
 | 
			
		||||
        );
 | 
			
		||||
        // Refund ETH
 | 
			
		||||
        if (ethBalanceAfter > ethBalanceBefore) {
 | 
			
		||||
            _transferEth(msg.sender, ethBalanceAfter - ethBalanceBefore);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Similar to FQT. If `fillData.sellAmount` is set to `type(uint256).max`,
 | 
			
		||||
    // this is effectively a batch fill. Otherwise it can be set to perform a
 | 
			
		||||
    // market sell of some amount. Note that the `outputTokenAmount` returned
 | 
			
		||||
    // by this function could theoretically be inaccurate if `msg.sender` has
 | 
			
		||||
    // set a token allowance on an external contract that gets called during
 | 
			
		||||
    // the execution of this function.
 | 
			
		||||
    function _batchFill(BatchFillData memory fillData)
 | 
			
		||||
        internal
 | 
			
		||||
        returns (uint256 outputTokenAmount, uint256 remainingEth)
 | 
			
		||||
    {
 | 
			
		||||
        // Track the remaining ETH allocated to this call.
 | 
			
		||||
        remainingEth = msg.value;
 | 
			
		||||
        // Track the amount of input token sold.
 | 
			
		||||
        uint256 soldAmount;
 | 
			
		||||
        for (uint256 i = 0; i != fillData.calls.length; i++) {
 | 
			
		||||
            // Check if we've hit our target.
 | 
			
		||||
            if (soldAmount >= fillData.sellAmount) { break; }
 | 
			
		||||
            WrappedBatchCall memory wrappedCall = fillData.calls[i];
 | 
			
		||||
            // Compute the fill amount.
 | 
			
		||||
            uint256 inputTokenAmount = LibSafeMathV06.min256(
 | 
			
		||||
                wrappedCall.sellAmount,
 | 
			
		||||
                fillData.sellAmount.safeSub(soldAmount)
 | 
			
		||||
            );
 | 
			
		||||
            if (wrappedCall.selector == INativeOrdersFeature._fillRfqOrder.selector) {
 | 
			
		||||
                // Decode the RFQ order and signature.
 | 
			
		||||
                (
 | 
			
		||||
                    LibNativeOrder.RfqOrder memory order,
 | 
			
		||||
                    LibSignature.Signature memory signature
 | 
			
		||||
                ) = abi.decode(
 | 
			
		||||
                    wrappedCall.data,
 | 
			
		||||
                    (LibNativeOrder.RfqOrder, LibSignature.Signature)
 | 
			
		||||
                );
 | 
			
		||||
                if (order.expiry <= uint64(block.timestamp)) {
 | 
			
		||||
                    bytes32 orderHash = _getEIP712Hash(
 | 
			
		||||
                        LibNativeOrder.getRfqOrderStructHash(order)
 | 
			
		||||
                    );
 | 
			
		||||
                    emit ExpiredRfqOrder(
 | 
			
		||||
                        orderHash,
 | 
			
		||||
                        order.maker,
 | 
			
		||||
                        order.expiry
 | 
			
		||||
                    );
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                require(
 | 
			
		||||
                    order.takerToken == fillData.inputToken &&
 | 
			
		||||
                    order.makerToken == fillData.outputToken,
 | 
			
		||||
                    "MultiplexFeature::_batchFill/RFQ_ORDER_INVALID_TOKENS"
 | 
			
		||||
                );
 | 
			
		||||
                // Try filling the RFQ order. Swallows reverts.
 | 
			
		||||
                try
 | 
			
		||||
                    INativeOrdersFeature(address(this))._fillRfqOrder
 | 
			
		||||
                        (
 | 
			
		||||
                            order,
 | 
			
		||||
                            signature,
 | 
			
		||||
                            inputTokenAmount.safeDowncastToUint128(),
 | 
			
		||||
                            msg.sender
 | 
			
		||||
                        )
 | 
			
		||||
                    returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
 | 
			
		||||
                {
 | 
			
		||||
                    // Increment the sold and bought amounts.
 | 
			
		||||
                    soldAmount = soldAmount.safeAdd(takerTokenFilledAmount);
 | 
			
		||||
                    outputTokenAmount = outputTokenAmount.safeAdd(makerTokenFilledAmount);
 | 
			
		||||
                } catch {}
 | 
			
		||||
            } else if (wrappedCall.selector == this._sellToUniswap.selector) {
 | 
			
		||||
                (address[] memory tokens, bool isSushi) = abi.decode(
 | 
			
		||||
                    wrappedCall.data,
 | 
			
		||||
                    (address[], bool)
 | 
			
		||||
                );
 | 
			
		||||
                require(
 | 
			
		||||
                    tokens.length >= 2 &&
 | 
			
		||||
                    tokens[0] == address(fillData.inputToken) &&
 | 
			
		||||
                    tokens[tokens.length - 1] == address(fillData.outputToken),
 | 
			
		||||
                    "MultiplexFeature::_batchFill/UNISWAP_INVALID_TOKENS"
 | 
			
		||||
                );
 | 
			
		||||
                // Perform the Uniswap/Sushiswap trade.
 | 
			
		||||
                uint256 outputTokenAmount_  = _sellToUniswap(
 | 
			
		||||
                    tokens,
 | 
			
		||||
                    inputTokenAmount,
 | 
			
		||||
                    isSushi,
 | 
			
		||||
                    address(0),
 | 
			
		||||
                    msg.sender
 | 
			
		||||
                );
 | 
			
		||||
                // Increment the sold and bought amounts.
 | 
			
		||||
                soldAmount = soldAmount.safeAdd(inputTokenAmount);
 | 
			
		||||
                outputTokenAmount = outputTokenAmount.safeAdd(outputTokenAmount_);
 | 
			
		||||
            } else if (wrappedCall.selector == this._sellToLiquidityProvider.selector) {
 | 
			
		||||
                (address provider, bytes memory auxiliaryData) = abi.decode(
 | 
			
		||||
                    wrappedCall.data,
 | 
			
		||||
                    (address, bytes)
 | 
			
		||||
                );
 | 
			
		||||
                if (fillData.inputToken.isTokenETH()) {
 | 
			
		||||
                    inputTokenAmount = LibSafeMathV06.min256(
 | 
			
		||||
                        inputTokenAmount,
 | 
			
		||||
                        remainingEth
 | 
			
		||||
                    );
 | 
			
		||||
                    // Transfer the input ETH to the provider.
 | 
			
		||||
                    _transferEth(payable(provider), inputTokenAmount);
 | 
			
		||||
                    // Count that ETH as spent.
 | 
			
		||||
                    remainingEth -= inputTokenAmount;
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Transfer input ERC20 tokens to the provider.
 | 
			
		||||
                    _transferERC20Tokens(
 | 
			
		||||
                        fillData.inputToken,
 | 
			
		||||
                        msg.sender,
 | 
			
		||||
                        provider,
 | 
			
		||||
                        inputTokenAmount
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
                // Perform the PLP trade.
 | 
			
		||||
                uint256 outputTokenAmount_ = _sellToLiquidityProvider(
 | 
			
		||||
                    fillData.inputToken,
 | 
			
		||||
                    fillData.outputToken,
 | 
			
		||||
                    inputTokenAmount,
 | 
			
		||||
                    ILiquidityProvider(provider),
 | 
			
		||||
                    msg.sender,
 | 
			
		||||
                    auxiliaryData
 | 
			
		||||
                );
 | 
			
		||||
                // Increment the sold and bought amounts.
 | 
			
		||||
                soldAmount = soldAmount.safeAdd(inputTokenAmount);
 | 
			
		||||
                outputTokenAmount = outputTokenAmount.safeAdd(outputTokenAmount_);
 | 
			
		||||
            } else if (wrappedCall.selector == ITransformERC20Feature._transformERC20.selector) {
 | 
			
		||||
                ITransformERC20Feature.TransformERC20Args memory args;
 | 
			
		||||
                args.taker = msg.sender;
 | 
			
		||||
                args.inputToken = fillData.inputToken;
 | 
			
		||||
                args.outputToken = fillData.outputToken;
 | 
			
		||||
                args.inputTokenAmount = inputTokenAmount;
 | 
			
		||||
                args.minOutputTokenAmount = 0;
 | 
			
		||||
                uint256 ethValue;
 | 
			
		||||
                (args.transformations, ethValue) = abi.decode(
 | 
			
		||||
                    wrappedCall.data,
 | 
			
		||||
                    (ITransformERC20Feature.Transformation[], uint256)
 | 
			
		||||
                );
 | 
			
		||||
                // Do not spend more than the remaining ETH.
 | 
			
		||||
                ethValue = LibSafeMathV06.min256(
 | 
			
		||||
                    ethValue,
 | 
			
		||||
                    remainingEth
 | 
			
		||||
                );
 | 
			
		||||
                if (ethValue > 0) {
 | 
			
		||||
                    require(
 | 
			
		||||
                        args.inputToken.isTokenETH(),
 | 
			
		||||
                        "MultiplexFeature::_batchFill/ETH_TRANSFORM_ONLY"
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
                try ITransformERC20Feature(address(this))._transformERC20
 | 
			
		||||
                    {value: ethValue}
 | 
			
		||||
                    (args)
 | 
			
		||||
                    returns (uint256 outputTokenAmount_)
 | 
			
		||||
                {
 | 
			
		||||
                    remainingEth -= ethValue;
 | 
			
		||||
                    soldAmount = soldAmount.safeAdd(inputTokenAmount);
 | 
			
		||||
                    outputTokenAmount = outputTokenAmount.safeAdd(outputTokenAmount_);
 | 
			
		||||
                } catch {}
 | 
			
		||||
            } else if (wrappedCall.selector == this._multiHopFill.selector) {
 | 
			
		||||
                MultiHopFillData memory multiHopFillData;
 | 
			
		||||
                uint256 ethValue;
 | 
			
		||||
                (
 | 
			
		||||
                    multiHopFillData.tokens,
 | 
			
		||||
                    multiHopFillData.calls,
 | 
			
		||||
                    ethValue
 | 
			
		||||
                ) = abi.decode(
 | 
			
		||||
                    wrappedCall.data,
 | 
			
		||||
                    (address[], WrappedMultiHopCall[], uint256)
 | 
			
		||||
                );
 | 
			
		||||
                multiHopFillData.sellAmount = inputTokenAmount;
 | 
			
		||||
                // Do not spend more than the remaining ETH.
 | 
			
		||||
                ethValue = LibSafeMathV06.min256(
 | 
			
		||||
                    ethValue,
 | 
			
		||||
                    remainingEth
 | 
			
		||||
                );
 | 
			
		||||
                // Subtract the ethValue allocated to the nested multi-hop fill.
 | 
			
		||||
                remainingEth -= ethValue;
 | 
			
		||||
                (uint256 outputTokenAmount_, uint256 leftoverEth) =
 | 
			
		||||
                    _multiHopFill(multiHopFillData, ethValue);
 | 
			
		||||
                // Increment the sold and bought amounts.
 | 
			
		||||
                soldAmount = soldAmount.safeAdd(inputTokenAmount);
 | 
			
		||||
                outputTokenAmount = outputTokenAmount.safeAdd(outputTokenAmount_);
 | 
			
		||||
                // Add back any ETH that wasn't used by the nested multi-hop fill.
 | 
			
		||||
                remainingEth += leftoverEth;
 | 
			
		||||
            } else {
 | 
			
		||||
                revert("MultiplexFeature::_batchFill/UNRECOGNIZED_SELECTOR");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Internal variant of `multiHopFill`. This function can be nested within
 | 
			
		||||
    // a `_batchFill`.
 | 
			
		||||
    // This function executes a sequence of fills "hopping" through the
 | 
			
		||||
    // path of tokens given by `fillData.tokens`. The nested operations that
 | 
			
		||||
    // can be used as "hops" are:
 | 
			
		||||
    // - WETH.deposit (wraps ETH)
 | 
			
		||||
    // - WETH.withdraw (unwraps WETH)
 | 
			
		||||
    // - _sellToUniswap (executes a Uniswap/Sushiswap swap)
 | 
			
		||||
    // - _sellToLiquidityProvider (executes a PLP swap)
 | 
			
		||||
    // - _transformERC20 (executes arbitrary ERC20 Transformations)
 | 
			
		||||
    // This function optimizes the number of ERC20 transfers performed
 | 
			
		||||
    // by having each hop transfer its output tokens directly to the
 | 
			
		||||
    // target address of the next hop. Note that the `outputTokenAmount` returned
 | 
			
		||||
    // by this function could theoretically be inaccurate if `msg.sender` has
 | 
			
		||||
    // set a token allowance on an external contract that gets called during
 | 
			
		||||
    // the execution of this function.
 | 
			
		||||
    function _multiHopFill(MultiHopFillData memory fillData, uint256 totalEth)
 | 
			
		||||
        public
 | 
			
		||||
        returns (uint256 outputTokenAmount, uint256 remainingEth)
 | 
			
		||||
    {
 | 
			
		||||
        // There should be one call/hop between every two tokens
 | 
			
		||||
        // in the path.
 | 
			
		||||
        // tokens[0]––calls[0]––>tokens[1]––...––calls[n-1]––>tokens[n]
 | 
			
		||||
        require(
 | 
			
		||||
            fillData.tokens.length == fillData.calls.length + 1,
 | 
			
		||||
            "MultiplexFeature::_multiHopFill/MISMATCHED_ARRAY_LENGTHS"
 | 
			
		||||
        );
 | 
			
		||||
        // Track the remaining ETH allocated to this call.
 | 
			
		||||
        remainingEth = totalEth;
 | 
			
		||||
        // This variable is used as the input and output amounts of
 | 
			
		||||
        // each hop. After the final hop, this will contain the output
 | 
			
		||||
        // amount of the multi-hop fill.
 | 
			
		||||
        outputTokenAmount = fillData.sellAmount;
 | 
			
		||||
        // This variable is used to cache the address to target in the
 | 
			
		||||
        // next hop. See `_computeHopRecipient` for details.
 | 
			
		||||
        address nextTarget;
 | 
			
		||||
        for (uint256 i = 0; i != fillData.calls.length; i++) {
 | 
			
		||||
            WrappedMultiHopCall memory wrappedCall = fillData.calls[i];
 | 
			
		||||
            if (wrappedCall.selector == this._sellToUniswap.selector) {
 | 
			
		||||
                // If the next hop supports a "transfer then execute" pattern,
 | 
			
		||||
                // the recipient will not be `msg.sender`. See `_computeHopRecipient`
 | 
			
		||||
                // for details.
 | 
			
		||||
                address recipient = _computeHopRecipient(fillData.calls, i);
 | 
			
		||||
                (address[] memory tokens, bool isSushi) = abi.decode(
 | 
			
		||||
                    wrappedCall.data,
 | 
			
		||||
                    (address[], bool)
 | 
			
		||||
                );
 | 
			
		||||
                // Perform the Uniswap/Sushiswap trade.
 | 
			
		||||
                outputTokenAmount = _sellToUniswap(
 | 
			
		||||
                    tokens,
 | 
			
		||||
                    outputTokenAmount,
 | 
			
		||||
                    isSushi,
 | 
			
		||||
                    nextTarget,
 | 
			
		||||
                    recipient
 | 
			
		||||
                );
 | 
			
		||||
                // If the recipient was not `msg.sender`, it must be the target
 | 
			
		||||
                // contract for the next hop.
 | 
			
		||||
                nextTarget = recipient == msg.sender ? address(0) : recipient;
 | 
			
		||||
            } else if (wrappedCall.selector == this._sellToLiquidityProvider.selector) {
 | 
			
		||||
                // If the next hop supports a "transfer then execute" pattern,
 | 
			
		||||
                // the recipient will not be `msg.sender`. See `_computeHopRecipient`
 | 
			
		||||
                // for details.
 | 
			
		||||
                address recipient = _computeHopRecipient(fillData.calls, i);
 | 
			
		||||
                // If `nextTarget` was not set in the previous hop, then we
 | 
			
		||||
                // need to send in the input ETH/tokens to the liquidity provider
 | 
			
		||||
                // contract before executing the trade.
 | 
			
		||||
                if (nextTarget == address(0)) {
 | 
			
		||||
                    (address provider, bytes memory auxiliaryData) = abi.decode(
 | 
			
		||||
                        wrappedCall.data,
 | 
			
		||||
                        (address, bytes)
 | 
			
		||||
                    );
 | 
			
		||||
                    // Transfer input ETH or ERC20 tokens to the liquidity
 | 
			
		||||
                    // provider contract.
 | 
			
		||||
                    if (IERC20TokenV06(fillData.tokens[i]).isTokenETH()) {
 | 
			
		||||
                        outputTokenAmount = LibSafeMathV06.min256(
 | 
			
		||||
                            outputTokenAmount,
 | 
			
		||||
                            remainingEth
 | 
			
		||||
                        );
 | 
			
		||||
                        _transferEth(payable(provider), outputTokenAmount);
 | 
			
		||||
                        remainingEth -= outputTokenAmount;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        _transferERC20Tokens(
 | 
			
		||||
                            IERC20TokenV06(fillData.tokens[i]),
 | 
			
		||||
                            msg.sender,
 | 
			
		||||
                            provider,
 | 
			
		||||
                            outputTokenAmount
 | 
			
		||||
                        );
 | 
			
		||||
                    }
 | 
			
		||||
                    outputTokenAmount = _sellToLiquidityProvider(
 | 
			
		||||
                        IERC20TokenV06(fillData.tokens[i]),
 | 
			
		||||
                        IERC20TokenV06(fillData.tokens[i + 1]),
 | 
			
		||||
                        outputTokenAmount,
 | 
			
		||||
                        ILiquidityProvider(provider),
 | 
			
		||||
                        recipient,
 | 
			
		||||
                        auxiliaryData
 | 
			
		||||
                    );
 | 
			
		||||
                } else {
 | 
			
		||||
                    (, bytes memory auxiliaryData) = abi.decode(
 | 
			
		||||
                        wrappedCall.data,
 | 
			
		||||
                        (address, bytes)
 | 
			
		||||
                    );
 | 
			
		||||
                    // Tokens and ETH have already been transferred to
 | 
			
		||||
                    // the liquidity provider contract in the previous hop.
 | 
			
		||||
                    outputTokenAmount = _sellToLiquidityProvider(
 | 
			
		||||
                        IERC20TokenV06(fillData.tokens[i]),
 | 
			
		||||
                        IERC20TokenV06(fillData.tokens[i + 1]),
 | 
			
		||||
                        outputTokenAmount,
 | 
			
		||||
                        ILiquidityProvider(nextTarget),
 | 
			
		||||
                        recipient,
 | 
			
		||||
                        auxiliaryData
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
                // If the recipient was not `msg.sender`, it must be the target
 | 
			
		||||
                // contract for the next hop.
 | 
			
		||||
                nextTarget = recipient == msg.sender ? address(0) : recipient;
 | 
			
		||||
            } else if (wrappedCall.selector == ITransformERC20Feature._transformERC20.selector) {
 | 
			
		||||
                ITransformERC20Feature.TransformERC20Args memory args;
 | 
			
		||||
                args.inputToken = IERC20TokenV06(fillData.tokens[i]);
 | 
			
		||||
                args.outputToken = IERC20TokenV06(fillData.tokens[i + 1]);
 | 
			
		||||
                args.minOutputTokenAmount = 0;
 | 
			
		||||
                args.taker = payable(_computeHopRecipient(fillData.calls, i));
 | 
			
		||||
                if (nextTarget != address(0)) {
 | 
			
		||||
                    // If `nextTarget` was set in the previous hop, then the input
 | 
			
		||||
                    // token was already sent to the FlashWallet. Setting
 | 
			
		||||
                    // `inputTokenAmount` to 0 indicates that no tokens need to
 | 
			
		||||
                    // be pulled into the FlashWallet before executing the
 | 
			
		||||
                    // transformations.
 | 
			
		||||
                    args.inputTokenAmount = 0;
 | 
			
		||||
                } else if (
 | 
			
		||||
                    args.taker != msg.sender &&
 | 
			
		||||
                    !args.inputToken.isTokenETH()
 | 
			
		||||
                ) {
 | 
			
		||||
                    address flashWallet = address(
 | 
			
		||||
                        ITransformERC20Feature(address(this)).getTransformWallet()
 | 
			
		||||
                    );
 | 
			
		||||
                    // The input token has _not_ already been sent to the
 | 
			
		||||
                    // FlashWallet. We also want PayTakerTransformer to
 | 
			
		||||
                    // send the output token to some address other than
 | 
			
		||||
                    // msg.sender, so we must transfer the input token
 | 
			
		||||
                    // to the FlashWallet here.
 | 
			
		||||
                    _transferERC20Tokens(
 | 
			
		||||
                        args.inputToken,
 | 
			
		||||
                        msg.sender,
 | 
			
		||||
                        flashWallet,
 | 
			
		||||
                        outputTokenAmount
 | 
			
		||||
                    );
 | 
			
		||||
                    args.inputTokenAmount = 0;
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Otherwise, either:
 | 
			
		||||
                    // (1) args.taker == msg.sender, in which case
 | 
			
		||||
                    //     `_transformERC20` will pull the input token
 | 
			
		||||
                    //     into the FlashWallet, or
 | 
			
		||||
                    // (2) args.inputToken == ETH_TOKEN_ADDRESS, in which
 | 
			
		||||
                    //     case ETH is attached to the call and no token
 | 
			
		||||
                    //     transfer occurs.
 | 
			
		||||
                    args.inputTokenAmount = outputTokenAmount;
 | 
			
		||||
                }
 | 
			
		||||
                uint256 ethValue;
 | 
			
		||||
                (args.transformations, ethValue) = abi.decode(
 | 
			
		||||
                    wrappedCall.data,
 | 
			
		||||
                    (ITransformERC20Feature.Transformation[], uint256)
 | 
			
		||||
                );
 | 
			
		||||
                // Do not spend more than the remaining ETH.
 | 
			
		||||
                ethValue = LibSafeMathV06.min256(ethValue, remainingEth);
 | 
			
		||||
                if (ethValue > 0) {
 | 
			
		||||
                    require(
 | 
			
		||||
                        args.inputToken.isTokenETH(),
 | 
			
		||||
                        "MultiplexFeature::_multiHopFill/ETH_TRANSFORM_ONLY"
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
                // Call `_transformERC20`.
 | 
			
		||||
                outputTokenAmount = ITransformERC20Feature(address(this))
 | 
			
		||||
                    ._transformERC20{value: ethValue}(args);
 | 
			
		||||
                // Decrement the remaining ETH.
 | 
			
		||||
                remainingEth -= ethValue;
 | 
			
		||||
                // If the recipient was not `msg.sender`, it must be the target
 | 
			
		||||
                // contract for the next hop.
 | 
			
		||||
                nextTarget = args.taker == msg.sender ? address(0) : args.taker;
 | 
			
		||||
            } else if (wrappedCall.selector == IEtherTokenV06.deposit.selector) {
 | 
			
		||||
                require(
 | 
			
		||||
                    i == 0,
 | 
			
		||||
                    "MultiplexFeature::_multiHopFill/DEPOSIT_FIRST_HOP_ONLY"
 | 
			
		||||
                );
 | 
			
		||||
                uint256 ethValue = LibSafeMathV06.min256(outputTokenAmount, remainingEth);
 | 
			
		||||
                // Wrap ETH.
 | 
			
		||||
                weth.deposit{value: ethValue}();
 | 
			
		||||
                nextTarget = _computeHopRecipient(fillData.calls, i);
 | 
			
		||||
                weth.transfer(nextTarget, ethValue);
 | 
			
		||||
                remainingEth -= ethValue;
 | 
			
		||||
            } else if (wrappedCall.selector == IEtherTokenV06.withdraw.selector) {
 | 
			
		||||
                require(
 | 
			
		||||
                    i == fillData.calls.length - 1,
 | 
			
		||||
                    "MultiplexFeature::_multiHopFill/WITHDRAW_LAST_HOP_ONLY"
 | 
			
		||||
                );
 | 
			
		||||
                // Unwrap WETH and send to `msg.sender`.
 | 
			
		||||
                weth.withdraw(outputTokenAmount);
 | 
			
		||||
                _transferEth(msg.sender, outputTokenAmount);
 | 
			
		||||
                nextTarget = address(0);
 | 
			
		||||
            } else {
 | 
			
		||||
                revert("MultiplexFeature::_multiHopFill/UNRECOGNIZED_SELECTOR");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Similar to the UniswapFeature, but with a couple of differences:
 | 
			
		||||
    // - Does not perform the transfer in if `pairAddress` is given,
 | 
			
		||||
    //   which indicates that the transfer in was already performed
 | 
			
		||||
    //   in the previous hop of a multi-hop fill.
 | 
			
		||||
    // - Does not include a minBuyAmount check (which is performed in
 | 
			
		||||
    //   either `batchFill` or `multiHopFill`).
 | 
			
		||||
    // - Takes a `recipient` address parameter, so the output of the
 | 
			
		||||
    //   final `swap` call can be sent to an address other than `msg.sender`.
 | 
			
		||||
    function _sellToUniswap(
 | 
			
		||||
        address[] memory tokens,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        bool isSushi,
 | 
			
		||||
        address pairAddress,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        returns (uint256 outputTokenAmount)
 | 
			
		||||
    {
 | 
			
		||||
        require(tokens.length > 1, "MultiplexFeature::_sellToUniswap/InvalidTokensLength");
 | 
			
		||||
 | 
			
		||||
        if (pairAddress == address(0)) {
 | 
			
		||||
            pairAddress = _computeUniswapPairAddress(tokens[0], tokens[1], isSushi);
 | 
			
		||||
            _transferERC20Tokens(
 | 
			
		||||
                IERC20TokenV06(tokens[0]),
 | 
			
		||||
                msg.sender,
 | 
			
		||||
                pairAddress,
 | 
			
		||||
                sellAmount
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < tokens.length - 1; i++) {
 | 
			
		||||
            (address inputToken, address outputToken) = (tokens[i], tokens[i + 1]);
 | 
			
		||||
            outputTokenAmount = _computeUniswapOutputAmount(
 | 
			
		||||
                pairAddress,
 | 
			
		||||
                inputToken,
 | 
			
		||||
                outputToken,
 | 
			
		||||
                sellAmount
 | 
			
		||||
            );
 | 
			
		||||
            (uint256 amount0Out, uint256 amount1Out) = inputToken < outputToken
 | 
			
		||||
                ? (uint256(0), outputTokenAmount)
 | 
			
		||||
                : (outputTokenAmount, uint256(0));
 | 
			
		||||
            address to = i < tokens.length - 2
 | 
			
		||||
                ? _computeUniswapPairAddress(outputToken, tokens[i + 2], isSushi)
 | 
			
		||||
                : recipient;
 | 
			
		||||
            IUniswapV2Pair(pairAddress).swap(
 | 
			
		||||
                amount0Out,
 | 
			
		||||
                amount1Out,
 | 
			
		||||
                to,
 | 
			
		||||
                new bytes(0)
 | 
			
		||||
            );
 | 
			
		||||
            pairAddress = to;
 | 
			
		||||
            sellAmount = outputTokenAmount;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Same as the LiquidityProviderFeature, but without the transfer in
 | 
			
		||||
    // (which is potentially done in the previous hop of a multi-hop fill)
 | 
			
		||||
    // and without the minBuyAmount check (which is performed at the top, i.e.
 | 
			
		||||
    // in either `batchFill` or `multiHopFill`).
 | 
			
		||||
    function _sellToLiquidityProvider(
 | 
			
		||||
        IERC20TokenV06 inputToken,
 | 
			
		||||
        IERC20TokenV06 outputToken,
 | 
			
		||||
        uint256 inputTokenAmount,
 | 
			
		||||
        ILiquidityProvider provider,
 | 
			
		||||
        address recipient,
 | 
			
		||||
        bytes memory auxiliaryData
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        returns (uint256 outputTokenAmount)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 balanceBefore = IERC20TokenV06(outputToken).getTokenBalanceOf(recipient);
 | 
			
		||||
        if (IERC20TokenV06(inputToken).isTokenETH()) {
 | 
			
		||||
            sandbox.executeSellEthForToken(
 | 
			
		||||
                provider,
 | 
			
		||||
                outputToken,
 | 
			
		||||
                recipient,
 | 
			
		||||
                0,
 | 
			
		||||
                auxiliaryData
 | 
			
		||||
            );
 | 
			
		||||
        } else if (IERC20TokenV06(outputToken).isTokenETH()) {
 | 
			
		||||
            sandbox.executeSellTokenForEth(
 | 
			
		||||
                provider,
 | 
			
		||||
                inputToken,
 | 
			
		||||
                recipient,
 | 
			
		||||
                0,
 | 
			
		||||
                auxiliaryData
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            sandbox.executeSellTokenForToken(
 | 
			
		||||
                provider,
 | 
			
		||||
                inputToken,
 | 
			
		||||
                outputToken,
 | 
			
		||||
                recipient,
 | 
			
		||||
                0,
 | 
			
		||||
                auxiliaryData
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        outputTokenAmount = IERC20TokenV06(outputToken).getTokenBalanceOf(recipient)
 | 
			
		||||
            .safeSub(balanceBefore);
 | 
			
		||||
        emit LiquidityProviderSwap(
 | 
			
		||||
            address(inputToken),
 | 
			
		||||
            address(outputToken),
 | 
			
		||||
            inputTokenAmount,
 | 
			
		||||
            outputTokenAmount,
 | 
			
		||||
            address(provider),
 | 
			
		||||
            recipient
 | 
			
		||||
        );
 | 
			
		||||
        return outputTokenAmount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _transferEth(address payable recipient, uint256 amount)
 | 
			
		||||
        private
 | 
			
		||||
    {
 | 
			
		||||
        (bool success,) = recipient.call{value: amount}("");
 | 
			
		||||
        require(success, "MultiplexFeature::_transferEth/TRANSFER_FALIED");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Some liquidity sources (e.g. Uniswap, Sushiswap, and PLP) can be passed
 | 
			
		||||
    // a `recipient` parameter so the boguht tokens are transferred to the
 | 
			
		||||
    // `recipient` address rather than `msg.sender`.
 | 
			
		||||
    // Some liquidity sources (also Uniswap, Sushiswap, and PLP incidentally)
 | 
			
		||||
    // support a "transfer then execute" pattern, where the token being sold
 | 
			
		||||
    // can be transferred into the contract before calling a swap function to
 | 
			
		||||
    // execute the trade.
 | 
			
		||||
    // If the current hop in a multi-hop fill satisfies the first condition,
 | 
			
		||||
    // and the next hop satisfies the second condition, the tokens bought
 | 
			
		||||
    // in the current hop can be directly sent to the target contract of
 | 
			
		||||
    // the next hop to save a transfer.
 | 
			
		||||
    function _computeHopRecipient(
 | 
			
		||||
        WrappedMultiHopCall[] memory calls,
 | 
			
		||||
        uint256 i
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (address recipient)
 | 
			
		||||
    {
 | 
			
		||||
        recipient = msg.sender;
 | 
			
		||||
        if (i < calls.length - 1) {
 | 
			
		||||
            WrappedMultiHopCall memory nextCall = calls[i + 1];
 | 
			
		||||
            if (nextCall.selector == this._sellToUniswap.selector) {
 | 
			
		||||
                (address[] memory tokens, bool isSushi) = abi.decode(
 | 
			
		||||
                    nextCall.data,
 | 
			
		||||
                    (address[], bool)
 | 
			
		||||
                );
 | 
			
		||||
                recipient = _computeUniswapPairAddress(tokens[0], tokens[1], isSushi);
 | 
			
		||||
            } else if (nextCall.selector == this._sellToLiquidityProvider.selector) {
 | 
			
		||||
                (recipient,) = abi.decode(
 | 
			
		||||
                    nextCall.data,
 | 
			
		||||
                    (address, bytes)
 | 
			
		||||
                );
 | 
			
		||||
            } else if (nextCall.selector == IEtherTokenV06.withdraw.selector) {
 | 
			
		||||
                recipient = address(this);
 | 
			
		||||
            } else if (nextCall.selector == ITransformERC20Feature._transformERC20.selector) {
 | 
			
		||||
                recipient = address(
 | 
			
		||||
                    ITransformERC20Feature(address(this)).getTransformWallet()
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        require(
 | 
			
		||||
            recipient != address(0),
 | 
			
		||||
            "MultiplexFeature::_computeHopRecipient/RECIPIENT_IS_NULL"
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Computes the the amount of output token that would be bought
 | 
			
		||||
    // from Uniswap/Sushiswap given the input amount.
 | 
			
		||||
    function _computeUniswapOutputAmount(
 | 
			
		||||
        address pairAddress,
 | 
			
		||||
        address inputToken,
 | 
			
		||||
        address outputToken,
 | 
			
		||||
        uint256 inputAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 outputAmount)
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            inputAmount > 0,
 | 
			
		||||
            "MultiplexFeature::_computeUniswapOutputAmount/INSUFFICIENT_INPUT_AMOUNT"
 | 
			
		||||
        );
 | 
			
		||||
        (uint256 reserve0, uint256 reserve1,) = IUniswapV2Pair(pairAddress).getReserves();
 | 
			
		||||
        require(
 | 
			
		||||
            reserve0 > 0 && reserve1 > 0,
 | 
			
		||||
            'MultiplexFeature::_computeUniswapOutputAmount/INSUFFICIENT_LIQUIDITY'
 | 
			
		||||
        );
 | 
			
		||||
        (uint256 inputReserve, uint256 outputReserve) = inputToken < outputToken
 | 
			
		||||
            ? (reserve0, reserve1)
 | 
			
		||||
            : (reserve1, reserve0);
 | 
			
		||||
        uint256 inputAmountWithFee = inputAmount.safeMul(997);
 | 
			
		||||
        uint256 numerator = inputAmountWithFee.safeMul(outputReserve);
 | 
			
		||||
        uint256 denominator = inputReserve.safeMul(1000).safeAdd(inputAmountWithFee);
 | 
			
		||||
        return numerator / denominator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Computes the Uniswap/Sushiswap pair contract address for the
 | 
			
		||||
    // given tokens.
 | 
			
		||||
    function _computeUniswapPairAddress(
 | 
			
		||||
        address tokenA,
 | 
			
		||||
        address tokenB,
 | 
			
		||||
        bool isSushi
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        pure
 | 
			
		||||
        returns (address pairAddress)
 | 
			
		||||
    {
 | 
			
		||||
        (address token0, address token1) = tokenA < tokenB
 | 
			
		||||
            ? (tokenA, tokenB)
 | 
			
		||||
            : (tokenB, tokenA);
 | 
			
		||||
        if (isSushi) {
 | 
			
		||||
            return address(uint256(keccak256(abi.encodePacked(
 | 
			
		||||
                hex'ff',
 | 
			
		||||
                SUSHISWAP_FACTORY,
 | 
			
		||||
                keccak256(abi.encodePacked(token0, token1)),
 | 
			
		||||
                SUSHISWAP_PAIR_INIT_CODE_HASH
 | 
			
		||||
            ))));
 | 
			
		||||
        } else {
 | 
			
		||||
            return address(uint256(keccak256(abi.encodePacked(
 | 
			
		||||
                hex'ff',
 | 
			
		||||
                UNISWAP_FACTORY,
 | 
			
		||||
                keccak256(abi.encodePacked(token0, token1)),
 | 
			
		||||
                UNISWAP_PAIR_INIT_CODE_HASH
 | 
			
		||||
            ))));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -34,7 +34,7 @@ contract NativeOrdersFeature is
 | 
			
		||||
    /// @dev Name of this feature.
 | 
			
		||||
    string public constant override FEATURE_NAME = "LimitOrders";
 | 
			
		||||
    /// @dev Version of this feature.
 | 
			
		||||
    uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 2, 0);
 | 
			
		||||
    uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 3, 0);
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        address zeroExAddress,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										637
									
								
								contracts/zero-ex/contracts/src/features/OtcOrdersFeature.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										637
									
								
								contracts/zero-ex/contracts/src/features/OtcOrdersFeature.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,637 @@
 | 
			
		||||
// 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/IEtherTokenV06.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
 | 
			
		||||
import "../errors/LibNativeOrdersRichErrors.sol";
 | 
			
		||||
import "../fixins/FixinCommon.sol";
 | 
			
		||||
import "../fixins/FixinEIP712.sol";
 | 
			
		||||
import "../fixins/FixinTokenSpender.sol";
 | 
			
		||||
import "../migrations/LibMigrate.sol";
 | 
			
		||||
import "../storage/LibNativeOrdersStorage.sol";
 | 
			
		||||
import "../storage/LibOtcOrdersStorage.sol";
 | 
			
		||||
import "./interfaces/IFeature.sol";
 | 
			
		||||
import "./interfaces/IOtcOrdersFeature.sol";
 | 
			
		||||
import "./libs/LibNativeOrder.sol";
 | 
			
		||||
import "./libs/LibSignature.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev Feature for interacting with OTC orders.
 | 
			
		||||
contract OtcOrdersFeature is
 | 
			
		||||
    IFeature,
 | 
			
		||||
    IOtcOrdersFeature,
 | 
			
		||||
    FixinCommon,
 | 
			
		||||
    FixinEIP712,
 | 
			
		||||
    FixinTokenSpender
 | 
			
		||||
{
 | 
			
		||||
    using LibSafeMathV06 for uint256;
 | 
			
		||||
    using LibSafeMathV06 for uint128;
 | 
			
		||||
 | 
			
		||||
    /// @dev Name of this feature.
 | 
			
		||||
    string public constant override FEATURE_NAME = "OtcOrders";
 | 
			
		||||
    /// @dev Version of this feature.
 | 
			
		||||
    uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
 | 
			
		||||
    /// @dev ETH pseudo-token address.
 | 
			
		||||
    address constant private ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
 | 
			
		||||
    /// @dev The WETH token contract.
 | 
			
		||||
    IEtherTokenV06 private immutable WETH;
 | 
			
		||||
 | 
			
		||||
    constructor(address zeroExAddress, IEtherTokenV06 weth)
 | 
			
		||||
        public
 | 
			
		||||
        FixinEIP712(zeroExAddress)
 | 
			
		||||
    {
 | 
			
		||||
        WETH = weth;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Initialize and register this feature.
 | 
			
		||||
    ///      Should be delegatecalled by `Migrate.migrate()`.
 | 
			
		||||
    /// @return success `LibMigrate.SUCCESS` on success.
 | 
			
		||||
    function migrate()
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        _registerFeatureFunction(this.fillOtcOrder.selector);
 | 
			
		||||
        _registerFeatureFunction(this.fillOtcOrderForEth.selector);
 | 
			
		||||
        _registerFeatureFunction(this.fillOtcOrderWithEth.selector);
 | 
			
		||||
        _registerFeatureFunction(this.fillTakerSignedOtcOrderForEth.selector);
 | 
			
		||||
        _registerFeatureFunction(this.fillTakerSignedOtcOrder.selector);
 | 
			
		||||
        _registerFeatureFunction(this.batchFillTakerSignedOtcOrders.selector);
 | 
			
		||||
        _registerFeatureFunction(this._fillOtcOrder.selector);
 | 
			
		||||
        _registerFeatureFunction(this.getOtcOrderInfo.selector);
 | 
			
		||||
        _registerFeatureFunction(this.getOtcOrderHash.selector);
 | 
			
		||||
        _registerFeatureFunction(this.lastOtcTxOriginNonce.selector);
 | 
			
		||||
        return LibMigrate.MIGRATE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Fill an OTC order for up to `takerTokenFillAmount` taker tokens.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @param makerSignature The order signature from the maker.
 | 
			
		||||
    /// @param takerTokenFillAmount Maximum taker token amount to fill this
 | 
			
		||||
    ///        order with.
 | 
			
		||||
    /// @return takerTokenFilledAmount How much taker token was filled.
 | 
			
		||||
    /// @return makerTokenFilledAmount How much maker token was filled.
 | 
			
		||||
    function fillOtcOrder(
 | 
			
		||||
        LibNativeOrder.OtcOrder memory order,
 | 
			
		||||
        LibSignature.Signature memory makerSignature,
 | 
			
		||||
        uint128 takerTokenFillAmount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
 | 
			
		||||
    {
 | 
			
		||||
        LibNativeOrder.OtcOrderInfo memory orderInfo = getOtcOrderInfo(order);
 | 
			
		||||
        _validateOtcOrder(
 | 
			
		||||
            order, 
 | 
			
		||||
            orderInfo,
 | 
			
		||||
            makerSignature,
 | 
			
		||||
            msg.sender
 | 
			
		||||
        );
 | 
			
		||||
        (takerTokenFilledAmount, makerTokenFilledAmount) = _settleOtcOrder(
 | 
			
		||||
            order,
 | 
			
		||||
            takerTokenFillAmount,
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            msg.sender
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        emit OtcOrderFilled(
 | 
			
		||||
            orderInfo.orderHash,
 | 
			
		||||
            order.maker,
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            address(order.makerToken),
 | 
			
		||||
            address(order.takerToken),
 | 
			
		||||
            makerTokenFilledAmount,
 | 
			
		||||
            takerTokenFilledAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Fill an OTC order for up to `takerTokenFillAmount` taker tokens.
 | 
			
		||||
    ///      Unwraps bought WETH into ETH. before sending it to 
 | 
			
		||||
    ///      the taker.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @param makerSignature The order signature from the maker.
 | 
			
		||||
    /// @param takerTokenFillAmount Maximum taker token amount to fill this
 | 
			
		||||
    ///        order with.
 | 
			
		||||
    /// @return takerTokenFilledAmount How much taker token was filled.
 | 
			
		||||
    /// @return makerTokenFilledAmount How much maker token was filled.
 | 
			
		||||
    function fillOtcOrderForEth(
 | 
			
		||||
        LibNativeOrder.OtcOrder memory order,
 | 
			
		||||
        LibSignature.Signature memory makerSignature,
 | 
			
		||||
        uint128 takerTokenFillAmount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            order.makerToken == WETH,
 | 
			
		||||
            "OtcOrdersFeature::fillOtcOrderForEth/MAKER_TOKEN_NOT_WETH"
 | 
			
		||||
        );
 | 
			
		||||
        LibNativeOrder.OtcOrderInfo memory orderInfo = getOtcOrderInfo(order);
 | 
			
		||||
        _validateOtcOrder(
 | 
			
		||||
            order, 
 | 
			
		||||
            orderInfo,
 | 
			
		||||
            makerSignature,
 | 
			
		||||
            msg.sender
 | 
			
		||||
        );
 | 
			
		||||
        (takerTokenFilledAmount, makerTokenFilledAmount) = _settleOtcOrder(
 | 
			
		||||
            order,
 | 
			
		||||
            takerTokenFillAmount, 
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            address(this)
 | 
			
		||||
        );
 | 
			
		||||
        // Unwrap WETH
 | 
			
		||||
        WETH.withdraw(makerTokenFilledAmount);
 | 
			
		||||
        // Transfer ETH to taker
 | 
			
		||||
        _transferEth(msg.sender, makerTokenFilledAmount);
 | 
			
		||||
 | 
			
		||||
        emit OtcOrderFilled(
 | 
			
		||||
            orderInfo.orderHash,
 | 
			
		||||
            order.maker,
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            address(order.makerToken),
 | 
			
		||||
            address(order.takerToken),
 | 
			
		||||
            makerTokenFilledAmount,
 | 
			
		||||
            takerTokenFilledAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Fill an OTC order whose taker token is WETH for up
 | 
			
		||||
    ///      to `msg.value`.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @param makerSignature The order signature from the maker.
 | 
			
		||||
    /// @return takerTokenFilledAmount How much taker token was filled.
 | 
			
		||||
    /// @return makerTokenFilledAmount How much maker token was filled.
 | 
			
		||||
    function fillOtcOrderWithEth(
 | 
			
		||||
        LibNativeOrder.OtcOrder memory order,
 | 
			
		||||
        LibSignature.Signature memory makerSignature
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
 | 
			
		||||
    {
 | 
			
		||||
        if (order.takerToken == WETH) {
 | 
			
		||||
            // Wrap ETH
 | 
			
		||||
            WETH.deposit{value: msg.value}();
 | 
			
		||||
        } else {
 | 
			
		||||
            require(
 | 
			
		||||
                address(order.takerToken) == ETH_TOKEN_ADDRESS,
 | 
			
		||||
                "OtcOrdersFeature::fillOtcOrderWithEth/INVALID_TAKER_TOKEN"
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        LibNativeOrder.OtcOrderInfo memory orderInfo = getOtcOrderInfo(order);
 | 
			
		||||
        _validateOtcOrder(
 | 
			
		||||
            order, 
 | 
			
		||||
            orderInfo,
 | 
			
		||||
            makerSignature,
 | 
			
		||||
            msg.sender
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        (takerTokenFilledAmount, makerTokenFilledAmount) =  _settleOtcOrder(
 | 
			
		||||
            order,
 | 
			
		||||
            msg.value.safeDowncastToUint128(),
 | 
			
		||||
            address(this),
 | 
			
		||||
            msg.sender
 | 
			
		||||
        );
 | 
			
		||||
        if (takerTokenFilledAmount < msg.value) {
 | 
			
		||||
            uint256 refundAmount = msg.value - uint256(takerTokenFilledAmount);
 | 
			
		||||
            if (order.takerToken == WETH) {
 | 
			
		||||
                WETH.withdraw(refundAmount);
 | 
			
		||||
            }
 | 
			
		||||
            // Refund unused ETH
 | 
			
		||||
            _transferEth(msg.sender, refundAmount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        emit OtcOrderFilled(
 | 
			
		||||
            orderInfo.orderHash,
 | 
			
		||||
            order.maker,
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            address(order.makerToken),
 | 
			
		||||
            address(order.takerToken),
 | 
			
		||||
            makerTokenFilledAmount,
 | 
			
		||||
            takerTokenFilledAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Fully fill an OTC order. "Meta-transaction" variant,
 | 
			
		||||
    ///      requires order to be signed by both maker and taker.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @param makerSignature The order signature from the maker.
 | 
			
		||||
    /// @param takerSignature The order signature from the taker.
 | 
			
		||||
    function fillTakerSignedOtcOrder(
 | 
			
		||||
        LibNativeOrder.OtcOrder memory order,
 | 
			
		||||
        LibSignature.Signature memory makerSignature,
 | 
			
		||||
        LibSignature.Signature memory takerSignature
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
    {
 | 
			
		||||
        LibNativeOrder.OtcOrderInfo memory orderInfo = getOtcOrderInfo(order);
 | 
			
		||||
        address taker = LibSignature.getSignerOfHash(orderInfo.orderHash, takerSignature);
 | 
			
		||||
        
 | 
			
		||||
        _validateOtcOrder(
 | 
			
		||||
            order, 
 | 
			
		||||
            orderInfo,
 | 
			
		||||
            makerSignature,
 | 
			
		||||
            taker
 | 
			
		||||
        );
 | 
			
		||||
        _settleOtcOrder(
 | 
			
		||||
            order,
 | 
			
		||||
            order.takerAmount,
 | 
			
		||||
            taker,
 | 
			
		||||
            taker
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        emit OtcOrderFilled(
 | 
			
		||||
            orderInfo.orderHash,
 | 
			
		||||
            order.maker,
 | 
			
		||||
            taker,
 | 
			
		||||
            address(order.makerToken),
 | 
			
		||||
            address(order.takerToken),
 | 
			
		||||
            order.makerAmount,
 | 
			
		||||
            order.takerAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Fully fill an OTC order. "Meta-transaction" variant,
 | 
			
		||||
    ///      requires order to be signed by both maker and taker.
 | 
			
		||||
    ///      Unwraps bought WETH into ETH. before sending it to 
 | 
			
		||||
    ///      the taker.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @param makerSignature The order signature from the maker.
 | 
			
		||||
    /// @param takerSignature The order signature from the taker.
 | 
			
		||||
    function fillTakerSignedOtcOrderForEth(
 | 
			
		||||
        LibNativeOrder.OtcOrder memory order,
 | 
			
		||||
        LibSignature.Signature memory makerSignature,
 | 
			
		||||
        LibSignature.Signature memory takerSignature
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            order.makerToken == WETH,
 | 
			
		||||
            "OtcOrdersFeature::fillTakerSignedOtcOrder/MAKER_TOKEN_NOT_WETH"
 | 
			
		||||
        );
 | 
			
		||||
        LibNativeOrder.OtcOrderInfo memory orderInfo = getOtcOrderInfo(order);
 | 
			
		||||
        address taker = LibSignature.getSignerOfHash(orderInfo.orderHash, takerSignature);
 | 
			
		||||
        
 | 
			
		||||
        _validateOtcOrder(
 | 
			
		||||
            order, 
 | 
			
		||||
            orderInfo,
 | 
			
		||||
            makerSignature,
 | 
			
		||||
            taker
 | 
			
		||||
        );
 | 
			
		||||
        _settleOtcOrder(
 | 
			
		||||
            order,
 | 
			
		||||
            order.takerAmount,
 | 
			
		||||
            taker,
 | 
			
		||||
            address(this)
 | 
			
		||||
        );
 | 
			
		||||
        // Unwrap WETH
 | 
			
		||||
        WETH.withdraw(order.makerAmount);
 | 
			
		||||
        // Transfer ETH to taker
 | 
			
		||||
        _transferEth(taker, order.makerAmount);
 | 
			
		||||
 | 
			
		||||
        emit OtcOrderFilled(
 | 
			
		||||
            orderInfo.orderHash,
 | 
			
		||||
            order.maker,
 | 
			
		||||
            taker,
 | 
			
		||||
            address(order.makerToken),
 | 
			
		||||
            address(order.takerToken),
 | 
			
		||||
            order.makerAmount,
 | 
			
		||||
            order.takerAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Fills multiple taker-signed OTC orders.
 | 
			
		||||
    /// @param orders Array of OTC orders.
 | 
			
		||||
    /// @param makerSignatures Array of maker signatures for each order.
 | 
			
		||||
    /// @param takerSignatures Array of taker signatures for each order.
 | 
			
		||||
    /// @param unwrapWeth Array of booleans representing whether or not 
 | 
			
		||||
    ///        to unwrap bought WETH into ETH for each order. Should be set 
 | 
			
		||||
    ///        to false if the maker token is not WETH.
 | 
			
		||||
    /// @return successes Array of booleans representing whether or not
 | 
			
		||||
    ///         each order in `orders` was filled successfully.
 | 
			
		||||
    function batchFillTakerSignedOtcOrders(
 | 
			
		||||
        LibNativeOrder.OtcOrder[] memory orders,
 | 
			
		||||
        LibSignature.Signature[] memory makerSignatures,
 | 
			
		||||
        LibSignature.Signature[] memory takerSignatures,
 | 
			
		||||
        bool[] memory unwrapWeth
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        returns (bool[] memory successes)
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            orders.length == makerSignatures.length && 
 | 
			
		||||
            orders.length == takerSignatures.length &&
 | 
			
		||||
            orders.length == unwrapWeth.length,
 | 
			
		||||
            "OtcOrdersFeature::batchFillTakerSignedOtcOrders/MISMATCHED_ARRAY_LENGTHS"
 | 
			
		||||
        );
 | 
			
		||||
        successes = new bool[](orders.length);
 | 
			
		||||
        for (uint256 i = 0; i != orders.length; i++) {
 | 
			
		||||
            bytes4 fnSelector = unwrapWeth[i] 
 | 
			
		||||
                ? this.fillTakerSignedOtcOrderForEth.selector
 | 
			
		||||
                : this.fillTakerSignedOtcOrder.selector;
 | 
			
		||||
            // Swallow reverts
 | 
			
		||||
            (successes[i], ) = _implementation.delegatecall(
 | 
			
		||||
                abi.encodeWithSelector(
 | 
			
		||||
                    fnSelector,
 | 
			
		||||
                    orders[i],
 | 
			
		||||
                    makerSignatures[i],
 | 
			
		||||
                    takerSignatures[i]
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Fill an OTC order for up to `takerTokenFillAmount` taker tokens.
 | 
			
		||||
    ///      Internal variant.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @param makerSignature The order signature from the maker.
 | 
			
		||||
    /// @param takerTokenFillAmount Maximum taker token amount to fill this
 | 
			
		||||
    ///        order with.
 | 
			
		||||
    /// @param taker The address to fill the order in the context of.
 | 
			
		||||
    /// @param useSelfBalance Whether to use the Exchange Proxy's balance
 | 
			
		||||
    ///        of input tokens.
 | 
			
		||||
    /// @param recipient The recipient of the bought maker tokens.
 | 
			
		||||
    /// @return takerTokenFilledAmount How much taker token was filled.
 | 
			
		||||
    /// @return makerTokenFilledAmount How much maker token was filled.
 | 
			
		||||
    function _fillOtcOrder(
 | 
			
		||||
        LibNativeOrder.OtcOrder memory order,
 | 
			
		||||
        LibSignature.Signature memory makerSignature,
 | 
			
		||||
        uint128 takerTokenFillAmount,
 | 
			
		||||
        address taker,
 | 
			
		||||
        bool useSelfBalance,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        onlySelf
 | 
			
		||||
        returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
 | 
			
		||||
    {
 | 
			
		||||
        LibNativeOrder.OtcOrderInfo memory orderInfo = getOtcOrderInfo(order);
 | 
			
		||||
        _validateOtcOrder(
 | 
			
		||||
            order, 
 | 
			
		||||
            orderInfo,
 | 
			
		||||
            makerSignature,
 | 
			
		||||
            taker
 | 
			
		||||
        );
 | 
			
		||||
        (takerTokenFilledAmount, makerTokenFilledAmount) = _settleOtcOrder(
 | 
			
		||||
            order,
 | 
			
		||||
            takerTokenFillAmount,
 | 
			
		||||
            useSelfBalance ? address(this) : taker,
 | 
			
		||||
            recipient
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        emit OtcOrderFilled(
 | 
			
		||||
            orderInfo.orderHash,
 | 
			
		||||
            order.maker,
 | 
			
		||||
            taker,
 | 
			
		||||
            address(order.makerToken),
 | 
			
		||||
            address(order.takerToken),
 | 
			
		||||
            makerTokenFilledAmount,
 | 
			
		||||
            takerTokenFilledAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Validates an OTC order, reverting if the order cannot be 
 | 
			
		||||
    ///      filled by the given taker.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @param orderInfo Info on the order.
 | 
			
		||||
    /// @param makerSignature The order signature from the maker.
 | 
			
		||||
    /// @param taker The order taker.
 | 
			
		||||
    function _validateOtcOrder(
 | 
			
		||||
        LibNativeOrder.OtcOrder memory order,
 | 
			
		||||
        LibNativeOrder.OtcOrderInfo memory orderInfo,
 | 
			
		||||
        LibSignature.Signature memory makerSignature,
 | 
			
		||||
        address taker
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
    {
 | 
			
		||||
        // Must be fillable.
 | 
			
		||||
        if (orderInfo.status != LibNativeOrder.OrderStatus.FILLABLE) {
 | 
			
		||||
            LibNativeOrdersRichErrors.OrderNotFillableError(
 | 
			
		||||
                orderInfo.orderHash,
 | 
			
		||||
                uint8(orderInfo.status)
 | 
			
		||||
            ).rrevert();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Must be a valid taker for the order.
 | 
			
		||||
        if (order.taker != address(0) && order.taker != taker) {
 | 
			
		||||
            LibNativeOrdersRichErrors.OrderNotFillableByTakerError(
 | 
			
		||||
                orderInfo.orderHash,
 | 
			
		||||
                taker,
 | 
			
		||||
                order.taker
 | 
			
		||||
            ).rrevert();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        LibNativeOrdersStorage.Storage storage stor =
 | 
			
		||||
            LibNativeOrdersStorage.getStorage();
 | 
			
		||||
 | 
			
		||||
        // Must be fillable by the tx.origin.
 | 
			
		||||
        if (
 | 
			
		||||
            order.txOrigin != tx.origin &&
 | 
			
		||||
            !stor.originRegistry[order.txOrigin][tx.origin]
 | 
			
		||||
        ) {
 | 
			
		||||
            LibNativeOrdersRichErrors.OrderNotFillableByOriginError(
 | 
			
		||||
                orderInfo.orderHash,
 | 
			
		||||
                tx.origin,
 | 
			
		||||
                order.txOrigin
 | 
			
		||||
            ).rrevert();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Maker signature must be valid for the order.
 | 
			
		||||
        address makerSigner = LibSignature.getSignerOfHash(orderInfo.orderHash, makerSignature);
 | 
			
		||||
        if (
 | 
			
		||||
            makerSigner != order.maker &&
 | 
			
		||||
            !stor.orderSignerRegistry[order.maker][makerSigner]
 | 
			
		||||
        ) {
 | 
			
		||||
            LibNativeOrdersRichErrors.OrderNotSignedByMakerError(
 | 
			
		||||
                orderInfo.orderHash,
 | 
			
		||||
                makerSigner,
 | 
			
		||||
                order.maker
 | 
			
		||||
            ).rrevert();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Settle the trade between an OTC order's maker and taker.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @param takerTokenFillAmount Maximum taker token amount to fill this
 | 
			
		||||
    ///        order with.
 | 
			
		||||
    /// @param payer The address holding the taker tokens.
 | 
			
		||||
    /// @param recipient The recipient of the maker tokens.
 | 
			
		||||
    /// @return takerTokenFilledAmount How much taker token was filled.
 | 
			
		||||
    /// @return makerTokenFilledAmount How much maker token was filled.
 | 
			
		||||
    function _settleOtcOrder(
 | 
			
		||||
        LibNativeOrder.OtcOrder memory order,
 | 
			
		||||
        uint128 takerTokenFillAmount,
 | 
			
		||||
        address payer,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
 | 
			
		||||
    {
 | 
			
		||||
        {
 | 
			
		||||
            // Unpack nonce fields
 | 
			
		||||
            uint64 nonceBucket = uint64(order.expiryAndNonce >> 128);
 | 
			
		||||
            uint128 nonce = uint128(order.expiryAndNonce);
 | 
			
		||||
            // Update tx origin nonce for the order
 | 
			
		||||
            LibOtcOrdersStorage.getStorage().txOriginNonces
 | 
			
		||||
                [order.txOrigin][nonceBucket] = nonce;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (takerTokenFillAmount == order.takerAmount) {
 | 
			
		||||
            takerTokenFilledAmount = order.takerAmount;
 | 
			
		||||
            makerTokenFilledAmount = order.makerAmount;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Clamp the taker token fill amount to the fillable amount.
 | 
			
		||||
            takerTokenFilledAmount = LibSafeMathV06.min128(
 | 
			
		||||
                takerTokenFillAmount,
 | 
			
		||||
                order.takerAmount
 | 
			
		||||
            );
 | 
			
		||||
            // Compute the maker token amount.
 | 
			
		||||
            // This should never overflow because the values are all clamped to
 | 
			
		||||
            // (2^128-1).
 | 
			
		||||
            makerTokenFilledAmount = uint128(LibMathV06.getPartialAmountFloor(
 | 
			
		||||
                uint256(takerTokenFilledAmount),
 | 
			
		||||
                uint256(order.takerAmount),
 | 
			
		||||
                uint256(order.makerAmount)
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (payer == address(this)) {
 | 
			
		||||
            if (address(order.takerToken) == ETH_TOKEN_ADDRESS) {
 | 
			
		||||
                // Transfer ETH to the maker.
 | 
			
		||||
                payable(order.maker).transfer(takerTokenFilledAmount);
 | 
			
		||||
            } else {
 | 
			
		||||
                // Transfer this -> maker.
 | 
			
		||||
                _transferERC20Tokens(
 | 
			
		||||
                    order.takerToken,
 | 
			
		||||
                    order.maker,
 | 
			
		||||
                    takerTokenFilledAmount
 | 
			
		||||
                );                
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            // Transfer taker -> maker
 | 
			
		||||
            _transferERC20TokensFrom(
 | 
			
		||||
                order.takerToken,
 | 
			
		||||
                payer,
 | 
			
		||||
                order.maker,
 | 
			
		||||
                takerTokenFilledAmount
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        // Transfer maker -> recipient.
 | 
			
		||||
        _transferERC20TokensFrom(
 | 
			
		||||
            order.makerToken,
 | 
			
		||||
            order.maker,
 | 
			
		||||
            recipient,
 | 
			
		||||
            makerTokenFilledAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the order info for an OTC order.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @return orderInfo Info about the order.
 | 
			
		||||
    function getOtcOrderInfo(LibNativeOrder.OtcOrder memory order)
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        view
 | 
			
		||||
        returns (LibNativeOrder.OtcOrderInfo memory orderInfo)
 | 
			
		||||
    {
 | 
			
		||||
        // compute order hash.
 | 
			
		||||
        orderInfo.orderHash = getOtcOrderHash(order);
 | 
			
		||||
 | 
			
		||||
        LibOtcOrdersStorage.Storage storage stor =
 | 
			
		||||
            LibOtcOrdersStorage.getStorage();
 | 
			
		||||
 | 
			
		||||
        // Unpack expiry and nonce fields
 | 
			
		||||
        uint64 expiry = uint64(order.expiryAndNonce >> 192);
 | 
			
		||||
        uint64 nonceBucket = uint64(order.expiryAndNonce >> 128);
 | 
			
		||||
        uint128 nonce = uint128(order.expiryAndNonce);
 | 
			
		||||
 | 
			
		||||
        // check tx origin nonce
 | 
			
		||||
        uint128 lastNonce = stor.txOriginNonces
 | 
			
		||||
            [order.txOrigin]
 | 
			
		||||
            [nonceBucket];
 | 
			
		||||
        if (nonce <= lastNonce) {
 | 
			
		||||
            orderInfo.status = LibNativeOrder.OrderStatus.INVALID;
 | 
			
		||||
            return orderInfo;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check for expiration.
 | 
			
		||||
        if (expiry <= uint64(block.timestamp)) {
 | 
			
		||||
            orderInfo.status = LibNativeOrder.OrderStatus.EXPIRED;
 | 
			
		||||
            return orderInfo;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        orderInfo.status = LibNativeOrder.OrderStatus.FILLABLE;
 | 
			
		||||
        return orderInfo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the canonical hash of an OTC order.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @return orderHash The order hash.
 | 
			
		||||
    function getOtcOrderHash(LibNativeOrder.OtcOrder memory order)
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes32 orderHash)
 | 
			
		||||
    {
 | 
			
		||||
        return _getEIP712Hash(
 | 
			
		||||
            LibNativeOrder.getOtcOrderStructHash(order)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the last nonce used for a particular
 | 
			
		||||
    ///      tx.origin address and nonce bucket.
 | 
			
		||||
    /// @param txOrigin The address.
 | 
			
		||||
    /// @param nonceBucket The nonce bucket index.
 | 
			
		||||
    /// @return lastNonce The last nonce value used.
 | 
			
		||||
    function lastOtcTxOriginNonce(address txOrigin, uint64 nonceBucket)
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint128 lastNonce)
 | 
			
		||||
    {
 | 
			
		||||
        LibOtcOrdersStorage.Storage storage stor =
 | 
			
		||||
            LibOtcOrdersStorage.getStorage();
 | 
			
		||||
        return stor.txOriginNonces
 | 
			
		||||
            [txOrigin]
 | 
			
		||||
            [nonceBucket];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _transferEth(address recipient, uint256 amount)
 | 
			
		||||
        private
 | 
			
		||||
    {
 | 
			
		||||
        // Transfer ETH to recipient
 | 
			
		||||
        (bool success, bytes memory revertData) =
 | 
			
		||||
            recipient.call{value: amount}("");
 | 
			
		||||
        // Revert on failure
 | 
			
		||||
        if (!success) {
 | 
			
		||||
            revertData.rrevert();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
 | 
			
		||||
import "../errors/LibTransformERC20RichErrors.sol";
 | 
			
		||||
@@ -51,16 +52,14 @@ contract TransformERC20Feature is
 | 
			
		||||
    struct TransformERC20PrivateState {
 | 
			
		||||
        IFlashWallet wallet;
 | 
			
		||||
        address transformerDeployer;
 | 
			
		||||
        uint256 takerOutputTokenBalanceBefore;
 | 
			
		||||
        uint256 takerOutputTokenBalanceAfter;
 | 
			
		||||
        uint256 recipientOutputTokenBalanceBefore;
 | 
			
		||||
        uint256 recipientOutputTokenBalanceAfter;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Name of this feature.
 | 
			
		||||
    string public constant override FEATURE_NAME = "TransformERC20";
 | 
			
		||||
    /// @dev Version of this feature.
 | 
			
		||||
    uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 3, 1);
 | 
			
		||||
 | 
			
		||||
    constructor() public {}
 | 
			
		||||
    uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 4, 0);
 | 
			
		||||
 | 
			
		||||
    /// @dev Initialize and register this feature.
 | 
			
		||||
    ///      Should be delegatecalled by `Migrate.migrate()`.
 | 
			
		||||
@@ -76,7 +75,7 @@ contract TransformERC20Feature is
 | 
			
		||||
        _registerFeatureFunction(this.setTransformerDeployer.selector);
 | 
			
		||||
        _registerFeatureFunction(this.setQuoteSigner.selector);
 | 
			
		||||
        _registerFeatureFunction(this.getQuoteSigner.selector);
 | 
			
		||||
        _registerFeatureFunction(this.transformERC20.selector);
 | 
			
		||||
        _registerFeatureFunction(this.transformERC20Staging.selector);
 | 
			
		||||
        _registerFeatureFunction(this._transformERC20.selector);
 | 
			
		||||
        if (this.getTransformWallet() == IFlashWallet(address(0))) {
 | 
			
		||||
            // Create the transform wallet if it doesn't exist.
 | 
			
		||||
@@ -146,6 +145,44 @@ contract TransformERC20Feature is
 | 
			
		||||
        LibTransformERC20Storage.getStorage().wallet = wallet;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Wrapper for `transformERC20`. This selector will be temporarily
 | 
			
		||||
    ///      registered to the Exchange Proxy so that we can migrate 0x API
 | 
			
		||||
    ///      with no downtime. Once 0x API has been updated to point to this
 | 
			
		||||
    ///      function, we can safely re-register `transformERC20`, point 
 | 
			
		||||
    ///      0x API back to `transformERC20`, and deregister this function.
 | 
			
		||||
    /// @param inputToken The token being provided by the sender.
 | 
			
		||||
    ///        If `0xeee...`, ETH is implied and should be provided with the call.`
 | 
			
		||||
    /// @param outputToken The token to be acquired by the sender.
 | 
			
		||||
    ///        `0xeee...` implies ETH.
 | 
			
		||||
    /// @param inputTokenAmount The amount of `inputToken` to take from the sender.
 | 
			
		||||
    ///        If set to `uint256(-1)`, the entire spendable balance of the taker
 | 
			
		||||
    ///        will be solt.
 | 
			
		||||
    /// @param minOutputTokenAmount The minimum amount of `outputToken` the sender
 | 
			
		||||
    ///        must receive for the entire transformation to succeed. If set to zero,
 | 
			
		||||
    ///        the minimum output token transfer will not be asserted.
 | 
			
		||||
    /// @param transformations The transformations to execute on the token balance(s)
 | 
			
		||||
    ///        in sequence.
 | 
			
		||||
    /// @return outputTokenAmount The amount of `outputToken` received by the sender.
 | 
			
		||||
    function transformERC20Staging(
 | 
			
		||||
        IERC20TokenV06 inputToken,
 | 
			
		||||
        IERC20TokenV06 outputToken,
 | 
			
		||||
        uint256 inputTokenAmount,
 | 
			
		||||
        uint256 minOutputTokenAmount,
 | 
			
		||||
        Transformation[] memory transformations
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 outputTokenAmount)
 | 
			
		||||
    {
 | 
			
		||||
        return transformERC20(
 | 
			
		||||
            inputToken, 
 | 
			
		||||
            outputToken, 
 | 
			
		||||
            inputTokenAmount, 
 | 
			
		||||
            minOutputTokenAmount, 
 | 
			
		||||
            transformations
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes a series of transformations to convert an ERC20 `inputToken`
 | 
			
		||||
    ///      to an ERC20 `outputToken`.
 | 
			
		||||
    /// @param inputToken The token being provided by the sender.
 | 
			
		||||
@@ -180,7 +217,9 @@ contract TransformERC20Feature is
 | 
			
		||||
                outputToken: outputToken,
 | 
			
		||||
                inputTokenAmount: inputTokenAmount,
 | 
			
		||||
                minOutputTokenAmount: minOutputTokenAmount,
 | 
			
		||||
                transformations: transformations
 | 
			
		||||
                transformations: transformations,
 | 
			
		||||
                useSelfBalance: false,
 | 
			
		||||
                recipient: msg.sender
 | 
			
		||||
            })
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
@@ -208,7 +247,7 @@ contract TransformERC20Feature is
 | 
			
		||||
    {
 | 
			
		||||
        // If the input token amount is -1 and we are not selling ETH,
 | 
			
		||||
        // transform the taker's entire spendable balance.
 | 
			
		||||
        if (args.inputTokenAmount == uint256(-1)) {
 | 
			
		||||
        if (!args.useSelfBalance && args.inputTokenAmount == uint256(-1)) {
 | 
			
		||||
            if (LibERC20Transformer.isTokenETH(args.inputToken)) {
 | 
			
		||||
                // We can't pull more ETH from the taker, so we just set the
 | 
			
		||||
                // input token amount to the value attached to the call.
 | 
			
		||||
@@ -225,17 +264,12 @@ contract TransformERC20Feature is
 | 
			
		||||
        state.wallet = getTransformWallet();
 | 
			
		||||
        state.transformerDeployer = getTransformerDeployer();
 | 
			
		||||
 | 
			
		||||
        // Remember the initial output token balance of the taker.
 | 
			
		||||
        state.takerOutputTokenBalanceBefore =
 | 
			
		||||
            LibERC20Transformer.getTokenBalanceOf(args.outputToken, args.taker);
 | 
			
		||||
        // Remember the initial output token balance of the recipient.
 | 
			
		||||
        state.recipientOutputTokenBalanceBefore =
 | 
			
		||||
            LibERC20Transformer.getTokenBalanceOf(args.outputToken, args.recipient);
 | 
			
		||||
 | 
			
		||||
        // Pull input tokens from the taker to the wallet and transfer attached ETH.
 | 
			
		||||
        _transferInputTokensAndAttachedEth(
 | 
			
		||||
            args.inputToken,
 | 
			
		||||
            args.taker,
 | 
			
		||||
            address(state.wallet),
 | 
			
		||||
            args.inputTokenAmount
 | 
			
		||||
        );
 | 
			
		||||
        _transferInputTokensAndAttachedEth(args, address(state.wallet));
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            // Perform transformations.
 | 
			
		||||
@@ -244,22 +278,29 @@ contract TransformERC20Feature is
 | 
			
		||||
                    state.wallet,
 | 
			
		||||
                    args.transformations[i],
 | 
			
		||||
                    state.transformerDeployer,
 | 
			
		||||
                    args.taker
 | 
			
		||||
                    args.recipient
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
            // Transfer output tokens from wallet to recipient
 | 
			
		||||
            outputTokenAmount = _executeOutputTokenTransfer(
 | 
			
		||||
                args.outputToken, 
 | 
			
		||||
                state.wallet, 
 | 
			
		||||
                args.recipient
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Compute how much output token has been transferred to the taker.
 | 
			
		||||
        state.takerOutputTokenBalanceAfter =
 | 
			
		||||
            LibERC20Transformer.getTokenBalanceOf(args.outputToken, args.taker);
 | 
			
		||||
        if (state.takerOutputTokenBalanceAfter < state.takerOutputTokenBalanceBefore) {
 | 
			
		||||
        // Compute how much output token has been transferred to the recipient.
 | 
			
		||||
        state.recipientOutputTokenBalanceAfter =
 | 
			
		||||
            LibERC20Transformer.getTokenBalanceOf(args.outputToken, args.recipient);
 | 
			
		||||
        if (state.recipientOutputTokenBalanceAfter < state.recipientOutputTokenBalanceBefore) {
 | 
			
		||||
            LibTransformERC20RichErrors.NegativeTransformERC20OutputError(
 | 
			
		||||
                address(args.outputToken),
 | 
			
		||||
                state.takerOutputTokenBalanceBefore - state.takerOutputTokenBalanceAfter
 | 
			
		||||
                state.recipientOutputTokenBalanceBefore - state.recipientOutputTokenBalanceAfter
 | 
			
		||||
            ).rrevert();
 | 
			
		||||
        }
 | 
			
		||||
        outputTokenAmount = state.takerOutputTokenBalanceAfter.safeSub(
 | 
			
		||||
            state.takerOutputTokenBalanceBefore
 | 
			
		||||
        outputTokenAmount = LibSafeMathV06.min256(
 | 
			
		||||
            outputTokenAmount,
 | 
			
		||||
            state.recipientOutputTokenBalanceAfter.safeSub(state.recipientOutputTokenBalanceBefore)
 | 
			
		||||
        );
 | 
			
		||||
        // Ensure enough output token has been sent to the taker.
 | 
			
		||||
        if (outputTokenAmount < args.minOutputTokenAmount) {
 | 
			
		||||
@@ -292,38 +333,49 @@ contract TransformERC20Feature is
 | 
			
		||||
        return LibTransformERC20Storage.getStorage().wallet;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Transfer input tokens from the taker and any attached ETH to `to`
 | 
			
		||||
    /// @param inputToken The token to pull from the taker.
 | 
			
		||||
    /// @param from The from (taker) address.
 | 
			
		||||
    /// @dev Transfer input tokens and any attached ETH to `to`
 | 
			
		||||
    /// @param args A `TransformERC20Args` struct.
 | 
			
		||||
    /// @param to The recipient of tokens and ETH.
 | 
			
		||||
    /// @param amount Amount of `inputToken` tokens to transfer.
 | 
			
		||||
    function _transferInputTokensAndAttachedEth(
 | 
			
		||||
        IERC20TokenV06 inputToken,
 | 
			
		||||
        address from,
 | 
			
		||||
        address payable to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
        TransformERC20Args memory args,
 | 
			
		||||
        address payable to
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
    {
 | 
			
		||||
        if (
 | 
			
		||||
            LibERC20Transformer.isTokenETH(args.inputToken) &&
 | 
			
		||||
            msg.value < args.inputTokenAmount
 | 
			
		||||
        ) {
 | 
			
		||||
             // Token is ETH, so the caller must attach enough ETH to the call.
 | 
			
		||||
            LibTransformERC20RichErrors.InsufficientEthAttachedError(
 | 
			
		||||
                msg.value,
 | 
			
		||||
                args.inputTokenAmount
 | 
			
		||||
            ).rrevert();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Transfer any attached ETH.
 | 
			
		||||
        if (msg.value != 0) {
 | 
			
		||||
            to.transfer(msg.value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Transfer input tokens.
 | 
			
		||||
        if (!LibERC20Transformer.isTokenETH(inputToken) && amount != 0) {
 | 
			
		||||
            // Token is not ETH, so pull ERC20 tokens.
 | 
			
		||||
            _transferERC20Tokens(
 | 
			
		||||
                inputToken,
 | 
			
		||||
                from,
 | 
			
		||||
                to,
 | 
			
		||||
                amount
 | 
			
		||||
            );
 | 
			
		||||
        } else if (msg.value < amount) {
 | 
			
		||||
             // Token is ETH, so the caller must attach enough ETH to the call.
 | 
			
		||||
            LibTransformERC20RichErrors.InsufficientEthAttachedError(
 | 
			
		||||
                msg.value,
 | 
			
		||||
                amount
 | 
			
		||||
            ).rrevert();
 | 
			
		||||
        if (!LibERC20Transformer.isTokenETH(args.inputToken)) {
 | 
			
		||||
            if (args.useSelfBalance) {
 | 
			
		||||
                // Use EP balance input token.
 | 
			
		||||
                _transferERC20Tokens(
 | 
			
		||||
                    args.inputToken,
 | 
			
		||||
                    to,
 | 
			
		||||
                    args.inputTokenAmount
 | 
			
		||||
                );
 | 
			
		||||
            } else {
 | 
			
		||||
                // Pull ERC20 tokens from taker.
 | 
			
		||||
                _transferERC20TokensFrom(
 | 
			
		||||
                    args.inputToken,
 | 
			
		||||
                    args.taker,
 | 
			
		||||
                    to,
 | 
			
		||||
                    args.inputTokenAmount
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -331,12 +383,12 @@ contract TransformERC20Feature is
 | 
			
		||||
    /// @param wallet The wallet instance.
 | 
			
		||||
    /// @param transformation The transformation.
 | 
			
		||||
    /// @param transformerDeployer The address of the transformer deployer.
 | 
			
		||||
    /// @param taker The taker address.
 | 
			
		||||
    /// @param recipient The recipient address.
 | 
			
		||||
    function _executeTransformation(
 | 
			
		||||
        IFlashWallet wallet,
 | 
			
		||||
        Transformation memory transformation,
 | 
			
		||||
        address transformerDeployer,
 | 
			
		||||
        address payable taker
 | 
			
		||||
        address payable recipient
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
    {
 | 
			
		||||
@@ -354,7 +406,7 @@ contract TransformERC20Feature is
 | 
			
		||||
                IERC20Transformer.transform.selector,
 | 
			
		||||
                IERC20Transformer.TransformContext({
 | 
			
		||||
                    sender: msg.sender,
 | 
			
		||||
                    taker: taker,
 | 
			
		||||
                    recipient: recipient,
 | 
			
		||||
                    data: transformation.data
 | 
			
		||||
                })
 | 
			
		||||
            )
 | 
			
		||||
@@ -370,4 +422,52 @@ contract TransformERC20Feature is
 | 
			
		||||
            ).rrevert();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _executeOutputTokenTransfer(
 | 
			
		||||
        IERC20TokenV06 outputToken,
 | 
			
		||||
        IFlashWallet wallet,
 | 
			
		||||
        address payable recipient
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        returns (uint256 transferAmount)
 | 
			
		||||
    {
 | 
			
		||||
        transferAmount =
 | 
			
		||||
            LibERC20Transformer.getTokenBalanceOf(outputToken, address(wallet));
 | 
			
		||||
        if (LibERC20Transformer.isTokenETH(outputToken)) {
 | 
			
		||||
            wallet.executeCall(
 | 
			
		||||
                recipient,
 | 
			
		||||
                "",
 | 
			
		||||
                transferAmount
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            bytes memory resultData = wallet.executeCall(
 | 
			
		||||
                payable(address(outputToken)),
 | 
			
		||||
                abi.encodeWithSelector(
 | 
			
		||||
                    IERC20TokenV06.transfer.selector,
 | 
			
		||||
                    recipient,
 | 
			
		||||
                    transferAmount
 | 
			
		||||
                ),
 | 
			
		||||
                0
 | 
			
		||||
            );
 | 
			
		||||
            if (resultData.length == 0) {
 | 
			
		||||
                // If we get back 0 returndata, this may be a non-standard ERC-20 that
 | 
			
		||||
                // does not return a boolean. Check that it at least contains code.
 | 
			
		||||
                uint256 size;
 | 
			
		||||
                assembly { size := extcodesize(outputToken) }
 | 
			
		||||
                require(size > 0, "invalid token address, contains no code");
 | 
			
		||||
            } else if (resultData.length >= 32) {
 | 
			
		||||
                // If we get back at least 32 bytes, we know the target address
 | 
			
		||||
                // contains code, and we assume it is a token that returned a boolean
 | 
			
		||||
                // success value, which must be true.
 | 
			
		||||
                uint256 result = LibBytesV06.readUint256(resultData, 0);
 | 
			
		||||
                if (result != 1) {
 | 
			
		||||
                    LibRichErrorsV06.rrevert(resultData);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                // If 0 < returndatasize < 32, the target is a contract, but not a
 | 
			
		||||
                // valid token.
 | 
			
		||||
                LibRichErrorsV06.rrevert(resultData);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										447
									
								
								contracts/zero-ex/contracts/src/features/UniswapV3Feature.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										447
									
								
								contracts/zero-ex/contracts/src/features/UniswapV3Feature.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,447 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2021 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6.5;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
 | 
			
		||||
import "../vendor/IUniswapV3Pool.sol";
 | 
			
		||||
import "../migrations/LibMigrate.sol";
 | 
			
		||||
import "../fixins/FixinCommon.sol";
 | 
			
		||||
import "../fixins/FixinTokenSpender.sol";
 | 
			
		||||
import "./interfaces/IFeature.sol";
 | 
			
		||||
import "./interfaces/IUniswapV3Feature.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev VIP uniswap fill functions.
 | 
			
		||||
contract UniswapV3Feature is
 | 
			
		||||
    IFeature,
 | 
			
		||||
    IUniswapV3Feature,
 | 
			
		||||
    FixinCommon,
 | 
			
		||||
    FixinTokenSpender
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Name of this feature.
 | 
			
		||||
    string public constant override FEATURE_NAME = "UniswapV3Feature";
 | 
			
		||||
    /// @dev Version of this feature.
 | 
			
		||||
    uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 0);
 | 
			
		||||
    /// @dev WETH contract.
 | 
			
		||||
    IEtherTokenV06 private immutable WETH;
 | 
			
		||||
    /// @dev UniswapV3 Factory contract address prepended with '0xff' and left-aligned.
 | 
			
		||||
    bytes32 private immutable UNI_FF_FACTORY_ADDRESS;
 | 
			
		||||
    /// @dev UniswapV3 pool init code hash.
 | 
			
		||||
    bytes32 private immutable UNI_POOL_INIT_CODE_HASH;
 | 
			
		||||
    /// @dev Minimum size of an encoded swap path:
 | 
			
		||||
    ///      sizeof(address(inputToken) | uint24(fee) | address(outputToken))
 | 
			
		||||
    uint256 private constant SINGLE_HOP_PATH_SIZE = 20 + 3 + 20;
 | 
			
		||||
    /// @dev How many bytes to skip ahead in an encoded path to start at the next hop:
 | 
			
		||||
    ///      sizeof(address(inputToken) | uint24(fee))
 | 
			
		||||
    uint256 private constant PATH_SKIP_HOP_SIZE = 20 + 3;
 | 
			
		||||
    /// @dev The size of the swap callback data.
 | 
			
		||||
    uint256 private constant SWAP_CALLBACK_DATA_SIZE = 128;
 | 
			
		||||
    /// @dev Minimum tick price sqrt ratio.
 | 
			
		||||
    uint160 internal constant MIN_PRICE_SQRT_RATIO = 4295128739;
 | 
			
		||||
    /// @dev Minimum tick price sqrt ratio.
 | 
			
		||||
    uint160 internal constant MAX_PRICE_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
 | 
			
		||||
    /// @dev Mask of lower 20 bytes.
 | 
			
		||||
    uint256 private constant ADDRESS_MASK = 0x00ffffffffffffffffffffffffffffffffffffffff;
 | 
			
		||||
    /// @dev Mask of lower 3 bytes.
 | 
			
		||||
    uint256 private constant UINT24_MASK = 0xffffff;
 | 
			
		||||
 | 
			
		||||
    /// @dev Construct this contract.
 | 
			
		||||
    /// @param weth The WETH contract.
 | 
			
		||||
    /// @param uniFactory The UniswapV3 factory contract.
 | 
			
		||||
    /// @param poolInitCodeHash The UniswapV3 pool init code hash.
 | 
			
		||||
    constructor(
 | 
			
		||||
        IEtherTokenV06 weth,
 | 
			
		||||
        address uniFactory,
 | 
			
		||||
        bytes32 poolInitCodeHash
 | 
			
		||||
    ) public {
 | 
			
		||||
        WETH = weth;
 | 
			
		||||
        UNI_FF_FACTORY_ADDRESS = bytes32((uint256(0xff) << 248) | (uint256(uniFactory) << 88));
 | 
			
		||||
        UNI_POOL_INIT_CODE_HASH = poolInitCodeHash;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Initialize and register this feature.
 | 
			
		||||
    ///      Should be delegatecalled by `Migrate.migrate()`.
 | 
			
		||||
    /// @return success `LibMigrate.SUCCESS` on success.
 | 
			
		||||
    function migrate()
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        _registerFeatureFunction(this.sellEthForTokenToUniswapV3.selector);
 | 
			
		||||
        _registerFeatureFunction(this.sellTokenForEthToUniswapV3.selector);
 | 
			
		||||
        _registerFeatureFunction(this.sellTokenForTokenToUniswapV3.selector);
 | 
			
		||||
        _registerFeatureFunction(this._sellHeldTokenForTokenToUniswapV3.selector);
 | 
			
		||||
        _registerFeatureFunction(this.uniswapV3SwapCallback.selector);
 | 
			
		||||
        return LibMigrate.MIGRATE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sell attached ETH directly against uniswap v3.
 | 
			
		||||
    /// @param encodedPath Uniswap-encoded path, where the first token is WETH.
 | 
			
		||||
    /// @param recipient The recipient of the bought tokens. Can be zero for sender.
 | 
			
		||||
    /// @param minBuyAmount Minimum amount of the last token in the path to buy.
 | 
			
		||||
    /// @return buyAmount Amount of the last token in the path bought.
 | 
			
		||||
    function sellEthForTokenToUniswapV3(
 | 
			
		||||
        bytes memory encodedPath,
 | 
			
		||||
        uint256 minBuyAmount,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        payable
 | 
			
		||||
        override
 | 
			
		||||
        returns (uint256 buyAmount)
 | 
			
		||||
    {
 | 
			
		||||
        // Wrap ETH.
 | 
			
		||||
        WETH.deposit{ value: msg.value }();
 | 
			
		||||
        return _swap(
 | 
			
		||||
            encodedPath,
 | 
			
		||||
            msg.value,
 | 
			
		||||
            minBuyAmount,
 | 
			
		||||
            address(this), // we are payer because we hold the WETH
 | 
			
		||||
            _normalizeRecipient(recipient)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sell a token for ETH directly against uniswap v3.
 | 
			
		||||
    /// @param encodedPath Uniswap-encoded path, where the last token is WETH.
 | 
			
		||||
    /// @param sellAmount amount of the first token in the path to sell.
 | 
			
		||||
    /// @param minBuyAmount Minimum amount of ETH to buy.
 | 
			
		||||
    /// @param recipient The recipient of the bought tokens. Can be zero for sender.
 | 
			
		||||
    /// @return buyAmount Amount of ETH bought.
 | 
			
		||||
    function sellTokenForEthToUniswapV3(
 | 
			
		||||
        bytes memory encodedPath,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount,
 | 
			
		||||
        address payable recipient
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        returns (uint256 buyAmount)
 | 
			
		||||
    {
 | 
			
		||||
        buyAmount = _swap(
 | 
			
		||||
            encodedPath,
 | 
			
		||||
            sellAmount,
 | 
			
		||||
            minBuyAmount,
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            address(this) // we are recipient because we need to unwrap WETH
 | 
			
		||||
        );
 | 
			
		||||
        WETH.withdraw(buyAmount);
 | 
			
		||||
        // Transfer ETH to recipient.
 | 
			
		||||
        (bool success, bytes memory revertData) =
 | 
			
		||||
            _normalizeRecipient(recipient).call{ value: buyAmount }("");
 | 
			
		||||
        if (!success) {
 | 
			
		||||
            revertData.rrevert();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sell a token for another token directly against uniswap v3.
 | 
			
		||||
    /// @param encodedPath Uniswap-encoded path.
 | 
			
		||||
    /// @param sellAmount amount of the first token in the path to sell.
 | 
			
		||||
    /// @param minBuyAmount Minimum amount of the last token in the path to buy.
 | 
			
		||||
    /// @param recipient The recipient of the bought tokens. Can be zero for sender.
 | 
			
		||||
    /// @return buyAmount Amount of the last token in the path bought.
 | 
			
		||||
    function sellTokenForTokenToUniswapV3(
 | 
			
		||||
        bytes memory encodedPath,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        returns (uint256 buyAmount)
 | 
			
		||||
    {
 | 
			
		||||
        buyAmount = _swap(
 | 
			
		||||
            encodedPath,
 | 
			
		||||
            sellAmount,
 | 
			
		||||
            minBuyAmount,
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            _normalizeRecipient(recipient)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sell a token for another token directly against uniswap v3.
 | 
			
		||||
    ///      Private variant, uses tokens held by `address(this)`.
 | 
			
		||||
    /// @param encodedPath Uniswap-encoded path.
 | 
			
		||||
    /// @param sellAmount amount of the first token in the path to sell.
 | 
			
		||||
    /// @param minBuyAmount Minimum amount of the last token in the path to buy.
 | 
			
		||||
    /// @param recipient The recipient of the bought tokens. Can be zero for sender.
 | 
			
		||||
    /// @return buyAmount Amount of the last token in the path bought.
 | 
			
		||||
    function _sellHeldTokenForTokenToUniswapV3(
 | 
			
		||||
        bytes memory encodedPath,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        onlySelf
 | 
			
		||||
        returns (uint256 buyAmount)
 | 
			
		||||
    {
 | 
			
		||||
        buyAmount = _swap(
 | 
			
		||||
            encodedPath,
 | 
			
		||||
            sellAmount,
 | 
			
		||||
            minBuyAmount,
 | 
			
		||||
            address(this),
 | 
			
		||||
            _normalizeRecipient(recipient)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev The UniswapV3 pool swap callback which pays the funds requested
 | 
			
		||||
    ///      by the caller/pool to the pool. Can only be called by a valid
 | 
			
		||||
    ///      UniswapV3 pool.
 | 
			
		||||
    /// @param amount0Delta Token0 amount owed.
 | 
			
		||||
    /// @param amount1Delta Token1 amount owed.
 | 
			
		||||
    /// @param data Arbitrary data forwarded from swap() caller. An ABI-encoded
 | 
			
		||||
    ///        struct of: inputToken, outputToken, fee, payer
 | 
			
		||||
    function uniswapV3SwapCallback(
 | 
			
		||||
        int256 amount0Delta,
 | 
			
		||||
        int256 amount1Delta,
 | 
			
		||||
        bytes calldata data
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        override
 | 
			
		||||
    {
 | 
			
		||||
        IERC20TokenV06 token0;
 | 
			
		||||
        IERC20TokenV06 token1;
 | 
			
		||||
        address payer;
 | 
			
		||||
        {
 | 
			
		||||
            uint24 fee;
 | 
			
		||||
            // Decode the data.
 | 
			
		||||
            require(data.length == SWAP_CALLBACK_DATA_SIZE, "UniswapFeature/INVALID_SWAP_CALLBACK_DATA");
 | 
			
		||||
            assembly {
 | 
			
		||||
                let p := add(36, calldataload(68))
 | 
			
		||||
                token0 := calldataload(p)
 | 
			
		||||
                token1 := calldataload(add(p, 32))
 | 
			
		||||
                fee := calldataload(add(p, 64))
 | 
			
		||||
                payer := calldataload(add(p, 96))
 | 
			
		||||
            }
 | 
			
		||||
            (token0, token1) = token0 < token1
 | 
			
		||||
                ? (token0, token1)
 | 
			
		||||
                : (token1, token0);
 | 
			
		||||
            // Only a valid pool contract can call this function.
 | 
			
		||||
            require(
 | 
			
		||||
                msg.sender == address(_toPool(token0, fee, token1)),
 | 
			
		||||
                "UniswapV3Feature/INVALID_SWAP_CALLBACK_CALLER"
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        // Pay the amount owed to the pool.
 | 
			
		||||
        if (amount0Delta > 0) {
 | 
			
		||||
            _pay(token0, payer, msg.sender, uint256(amount0Delta));
 | 
			
		||||
        } else if (amount1Delta > 0) {
 | 
			
		||||
            _pay(token1, payer, msg.sender, uint256(amount1Delta));
 | 
			
		||||
        } else {
 | 
			
		||||
            revert("UniswapV3Feature/INVALID_SWAP_AMOUNTS");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Executes successive swaps along an encoded uniswap path.
 | 
			
		||||
    function _swap(
 | 
			
		||||
        bytes memory encodedPath,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount,
 | 
			
		||||
        address payer,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        returns (uint256 buyAmount)
 | 
			
		||||
    {
 | 
			
		||||
        if (sellAmount != 0) {
 | 
			
		||||
            require(sellAmount <= uint256(type(int256).max), "UniswapV3Feature/SELL_AMOUNT_OVERFLOW");
 | 
			
		||||
 | 
			
		||||
            // Perform a swap for each hop in the path.
 | 
			
		||||
            bytes memory swapCallbackData = new bytes(SWAP_CALLBACK_DATA_SIZE);
 | 
			
		||||
            while (true) {
 | 
			
		||||
                bool isPathMultiHop = _isPathMultiHop(encodedPath);
 | 
			
		||||
                bool zeroForOne;
 | 
			
		||||
                IUniswapV3Pool pool;
 | 
			
		||||
                {
 | 
			
		||||
                    (
 | 
			
		||||
                        IERC20TokenV06 inputToken,
 | 
			
		||||
                        uint24 fee,
 | 
			
		||||
                        IERC20TokenV06 outputToken
 | 
			
		||||
                    ) = _decodeFirstPoolInfoFromPath(encodedPath);
 | 
			
		||||
                    pool = _toPool(inputToken, fee, outputToken);
 | 
			
		||||
                    zeroForOne = inputToken < outputToken;
 | 
			
		||||
                    _updateSwapCallbackData(
 | 
			
		||||
                        swapCallbackData,
 | 
			
		||||
                        inputToken,
 | 
			
		||||
                        outputToken,
 | 
			
		||||
                        fee,
 | 
			
		||||
                        payer
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
                (int256 amount0, int256 amount1) = pool.swap(
 | 
			
		||||
                    // Intermediate tokens go to this contract.
 | 
			
		||||
                    isPathMultiHop ? address(this) : recipient,
 | 
			
		||||
                    zeroForOne,
 | 
			
		||||
                    int256(sellAmount),
 | 
			
		||||
                    zeroForOne
 | 
			
		||||
                        ? MIN_PRICE_SQRT_RATIO + 1
 | 
			
		||||
                        : MAX_PRICE_SQRT_RATIO - 1,
 | 
			
		||||
                    swapCallbackData
 | 
			
		||||
                );
 | 
			
		||||
                {
 | 
			
		||||
                    int256 _buyAmount = -(zeroForOne ? amount1 : amount0);
 | 
			
		||||
                    require(_buyAmount >= 0, "UniswapV3Feature/INVALID_BUY_AMOUNT");
 | 
			
		||||
                    buyAmount = uint256(_buyAmount);
 | 
			
		||||
                }
 | 
			
		||||
                if (!isPathMultiHop) {
 | 
			
		||||
                    // Done.
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                // Continue with next hop.
 | 
			
		||||
                payer = address(this); // Subsequent hops are paid for by us.
 | 
			
		||||
                sellAmount = buyAmount;
 | 
			
		||||
                // Skip to next hop along path.
 | 
			
		||||
                encodedPath = _shiftHopFromPathInPlace(encodedPath);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        require(minBuyAmount <= buyAmount, "UniswapV3Feature/UNDERBOUGHT");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Pay tokens from `payer` to `to`, using `transferFrom()` if
 | 
			
		||||
    // `payer` != this contract.
 | 
			
		||||
    function _pay(
 | 
			
		||||
        IERC20TokenV06 token,
 | 
			
		||||
        address payer,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
    {
 | 
			
		||||
        if (payer != address(this)) {
 | 
			
		||||
            _transferERC20TokensFrom(token, payer, to, amount);
 | 
			
		||||
        } else {
 | 
			
		||||
            _transferERC20Tokens(token, to, amount);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Update `swapCallbackData` in place with new values.
 | 
			
		||||
    function _updateSwapCallbackData(
 | 
			
		||||
        bytes memory swapCallbackData,
 | 
			
		||||
        IERC20TokenV06 inputToken,
 | 
			
		||||
        IERC20TokenV06 outputToken,
 | 
			
		||||
        uint24 fee,
 | 
			
		||||
        address payer
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        pure
 | 
			
		||||
    {
 | 
			
		||||
        assembly {
 | 
			
		||||
            let p := add(swapCallbackData, 32)
 | 
			
		||||
            mstore(p, inputToken)
 | 
			
		||||
            mstore(add(p, 32), outputToken)
 | 
			
		||||
            mstore(add(p, 64), and(UINT24_MASK, fee))
 | 
			
		||||
            mstore(add(p, 96), and(ADDRESS_MASK, payer))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Compute the pool address given two tokens and a fee.
 | 
			
		||||
    function _toPool(
 | 
			
		||||
        IERC20TokenV06 inputToken,
 | 
			
		||||
        uint24 fee,
 | 
			
		||||
        IERC20TokenV06 outputToken
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (IUniswapV3Pool pool)
 | 
			
		||||
    {
 | 
			
		||||
        // address(keccak256(abi.encodePacked(
 | 
			
		||||
        //     hex"ff",
 | 
			
		||||
        //     UNI_FACTORY_ADDRESS,
 | 
			
		||||
        //     keccak256(abi.encode(inputToken, outputToken, fee)),
 | 
			
		||||
        //     UNI_POOL_INIT_CODE_HASH
 | 
			
		||||
        // )))
 | 
			
		||||
        bytes32 ffFactoryAddress = UNI_FF_FACTORY_ADDRESS;
 | 
			
		||||
        bytes32 poolInitCodeHash = UNI_POOL_INIT_CODE_HASH;
 | 
			
		||||
        (IERC20TokenV06 token0, IERC20TokenV06 token1) = inputToken < outputToken
 | 
			
		||||
            ? (inputToken, outputToken)
 | 
			
		||||
            : (outputToken, inputToken);
 | 
			
		||||
        assembly {
 | 
			
		||||
            let s := mload(0x40)
 | 
			
		||||
            let p := s
 | 
			
		||||
            mstore(p, ffFactoryAddress)
 | 
			
		||||
            p := add(p, 21)
 | 
			
		||||
            // Compute the inner hash in-place
 | 
			
		||||
                mstore(p, token0)
 | 
			
		||||
                mstore(add(p, 32), token1)
 | 
			
		||||
                mstore(add(p, 64), and(UINT24_MASK, fee))
 | 
			
		||||
                mstore(p, keccak256(p, 96))
 | 
			
		||||
            p := add(p, 32)
 | 
			
		||||
            mstore(p, poolInitCodeHash)
 | 
			
		||||
            pool := and(ADDRESS_MASK, keccak256(s, 85))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Return whether or not an encoded uniswap path contains more than one hop.
 | 
			
		||||
    function _isPathMultiHop(bytes memory encodedPath)
 | 
			
		||||
        private
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bool isMultiHop)
 | 
			
		||||
    {
 | 
			
		||||
        return encodedPath.length > SINGLE_HOP_PATH_SIZE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Return the first input token, output token, and fee of an encoded uniswap path.
 | 
			
		||||
    function _decodeFirstPoolInfoFromPath(bytes memory encodedPath)
 | 
			
		||||
        private
 | 
			
		||||
        pure
 | 
			
		||||
        returns (
 | 
			
		||||
            IERC20TokenV06 inputToken,
 | 
			
		||||
            uint24 fee,
 | 
			
		||||
            IERC20TokenV06 outputToken
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        require(encodedPath.length >= SINGLE_HOP_PATH_SIZE, "UniswapV3Feature/BAD_PATH_ENCODING");
 | 
			
		||||
        assembly {
 | 
			
		||||
            let p := add(encodedPath, 32)
 | 
			
		||||
            inputToken := shr(96, mload(p))
 | 
			
		||||
            p := add(p, 20)
 | 
			
		||||
            fee := shr(232, mload(p))
 | 
			
		||||
            p := add(p, 3)
 | 
			
		||||
            outputToken := shr(96, mload(p))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Skip past the first hop of an encoded uniswap path in-place.
 | 
			
		||||
    function _shiftHopFromPathInPlace(bytes memory encodedPath)
 | 
			
		||||
        private
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes memory shiftedEncodedPath)
 | 
			
		||||
    {
 | 
			
		||||
        require(encodedPath.length >= PATH_SKIP_HOP_SIZE, "UniswapV3Feature/BAD_PATH_ENCODING");
 | 
			
		||||
        uint256 shiftSize = PATH_SKIP_HOP_SIZE;
 | 
			
		||||
        uint256 newSize = encodedPath.length - shiftSize;
 | 
			
		||||
        assembly {
 | 
			
		||||
            shiftedEncodedPath := add(encodedPath, shiftSize)
 | 
			
		||||
            mstore(shiftedEncodedPath, newSize)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Convert null address values to msg.sender.
 | 
			
		||||
    function _normalizeRecipient(address recipient)
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (address payable normalizedRecipient)
 | 
			
		||||
    {
 | 
			
		||||
        return recipient == address(0) ? msg.sender : payable(recipient);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -24,9 +24,21 @@ import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IMultiplexFeature {
 | 
			
		||||
    // Identifies the type of subcall.
 | 
			
		||||
    enum MultiplexSubcall {
 | 
			
		||||
        Invalid,
 | 
			
		||||
        RFQ,
 | 
			
		||||
        OTC,
 | 
			
		||||
        UniswapV2,
 | 
			
		||||
        UniswapV3,
 | 
			
		||||
        LiquidityProvider,
 | 
			
		||||
        TransformERC20,
 | 
			
		||||
        BatchSell,
 | 
			
		||||
        MultiHopSell
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Parameters for `batchFill`.
 | 
			
		||||
    struct BatchFillData {
 | 
			
		||||
    // Parameters for a batch sell.
 | 
			
		||||
    struct BatchSellParams {
 | 
			
		||||
        // The token being sold.
 | 
			
		||||
        IERC20TokenV06 inputToken;
 | 
			
		||||
        // The token being bought.
 | 
			
		||||
@@ -34,84 +46,182 @@ interface IMultiplexFeature {
 | 
			
		||||
        // The amount of `inputToken` to sell.
 | 
			
		||||
        uint256 sellAmount;
 | 
			
		||||
        // The nested calls to perform.
 | 
			
		||||
        WrappedBatchCall[] calls;
 | 
			
		||||
        BatchSellSubcall[] calls;
 | 
			
		||||
        // Whether to use the Exchange Proxy's balance
 | 
			
		||||
        // of input tokens.
 | 
			
		||||
        bool useSelfBalance;
 | 
			
		||||
        // The recipient of the bought output tokens.
 | 
			
		||||
        address recipient;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Represents a call nested within a `batchFill`.
 | 
			
		||||
    struct WrappedBatchCall {
 | 
			
		||||
        // The selector of the function to call.
 | 
			
		||||
        bytes4 selector;
 | 
			
		||||
        // Amount of `inputToken` to sell.
 | 
			
		||||
    // Represents a constituent call of a batch sell.
 | 
			
		||||
    struct BatchSellSubcall {
 | 
			
		||||
        // The function to call.
 | 
			
		||||
        MultiplexSubcall id;
 | 
			
		||||
        // Amount of input token to sell. If the highest bit is 1,
 | 
			
		||||
        // this value represents a proportion of the total
 | 
			
		||||
        // `sellAmount` of the batch sell. See `_normalizeSellAmount`
 | 
			
		||||
        // for details.
 | 
			
		||||
        uint256 sellAmount;
 | 
			
		||||
        // ABI-encoded parameters needed to perform the call.
 | 
			
		||||
        bytes data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Parameters for `multiHopFill`.
 | 
			
		||||
    struct MultiHopFillData {
 | 
			
		||||
    // Parameters for a multi-hop sell.
 | 
			
		||||
    struct MultiHopSellParams {
 | 
			
		||||
        // The sell path, i.e.
 | 
			
		||||
        // tokens = [inputToken, hopToken1, ..., hopTokenN, outputToken]
 | 
			
		||||
        address[] tokens;
 | 
			
		||||
        // The amount of `tokens[0]` to sell.
 | 
			
		||||
        uint256 sellAmount;
 | 
			
		||||
        // The nested calls to perform.
 | 
			
		||||
        WrappedMultiHopCall[] calls;
 | 
			
		||||
        MultiHopSellSubcall[] calls;
 | 
			
		||||
        // Whether to use the Exchange Proxy's balance
 | 
			
		||||
        // of input tokens.
 | 
			
		||||
        bool useSelfBalance;
 | 
			
		||||
        // The recipient of the bought output tokens.
 | 
			
		||||
        address recipient;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Represents a call nested within a `multiHopFill`.
 | 
			
		||||
    struct WrappedMultiHopCall {
 | 
			
		||||
        // The selector of the function to call.
 | 
			
		||||
        bytes4 selector;
 | 
			
		||||
    // Represents a constituent call of a multi-hop sell.
 | 
			
		||||
    struct MultiHopSellSubcall {
 | 
			
		||||
        // The function to call.
 | 
			
		||||
        MultiplexSubcall id;
 | 
			
		||||
        // ABI-encoded parameters needed to perform the call.
 | 
			
		||||
        bytes data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    event LiquidityProviderSwap(
 | 
			
		||||
        address inputToken,
 | 
			
		||||
        address outputToken,
 | 
			
		||||
        uint256 inputTokenAmount,
 | 
			
		||||
        uint256 outputTokenAmount,
 | 
			
		||||
        address provider,
 | 
			
		||||
        address recipient
 | 
			
		||||
    );
 | 
			
		||||
    struct BatchSellState {
 | 
			
		||||
        // Tracks the amount of input token sold.
 | 
			
		||||
        uint256 soldAmount;
 | 
			
		||||
        // Tracks the amount of output token bought.
 | 
			
		||||
        uint256 boughtAmount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    event ExpiredRfqOrder(
 | 
			
		||||
        bytes32 orderHash,
 | 
			
		||||
        address maker,
 | 
			
		||||
        uint64 expiry
 | 
			
		||||
    );
 | 
			
		||||
    struct MultiHopSellState {
 | 
			
		||||
        // This variable is used for the input and output amounts of
 | 
			
		||||
        // each hop. After the final hop, this will contain the output
 | 
			
		||||
        // amount of the multi-hop sell.
 | 
			
		||||
        uint256 outputTokenAmount;
 | 
			
		||||
        // For each hop in a multi-hop sell, `from` is the
 | 
			
		||||
        // address that holds the input tokens of the hop,
 | 
			
		||||
        // `to` is the address that receives the output tokens
 | 
			
		||||
        // of the hop.
 | 
			
		||||
        // See `_computeHopTarget` for details.
 | 
			
		||||
        address from;
 | 
			
		||||
        address to;
 | 
			
		||||
        // The index of the current hop in the multi-hop chain.
 | 
			
		||||
        uint256 hopIndex;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes a batch of fills selling `fillData.inputToken`
 | 
			
		||||
    ///      for `fillData.outputToken` in sequence. Refer to the
 | 
			
		||||
    ///      internal variant `_batchFill` for the allowed nested
 | 
			
		||||
    ///      operations.
 | 
			
		||||
    /// @param fillData Encodes the input/output tokens, the sell
 | 
			
		||||
    ///        amount, and the nested operations for this batch fill.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of `fillData.outputToken`
 | 
			
		||||
    ///        to buy. Reverts if this amount is not met.
 | 
			
		||||
    /// @return outputTokenAmount The amount of the output token bought.
 | 
			
		||||
    function batchFill(
 | 
			
		||||
        BatchFillData calldata fillData,
 | 
			
		||||
    /// @dev Sells attached ETH for `outputToken` using the provided
 | 
			
		||||
    ///      calls.
 | 
			
		||||
    /// @param outputToken The token to buy.
 | 
			
		||||
    /// @param calls The calls to use to sell the attached ETH.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of `outputToken` that
 | 
			
		||||
    ///        must be bought for this function to not revert.
 | 
			
		||||
    /// @return boughtAmount The amount of `outputToken` bought.
 | 
			
		||||
    function multiplexBatchSellEthForToken(
 | 
			
		||||
        IERC20TokenV06 outputToken,
 | 
			
		||||
        BatchSellSubcall[] calldata calls,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 outputTokenAmount);
 | 
			
		||||
        returns (uint256 boughtAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes a sequence of fills "hopping" through the
 | 
			
		||||
    ///      path of tokens given by `fillData.tokens`. Refer to the
 | 
			
		||||
    ///      internal variant `_multiHopFill` for the allowed nested
 | 
			
		||||
    ///      operations.
 | 
			
		||||
    /// @param fillData Encodes the path of tokens, the sell amount,
 | 
			
		||||
    ///        and the nested operations for this multi-hop fill.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of the output token
 | 
			
		||||
    ///        to buy. Reverts if this amount is not met.
 | 
			
		||||
    /// @return outputTokenAmount The amount of the output token bought.
 | 
			
		||||
    function multiHopFill(
 | 
			
		||||
        MultiHopFillData calldata fillData,
 | 
			
		||||
    /// @dev Sells `sellAmount` of the given `inputToken` for ETH
 | 
			
		||||
    ///      using the provided calls.
 | 
			
		||||
    /// @param inputToken The token to sell.
 | 
			
		||||
    /// @param calls The calls to use to sell the input tokens.
 | 
			
		||||
    /// @param sellAmount The amount of `inputToken` to sell.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of ETH that
 | 
			
		||||
    ///        must be bought for this function to not revert.
 | 
			
		||||
    /// @return boughtAmount The amount of ETH bought.
 | 
			
		||||
    function multiplexBatchSellTokenForEth(
 | 
			
		||||
        IERC20TokenV06 inputToken,
 | 
			
		||||
        BatchSellSubcall[] calldata calls,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 boughtAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Sells `sellAmount` of the given `inputToken` for
 | 
			
		||||
    ///      `outputToken` using the provided calls.
 | 
			
		||||
    /// @param inputToken The token to sell.
 | 
			
		||||
    /// @param outputToken The token to buy.
 | 
			
		||||
    /// @param calls The calls to use to sell the input tokens.
 | 
			
		||||
    /// @param sellAmount The amount of `inputToken` to sell.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of `outputToken`
 | 
			
		||||
    ///        that must be bought for this function to not revert.
 | 
			
		||||
    /// @return boughtAmount The amount of `outputToken` bought.
 | 
			
		||||
    function multiplexBatchSellTokenForToken(
 | 
			
		||||
        IERC20TokenV06 inputToken,
 | 
			
		||||
        IERC20TokenV06 outputToken,
 | 
			
		||||
        BatchSellSubcall[] calldata calls,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 boughtAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Sells attached ETH via the given sequence of tokens
 | 
			
		||||
    ///      and calls. `tokens[0]` must be WETH.
 | 
			
		||||
    ///      The last token in `tokens` is the output token that
 | 
			
		||||
    ///      will ultimately be sent to `msg.sender`
 | 
			
		||||
    /// @param tokens The sequence of tokens to use for the sell,
 | 
			
		||||
    ///        i.e. `tokens[i]` will be sold for `tokens[i+1]` via
 | 
			
		||||
    ///        `calls[i]`.
 | 
			
		||||
    /// @param calls The sequence of calls to use for the sell.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of output tokens that
 | 
			
		||||
    ///        must be bought for this function to not revert.
 | 
			
		||||
    /// @return boughtAmount The amount of output tokens bought.
 | 
			
		||||
    function multiplexMultiHopSellEthForToken(
 | 
			
		||||
        address[] calldata tokens,
 | 
			
		||||
        MultiHopSellSubcall[] calldata calls,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 outputTokenAmount);
 | 
			
		||||
        returns (uint256 boughtAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Sells `sellAmount` of the input token (`tokens[0]`)
 | 
			
		||||
    ///      for ETH via the given sequence of tokens and calls.
 | 
			
		||||
    ///      The last token in `tokens` must be WETH.
 | 
			
		||||
    /// @param tokens The sequence of tokens to use for the sell,
 | 
			
		||||
    ///        i.e. `tokens[i]` will be sold for `tokens[i+1]` via
 | 
			
		||||
    ///        `calls[i]`.
 | 
			
		||||
    /// @param calls The sequence of calls to use for the sell.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of ETH that
 | 
			
		||||
    ///        must be bought for this function to not revert.
 | 
			
		||||
    /// @return boughtAmount The amount of ETH bought.
 | 
			
		||||
    function multiplexMultiHopSellTokenForEth(
 | 
			
		||||
        address[] calldata tokens,
 | 
			
		||||
        MultiHopSellSubcall[] calldata calls,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 boughtAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Sells `sellAmount` of the input token (`tokens[0]`)
 | 
			
		||||
    ///      via the given sequence of tokens and calls.
 | 
			
		||||
    ///      The last token in `tokens` is the output token that
 | 
			
		||||
    ///      will ultimately be sent to `msg.sender`
 | 
			
		||||
    /// @param tokens The sequence of tokens to use for the sell,
 | 
			
		||||
    ///        i.e. `tokens[i]` will be sold for `tokens[i+1]` via
 | 
			
		||||
    ///        `calls[i]`.
 | 
			
		||||
    /// @param calls The sequence of calls to use for the sell.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of output tokens that
 | 
			
		||||
    ///        must be bought for this function to not revert.
 | 
			
		||||
    /// @return boughtAmount The amount of output tokens bought.
 | 
			
		||||
    function multiplexMultiHopSellTokenForToken(
 | 
			
		||||
        address[] calldata tokens,
 | 
			
		||||
        MultiHopSellSubcall[] calldata calls,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 boughtAmount);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -126,13 +126,18 @@ interface INativeOrdersFeature is
 | 
			
		||||
    /// @param signature The order signature.
 | 
			
		||||
    /// @param takerTokenFillAmount Maximum taker token to fill this order with.
 | 
			
		||||
    /// @param taker The order taker.
 | 
			
		||||
    /// @param useSelfBalance Whether to use the ExchangeProxy's transient
 | 
			
		||||
    ///        balance of taker tokens to fill the order.
 | 
			
		||||
    /// @param recipient The recipient of the maker tokens.
 | 
			
		||||
    /// @return takerTokenFilledAmount How much maker token was filled.
 | 
			
		||||
    /// @return makerTokenFilledAmount How much maker token was filled.
 | 
			
		||||
    function _fillRfqOrder(
 | 
			
		||||
        LibNativeOrder.RfqOrder calldata order,
 | 
			
		||||
        LibSignature.Signature calldata signature,
 | 
			
		||||
        uint128 takerTokenFillAmount,
 | 
			
		||||
        address taker
 | 
			
		||||
        address taker,
 | 
			
		||||
        bool useSelfBalance,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount);
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,184 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2021 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6.5;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "../libs/LibNativeOrder.sol";
 | 
			
		||||
import "../libs/LibSignature.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev Feature for interacting with OTC orders.
 | 
			
		||||
interface IOtcOrdersFeature {
 | 
			
		||||
 | 
			
		||||
    /// @dev Emitted whenever an `OtcOrder` is filled.
 | 
			
		||||
    /// @param orderHash The canonical hash of the order.
 | 
			
		||||
    /// @param maker The maker of the order.
 | 
			
		||||
    /// @param taker The taker of the order.
 | 
			
		||||
    /// @param makerTokenFilledAmount How much maker token was filled.
 | 
			
		||||
    /// @param takerTokenFilledAmount How much taker token was filled.
 | 
			
		||||
    event OtcOrderFilled(
 | 
			
		||||
        bytes32 orderHash,
 | 
			
		||||
        address maker,
 | 
			
		||||
        address taker,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        uint128 makerTokenFilledAmount,
 | 
			
		||||
        uint128 takerTokenFilledAmount
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /// @dev Fill an OTC order for up to `takerTokenFillAmount` taker tokens.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @param makerSignature The order signature from the maker.
 | 
			
		||||
    /// @param takerTokenFillAmount Maximum taker token amount to fill this
 | 
			
		||||
    ///        order with.
 | 
			
		||||
    /// @return takerTokenFilledAmount How much taker token was filled.
 | 
			
		||||
    /// @return makerTokenFilledAmount How much maker token was filled.
 | 
			
		||||
    function fillOtcOrder(
 | 
			
		||||
        LibNativeOrder.OtcOrder calldata order,
 | 
			
		||||
        LibSignature.Signature calldata makerSignature,
 | 
			
		||||
        uint128 takerTokenFillAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Fill an OTC order for up to `takerTokenFillAmount` taker tokens.
 | 
			
		||||
    ///      Unwraps bought WETH into ETH before sending it to 
 | 
			
		||||
    ///      the taker.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @param makerSignature The order signature from the maker.
 | 
			
		||||
    /// @param takerTokenFillAmount Maximum taker token amount to fill this
 | 
			
		||||
    ///        order with.
 | 
			
		||||
    /// @return takerTokenFilledAmount How much taker token was filled.
 | 
			
		||||
    /// @return makerTokenFilledAmount How much maker token was filled.
 | 
			
		||||
    function fillOtcOrderForEth(
 | 
			
		||||
        LibNativeOrder.OtcOrder calldata order,
 | 
			
		||||
        LibSignature.Signature calldata makerSignature,
 | 
			
		||||
        uint128 takerTokenFillAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Fill an OTC order whose taker token is WETH for up
 | 
			
		||||
    ///      to `msg.value`.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @param makerSignature The order signature from the maker.
 | 
			
		||||
    /// @return takerTokenFilledAmount How much taker token was filled.
 | 
			
		||||
    /// @return makerTokenFilledAmount How much maker token was filled.
 | 
			
		||||
    function fillOtcOrderWithEth(
 | 
			
		||||
        LibNativeOrder.OtcOrder calldata order,
 | 
			
		||||
        LibSignature.Signature calldata makerSignature
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Fully fill an OTC order. "Meta-transaction" variant,
 | 
			
		||||
    ///      requires order to be signed by both maker and taker.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @param makerSignature The order signature from the maker.
 | 
			
		||||
    /// @param takerSignature The order signature from the taker.
 | 
			
		||||
    function fillTakerSignedOtcOrder(
 | 
			
		||||
        LibNativeOrder.OtcOrder calldata order,
 | 
			
		||||
        LibSignature.Signature calldata makerSignature,
 | 
			
		||||
        LibSignature.Signature calldata takerSignature
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Fully fill an OTC order. "Meta-transaction" variant,
 | 
			
		||||
    ///      requires order to be signed by both maker and taker.
 | 
			
		||||
    ///      Unwraps bought WETH into ETH before sending it to 
 | 
			
		||||
    ///      the taker.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @param makerSignature The order signature from the maker.
 | 
			
		||||
    /// @param takerSignature The order signature from the taker.
 | 
			
		||||
    function fillTakerSignedOtcOrderForEth(
 | 
			
		||||
        LibNativeOrder.OtcOrder calldata order,
 | 
			
		||||
        LibSignature.Signature calldata makerSignature,
 | 
			
		||||
        LibSignature.Signature calldata takerSignature
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Fills multiple taker-signed OTC orders.
 | 
			
		||||
    /// @param orders Array of OTC orders.
 | 
			
		||||
    /// @param makerSignatures Array of maker signatures for each order.
 | 
			
		||||
    /// @param takerSignatures Array of taker signatures for each order.
 | 
			
		||||
    /// @param unwrapWeth Array of booleans representing whether or not 
 | 
			
		||||
    ///        to unwrap bought WETH into ETH for each order. Should be set 
 | 
			
		||||
    ///        to false if the maker token is not WETH.
 | 
			
		||||
    /// @return successes Array of booleans representing whether or not
 | 
			
		||||
    ///         each order in `orders` was filled successfully.
 | 
			
		||||
    function batchFillTakerSignedOtcOrders(
 | 
			
		||||
        LibNativeOrder.OtcOrder[] calldata orders,
 | 
			
		||||
        LibSignature.Signature[] calldata makerSignatures,
 | 
			
		||||
        LibSignature.Signature[] calldata takerSignatures,
 | 
			
		||||
        bool[] calldata unwrapWeth
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool[] memory successes);
 | 
			
		||||
 | 
			
		||||
    /// @dev Fill an OTC order for up to `takerTokenFillAmount` taker tokens.
 | 
			
		||||
    ///      Internal variant.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @param makerSignature The order signature from the maker.
 | 
			
		||||
    /// @param takerTokenFillAmount Maximum taker token amount to fill this
 | 
			
		||||
    ///        order with.
 | 
			
		||||
    /// @param taker The address to fill the order in the context of.
 | 
			
		||||
    /// @param useSelfBalance Whether to use the Exchange Proxy's balance
 | 
			
		||||
    ///        of input tokens.
 | 
			
		||||
    /// @param recipient The recipient of the bought maker tokens.
 | 
			
		||||
    /// @return takerTokenFilledAmount How much taker token was filled.
 | 
			
		||||
    /// @return makerTokenFilledAmount How much maker token was filled.
 | 
			
		||||
    function _fillOtcOrder(
 | 
			
		||||
        LibNativeOrder.OtcOrder calldata order,
 | 
			
		||||
        LibSignature.Signature calldata makerSignature,
 | 
			
		||||
        uint128 takerTokenFillAmount,
 | 
			
		||||
        address taker,
 | 
			
		||||
        bool useSelfBalance,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the order info for an OTC order.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @return orderInfo Info about the order.
 | 
			
		||||
    function getOtcOrderInfo(LibNativeOrder.OtcOrder calldata order)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (LibNativeOrder.OtcOrderInfo memory orderInfo);
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the canonical hash of an OTC order.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @return orderHash The order hash.
 | 
			
		||||
    function getOtcOrderHash(LibNativeOrder.OtcOrder calldata order)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes32 orderHash);
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the last nonce used for a particular
 | 
			
		||||
    ///      tx.origin address and nonce bucket.
 | 
			
		||||
    /// @param txOrigin The address.
 | 
			
		||||
    /// @param nonceBucket The nonce bucket index.
 | 
			
		||||
    /// @return lastNonce The last nonce value used.
 | 
			
		||||
    function lastOtcTxOriginNonce(address txOrigin, uint64 nonceBucket)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint128 lastNonce);
 | 
			
		||||
}
 | 
			
		||||
@@ -59,6 +59,10 @@ interface ITransformERC20Feature {
 | 
			
		||||
        // The transformations to execute on the token balance(s)
 | 
			
		||||
        // in sequence.
 | 
			
		||||
        Transformation[] transformations;
 | 
			
		||||
        // Whether to use the Exchange Proxy's balance of `inputToken`.
 | 
			
		||||
        bool useSelfBalance;
 | 
			
		||||
        // The recipient of the bought `outputToken`.
 | 
			
		||||
        address payable recipient;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Raised upon a successful `transformERC20`.
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,102 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6.5;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev VIP uniswap v3 fill functions.
 | 
			
		||||
interface IUniswapV3Feature {
 | 
			
		||||
 | 
			
		||||
    /// @dev Sell attached ETH directly against uniswap v3.
 | 
			
		||||
    /// @param encodedPath Uniswap-encoded path, where the first token is WETH.
 | 
			
		||||
    /// @param minBuyAmount Minimum amount of the last token in the path to buy.
 | 
			
		||||
    /// @param recipient The recipient of the bought tokens. Can be zero for sender.
 | 
			
		||||
    /// @return buyAmount Amount of the last token in the path bought.
 | 
			
		||||
    function sellEthForTokenToUniswapV3(
 | 
			
		||||
        bytes memory encodedPath,
 | 
			
		||||
        uint256 minBuyAmount,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 buyAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Sell a token for ETH directly against uniswap v3.
 | 
			
		||||
    /// @param encodedPath Uniswap-encoded path, where the last token is WETH.
 | 
			
		||||
    /// @param sellAmount amount of the first token in the path to sell.
 | 
			
		||||
    /// @param minBuyAmount Minimum amount of ETH to buy.
 | 
			
		||||
    /// @param recipient The recipient of the bought tokens. Can be zero for sender.
 | 
			
		||||
    /// @return buyAmount Amount of ETH bought.
 | 
			
		||||
    function sellTokenForEthToUniswapV3(
 | 
			
		||||
        bytes memory encodedPath,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount,
 | 
			
		||||
        address payable recipient
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 buyAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Sell a token for another token directly against uniswap v3.
 | 
			
		||||
    /// @param encodedPath Uniswap-encoded path.
 | 
			
		||||
    /// @param sellAmount amount of the first token in the path to sell.
 | 
			
		||||
    /// @param minBuyAmount Minimum amount of the last token in the path to buy.
 | 
			
		||||
    /// @param recipient The recipient of the bought tokens. Can be zero for sender.
 | 
			
		||||
    /// @return buyAmount Amount of the last token in the path bought.
 | 
			
		||||
    function sellTokenForTokenToUniswapV3(
 | 
			
		||||
        bytes memory encodedPath,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 buyAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Sell a token for another token directly against uniswap v3.
 | 
			
		||||
    ///      Private variant, uses tokens held by `address(this)`.
 | 
			
		||||
    /// @param encodedPath Uniswap-encoded path.
 | 
			
		||||
    /// @param sellAmount amount of the first token in the path to sell.
 | 
			
		||||
    /// @param minBuyAmount Minimum amount of the last token in the path to buy.
 | 
			
		||||
    /// @param recipient The recipient of the bought tokens. Can be zero for sender.
 | 
			
		||||
    /// @return buyAmount Amount of the last token in the path bought.
 | 
			
		||||
    function _sellHeldTokenForTokenToUniswapV3(
 | 
			
		||||
        bytes memory encodedPath,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 buyAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev The UniswapV3 pool swap callback which pays the funds requested
 | 
			
		||||
    ///      by the caller/pool to the pool. Can only be called by a valid
 | 
			
		||||
    ///      UniswapV3 pool.
 | 
			
		||||
    /// @param amount0Delta Token0 amount owed.
 | 
			
		||||
    /// @param amount1Delta Token1 amount owed.
 | 
			
		||||
    /// @param data Arbitrary data forwarded from swap() caller. An ABI-encoded
 | 
			
		||||
    ///        struct of: inputToken, outputToken, fee, payer
 | 
			
		||||
    function uniswapV3SwapCallback(
 | 
			
		||||
        int256 amount0Delta,
 | 
			
		||||
        int256 amount1Delta,
 | 
			
		||||
        bytes calldata data
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
}
 | 
			
		||||
@@ -69,6 +69,18 @@ library LibNativeOrder {
 | 
			
		||||
        uint256 salt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev An OTC limit order.
 | 
			
		||||
    struct OtcOrder {
 | 
			
		||||
        IERC20TokenV06 makerToken;
 | 
			
		||||
        IERC20TokenV06 takerToken;
 | 
			
		||||
        uint128 makerAmount;
 | 
			
		||||
        uint128 takerAmount;
 | 
			
		||||
        address maker;
 | 
			
		||||
        address taker;
 | 
			
		||||
        address txOrigin;
 | 
			
		||||
        uint256 expiryAndNonce; // [uint64 expiry, uint64 nonceBucket, uint128 nonce]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Info on a limit or RFQ order.
 | 
			
		||||
    struct OrderInfo {
 | 
			
		||||
        bytes32 orderHash;
 | 
			
		||||
@@ -76,6 +88,12 @@ library LibNativeOrder {
 | 
			
		||||
        uint128 takerTokenFilledAmount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Info on an OTC order.
 | 
			
		||||
    struct OtcOrderInfo {
 | 
			
		||||
        bytes32 orderHash;
 | 
			
		||||
        OrderStatus status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint256 private constant UINT_128_MASK = (1 << 128) - 1;
 | 
			
		||||
    uint256 private constant UINT_64_MASK = (1 << 64) - 1;
 | 
			
		||||
    uint256 private constant ADDRESS_MASK = (1 << 160) - 1;
 | 
			
		||||
@@ -118,6 +136,22 @@ library LibNativeOrder {
 | 
			
		||||
    uint256 private constant _RFQ_ORDER_TYPEHASH =
 | 
			
		||||
        0xe593d3fdfa8b60e5e17a1b2204662ecbe15c23f2084b9ad5bae40359540a7da9;
 | 
			
		||||
 | 
			
		||||
    // The type hash for OTC orders, which is:
 | 
			
		||||
    // keccak256(abi.encodePacked(
 | 
			
		||||
    //     "OtcOrder(",
 | 
			
		||||
    //       "address makerToken,",
 | 
			
		||||
    //       "address takerToken,",
 | 
			
		||||
    //       "uint128 makerAmount,",
 | 
			
		||||
    //       "uint128 takerAmount,",
 | 
			
		||||
    //       "address maker,",
 | 
			
		||||
    //       "address taker,",
 | 
			
		||||
    //       "address txOrigin,",
 | 
			
		||||
    //       "uint256 expiryAndNonce"
 | 
			
		||||
    //     ")"
 | 
			
		||||
    // ))
 | 
			
		||||
    uint256 private constant _OTC_ORDER_TYPEHASH =
 | 
			
		||||
        0x2f754524de756ae72459efbe1ec88c19a745639821de528ac3fb88f9e65e35c8;
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the struct hash of a limit order.
 | 
			
		||||
    /// @param order The limit order.
 | 
			
		||||
    /// @return structHash The struct hash of the order.
 | 
			
		||||
@@ -222,6 +256,49 @@ library LibNativeOrder {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the struct hash of an OTC order.
 | 
			
		||||
    /// @param order The OTC order.
 | 
			
		||||
    /// @return structHash The struct hash of the order.
 | 
			
		||||
    function getOtcOrderStructHash(OtcOrder memory order)
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes32 structHash)
 | 
			
		||||
    {
 | 
			
		||||
        // The struct hash is:
 | 
			
		||||
        // keccak256(abi.encode(
 | 
			
		||||
        //   TYPE_HASH,
 | 
			
		||||
        //   order.makerToken,
 | 
			
		||||
        //   order.takerToken,
 | 
			
		||||
        //   order.makerAmount,
 | 
			
		||||
        //   order.takerAmount,
 | 
			
		||||
        //   order.maker,
 | 
			
		||||
        //   order.taker,
 | 
			
		||||
        //   order.txOrigin,
 | 
			
		||||
        //   order.expiryAndNonce,
 | 
			
		||||
        // ))
 | 
			
		||||
        assembly {
 | 
			
		||||
            let mem := mload(0x40)
 | 
			
		||||
            mstore(mem, _OTC_ORDER_TYPEHASH)
 | 
			
		||||
            // order.makerToken;
 | 
			
		||||
            mstore(add(mem, 0x20), and(ADDRESS_MASK, mload(order)))
 | 
			
		||||
            // order.takerToken;
 | 
			
		||||
            mstore(add(mem, 0x40), and(ADDRESS_MASK, mload(add(order, 0x20))))
 | 
			
		||||
            // order.makerAmount;
 | 
			
		||||
            mstore(add(mem, 0x60), and(UINT_128_MASK, mload(add(order, 0x40))))
 | 
			
		||||
            // order.takerAmount;
 | 
			
		||||
            mstore(add(mem, 0x80), and(UINT_128_MASK, mload(add(order, 0x60))))
 | 
			
		||||
            // order.maker;
 | 
			
		||||
            mstore(add(mem, 0xA0), and(ADDRESS_MASK, mload(add(order, 0x80))))
 | 
			
		||||
            // order.taker;
 | 
			
		||||
            mstore(add(mem, 0xC0), and(ADDRESS_MASK, mload(add(order, 0xA0))))
 | 
			
		||||
            // order.txOrigin;
 | 
			
		||||
            mstore(add(mem, 0xE0), and(ADDRESS_MASK, mload(add(order, 0xC0))))
 | 
			
		||||
            // order.expiryAndNonce;
 | 
			
		||||
            mstore(add(mem, 0x100), mload(add(order, 0xE0)))
 | 
			
		||||
            structHash := keccak256(mem, 0x120)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Refund any leftover protocol fees in `msg.value` to `msg.sender`.
 | 
			
		||||
    /// @param ethProtocolFeePaid How much ETH was paid in protocol fees.
 | 
			
		||||
    function refundExcessProtocolFeeToSender(uint256 ethProtocolFeePaid)
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,742 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2021 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6.5;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
 | 
			
		||||
import "../../external/ILiquidityProviderSandbox.sol";
 | 
			
		||||
import "../../fixins/FixinCommon.sol";
 | 
			
		||||
import "../../fixins/FixinEIP712.sol";
 | 
			
		||||
import "../../migrations/LibMigrate.sol";
 | 
			
		||||
import "../interfaces/IFeature.sol";
 | 
			
		||||
import "../interfaces/IMultiplexFeature.sol";
 | 
			
		||||
import "./MultiplexLiquidityProvider.sol";
 | 
			
		||||
import "./MultiplexOtc.sol";
 | 
			
		||||
import "./MultiplexRfq.sol";
 | 
			
		||||
import "./MultiplexTransformERC20.sol";
 | 
			
		||||
import "./MultiplexUniswapV2.sol";
 | 
			
		||||
import "./MultiplexUniswapV3.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev This feature enables efficient batch and multi-hop trades
 | 
			
		||||
///      using different liquidity sources.
 | 
			
		||||
contract MultiplexFeature is
 | 
			
		||||
    IFeature,
 | 
			
		||||
    IMultiplexFeature,
 | 
			
		||||
    FixinCommon,
 | 
			
		||||
    MultiplexLiquidityProvider,
 | 
			
		||||
    MultiplexOtc,
 | 
			
		||||
    MultiplexRfq,
 | 
			
		||||
    MultiplexTransformERC20,
 | 
			
		||||
    MultiplexUniswapV2,
 | 
			
		||||
    MultiplexUniswapV3
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Name of this feature.
 | 
			
		||||
    string public constant override FEATURE_NAME = "MultiplexFeature";
 | 
			
		||||
    /// @dev Version of this feature.
 | 
			
		||||
    uint256 public immutable override FEATURE_VERSION = _encodeVersion(2, 0, 0);
 | 
			
		||||
    /// @dev The highest bit of a uint256 value.
 | 
			
		||||
    uint256 private constant HIGH_BIT = 2 ** 255;
 | 
			
		||||
    /// @dev Mask of the lower 255 bits of a uint256 value.
 | 
			
		||||
    uint256 private constant LOWER_255_BITS = HIGH_BIT - 1;
 | 
			
		||||
 | 
			
		||||
    /// @dev The WETH token contract.
 | 
			
		||||
    IEtherTokenV06 private immutable WETH;
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        address zeroExAddress,
 | 
			
		||||
        IEtherTokenV06 weth,
 | 
			
		||||
        ILiquidityProviderSandbox sandbox,
 | 
			
		||||
        address uniswapFactory,
 | 
			
		||||
        address sushiswapFactory,
 | 
			
		||||
        bytes32 uniswapPairInitCodeHash,
 | 
			
		||||
        bytes32 sushiswapPairInitCodeHash
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        FixinEIP712(zeroExAddress)
 | 
			
		||||
        MultiplexLiquidityProvider(sandbox)
 | 
			
		||||
        MultiplexUniswapV2(
 | 
			
		||||
            uniswapFactory,
 | 
			
		||||
            sushiswapFactory,
 | 
			
		||||
            uniswapPairInitCodeHash,
 | 
			
		||||
            sushiswapPairInitCodeHash
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        WETH = weth;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Initialize and register this feature.
 | 
			
		||||
    ///      Should be delegatecalled by `Migrate.migrate()`.
 | 
			
		||||
    /// @return success `LibMigrate.SUCCESS` on success.
 | 
			
		||||
    function migrate()
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        _registerFeatureFunction(this.multiplexBatchSellEthForToken.selector);
 | 
			
		||||
        _registerFeatureFunction(this.multiplexBatchSellTokenForEth.selector);
 | 
			
		||||
        _registerFeatureFunction(this.multiplexBatchSellTokenForToken.selector);
 | 
			
		||||
        _registerFeatureFunction(this.multiplexMultiHopSellEthForToken.selector);
 | 
			
		||||
        _registerFeatureFunction(this.multiplexMultiHopSellTokenForEth.selector);
 | 
			
		||||
        _registerFeatureFunction(this.multiplexMultiHopSellTokenForToken.selector);
 | 
			
		||||
        return LibMigrate.MIGRATE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sells attached ETH for `outputToken` using the provided
 | 
			
		||||
    ///      calls.
 | 
			
		||||
    /// @param outputToken The token to buy.
 | 
			
		||||
    /// @param calls The calls to use to sell the attached ETH.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of `outputToken` that
 | 
			
		||||
    ///        must be bought for this function to not revert.
 | 
			
		||||
    /// @return boughtAmount The amount of `outputToken` bought.
 | 
			
		||||
    function multiplexBatchSellEthForToken(
 | 
			
		||||
        IERC20TokenV06 outputToken,
 | 
			
		||||
        BatchSellSubcall[] memory calls,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 boughtAmount)
 | 
			
		||||
    {
 | 
			
		||||
        // Wrap ETH.
 | 
			
		||||
        WETH.deposit{value: msg.value}();
 | 
			
		||||
        // WETH is now held by this contract,
 | 
			
		||||
        // so `useSelfBalance` is true.
 | 
			
		||||
        return _multiplexBatchSell(
 | 
			
		||||
            BatchSellParams({
 | 
			
		||||
                inputToken: WETH,
 | 
			
		||||
                outputToken: outputToken,
 | 
			
		||||
                sellAmount: msg.value,
 | 
			
		||||
                calls: calls,
 | 
			
		||||
                useSelfBalance: true,
 | 
			
		||||
                recipient: msg.sender
 | 
			
		||||
            }),
 | 
			
		||||
            minBuyAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sells `sellAmount` of the given `inputToken` for ETH
 | 
			
		||||
    ///      using the provided calls.
 | 
			
		||||
    /// @param inputToken The token to sell.
 | 
			
		||||
    /// @param calls The calls to use to sell the input tokens.
 | 
			
		||||
    /// @param sellAmount The amount of `inputToken` to sell.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of ETH that
 | 
			
		||||
    ///        must be bought for this function to not revert.
 | 
			
		||||
    /// @return boughtAmount The amount of ETH bought.
 | 
			
		||||
    function multiplexBatchSellTokenForEth(
 | 
			
		||||
        IERC20TokenV06 inputToken,
 | 
			
		||||
        BatchSellSubcall[] memory calls,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        returns (uint256 boughtAmount)
 | 
			
		||||
    {
 | 
			
		||||
        // The outputToken is implicitly WETH. The `recipient`
 | 
			
		||||
        // of the WETH is set to  this contract, since we
 | 
			
		||||
        // must unwrap the WETH and transfer the resulting ETH.
 | 
			
		||||
        boughtAmount = _multiplexBatchSell(
 | 
			
		||||
            BatchSellParams({
 | 
			
		||||
                inputToken: inputToken,
 | 
			
		||||
                outputToken: WETH,
 | 
			
		||||
                sellAmount: sellAmount,
 | 
			
		||||
                calls: calls,
 | 
			
		||||
                useSelfBalance: false,
 | 
			
		||||
                recipient: address(this)
 | 
			
		||||
            }),
 | 
			
		||||
            minBuyAmount
 | 
			
		||||
        );
 | 
			
		||||
        // Unwrap WETH.
 | 
			
		||||
        WETH.withdraw(boughtAmount);
 | 
			
		||||
        // Transfer ETH to `msg.sender`.
 | 
			
		||||
        _transferEth(msg.sender, boughtAmount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sells `sellAmount` of the given `inputToken` for
 | 
			
		||||
    ///      `outputToken` using the provided calls.
 | 
			
		||||
    /// @param inputToken The token to sell.
 | 
			
		||||
    /// @param outputToken The token to buy.
 | 
			
		||||
    /// @param calls The calls to use to sell the input tokens.
 | 
			
		||||
    /// @param sellAmount The amount of `inputToken` to sell.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of `outputToken`
 | 
			
		||||
    ///        that must be bought for this function to not revert.
 | 
			
		||||
    /// @return boughtAmount The amount of `outputToken` bought.
 | 
			
		||||
    function multiplexBatchSellTokenForToken(
 | 
			
		||||
        IERC20TokenV06 inputToken,
 | 
			
		||||
        IERC20TokenV06 outputToken,
 | 
			
		||||
        BatchSellSubcall[] memory calls,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        returns (uint256 boughtAmount)
 | 
			
		||||
    {
 | 
			
		||||
        return _multiplexBatchSell(
 | 
			
		||||
            BatchSellParams({
 | 
			
		||||
                inputToken: inputToken,
 | 
			
		||||
                outputToken: outputToken,
 | 
			
		||||
                sellAmount: sellAmount,
 | 
			
		||||
                calls: calls,
 | 
			
		||||
                useSelfBalance: false,
 | 
			
		||||
                recipient: msg.sender
 | 
			
		||||
            }),
 | 
			
		||||
            minBuyAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes a batch sell and checks that at least
 | 
			
		||||
    ///      `minBuyAmount` of `outputToken` was bought.
 | 
			
		||||
    /// @param params Batch sell parameters.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of `outputToken` that
 | 
			
		||||
    ///        must be bought for this function to not revert.
 | 
			
		||||
    /// @return boughtAmount The amount of `outputToken` bought.
 | 
			
		||||
    function _multiplexBatchSell(
 | 
			
		||||
        BatchSellParams memory params,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        returns (uint256 boughtAmount)
 | 
			
		||||
    {
 | 
			
		||||
        // Cache the recipient's initial balance of the output token.
 | 
			
		||||
        uint256 balanceBefore = params.outputToken.balanceOf(params.recipient);
 | 
			
		||||
        // Execute the batch sell.
 | 
			
		||||
        BatchSellState memory state = _executeBatchSell(params);
 | 
			
		||||
        // Compute the change in balance of the output token.
 | 
			
		||||
        uint256 balanceDelta = params.outputToken.balanceOf(params.recipient)
 | 
			
		||||
            .safeSub(balanceBefore);
 | 
			
		||||
        // Use the minimum of the balanceDelta and the returned bought
 | 
			
		||||
        // amount in case of weird tokens and whatnot.
 | 
			
		||||
        boughtAmount = LibSafeMathV06.min256(balanceDelta, state.boughtAmount);
 | 
			
		||||
        // Enforce `minBuyAmount`.
 | 
			
		||||
        require(
 | 
			
		||||
            boughtAmount >= minBuyAmount,
 | 
			
		||||
            "MultiplexFeature::_multiplexBatchSell/UNDERBOUGHT"
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sells attached ETH via the given sequence of tokens
 | 
			
		||||
    ///      and calls. `tokens[0]` must be WETH.
 | 
			
		||||
    ///      The last token in `tokens` is the output token that
 | 
			
		||||
    ///      will ultimately be sent to `msg.sender`
 | 
			
		||||
    /// @param tokens The sequence of tokens to use for the sell,
 | 
			
		||||
    ///        i.e. `tokens[i]` will be sold for `tokens[i+1]` via
 | 
			
		||||
    ///        `calls[i]`.
 | 
			
		||||
    /// @param calls The sequence of calls to use for the sell.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of output tokens that
 | 
			
		||||
    ///        must be bought for this function to not revert.
 | 
			
		||||
    /// @return boughtAmount The amount of output tokens bought.
 | 
			
		||||
    function multiplexMultiHopSellEthForToken(
 | 
			
		||||
        address[] memory tokens,
 | 
			
		||||
        MultiHopSellSubcall[] memory calls,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 boughtAmount)
 | 
			
		||||
    {
 | 
			
		||||
        // First token must be WETH.
 | 
			
		||||
        require(
 | 
			
		||||
            tokens[0] == address(WETH),
 | 
			
		||||
            "MultiplexFeature::multiplexMultiHopSellEthForToken/NOT_WETH"
 | 
			
		||||
        );
 | 
			
		||||
        // Wrap ETH.
 | 
			
		||||
        WETH.deposit{value: msg.value}();
 | 
			
		||||
        // WETH is now held by this contract,
 | 
			
		||||
        // so `useSelfBalance` is true.
 | 
			
		||||
        return _multiplexMultiHopSell(
 | 
			
		||||
            MultiHopSellParams({
 | 
			
		||||
                tokens: tokens,
 | 
			
		||||
                sellAmount: msg.value,
 | 
			
		||||
                calls: calls,
 | 
			
		||||
                useSelfBalance: true,
 | 
			
		||||
                recipient: msg.sender
 | 
			
		||||
            }),
 | 
			
		||||
            minBuyAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sells `sellAmount` of the input token (`tokens[0]`)
 | 
			
		||||
    ///      for ETH via the given sequence of tokens and calls.
 | 
			
		||||
    ///      The last token in `tokens` must be WETH.
 | 
			
		||||
    /// @param tokens The sequence of tokens to use for the sell,
 | 
			
		||||
    ///        i.e. `tokens[i]` will be sold for `tokens[i+1]` via
 | 
			
		||||
    ///        `calls[i]`.
 | 
			
		||||
    /// @param calls The sequence of calls to use for the sell.
 | 
			
		||||
    /// @param sellAmount The amount of `inputToken` to sell.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of ETH that
 | 
			
		||||
    ///        must be bought for this function to not revert.
 | 
			
		||||
    /// @return boughtAmount The amount of ETH bought.
 | 
			
		||||
    function multiplexMultiHopSellTokenForEth(
 | 
			
		||||
        address[] memory tokens,
 | 
			
		||||
        MultiHopSellSubcall[] memory calls,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        returns (uint256 boughtAmount)
 | 
			
		||||
    {
 | 
			
		||||
        // Last token must be WETH.
 | 
			
		||||
        require(
 | 
			
		||||
            tokens[tokens.length - 1] == address(WETH),
 | 
			
		||||
            "MultiplexFeature::multiplexMultiHopSellTokenForEth/NOT_WETH"
 | 
			
		||||
        );
 | 
			
		||||
        // The `recipient of the WETH is set to  this contract, since
 | 
			
		||||
        // we must unwrap the WETH and transfer the resulting ETH.
 | 
			
		||||
        boughtAmount = _multiplexMultiHopSell(
 | 
			
		||||
            MultiHopSellParams({
 | 
			
		||||
                tokens: tokens,
 | 
			
		||||
                sellAmount: sellAmount,
 | 
			
		||||
                calls: calls,
 | 
			
		||||
                useSelfBalance: false,
 | 
			
		||||
                recipient: address(this)
 | 
			
		||||
            }),
 | 
			
		||||
            minBuyAmount
 | 
			
		||||
        );
 | 
			
		||||
        // Unwrap WETH.
 | 
			
		||||
        WETH.withdraw(boughtAmount);
 | 
			
		||||
        // Transfer ETH to `msg.sender`.
 | 
			
		||||
        _transferEth(msg.sender, boughtAmount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sells `sellAmount` of the input token (`tokens[0]`)
 | 
			
		||||
    ///      via the given sequence of tokens and calls.
 | 
			
		||||
    ///      The last token in `tokens` is the output token that
 | 
			
		||||
    ///      will ultimately be sent to `msg.sender`
 | 
			
		||||
    /// @param tokens The sequence of tokens to use for the sell,
 | 
			
		||||
    ///        i.e. `tokens[i]` will be sold for `tokens[i+1]` via
 | 
			
		||||
    ///        `calls[i]`.
 | 
			
		||||
    /// @param calls The sequence of calls to use for the sell.
 | 
			
		||||
    /// @param sellAmount The amount of `inputToken` to sell.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of output tokens that
 | 
			
		||||
    ///        must be bought for this function to not revert.
 | 
			
		||||
    /// @return boughtAmount The amount of output tokens bought.
 | 
			
		||||
    function multiplexMultiHopSellTokenForToken(
 | 
			
		||||
        address[] memory tokens,
 | 
			
		||||
        MultiHopSellSubcall[] memory calls,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        override
 | 
			
		||||
        returns (uint256 boughtAmount)
 | 
			
		||||
    {
 | 
			
		||||
        return _multiplexMultiHopSell(
 | 
			
		||||
            MultiHopSellParams({
 | 
			
		||||
                tokens: tokens,
 | 
			
		||||
                sellAmount: sellAmount,
 | 
			
		||||
                calls: calls,
 | 
			
		||||
                useSelfBalance: false,
 | 
			
		||||
                recipient: msg.sender
 | 
			
		||||
            }),
 | 
			
		||||
            minBuyAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes a multi-hop sell and checks that at least
 | 
			
		||||
    ///      `minBuyAmount` of output tokens were bought.
 | 
			
		||||
    /// @param params Multi-hop sell parameters.
 | 
			
		||||
    /// @param minBuyAmount The minimum amount of output tokens that
 | 
			
		||||
    ///        must be bought for this function to not revert.
 | 
			
		||||
    /// @return boughtAmount The amount of output tokens bought.
 | 
			
		||||
    function _multiplexMultiHopSell(
 | 
			
		||||
        MultiHopSellParams memory params,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        returns (uint256 boughtAmount)
 | 
			
		||||
    {
 | 
			
		||||
        // There should be one call/hop between every two tokens
 | 
			
		||||
        // in the path.
 | 
			
		||||
        // tokens[0]––calls[0]––>tokens[1]––...––calls[n-1]––>tokens[n]
 | 
			
		||||
        require(
 | 
			
		||||
            params.tokens.length == params.calls.length + 1,
 | 
			
		||||
            "MultiplexFeature::_multiplexMultiHopSell/MISMATCHED_ARRAY_LENGTHS"
 | 
			
		||||
        );
 | 
			
		||||
        // The output token is the last token in the path.
 | 
			
		||||
        IERC20TokenV06 outputToken = IERC20TokenV06(
 | 
			
		||||
            params.tokens[params.tokens.length - 1]
 | 
			
		||||
        );
 | 
			
		||||
        // Cache the recipient's balance of the output token.
 | 
			
		||||
        uint256 balanceBefore = outputToken.balanceOf(params.recipient);
 | 
			
		||||
        // Execute the multi-hop sell.
 | 
			
		||||
        MultiHopSellState memory state = _executeMultiHopSell(params);
 | 
			
		||||
        // Compute the change in balance of the output token.
 | 
			
		||||
        uint256 balanceDelta = outputToken.balanceOf(params.recipient)
 | 
			
		||||
            .safeSub(balanceBefore);
 | 
			
		||||
        // Use the minimum of the balanceDelta and the returned bought
 | 
			
		||||
        // amount in case of weird tokens and whatnot.
 | 
			
		||||
        boughtAmount = LibSafeMathV06.min256(balanceDelta, state.outputTokenAmount);
 | 
			
		||||
        // Enforce `minBuyAmount`.
 | 
			
		||||
        require(
 | 
			
		||||
            boughtAmount >= minBuyAmount,
 | 
			
		||||
            "MultiplexFeature::_multiplexMultiHopSell/UNDERBOUGHT"
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Iterates through the constituent calls of a batch
 | 
			
		||||
    ///      sell and executes each one, until the full amount
 | 
			
		||||
    //       has been sold.
 | 
			
		||||
    /// @param params Batch sell parameters.
 | 
			
		||||
    /// @return state A struct containing the amounts of `inputToken`
 | 
			
		||||
    ///         sold and `outputToken` bought.
 | 
			
		||||
    function _executeBatchSell(BatchSellParams memory params)
 | 
			
		||||
        private
 | 
			
		||||
        returns (BatchSellState memory state)
 | 
			
		||||
    {
 | 
			
		||||
        // Iterate through the calls and execute each one
 | 
			
		||||
        // until the full amount has been sold.
 | 
			
		||||
        for (uint256 i = 0; i != params.calls.length; i++) {
 | 
			
		||||
            // Check if we've hit our target.
 | 
			
		||||
            if (state.soldAmount >= params.sellAmount) { break; }
 | 
			
		||||
            BatchSellSubcall memory subcall = params.calls[i];
 | 
			
		||||
            // Compute the input token amount.
 | 
			
		||||
            uint256 inputTokenAmount = _normalizeSellAmount(
 | 
			
		||||
                subcall.sellAmount,
 | 
			
		||||
                params.sellAmount,
 | 
			
		||||
                state.soldAmount
 | 
			
		||||
            );
 | 
			
		||||
            if (subcall.id == MultiplexSubcall.RFQ) {
 | 
			
		||||
                _batchSellRfqOrder(
 | 
			
		||||
                    state,
 | 
			
		||||
                    params,
 | 
			
		||||
                    subcall.data,
 | 
			
		||||
                    inputTokenAmount
 | 
			
		||||
                );
 | 
			
		||||
            } else if (subcall.id == MultiplexSubcall.OTC) {
 | 
			
		||||
                _batchSellOtcOrder(
 | 
			
		||||
                    state,
 | 
			
		||||
                    params,
 | 
			
		||||
                    subcall.data,
 | 
			
		||||
                    inputTokenAmount
 | 
			
		||||
                );
 | 
			
		||||
            } else if (subcall.id == MultiplexSubcall.UniswapV2) {
 | 
			
		||||
                _batchSellUniswapV2(
 | 
			
		||||
                    state,
 | 
			
		||||
                    params,
 | 
			
		||||
                    subcall.data,
 | 
			
		||||
                    inputTokenAmount
 | 
			
		||||
                );
 | 
			
		||||
            } else if (subcall.id == MultiplexSubcall.UniswapV3) {
 | 
			
		||||
                _batchSellUniswapV3(
 | 
			
		||||
                    state,
 | 
			
		||||
                    params,
 | 
			
		||||
                    subcall.data,
 | 
			
		||||
                    inputTokenAmount
 | 
			
		||||
                );
 | 
			
		||||
            } else if (subcall.id == MultiplexSubcall.LiquidityProvider) {
 | 
			
		||||
                _batchSellLiquidityProvider(
 | 
			
		||||
                    state,
 | 
			
		||||
                    params,
 | 
			
		||||
                    subcall.data,
 | 
			
		||||
                    inputTokenAmount
 | 
			
		||||
                );
 | 
			
		||||
            } else if (subcall.id == MultiplexSubcall.TransformERC20) {
 | 
			
		||||
                _batchSellTransformERC20(
 | 
			
		||||
                    state,
 | 
			
		||||
                    params,
 | 
			
		||||
                    subcall.data,
 | 
			
		||||
                    inputTokenAmount
 | 
			
		||||
                );
 | 
			
		||||
            } else if (subcall.id == MultiplexSubcall.MultiHopSell) {
 | 
			
		||||
                _nestedMultiHopSell(
 | 
			
		||||
                    state,
 | 
			
		||||
                    params,
 | 
			
		||||
                    subcall.data,
 | 
			
		||||
                    inputTokenAmount
 | 
			
		||||
                );
 | 
			
		||||
            } else {
 | 
			
		||||
                revert("MultiplexFeature::_executeBatchSell/INVALID_SUBCALL");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        require(
 | 
			
		||||
            state.soldAmount == params.sellAmount,
 | 
			
		||||
            "MultiplexFeature::_executeBatchSell/INCORRECT_AMOUNT_SOLD"
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // This function executes a sequence of fills "hopping" through the
 | 
			
		||||
    // path of tokens given by `params.tokens`.
 | 
			
		||||
    function _executeMultiHopSell(MultiHopSellParams memory params)
 | 
			
		||||
        private
 | 
			
		||||
        returns (MultiHopSellState memory state)
 | 
			
		||||
    {
 | 
			
		||||
        // This variable is used for the input and output amounts of
 | 
			
		||||
        // each hop. After the final hop, this will contain the output
 | 
			
		||||
        // amount of the multi-hop fill.
 | 
			
		||||
        state.outputTokenAmount = params.sellAmount;
 | 
			
		||||
        // The first call may expect the input tokens to be held by
 | 
			
		||||
        // `msg.sender`, `address(this)`, or some other address.
 | 
			
		||||
        // Compute the expected address and transfer the input tokens
 | 
			
		||||
        // there if necessary.
 | 
			
		||||
        state.from = _computeHopTarget(params, 0);
 | 
			
		||||
        // If the input tokens are currently held by `msg.sender` but
 | 
			
		||||
        // the first hop expects them elsewhere, perform a `transferFrom`.
 | 
			
		||||
        if (!params.useSelfBalance && state.from != msg.sender) {
 | 
			
		||||
            _transferERC20TokensFrom(
 | 
			
		||||
                IERC20TokenV06(params.tokens[0]),
 | 
			
		||||
                msg.sender,
 | 
			
		||||
                state.from,
 | 
			
		||||
                params.sellAmount
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        // If the input tokens are currently held by `address(this)` but
 | 
			
		||||
        // the first hop expects them elsewhere, perform a `transfer`.
 | 
			
		||||
        if (params.useSelfBalance && state.from != address(this)) {
 | 
			
		||||
            _transferERC20Tokens(
 | 
			
		||||
                IERC20TokenV06(params.tokens[0]),
 | 
			
		||||
                state.from,
 | 
			
		||||
                params.sellAmount
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        // Iterate through the calls and execute each one.
 | 
			
		||||
        for (state.hopIndex = 0; state.hopIndex != params.calls.length; state.hopIndex++) {
 | 
			
		||||
            MultiHopSellSubcall memory subcall = params.calls[state.hopIndex];
 | 
			
		||||
            // Compute the recipient of the tokens that will be
 | 
			
		||||
            // bought by the current hop.
 | 
			
		||||
            state.to = _computeHopTarget(params, state.hopIndex + 1);
 | 
			
		||||
 | 
			
		||||
            if (subcall.id == MultiplexSubcall.UniswapV2) {
 | 
			
		||||
                _multiHopSellUniswapV2(
 | 
			
		||||
                    state,
 | 
			
		||||
                    params,
 | 
			
		||||
                    subcall.data
 | 
			
		||||
                );
 | 
			
		||||
            } else if (subcall.id == MultiplexSubcall.UniswapV3) {
 | 
			
		||||
                _multiHopSellUniswapV3(state, subcall.data);
 | 
			
		||||
            } else if (subcall.id == MultiplexSubcall.LiquidityProvider) {
 | 
			
		||||
                _multiHopSellLiquidityProvider(
 | 
			
		||||
                    state,
 | 
			
		||||
                    params,
 | 
			
		||||
                    subcall.data
 | 
			
		||||
                );
 | 
			
		||||
            } else if (subcall.id == MultiplexSubcall.BatchSell) {
 | 
			
		||||
                _nestedBatchSell(
 | 
			
		||||
                    state,
 | 
			
		||||
                    params,
 | 
			
		||||
                    subcall.data
 | 
			
		||||
                );
 | 
			
		||||
            } else {
 | 
			
		||||
                revert("MultiplexFeature::_executeMultiHopSell/INVALID_SUBCALL");
 | 
			
		||||
            }
 | 
			
		||||
            // The recipient of the current hop will be the source
 | 
			
		||||
            // of tokens for the next hop.
 | 
			
		||||
            state.from = state.to;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _nestedMultiHopSell(
 | 
			
		||||
        IMultiplexFeature.BatchSellState memory state,
 | 
			
		||||
        IMultiplexFeature.BatchSellParams memory params,
 | 
			
		||||
        bytes memory data,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
    {
 | 
			
		||||
        MultiHopSellParams memory multiHopParams;
 | 
			
		||||
        // Decode the tokens and calls for the nested
 | 
			
		||||
        // multi-hop sell.
 | 
			
		||||
        (
 | 
			
		||||
            multiHopParams.tokens,
 | 
			
		||||
            multiHopParams.calls
 | 
			
		||||
        ) = abi.decode(
 | 
			
		||||
            data,
 | 
			
		||||
            (address[], MultiHopSellSubcall[])
 | 
			
		||||
        );
 | 
			
		||||
        multiHopParams.sellAmount = sellAmount;
 | 
			
		||||
        // If the batch sell is using input tokens held by
 | 
			
		||||
        // `address(this)`, then so should the nested
 | 
			
		||||
        // multi-hop sell.
 | 
			
		||||
        multiHopParams.useSelfBalance = params.useSelfBalance;
 | 
			
		||||
        // Likewise, the recipient of the multi-hop sell is
 | 
			
		||||
        // equal to the recipient of its containing batch sell.
 | 
			
		||||
        multiHopParams.recipient = params.recipient;
 | 
			
		||||
        // Execute the nested multi-hop sell.
 | 
			
		||||
        uint256 outputTokenAmount =
 | 
			
		||||
            _executeMultiHopSell(multiHopParams).outputTokenAmount;
 | 
			
		||||
        // Increment the sold and bought amounts.
 | 
			
		||||
        state.soldAmount = state.soldAmount.safeAdd(sellAmount);
 | 
			
		||||
        state.boughtAmount = state.boughtAmount.safeAdd(outputTokenAmount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _nestedBatchSell(
 | 
			
		||||
        IMultiplexFeature.MultiHopSellState memory state,
 | 
			
		||||
        IMultiplexFeature.MultiHopSellParams memory params,
 | 
			
		||||
        bytes memory data
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
    {
 | 
			
		||||
        BatchSellParams memory batchSellParams;
 | 
			
		||||
        // Decode the calls for the nested batch sell.
 | 
			
		||||
        batchSellParams.calls = abi.decode(
 | 
			
		||||
            data,
 | 
			
		||||
            (BatchSellSubcall[])
 | 
			
		||||
        );
 | 
			
		||||
        // The input and output tokens of the batch
 | 
			
		||||
        // sell are the current and next tokens in
 | 
			
		||||
        // `params.tokens`, respectively.
 | 
			
		||||
        batchSellParams.inputToken = IERC20TokenV06(
 | 
			
		||||
            params.tokens[state.hopIndex]
 | 
			
		||||
        );
 | 
			
		||||
        batchSellParams.outputToken = IERC20TokenV06(
 | 
			
		||||
            params.tokens[state.hopIndex + 1]
 | 
			
		||||
        );
 | 
			
		||||
        // The `sellAmount` for the batch sell is the
 | 
			
		||||
        // `outputTokenAmount` from the previous hop.
 | 
			
		||||
        batchSellParams.sellAmount = state.outputTokenAmount;
 | 
			
		||||
        // If the nested batch sell is the first hop
 | 
			
		||||
        // and `useSelfBalance` for the containing multi-
 | 
			
		||||
        // hop sell is false, the nested batch sell should
 | 
			
		||||
        // pull tokens from `msg.sender` (so  `batchSellParams.useSelfBalance`
 | 
			
		||||
        // should be false). Otherwise `batchSellParams.useSelfBalance`
 | 
			
		||||
        // should be true.
 | 
			
		||||
        batchSellParams.useSelfBalance = state.hopIndex > 0 || params.useSelfBalance;
 | 
			
		||||
        // `state.to` has been populated with the address
 | 
			
		||||
        // that should receive the output tokens of the
 | 
			
		||||
        // batch sell.
 | 
			
		||||
        batchSellParams.recipient = state.to;
 | 
			
		||||
        // Execute the nested batch sell.
 | 
			
		||||
        state.outputTokenAmount =
 | 
			
		||||
            _executeBatchSell(batchSellParams).boughtAmount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Transfers some amount of ETH to the given recipient and
 | 
			
		||||
    // reverts if the transfer fails.
 | 
			
		||||
    function _transferEth(address payable recipient, uint256 amount)
 | 
			
		||||
        private
 | 
			
		||||
    {
 | 
			
		||||
        (bool success,) = recipient.call{value: amount}("");
 | 
			
		||||
        require(success, "MultiplexFeature::_transferEth/TRANSFER_FAILED");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // This function computes the "target" address of hop index `i` within
 | 
			
		||||
    // a multi-hop sell.
 | 
			
		||||
    // If `i == 0`, the target is the address which should hold the input
 | 
			
		||||
    // tokens prior to executing `calls[0]`. Otherwise, it is the address
 | 
			
		||||
    // that should receive `tokens[i]` upon executing `calls[i-1]`.
 | 
			
		||||
    function _computeHopTarget(
 | 
			
		||||
        MultiHopSellParams memory params,
 | 
			
		||||
        uint256 i
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (address target)
 | 
			
		||||
    {
 | 
			
		||||
        if (i == params.calls.length) {
 | 
			
		||||
            // The last call should send the output tokens to the
 | 
			
		||||
            // multi-hop sell recipient.
 | 
			
		||||
            target = params.recipient;
 | 
			
		||||
        } else {
 | 
			
		||||
            MultiHopSellSubcall memory subcall = params.calls[i];
 | 
			
		||||
            if (subcall.id == MultiplexSubcall.UniswapV2) {
 | 
			
		||||
                // UniswapV2 (and Sushiswap) allow tokens to be
 | 
			
		||||
                // transferred into the pair contract before `swap`
 | 
			
		||||
                // is called, so we compute the pair contract's address.
 | 
			
		||||
                (address[] memory tokens, bool isSushi) = abi.decode(
 | 
			
		||||
                    subcall.data,
 | 
			
		||||
                    (address[], bool)
 | 
			
		||||
                );
 | 
			
		||||
                target = _computeUniswapPairAddress(
 | 
			
		||||
                    tokens[0],
 | 
			
		||||
                    tokens[1],
 | 
			
		||||
                    isSushi
 | 
			
		||||
                );
 | 
			
		||||
            } else if (subcall.id == MultiplexSubcall.LiquidityProvider) {
 | 
			
		||||
                // Similar to UniswapV2, LiquidityProvider contracts
 | 
			
		||||
                // allow tokens to be transferred in before the swap
 | 
			
		||||
                // is executed, so we the target is the address encoded
 | 
			
		||||
                // in the subcall data.
 | 
			
		||||
                (target,) = abi.decode(
 | 
			
		||||
                    subcall.data,
 | 
			
		||||
                    (address, bytes)
 | 
			
		||||
                );
 | 
			
		||||
            } else if (
 | 
			
		||||
                subcall.id == MultiplexSubcall.UniswapV3 ||
 | 
			
		||||
                subcall.id == MultiplexSubcall.BatchSell
 | 
			
		||||
            ) {
 | 
			
		||||
                // UniswapV3 uses a callback to pull in the tokens being
 | 
			
		||||
                // sold to it. The callback implemented in `UniswapV3Feature`
 | 
			
		||||
                // can either:
 | 
			
		||||
                // - call `transferFrom` to move tokens from `msg.sender` to the
 | 
			
		||||
                //   UniswapV3 pool, or
 | 
			
		||||
                // - call `transfer` to move tokens from `address(this)` to the
 | 
			
		||||
                //   UniswapV3 pool.
 | 
			
		||||
                // A nested batch sell is similar, in that it can either:
 | 
			
		||||
                // - use tokens from `msg.sender`, or
 | 
			
		||||
                // - use tokens held by `address(this)`.
 | 
			
		||||
 | 
			
		||||
                // Suppose UniswapV3/BatchSell is the first call in the multi-hop
 | 
			
		||||
                // path. The input tokens are either held by `msg.sender`,
 | 
			
		||||
                // or in the case of `multiplexMultiHopSellEthForToken` WETH is
 | 
			
		||||
                // held by `address(this)`. The target is set accordingly.
 | 
			
		||||
 | 
			
		||||
                // If this is _not_ the first call in the multi-hop path, we
 | 
			
		||||
                // are dealing with an "intermediate" token in the multi-hop path,
 | 
			
		||||
                // which `msg.sender` may not have an allowance set for. Thus
 | 
			
		||||
                // target must be set to `address(this)` for `i > 0`.
 | 
			
		||||
                if (i == 0 && !params.useSelfBalance) {
 | 
			
		||||
                    target = msg.sender;
 | 
			
		||||
                } else {
 | 
			
		||||
                    target = address(this);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                revert("MultiplexFeature::_computeHopTarget/INVALID_SUBCALL");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        require(
 | 
			
		||||
            target != address(0),
 | 
			
		||||
            "MultiplexFeature::_computeHopTarget/TARGET_IS_NULL"
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If `rawAmount` encodes a proportion of `totalSellAmount`, this function
 | 
			
		||||
    // converts it to an absolute quantity. Caps the normalized amount to
 | 
			
		||||
    // the remaining sell amount (`totalSellAmount - soldAmount`).
 | 
			
		||||
    function _normalizeSellAmount(
 | 
			
		||||
        uint256 rawAmount,
 | 
			
		||||
        uint256 totalSellAmount,
 | 
			
		||||
        uint256 soldAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        pure
 | 
			
		||||
        returns (uint256 normalized)
 | 
			
		||||
    {
 | 
			
		||||
        if ((rawAmount & HIGH_BIT) == HIGH_BIT) {
 | 
			
		||||
            // If the high bit of `rawAmount` is set then the lower 255 bits
 | 
			
		||||
            // specify a fraction of `totalSellAmount`.
 | 
			
		||||
            return LibSafeMathV06.min256(
 | 
			
		||||
                totalSellAmount
 | 
			
		||||
                    * LibSafeMathV06.min256(rawAmount & LOWER_255_BITS, 1e18)
 | 
			
		||||
                    / 1e18,
 | 
			
		||||
                totalSellAmount.safeSub(soldAmount)
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            return LibSafeMathV06.min256(
 | 
			
		||||
                rawAmount,
 | 
			
		||||
                totalSellAmount.safeSub(soldAmount)
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,202 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2021 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6.5;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
 | 
			
		||||
import "../../external/ILiquidityProviderSandbox.sol";
 | 
			
		||||
import "../../fixins/FixinCommon.sol";
 | 
			
		||||
import "../../fixins/FixinTokenSpender.sol";
 | 
			
		||||
import "../../vendor/ILiquidityProvider.sol";
 | 
			
		||||
import "../interfaces/IMultiplexFeature.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
abstract contract MultiplexLiquidityProvider is
 | 
			
		||||
    FixinCommon,
 | 
			
		||||
    FixinTokenSpender
 | 
			
		||||
{
 | 
			
		||||
    using LibERC20TokenV06 for IERC20TokenV06;
 | 
			
		||||
    using LibSafeMathV06 for uint256;
 | 
			
		||||
 | 
			
		||||
    // Same event fired by LiquidityProviderFeature
 | 
			
		||||
    event LiquidityProviderSwap(
 | 
			
		||||
        address inputToken,
 | 
			
		||||
        address outputToken,
 | 
			
		||||
        uint256 inputTokenAmount,
 | 
			
		||||
        uint256 outputTokenAmount,
 | 
			
		||||
        address provider,
 | 
			
		||||
        address recipient
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /// @dev The sandbox contract address.
 | 
			
		||||
    ILiquidityProviderSandbox private immutable SANDBOX;
 | 
			
		||||
 | 
			
		||||
    constructor(ILiquidityProviderSandbox sandbox)
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        SANDBOX = sandbox;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // A payable external function that we can delegatecall to
 | 
			
		||||
    // swallow reverts and roll back the input token transfer.
 | 
			
		||||
    function _batchSellLiquidityProviderExternal(
 | 
			
		||||
        IMultiplexFeature.BatchSellParams calldata params,
 | 
			
		||||
        bytes calldata wrappedCallData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 boughtAmount)
 | 
			
		||||
    {
 | 
			
		||||
        // Revert if not a delegatecall.
 | 
			
		||||
        require(
 | 
			
		||||
            address(this) != _implementation,
 | 
			
		||||
            "MultiplexLiquidityProvider::_batchSellLiquidityProviderExternal/ONLY_DELEGATECALL"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Decode the provider address and auxiliary data.
 | 
			
		||||
        (address provider, bytes memory auxiliaryData) = abi.decode(
 | 
			
		||||
            wrappedCallData,
 | 
			
		||||
            (address, bytes)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (params.useSelfBalance) {
 | 
			
		||||
            // If `useSelfBalance` is true, use the input tokens
 | 
			
		||||
            // held by `address(this)`.
 | 
			
		||||
            _transferERC20Tokens(
 | 
			
		||||
                params.inputToken,
 | 
			
		||||
                provider,
 | 
			
		||||
                sellAmount
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            // Otherwise, transfer the input tokens from `msg.sender`.
 | 
			
		||||
            _transferERC20TokensFrom(
 | 
			
		||||
                params.inputToken,
 | 
			
		||||
                msg.sender,
 | 
			
		||||
                provider,
 | 
			
		||||
                sellAmount
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        // Cache the recipient's balance of the output token.
 | 
			
		||||
        uint256 balanceBefore = params.outputToken
 | 
			
		||||
            .balanceOf(params.recipient);
 | 
			
		||||
        // Execute the swap.
 | 
			
		||||
        SANDBOX.executeSellTokenForToken(
 | 
			
		||||
            ILiquidityProvider(provider),
 | 
			
		||||
            params.inputToken,
 | 
			
		||||
            params.outputToken,
 | 
			
		||||
            params.recipient,
 | 
			
		||||
            0,
 | 
			
		||||
            auxiliaryData
 | 
			
		||||
        );
 | 
			
		||||
        // Compute amount of output token received by the
 | 
			
		||||
        // recipient.
 | 
			
		||||
        boughtAmount = params.outputToken
 | 
			
		||||
            .balanceOf(params.recipient)
 | 
			
		||||
            .safeSub(balanceBefore);
 | 
			
		||||
 | 
			
		||||
        emit LiquidityProviderSwap(
 | 
			
		||||
            address(params.inputToken),
 | 
			
		||||
            address(params.outputToken),
 | 
			
		||||
            sellAmount,
 | 
			
		||||
            boughtAmount,
 | 
			
		||||
            provider,
 | 
			
		||||
            params.recipient
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _batchSellLiquidityProvider(
 | 
			
		||||
        IMultiplexFeature.BatchSellState memory state,
 | 
			
		||||
        IMultiplexFeature.BatchSellParams memory params,
 | 
			
		||||
        bytes memory wrappedCallData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        // Swallow reverts
 | 
			
		||||
        (bool success, bytes memory resultData) = _implementation.delegatecall(
 | 
			
		||||
            abi.encodeWithSelector(
 | 
			
		||||
                this._batchSellLiquidityProviderExternal.selector,
 | 
			
		||||
                params,
 | 
			
		||||
                wrappedCallData,
 | 
			
		||||
                sellAmount
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
        if (success) {
 | 
			
		||||
            // Decode the output token amount on success.
 | 
			
		||||
            uint256 boughtAmount = abi.decode(resultData, (uint256));
 | 
			
		||||
            // Increment the sold and bought amounts.
 | 
			
		||||
            state.soldAmount = state.soldAmount.safeAdd(sellAmount);
 | 
			
		||||
            state.boughtAmount = state.boughtAmount.safeAdd(boughtAmount);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // This function is called after tokens have already been transferred
 | 
			
		||||
    // into the liquidity provider contract (in the previous hop).
 | 
			
		||||
    function _multiHopSellLiquidityProvider(
 | 
			
		||||
        IMultiplexFeature.MultiHopSellState memory state,
 | 
			
		||||
        IMultiplexFeature.MultiHopSellParams memory params,
 | 
			
		||||
        bytes memory wrappedCallData
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        IERC20TokenV06 inputToken = IERC20TokenV06(params.tokens[state.hopIndex]);
 | 
			
		||||
        IERC20TokenV06 outputToken = IERC20TokenV06(params.tokens[state.hopIndex + 1]);
 | 
			
		||||
        // Decode the provider address and auxiliary data.
 | 
			
		||||
        (address provider, bytes memory auxiliaryData) = abi.decode(
 | 
			
		||||
            wrappedCallData,
 | 
			
		||||
            (address, bytes)
 | 
			
		||||
        );
 | 
			
		||||
        // Cache the recipient's balance of the output token.
 | 
			
		||||
        uint256 balanceBefore = outputToken
 | 
			
		||||
            .balanceOf(state.to);
 | 
			
		||||
        // Execute the swap.
 | 
			
		||||
        SANDBOX.executeSellTokenForToken(
 | 
			
		||||
            ILiquidityProvider(provider),
 | 
			
		||||
            inputToken,
 | 
			
		||||
            outputToken,
 | 
			
		||||
            state.to,
 | 
			
		||||
            0,
 | 
			
		||||
            auxiliaryData
 | 
			
		||||
        );
 | 
			
		||||
        // The previous `ouputTokenAmount` was effectively the
 | 
			
		||||
        // input amount for this call. Cache the value before
 | 
			
		||||
        // overwriting it with the new output token amount so
 | 
			
		||||
        // that both the input and ouput amounts can be in the
 | 
			
		||||
        // `LiquidityProviderSwap` event.
 | 
			
		||||
        uint256 sellAmount = state.outputTokenAmount;
 | 
			
		||||
        // Compute amount of output token received by the
 | 
			
		||||
        // recipient.
 | 
			
		||||
        state.outputTokenAmount = outputToken
 | 
			
		||||
            .balanceOf(state.to)
 | 
			
		||||
            .safeSub(balanceBefore);
 | 
			
		||||
 | 
			
		||||
        emit LiquidityProviderSwap(
 | 
			
		||||
            address(inputToken),
 | 
			
		||||
            address(outputToken),
 | 
			
		||||
            sellAmount,
 | 
			
		||||
            state.outputTokenAmount,
 | 
			
		||||
            provider,
 | 
			
		||||
            state.to
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,94 @@
 | 
			
		||||
// 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-utils/contracts/src/v06/LibSafeMathV06.sol";
 | 
			
		||||
import "../../fixins/FixinEIP712.sol";
 | 
			
		||||
import "../interfaces/IMultiplexFeature.sol";
 | 
			
		||||
import "../interfaces/IOtcOrdersFeature.sol";
 | 
			
		||||
import "../libs/LibNativeOrder.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
abstract contract MultiplexOtc is
 | 
			
		||||
    FixinEIP712
 | 
			
		||||
{
 | 
			
		||||
    using LibSafeMathV06 for uint256;
 | 
			
		||||
 | 
			
		||||
    event ExpiredOtcOrder(
 | 
			
		||||
        bytes32 orderHash,
 | 
			
		||||
        address maker,
 | 
			
		||||
        uint64 expiry
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    function _batchSellOtcOrder(
 | 
			
		||||
        IMultiplexFeature.BatchSellState memory state,
 | 
			
		||||
        IMultiplexFeature.BatchSellParams memory params,
 | 
			
		||||
        bytes memory wrappedCallData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        // Decode the Otc order and signature.
 | 
			
		||||
        (
 | 
			
		||||
            LibNativeOrder.OtcOrder memory order,
 | 
			
		||||
            LibSignature.Signature memory signature
 | 
			
		||||
        ) = abi.decode(
 | 
			
		||||
            wrappedCallData,
 | 
			
		||||
            (LibNativeOrder.OtcOrder, LibSignature.Signature)
 | 
			
		||||
        );
 | 
			
		||||
        // Validate tokens.
 | 
			
		||||
        require(
 | 
			
		||||
            order.takerToken == params.inputToken &&
 | 
			
		||||
            order.makerToken == params.outputToken,
 | 
			
		||||
            "MultiplexOtc::_batchSellOtcOrder/OTC_ORDER_INVALID_TOKENS"
 | 
			
		||||
        );
 | 
			
		||||
        // Pre-emptively check if the order is expired.
 | 
			
		||||
        uint64 expiry = uint64(order.expiryAndNonce >> 192);
 | 
			
		||||
        if (expiry <= uint64(block.timestamp)) {
 | 
			
		||||
            bytes32 orderHash = _getEIP712Hash(
 | 
			
		||||
                LibNativeOrder.getOtcOrderStructHash(order)
 | 
			
		||||
            );
 | 
			
		||||
            emit ExpiredOtcOrder(
 | 
			
		||||
                orderHash,
 | 
			
		||||
                order.maker,
 | 
			
		||||
                expiry
 | 
			
		||||
            );
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // Try filling the Otc order. Swallows reverts.
 | 
			
		||||
        try
 | 
			
		||||
            IOtcOrdersFeature(address(this))._fillOtcOrder
 | 
			
		||||
                (
 | 
			
		||||
                    order,
 | 
			
		||||
                    signature,
 | 
			
		||||
                    sellAmount.safeDowncastToUint128(),
 | 
			
		||||
                    msg.sender,
 | 
			
		||||
                    params.useSelfBalance,
 | 
			
		||||
                    params.recipient
 | 
			
		||||
                )
 | 
			
		||||
            returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
 | 
			
		||||
        {
 | 
			
		||||
            // Increment the sold and bought amounts.
 | 
			
		||||
            state.soldAmount = state.soldAmount.safeAdd(takerTokenFilledAmount);
 | 
			
		||||
            state.boughtAmount = state.boughtAmount.safeAdd(makerTokenFilledAmount);
 | 
			
		||||
        } catch {}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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-utils/contracts/src/v06/LibSafeMathV06.sol";
 | 
			
		||||
import "../../fixins/FixinEIP712.sol";
 | 
			
		||||
import "../interfaces/IMultiplexFeature.sol";
 | 
			
		||||
import "../interfaces/INativeOrdersFeature.sol";
 | 
			
		||||
import "../libs/LibNativeOrder.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
abstract contract MultiplexRfq is
 | 
			
		||||
    FixinEIP712
 | 
			
		||||
{
 | 
			
		||||
    using LibSafeMathV06 for uint256;
 | 
			
		||||
 | 
			
		||||
    event ExpiredRfqOrder(
 | 
			
		||||
        bytes32 orderHash,
 | 
			
		||||
        address maker,
 | 
			
		||||
        uint64 expiry
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    function _batchSellRfqOrder(
 | 
			
		||||
        IMultiplexFeature.BatchSellState memory state,
 | 
			
		||||
        IMultiplexFeature.BatchSellParams memory params,
 | 
			
		||||
        bytes memory wrappedCallData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        // Decode the RFQ order and signature.
 | 
			
		||||
        (
 | 
			
		||||
            LibNativeOrder.RfqOrder memory order,
 | 
			
		||||
            LibSignature.Signature memory signature
 | 
			
		||||
        ) = abi.decode(
 | 
			
		||||
            wrappedCallData,
 | 
			
		||||
            (LibNativeOrder.RfqOrder, LibSignature.Signature)
 | 
			
		||||
        );
 | 
			
		||||
        // Pre-emptively check if the order is expired.
 | 
			
		||||
        if (order.expiry <= uint64(block.timestamp)) {
 | 
			
		||||
            bytes32 orderHash = _getEIP712Hash(
 | 
			
		||||
                LibNativeOrder.getRfqOrderStructHash(order)
 | 
			
		||||
            );
 | 
			
		||||
            emit ExpiredRfqOrder(
 | 
			
		||||
                orderHash,
 | 
			
		||||
                order.maker,
 | 
			
		||||
                order.expiry
 | 
			
		||||
            );
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // Validate tokens.
 | 
			
		||||
        require(
 | 
			
		||||
            order.takerToken == params.inputToken &&
 | 
			
		||||
            order.makerToken == params.outputToken,
 | 
			
		||||
            "MultiplexRfq::_batchSellRfqOrder/RFQ_ORDER_INVALID_TOKENS"
 | 
			
		||||
        );
 | 
			
		||||
        // Try filling the RFQ order. Swallows reverts.
 | 
			
		||||
        try
 | 
			
		||||
            INativeOrdersFeature(address(this))._fillRfqOrder
 | 
			
		||||
                (
 | 
			
		||||
                    order,
 | 
			
		||||
                    signature,
 | 
			
		||||
                    sellAmount.safeDowncastToUint128(),
 | 
			
		||||
                    msg.sender,
 | 
			
		||||
                    params.useSelfBalance,
 | 
			
		||||
                    params.recipient
 | 
			
		||||
                )
 | 
			
		||||
            returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
 | 
			
		||||
        {
 | 
			
		||||
            // Increment the sold and bought amounts.
 | 
			
		||||
            state.soldAmount = state.soldAmount.safeAdd(takerTokenFilledAmount);
 | 
			
		||||
            state.boughtAmount = state.boughtAmount.safeAdd(makerTokenFilledAmount);
 | 
			
		||||
        } catch {}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,64 @@
 | 
			
		||||
// 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-utils/contracts/src/v06/LibSafeMathV06.sol";
 | 
			
		||||
import "../interfaces/IMultiplexFeature.sol";
 | 
			
		||||
import "../interfaces/ITransformERC20Feature.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
abstract contract MultiplexTransformERC20 {
 | 
			
		||||
 | 
			
		||||
    using LibSafeMathV06 for uint256;
 | 
			
		||||
 | 
			
		||||
    function _batchSellTransformERC20(
 | 
			
		||||
        IMultiplexFeature.BatchSellState memory state,
 | 
			
		||||
        IMultiplexFeature.BatchSellParams memory params,
 | 
			
		||||
        bytes memory wrappedCallData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        ITransformERC20Feature.TransformERC20Args memory args;
 | 
			
		||||
        // We want the TransformedERC20 event to have
 | 
			
		||||
        // `msg.sender` as the taker.
 | 
			
		||||
        args.taker = msg.sender;
 | 
			
		||||
        args.inputToken = params.inputToken;
 | 
			
		||||
        args.outputToken = params.outputToken;
 | 
			
		||||
        args.inputTokenAmount = sellAmount;
 | 
			
		||||
        args.minOutputTokenAmount = 0;
 | 
			
		||||
        args.useSelfBalance = params.useSelfBalance;
 | 
			
		||||
        args.recipient = payable(params.recipient);
 | 
			
		||||
        (args.transformations) = abi.decode(
 | 
			
		||||
            wrappedCallData,
 | 
			
		||||
            (ITransformERC20Feature.Transformation[])
 | 
			
		||||
        );
 | 
			
		||||
        // Execute the transformations and swallow reverts.
 | 
			
		||||
        try ITransformERC20Feature(address(this))._transformERC20
 | 
			
		||||
            (args)
 | 
			
		||||
            returns (uint256 outputTokenAmount)
 | 
			
		||||
        {
 | 
			
		||||
            // Increment the sold and bought amounts.
 | 
			
		||||
            state.soldAmount = state.soldAmount.safeAdd(sellAmount);
 | 
			
		||||
            state.boughtAmount = state.boughtAmount.safeAdd(outputTokenAmount);
 | 
			
		||||
        } catch {}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,290 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2021 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6.5;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
 | 
			
		||||
import "../../fixins/FixinCommon.sol";
 | 
			
		||||
import "../../fixins/FixinTokenSpender.sol";
 | 
			
		||||
import "../../vendor/IUniswapV2Pair.sol";
 | 
			
		||||
import "../interfaces/IMultiplexFeature.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
abstract contract MultiplexUniswapV2 is
 | 
			
		||||
    FixinCommon,
 | 
			
		||||
    FixinTokenSpender
 | 
			
		||||
{
 | 
			
		||||
    using LibSafeMathV06 for uint256;
 | 
			
		||||
 | 
			
		||||
    // address of the UniswapV2Factory contract.
 | 
			
		||||
    address private immutable UNISWAP_FACTORY;
 | 
			
		||||
    // address of the (Sushiswap) UniswapV2Factory contract.
 | 
			
		||||
    address private immutable SUSHISWAP_FACTORY;
 | 
			
		||||
    // Init code hash of the UniswapV2Pair contract.
 | 
			
		||||
    bytes32 private immutable UNISWAP_PAIR_INIT_CODE_HASH;
 | 
			
		||||
    // Init code hash of the (Sushiswap) UniswapV2Pair contract.
 | 
			
		||||
    bytes32 private immutable SUSHISWAP_PAIR_INIT_CODE_HASH;
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        address uniswapFactory,
 | 
			
		||||
        address sushiswapFactory,
 | 
			
		||||
        bytes32 uniswapPairInitCodeHash,
 | 
			
		||||
        bytes32 sushiswapPairInitCodeHash
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        UNISWAP_FACTORY = uniswapFactory;
 | 
			
		||||
        SUSHISWAP_FACTORY = sushiswapFactory;
 | 
			
		||||
        UNISWAP_PAIR_INIT_CODE_HASH = uniswapPairInitCodeHash;
 | 
			
		||||
        SUSHISWAP_PAIR_INIT_CODE_HASH = sushiswapPairInitCodeHash;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // A payable external function that we can delegatecall to
 | 
			
		||||
    // swallow reverts and roll back the input token transfer.
 | 
			
		||||
    function _batchSellUniswapV2External(
 | 
			
		||||
        IMultiplexFeature.BatchSellParams calldata params,
 | 
			
		||||
        bytes calldata wrappedCallData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 boughtAmount)
 | 
			
		||||
    {
 | 
			
		||||
        // Revert is not a delegatecall.
 | 
			
		||||
        require(
 | 
			
		||||
            address(this) != _implementation,
 | 
			
		||||
            "MultiplexLiquidityProvider::_batchSellUniswapV2External/ONLY_DELEGATECALL"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        (address[] memory tokens, bool isSushi) = abi.decode(
 | 
			
		||||
            wrappedCallData,
 | 
			
		||||
            (address[], bool)
 | 
			
		||||
        );
 | 
			
		||||
        // Validate tokens
 | 
			
		||||
        require(
 | 
			
		||||
            tokens.length >= 2 &&
 | 
			
		||||
            tokens[0] == address(params.inputToken) &&
 | 
			
		||||
            tokens[tokens.length - 1] == address(params.outputToken),
 | 
			
		||||
            "MultiplexUniswapV2::_batchSellUniswapV2/INVALID_TOKENS"
 | 
			
		||||
        );
 | 
			
		||||
        // Compute the address of the first Uniswap pair
 | 
			
		||||
        // contract that will execute a swap.
 | 
			
		||||
        address firstPairAddress = _computeUniswapPairAddress(
 | 
			
		||||
            tokens[0],
 | 
			
		||||
            tokens[1],
 | 
			
		||||
            isSushi
 | 
			
		||||
        );
 | 
			
		||||
        // `_sellToUniswapV2` assumes the input tokens have been
 | 
			
		||||
        // transferred into the pair contract before it is called,
 | 
			
		||||
        // so we transfer the tokens in now (either from `msg.sender`
 | 
			
		||||
        // or using the Exchange Proxy's balance).
 | 
			
		||||
        if (params.useSelfBalance) {
 | 
			
		||||
            _transferERC20Tokens(
 | 
			
		||||
                IERC20TokenV06(tokens[0]),
 | 
			
		||||
                firstPairAddress,
 | 
			
		||||
                sellAmount
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            _transferERC20TokensFrom(
 | 
			
		||||
                IERC20TokenV06(tokens[0]),
 | 
			
		||||
                msg.sender,
 | 
			
		||||
                firstPairAddress,
 | 
			
		||||
                sellAmount
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        // Execute the Uniswap/Sushiswap trade.
 | 
			
		||||
        return _sellToUniswapV2(
 | 
			
		||||
            tokens,
 | 
			
		||||
            sellAmount,
 | 
			
		||||
            isSushi,
 | 
			
		||||
            firstPairAddress,
 | 
			
		||||
            params.recipient
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _batchSellUniswapV2(
 | 
			
		||||
        IMultiplexFeature.BatchSellState memory state,
 | 
			
		||||
        IMultiplexFeature.BatchSellParams memory params,
 | 
			
		||||
        bytes memory wrappedCallData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        // Swallow reverts
 | 
			
		||||
        (bool success, bytes memory resultData) = _implementation.delegatecall(
 | 
			
		||||
            abi.encodeWithSelector(
 | 
			
		||||
                this._batchSellUniswapV2External.selector,
 | 
			
		||||
                params,
 | 
			
		||||
                wrappedCallData,
 | 
			
		||||
                sellAmount
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
        if (success) {
 | 
			
		||||
            // Decode the output token amount on success.
 | 
			
		||||
            uint256 boughtAmount = abi.decode(resultData, (uint256));
 | 
			
		||||
            // Increment the sold and bought amounts.
 | 
			
		||||
            state.soldAmount = state.soldAmount.safeAdd(sellAmount);
 | 
			
		||||
            state.boughtAmount = state.boughtAmount.safeAdd(boughtAmount);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _multiHopSellUniswapV2(
 | 
			
		||||
        IMultiplexFeature.MultiHopSellState memory state,
 | 
			
		||||
        IMultiplexFeature.MultiHopSellParams memory params,
 | 
			
		||||
        bytes memory wrappedCallData
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        (address[] memory tokens, bool isSushi) = abi.decode(
 | 
			
		||||
            wrappedCallData,
 | 
			
		||||
            (address[], bool)
 | 
			
		||||
        );
 | 
			
		||||
        // Validate the tokens
 | 
			
		||||
        require(
 | 
			
		||||
            tokens.length >= 2 &&
 | 
			
		||||
            tokens[0] == params.tokens[state.hopIndex] &&
 | 
			
		||||
            tokens[tokens.length - 1] == params.tokens[state.hopIndex + 1],
 | 
			
		||||
            "MultiplexUniswapV2::_multiHopSellUniswapV2/INVALID_TOKENS"
 | 
			
		||||
        );
 | 
			
		||||
        // Execute the Uniswap/Sushiswap trade.
 | 
			
		||||
        state.outputTokenAmount = _sellToUniswapV2(
 | 
			
		||||
            tokens,
 | 
			
		||||
            state.outputTokenAmount,
 | 
			
		||||
            isSushi,
 | 
			
		||||
            state.from,
 | 
			
		||||
            state.to
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _sellToUniswapV2(
 | 
			
		||||
        address[] memory tokens,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        bool isSushi,
 | 
			
		||||
        address pairAddress,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        returns (uint256 outputTokenAmount)
 | 
			
		||||
    {
 | 
			
		||||
        // Iterate through `tokens` perform a swap against the Uniswap
 | 
			
		||||
        // pair contract for each `(tokens[i], tokens[i+1])`.
 | 
			
		||||
        for (uint256 i = 0; i < tokens.length - 1; i++) {
 | 
			
		||||
            (address inputToken, address outputToken) = (tokens[i], tokens[i + 1]);
 | 
			
		||||
            // Compute the output token amount
 | 
			
		||||
            outputTokenAmount = _computeUniswapOutputAmount(
 | 
			
		||||
                pairAddress,
 | 
			
		||||
                inputToken,
 | 
			
		||||
                outputToken,
 | 
			
		||||
                sellAmount
 | 
			
		||||
            );
 | 
			
		||||
            (uint256 amount0Out, uint256 amount1Out) = inputToken < outputToken
 | 
			
		||||
                ? (uint256(0), outputTokenAmount)
 | 
			
		||||
                : (outputTokenAmount, uint256(0));
 | 
			
		||||
            // The Uniswap pair contract will transfer the output tokens to
 | 
			
		||||
            // the next pair contract if there is one, otherwise transfer to
 | 
			
		||||
            // `recipient`.
 | 
			
		||||
            address to = i < tokens.length - 2
 | 
			
		||||
                ? _computeUniswapPairAddress(outputToken, tokens[i + 2], isSushi)
 | 
			
		||||
                : recipient;
 | 
			
		||||
            // Execute the swap.
 | 
			
		||||
            IUniswapV2Pair(pairAddress).swap(
 | 
			
		||||
                amount0Out,
 | 
			
		||||
                amount1Out,
 | 
			
		||||
                to,
 | 
			
		||||
                new bytes(0)
 | 
			
		||||
            );
 | 
			
		||||
            // To avoid recomputing the pair address of the next pair, store
 | 
			
		||||
            // `to` in `pairAddress`.
 | 
			
		||||
            pairAddress = to;
 | 
			
		||||
            // The outputTokenAmount
 | 
			
		||||
            sellAmount = outputTokenAmount;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Computes the Uniswap/Sushiswap pair contract address for the
 | 
			
		||||
    // given tokens.
 | 
			
		||||
    function _computeUniswapPairAddress(
 | 
			
		||||
        address tokenA,
 | 
			
		||||
        address tokenB,
 | 
			
		||||
        bool isSushi
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address pairAddress)
 | 
			
		||||
    {
 | 
			
		||||
        // Tokens are lexicographically sorted in the Uniswap contract.
 | 
			
		||||
        (address token0, address token1) = tokenA < tokenB
 | 
			
		||||
            ? (tokenA, tokenB)
 | 
			
		||||
            : (tokenB, tokenA);
 | 
			
		||||
        if (isSushi) {
 | 
			
		||||
            // Use the Sushiswap factory address and codehash
 | 
			
		||||
            return address(uint256(keccak256(abi.encodePacked(
 | 
			
		||||
                hex'ff',
 | 
			
		||||
                SUSHISWAP_FACTORY,
 | 
			
		||||
                keccak256(abi.encodePacked(token0, token1)),
 | 
			
		||||
                SUSHISWAP_PAIR_INIT_CODE_HASH
 | 
			
		||||
            ))));
 | 
			
		||||
        } else {
 | 
			
		||||
            // Use the Uniswap factory address and codehash
 | 
			
		||||
            return address(uint256(keccak256(abi.encodePacked(
 | 
			
		||||
                hex'ff',
 | 
			
		||||
                UNISWAP_FACTORY,
 | 
			
		||||
                keccak256(abi.encodePacked(token0, token1)),
 | 
			
		||||
                UNISWAP_PAIR_INIT_CODE_HASH
 | 
			
		||||
            ))));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Computes the the amount of output token that would be bought
 | 
			
		||||
    // from Uniswap/Sushiswap given the input amount.
 | 
			
		||||
    function _computeUniswapOutputAmount(
 | 
			
		||||
        address pairAddress,
 | 
			
		||||
        address inputToken,
 | 
			
		||||
        address outputToken,
 | 
			
		||||
        uint256 inputAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 outputAmount)
 | 
			
		||||
    {
 | 
			
		||||
        // Input amount should be non-zero.
 | 
			
		||||
        require(
 | 
			
		||||
            inputAmount > 0,
 | 
			
		||||
            "MultiplexUniswapV2::_computeUniswapOutputAmount/INSUFFICIENT_INPUT_AMOUNT"
 | 
			
		||||
        );
 | 
			
		||||
        // Query the reserves of the pair contract.
 | 
			
		||||
        (uint256 reserve0, uint256 reserve1,) = IUniswapV2Pair(pairAddress).getReserves();
 | 
			
		||||
        // Reserves must be non-zero.
 | 
			
		||||
        require(
 | 
			
		||||
            reserve0 > 0 && reserve1 > 0,
 | 
			
		||||
            'MultiplexUniswapV2::_computeUniswapOutputAmount/INSUFFICIENT_LIQUIDITY'
 | 
			
		||||
        );
 | 
			
		||||
        // Tokens are lexicographically sorted in the Uniswap contract.
 | 
			
		||||
        (uint256 inputReserve, uint256 outputReserve) = inputToken < outputToken
 | 
			
		||||
            ? (reserve0, reserve1)
 | 
			
		||||
            : (reserve1, reserve0);
 | 
			
		||||
        // Compute the output amount.
 | 
			
		||||
        uint256 inputAmountWithFee = inputAmount.safeMul(997);
 | 
			
		||||
        uint256 numerator = inputAmountWithFee.safeMul(outputReserve);
 | 
			
		||||
        uint256 denominator = inputReserve.safeMul(1000).safeAdd(inputAmountWithFee);
 | 
			
		||||
        return numerator / denominator;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,123 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2021 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6.5;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
 | 
			
		||||
import "../../fixins/FixinTokenSpender.sol";
 | 
			
		||||
import "../interfaces/IMultiplexFeature.sol";
 | 
			
		||||
import "../interfaces/IUniswapV3Feature.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
abstract contract MultiplexUniswapV3 is
 | 
			
		||||
    FixinTokenSpender
 | 
			
		||||
{
 | 
			
		||||
    using LibSafeMathV06 for uint256;
 | 
			
		||||
 | 
			
		||||
    function _batchSellUniswapV3(
 | 
			
		||||
        IMultiplexFeature.BatchSellState memory state,
 | 
			
		||||
        IMultiplexFeature.BatchSellParams memory params,
 | 
			
		||||
        bytes memory wrappedCallData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        bool success;
 | 
			
		||||
        bytes memory resultData;
 | 
			
		||||
        if (params.useSelfBalance) {
 | 
			
		||||
            // If the tokens are held by `address(this)`, we call
 | 
			
		||||
            // the `onlySelf` variant `_sellHeldTokenForTokenToUniswapV3`,
 | 
			
		||||
            // which uses the Exchange Proxy's balance of input token.
 | 
			
		||||
            (success, resultData) = address(this).call(
 | 
			
		||||
                abi.encodeWithSelector(
 | 
			
		||||
                    IUniswapV3Feature._sellHeldTokenForTokenToUniswapV3.selector,
 | 
			
		||||
                    wrappedCallData,
 | 
			
		||||
                    sellAmount,
 | 
			
		||||
                    0,
 | 
			
		||||
                    params.recipient
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            // Otherwise, we self-delegatecall the normal variant
 | 
			
		||||
            // `sellTokenForTokenToUniswapV3`, which pulls the input token
 | 
			
		||||
            // from `msg.sender`.
 | 
			
		||||
            (success, resultData) = address(this).delegatecall(
 | 
			
		||||
                abi.encodeWithSelector(
 | 
			
		||||
                    IUniswapV3Feature.sellTokenForTokenToUniswapV3.selector,
 | 
			
		||||
                    wrappedCallData,
 | 
			
		||||
                    sellAmount,
 | 
			
		||||
                    0,
 | 
			
		||||
                    params.recipient
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        if (success) {
 | 
			
		||||
            // Decode the output token amount on success.
 | 
			
		||||
            uint256 outputTokenAmount = abi.decode(resultData, (uint256));
 | 
			
		||||
            // Increment the sold and bought amounts.
 | 
			
		||||
            state.soldAmount = state.soldAmount.safeAdd(sellAmount);
 | 
			
		||||
            state.boughtAmount = state.boughtAmount.safeAdd(outputTokenAmount);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _multiHopSellUniswapV3(
 | 
			
		||||
        IMultiplexFeature.MultiHopSellState memory state,
 | 
			
		||||
        bytes memory wrappedCallData
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        bool success;
 | 
			
		||||
        bytes memory resultData;
 | 
			
		||||
        if (state.from == address(this)) {
 | 
			
		||||
            // If the tokens are held by `address(this)`, we call
 | 
			
		||||
            // the `onlySelf` variant `_sellHeldTokenForTokenToUniswapV3`,
 | 
			
		||||
            // which uses the Exchange Proxy's balance of input token.
 | 
			
		||||
            (success, resultData) = address(this).call(
 | 
			
		||||
                abi.encodeWithSelector(
 | 
			
		||||
                    IUniswapV3Feature._sellHeldTokenForTokenToUniswapV3.selector,
 | 
			
		||||
                    wrappedCallData,
 | 
			
		||||
                    state.outputTokenAmount,
 | 
			
		||||
                    0,
 | 
			
		||||
                    state.to
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            // Otherwise, we self-delegatecall the normal variant
 | 
			
		||||
            // `sellTokenForTokenToUniswapV3`, which pulls the input token
 | 
			
		||||
            // from `msg.sender`.
 | 
			
		||||
            (success, resultData) = address(this).delegatecall(
 | 
			
		||||
                abi.encodeWithSelector(
 | 
			
		||||
                    IUniswapV3Feature.sellTokenForTokenToUniswapV3.selector,
 | 
			
		||||
                    wrappedCallData,
 | 
			
		||||
                    state.outputTokenAmount,
 | 
			
		||||
                    0,
 | 
			
		||||
                    state.to
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        if (success) {
 | 
			
		||||
            // Decode the output token amount on success.
 | 
			
		||||
            state.outputTokenAmount = abi.decode(resultData, (uint256));
 | 
			
		||||
        } else {
 | 
			
		||||
            revert("MultiplexUniswapV3::_multiHopSellUniswapV3/SWAP_FAILED");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -52,8 +52,10 @@ abstract contract NativeOrdersSettlement is
 | 
			
		||||
        bytes32 orderHash;
 | 
			
		||||
        // Maker of the order.
 | 
			
		||||
        address maker;
 | 
			
		||||
        // Taker of the order.
 | 
			
		||||
        address taker;
 | 
			
		||||
        // The address holding the taker tokens.
 | 
			
		||||
        address payer;
 | 
			
		||||
        // Recipient of the maker tokens.
 | 
			
		||||
        address recipient;
 | 
			
		||||
        // Maker token.
 | 
			
		||||
        IERC20TokenV06 makerToken;
 | 
			
		||||
        // Taker token.
 | 
			
		||||
@@ -82,6 +84,22 @@ abstract contract NativeOrdersSettlement is
 | 
			
		||||
        address sender;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Params for `_fillRfqOrderPrivate()`
 | 
			
		||||
    struct FillRfqOrderPrivateParams {
 | 
			
		||||
        LibNativeOrder.RfqOrder order;
 | 
			
		||||
        // The order signature.
 | 
			
		||||
        LibSignature.Signature signature;
 | 
			
		||||
        // Maximum taker token to fill this order with.
 | 
			
		||||
        uint128 takerTokenFillAmount;
 | 
			
		||||
        // The order taker.
 | 
			
		||||
        address taker;
 | 
			
		||||
        // Whether to use the Exchange Proxy's balance
 | 
			
		||||
        // of taker tokens.
 | 
			
		||||
        bool useSelfBalance;
 | 
			
		||||
        // The recipient of the maker tokens.
 | 
			
		||||
        address recipient;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @dev Fill results returned by `_fillLimitOrderPrivate()` and
 | 
			
		||||
    ///     `_fillRfqOrderPrivate()`.
 | 
			
		||||
    struct FillNativeOrderResults {
 | 
			
		||||
@@ -154,12 +172,14 @@ abstract contract NativeOrdersSettlement is
 | 
			
		||||
        returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
 | 
			
		||||
    {
 | 
			
		||||
        FillNativeOrderResults memory results =
 | 
			
		||||
            _fillRfqOrderPrivate(
 | 
			
		||||
                order,
 | 
			
		||||
                signature,
 | 
			
		||||
                takerTokenFillAmount,
 | 
			
		||||
                msg.sender
 | 
			
		||||
            );
 | 
			
		||||
            _fillRfqOrderPrivate(FillRfqOrderPrivateParams({
 | 
			
		||||
                order: order,
 | 
			
		||||
                signature: signature,
 | 
			
		||||
                takerTokenFillAmount: takerTokenFillAmount,
 | 
			
		||||
                taker: msg.sender,
 | 
			
		||||
                useSelfBalance: false,
 | 
			
		||||
                recipient: msg.sender
 | 
			
		||||
            }));
 | 
			
		||||
        (takerTokenFilledAmount, makerTokenFilledAmount) = (
 | 
			
		||||
            results.takerTokenFilledAmount,
 | 
			
		||||
            results.makerTokenFilledAmount
 | 
			
		||||
@@ -220,12 +240,14 @@ abstract contract NativeOrdersSettlement is
 | 
			
		||||
        returns (uint128 makerTokenFilledAmount)
 | 
			
		||||
    {
 | 
			
		||||
        FillNativeOrderResults memory results =
 | 
			
		||||
            _fillRfqOrderPrivate(
 | 
			
		||||
                order,
 | 
			
		||||
                signature,
 | 
			
		||||
                takerTokenFillAmount,
 | 
			
		||||
                msg.sender
 | 
			
		||||
            );
 | 
			
		||||
            _fillRfqOrderPrivate(FillRfqOrderPrivateParams({
 | 
			
		||||
                order: order,
 | 
			
		||||
                signature: signature,
 | 
			
		||||
                takerTokenFillAmount: takerTokenFillAmount,
 | 
			
		||||
                taker: msg.sender,
 | 
			
		||||
                useSelfBalance: false,
 | 
			
		||||
                recipient: msg.sender
 | 
			
		||||
            }));
 | 
			
		||||
        // Must have filled exactly the amount requested.
 | 
			
		||||
        if (results.takerTokenFilledAmount < takerTokenFillAmount) {
 | 
			
		||||
            LibNativeOrdersRichErrors.FillOrKillFailedError(
 | 
			
		||||
@@ -260,33 +282,36 @@ abstract contract NativeOrdersSettlement is
 | 
			
		||||
        returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
 | 
			
		||||
    {
 | 
			
		||||
        FillNativeOrderResults memory results =
 | 
			
		||||
            _fillLimitOrderPrivate(FillLimitOrderPrivateParams({
 | 
			
		||||
                order: order,
 | 
			
		||||
                signature: signature,
 | 
			
		||||
                takerTokenFillAmount: takerTokenFillAmount,
 | 
			
		||||
                taker: taker,
 | 
			
		||||
                sender: sender
 | 
			
		||||
            }));
 | 
			
		||||
            _fillLimitOrderPrivate(FillLimitOrderPrivateParams(
 | 
			
		||||
                order,
 | 
			
		||||
                signature,
 | 
			
		||||
                takerTokenFillAmount,
 | 
			
		||||
                taker,
 | 
			
		||||
                sender
 | 
			
		||||
            ));
 | 
			
		||||
        (takerTokenFilledAmount, makerTokenFilledAmount) = (
 | 
			
		||||
            results.takerTokenFilledAmount,
 | 
			
		||||
            results.makerTokenFilledAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Fill an RFQ order. Internal variant. ETH protocol fees can be
 | 
			
		||||
    ///      attached to this call. Any unspent ETH will be refunded to
 | 
			
		||||
    ///      `msg.sender` (not `sender`).
 | 
			
		||||
    /// @dev Fill an RFQ order. Internal variant.
 | 
			
		||||
    /// @param order The RFQ order.
 | 
			
		||||
    /// @param signature The order signature.
 | 
			
		||||
    /// @param takerTokenFillAmount Maximum taker token to fill this order with.
 | 
			
		||||
    /// @param taker The order taker.
 | 
			
		||||
    /// @param useSelfBalance Whether to use the ExchangeProxy's transient
 | 
			
		||||
    ///        balance of taker tokens to fill the order.
 | 
			
		||||
    /// @param recipient The recipient of the maker tokens.
 | 
			
		||||
    /// @return takerTokenFilledAmount How much maker token was filled.
 | 
			
		||||
    /// @return makerTokenFilledAmount How much maker token was filled.
 | 
			
		||||
    function _fillRfqOrder(
 | 
			
		||||
        LibNativeOrder.RfqOrder memory order,
 | 
			
		||||
        LibSignature.Signature memory signature,
 | 
			
		||||
        uint128 takerTokenFillAmount,
 | 
			
		||||
        address taker
 | 
			
		||||
        address taker,
 | 
			
		||||
        bool useSelfBalance,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        virtual
 | 
			
		||||
@@ -294,12 +319,14 @@ abstract contract NativeOrdersSettlement is
 | 
			
		||||
        returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
 | 
			
		||||
    {
 | 
			
		||||
        FillNativeOrderResults memory results =
 | 
			
		||||
            _fillRfqOrderPrivate(
 | 
			
		||||
            _fillRfqOrderPrivate(FillRfqOrderPrivateParams(
 | 
			
		||||
                order,
 | 
			
		||||
                signature,
 | 
			
		||||
                takerTokenFillAmount,
 | 
			
		||||
                taker
 | 
			
		||||
            );
 | 
			
		||||
                taker,
 | 
			
		||||
                useSelfBalance,
 | 
			
		||||
                recipient
 | 
			
		||||
            ));
 | 
			
		||||
        (takerTokenFilledAmount, makerTokenFilledAmount) = (
 | 
			
		||||
            results.takerTokenFilledAmount,
 | 
			
		||||
            results.makerTokenFilledAmount
 | 
			
		||||
@@ -387,7 +414,8 @@ abstract contract NativeOrdersSettlement is
 | 
			
		||||
            SettleOrderInfo({
 | 
			
		||||
                orderHash: orderInfo.orderHash,
 | 
			
		||||
                maker: params.order.maker,
 | 
			
		||||
                taker: params.taker,
 | 
			
		||||
                payer: params.taker,
 | 
			
		||||
                recipient: params.taker,
 | 
			
		||||
                makerToken: IERC20TokenV06(params.order.makerToken),
 | 
			
		||||
                takerToken: IERC20TokenV06(params.order.takerToken),
 | 
			
		||||
                makerAmount: params.order.makerAmount,
 | 
			
		||||
@@ -404,7 +432,7 @@ abstract contract NativeOrdersSettlement is
 | 
			
		||||
                params.order.takerAmount,
 | 
			
		||||
                params.order.takerTokenFeeAmount
 | 
			
		||||
            ));
 | 
			
		||||
            _transferERC20Tokens(
 | 
			
		||||
            _transferERC20TokensFrom(
 | 
			
		||||
                params.order.takerToken,
 | 
			
		||||
                params.taker,
 | 
			
		||||
                params.order.feeRecipient,
 | 
			
		||||
@@ -427,22 +455,14 @@ abstract contract NativeOrdersSettlement is
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Fill an RFQ order. Private variant. Does not refund protocol fees.
 | 
			
		||||
    /// @param order The RFQ order.
 | 
			
		||||
    /// @param signature The order signature.
 | 
			
		||||
    /// @param takerTokenFillAmount Maximum taker token to fill this order with.
 | 
			
		||||
    /// @param taker The order taker.
 | 
			
		||||
    /// @dev Fill an RFQ order. Private variant.
 | 
			
		||||
    /// @param params Function params.
 | 
			
		||||
    /// @return results Results of the fill.
 | 
			
		||||
    function _fillRfqOrderPrivate(
 | 
			
		||||
        LibNativeOrder.RfqOrder memory order,
 | 
			
		||||
        LibSignature.Signature memory signature,
 | 
			
		||||
        uint128 takerTokenFillAmount,
 | 
			
		||||
        address taker
 | 
			
		||||
    )
 | 
			
		||||
    function _fillRfqOrderPrivate(FillRfqOrderPrivateParams memory params)
 | 
			
		||||
        private
 | 
			
		||||
        returns (FillNativeOrderResults memory results)
 | 
			
		||||
    {
 | 
			
		||||
        LibNativeOrder.OrderInfo memory orderInfo = getRfqOrderInfo(order);
 | 
			
		||||
        LibNativeOrder.OrderInfo memory orderInfo = getRfqOrderInfo(params.order);
 | 
			
		||||
 | 
			
		||||
        // Must be fillable.
 | 
			
		||||
        if (orderInfo.status != LibNativeOrder.OrderStatus.FILLABLE) {
 | 
			
		||||
@@ -457,32 +477,41 @@ abstract contract NativeOrdersSettlement is
 | 
			
		||||
                LibNativeOrdersStorage.getStorage();
 | 
			
		||||
 | 
			
		||||
            // Must be fillable by the tx.origin.
 | 
			
		||||
            if (order.txOrigin != tx.origin && !stor.originRegistry[order.txOrigin][tx.origin]) {
 | 
			
		||||
            if (
 | 
			
		||||
                params.order.txOrigin != tx.origin &&
 | 
			
		||||
                !stor.originRegistry[params.order.txOrigin][tx.origin]
 | 
			
		||||
            ) {
 | 
			
		||||
                LibNativeOrdersRichErrors.OrderNotFillableByOriginError(
 | 
			
		||||
                    orderInfo.orderHash,
 | 
			
		||||
                    tx.origin,
 | 
			
		||||
                    order.txOrigin
 | 
			
		||||
                    params.order.txOrigin
 | 
			
		||||
                ).rrevert();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Must be fillable by the taker.
 | 
			
		||||
        if (order.taker != address(0) && order.taker != taker) {
 | 
			
		||||
        if (params.order.taker != address(0) && params.order.taker != params.taker) {
 | 
			
		||||
            LibNativeOrdersRichErrors.OrderNotFillableByTakerError(
 | 
			
		||||
                orderInfo.orderHash,
 | 
			
		||||
                taker,
 | 
			
		||||
                order.taker
 | 
			
		||||
                params.taker,
 | 
			
		||||
                params.order.taker
 | 
			
		||||
            ).rrevert();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Signature must be valid for the order.
 | 
			
		||||
        {
 | 
			
		||||
            address signer = LibSignature.getSignerOfHash(orderInfo.orderHash, signature);
 | 
			
		||||
            if (signer != order.maker && !isValidOrderSigner(order.maker, signer)) {
 | 
			
		||||
            address signer = LibSignature.getSignerOfHash(
 | 
			
		||||
                orderInfo.orderHash,
 | 
			
		||||
                params.signature
 | 
			
		||||
            );
 | 
			
		||||
            if (
 | 
			
		||||
                signer != params.order.maker &&
 | 
			
		||||
                !isValidOrderSigner(params.order.maker, signer)
 | 
			
		||||
            ) {
 | 
			
		||||
                LibNativeOrdersRichErrors.OrderNotSignedByMakerError(
 | 
			
		||||
                    orderInfo.orderHash,
 | 
			
		||||
                    signer,
 | 
			
		||||
                    order.maker
 | 
			
		||||
                    params.order.maker
 | 
			
		||||
                ).rrevert();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -491,26 +520,27 @@ abstract contract NativeOrdersSettlement is
 | 
			
		||||
        (results.takerTokenFilledAmount, results.makerTokenFilledAmount) = _settleOrder(
 | 
			
		||||
            SettleOrderInfo({
 | 
			
		||||
                orderHash: orderInfo.orderHash,
 | 
			
		||||
                maker: order.maker,
 | 
			
		||||
                taker: taker,
 | 
			
		||||
                makerToken: IERC20TokenV06(order.makerToken),
 | 
			
		||||
                takerToken: IERC20TokenV06(order.takerToken),
 | 
			
		||||
                makerAmount: order.makerAmount,
 | 
			
		||||
                takerAmount: order.takerAmount,
 | 
			
		||||
                takerTokenFillAmount: takerTokenFillAmount,
 | 
			
		||||
                maker: params.order.maker,
 | 
			
		||||
                payer: params.useSelfBalance ? address(this) : params.taker,
 | 
			
		||||
                recipient: params.recipient,
 | 
			
		||||
                makerToken: IERC20TokenV06(params.order.makerToken),
 | 
			
		||||
                takerToken: IERC20TokenV06(params.order.takerToken),
 | 
			
		||||
                makerAmount: params.order.makerAmount,
 | 
			
		||||
                takerAmount: params.order.takerAmount,
 | 
			
		||||
                takerTokenFillAmount: params.takerTokenFillAmount,
 | 
			
		||||
                takerTokenFilledAmount: orderInfo.takerTokenFilledAmount
 | 
			
		||||
            })
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        emit RfqOrderFilled(
 | 
			
		||||
            orderInfo.orderHash,
 | 
			
		||||
            order.maker,
 | 
			
		||||
            taker,
 | 
			
		||||
            address(order.makerToken),
 | 
			
		||||
            address(order.takerToken),
 | 
			
		||||
            params.order.maker,
 | 
			
		||||
            params.taker,
 | 
			
		||||
            address(params.order.makerToken),
 | 
			
		||||
            address(params.order.takerToken),
 | 
			
		||||
            results.takerTokenFilledAmount,
 | 
			
		||||
            results.makerTokenFilledAmount,
 | 
			
		||||
            order.pool
 | 
			
		||||
            params.order.pool
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -549,19 +579,28 @@ abstract contract NativeOrdersSettlement is
 | 
			
		||||
            // function if the order is cancelled.
 | 
			
		||||
                settleInfo.takerTokenFilledAmount.safeAdd128(takerTokenFilledAmount);
 | 
			
		||||
 | 
			
		||||
        // Transfer taker -> maker.
 | 
			
		||||
        _transferERC20Tokens(
 | 
			
		||||
            settleInfo.takerToken,
 | 
			
		||||
            settleInfo.taker,
 | 
			
		||||
            settleInfo.maker,
 | 
			
		||||
            takerTokenFilledAmount
 | 
			
		||||
        );
 | 
			
		||||
        if (settleInfo.payer == address(this)) {
 | 
			
		||||
            // Transfer this -> maker.
 | 
			
		||||
            _transferERC20Tokens(
 | 
			
		||||
                settleInfo.takerToken,
 | 
			
		||||
                settleInfo.maker,
 | 
			
		||||
                takerTokenFilledAmount
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            // Transfer taker -> maker.
 | 
			
		||||
            _transferERC20TokensFrom(
 | 
			
		||||
                settleInfo.takerToken,
 | 
			
		||||
                settleInfo.payer,
 | 
			
		||||
                settleInfo.maker,
 | 
			
		||||
                takerTokenFilledAmount
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Transfer maker -> taker.
 | 
			
		||||
        _transferERC20Tokens(
 | 
			
		||||
        // Transfer maker -> recipient.
 | 
			
		||||
        _transferERC20TokensFrom(
 | 
			
		||||
            settleInfo.makerToken,
 | 
			
		||||
            settleInfo.maker,
 | 
			
		||||
            settleInfo.taker,
 | 
			
		||||
            settleInfo.recipient,
 | 
			
		||||
            makerTokenFilledAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ abstract contract FixinTokenSpender {
 | 
			
		||||
    /// @param owner The owner of the tokens.
 | 
			
		||||
    /// @param to The recipient of the tokens.
 | 
			
		||||
    /// @param amount The amount of `token` to transfer.
 | 
			
		||||
    function _transferERC20Tokens(
 | 
			
		||||
    function _transferERC20TokensFrom(
 | 
			
		||||
        IERC20TokenV06 token,
 | 
			
		||||
        address owner,
 | 
			
		||||
        address to,
 | 
			
		||||
@@ -87,6 +87,60 @@ abstract contract FixinTokenSpender {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Transfers ERC20 tokens from ourselves to `to`.
 | 
			
		||||
    /// @param token The token to spend.
 | 
			
		||||
    /// @param to The recipient of the tokens.
 | 
			
		||||
    /// @param amount The amount of `token` to transfer.
 | 
			
		||||
    function _transferERC20Tokens(
 | 
			
		||||
        IERC20TokenV06 token,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        require(address(token) != address(this), "FixinTokenSpender/CANNOT_INVOKE_SELF");
 | 
			
		||||
 | 
			
		||||
        assembly {
 | 
			
		||||
            let ptr := mload(0x40) // free memory pointer
 | 
			
		||||
 | 
			
		||||
            // selector for transfer(address,uint256)
 | 
			
		||||
            mstore(ptr, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
            mstore(add(ptr, 0x04), and(to, ADDRESS_MASK))
 | 
			
		||||
            mstore(add(ptr, 0x24), amount)
 | 
			
		||||
 | 
			
		||||
            let success := call(
 | 
			
		||||
                gas(),
 | 
			
		||||
                and(token, ADDRESS_MASK),
 | 
			
		||||
                0,
 | 
			
		||||
                ptr,
 | 
			
		||||
                0x44,
 | 
			
		||||
                ptr,
 | 
			
		||||
                32
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            let rdsize := returndatasize()
 | 
			
		||||
 | 
			
		||||
            // Check for ERC20 success. ERC20 tokens should return a boolean,
 | 
			
		||||
            // but some don't. We accept 0-length return data as success, or at
 | 
			
		||||
            // least 32 bytes that starts with a 32-byte boolean true.
 | 
			
		||||
            success := and(
 | 
			
		||||
                success,                             // call itself succeeded
 | 
			
		||||
                or(
 | 
			
		||||
                    iszero(rdsize),                  // no return data, or
 | 
			
		||||
                    and(
 | 
			
		||||
                        iszero(lt(rdsize, 32)),      // at least 32 bytes
 | 
			
		||||
                        eq(mload(ptr), 1)            // starts with uint256(1)
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            if iszero(success) {
 | 
			
		||||
                returndatacopy(ptr, 0, rdsize)
 | 
			
		||||
                revert(ptr, rdsize)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets the maximum amount of an ERC20 token `token` that can be
 | 
			
		||||
    ///      pulled from `owner` by this address.
 | 
			
		||||
    /// @param token The token to spend.
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user